Muawwiz Ghani
Building industrial SCADA systems for motor fleet monitoring — safety-critical firmware, EMA sensor pipelines, and AI-powered diagnostics.
Mohammed Muawwiz Ghani
I'm an Electronics and Communication Engineering student with a strong interest in Front-End Engineering, Embedded Systems, and Artificial Intelligence. I enjoy building responsive, user-centric web applications while exploring how software and hardware come together to create intelligent, real-world solutions.
My experience includes developing modern web interfaces, working with C programming for embedded systems, and building a strong foundation in AI and cloud technologies through continuous learning and hands-on projects. I focus on writing clean, maintainable code and creating digital experiences that are both visually engaging and technically efficient.
Beyond coding, I enjoy solving engineering challenges, learning emerging technologies, and continuously improving my technical and problem-solving skills. I believe the best technology combines thoughtful design with reliable engineering to deliver meaningful user experiences.
I am currently seeking internship opportunities where I can contribute to impactful projects, collaborate with experienced professionals, and grow as a software and engineering professional.
Core Interests: Front-End Development • Embedded Systems • UI/UX Design • Artificial Intelligence • Cloud Technologies • IoT
Let's connect to discuss technology, innovation, and opportunities to build the next generation of digital solutions.
SmartMotorX
A full industrial SCADA platform monitoring a 6-motor fleet across 3 production lines (LINE-A/B/C). Each motor node reports temperature, vibration (g), current (A), RPM, power (kW), load %, bearing health, and insulation health at 1-second intervals. The system enforces 5 reliability pillars: fail-safe auto-trip at configurable setpoints (default 90°C / 5g), EMA sensor filtering (α=0.18, 30% step-clamp), offline data buffer with cloud sync on restore, sensor fault detection (NaN rejection + stuck-sensor flagging after 8 identical consecutive readings), and operator confirmation logic gating all motor control actions. Compliant with IEC 61511 / IEC 62061 — SIL-2. Integrated with Claude Sonnet 4 for live AI diagnostics and fleet scan. Python-generated self-contained HTML SCADA runtime — no server required.
Operational Evidence · Verified Artifacts
python3 SmartMotorX.py → produces SmartMotorX.html, a fully operational SCADA runtime. No server, no dependencies, no build step. 688 lines of Python generating ~600KB of production HTML + JS. Zero-dependency deployment.EMA_A=0.18 · MAX_S=0.30 · STUCK=8 · HIST=60 — exact constants from line 343 of SmartMotorX.py. All arch note descriptions match the actual implementation, not generalised descriptions.claude-sonnet-4-20250514 on fleet scan and chat. System prompt injects live motor telemetry, active alarms, and setpoints per call. Structured JSON response parsed and rendered as risk-prioritised findings. Offline fallback message implemented.Selected work
Full industrial SCADA platform monitoring a 6-motor fleet (MTR-001 through MTR-006) across 3 production lines. 5 reliability pillars: EMA sensor filtering (α=0.18), fail-safe auto-trip (90°C/5g setpoints), offline data buffer, NaN/stuck-sensor fault detection, and confirmation-gated control. IEC 61511 / IEC 62061 / SIL-2. Integrated Claude Sonnet 4 AI diagnostics with structured fleet scan. Python-generated self-contained SCADA runtime.
XGBoost-based stock forecasting platform with NLP sentiment scoring on live financial news, Shariah compliance screening, and portfolio P&L tracking. FastAPI sidecar handles async inference; Supabase manages auth with tier-gated access. Built solo in 8 weeks.
Multi-tenant SaaS platform with RBAC, attendance tracking, a task workflow engine using state machine logic, calling management, and real-time analytics. Delivered end-to-end: architecture, backend, database, and deployment.
ANPR pipeline using OpenCV contour detection and OCR — edge-preprocessed frames, Canny detection, perspective correction, and OCR inference optimized for real-world lighting variance.
Full-service digital agency — production web apps, AWS infrastructure, AI automation workflows, and IoT consulting. Leading all technical decisions from architecture to deployment across client projects.
Embedded firmware development at Pemchip Infotech. Wrote interrupt-driven sensor drivers, debugged I²C/SPI communication faults with a logic analyzer, and validated hardware behavior under edge-case inputs in a live industrial test environment. Delivered a working I²C/SPI sensor interface module — driver code, wiring schematics, and test bench documentation — integrated into a production board at client site.
Technical domains
Experience & timeline
Awards & Certifications
Architecture notes
Implementation decisions, real constants, and exact code from SmartMotorX.py — EMA filter, sensor fault detection, 5 reliability pillars, IEC 61511/SIL-2 compliance, and AI diagnostics.
Raw sensor readings from industrial motors contain high-frequency noise — thermal gradients, vibration coupling, EMI from motor drives. Passing raw values to the fault-detection layer generates false trips. An Exponential Moving Average filter with α=0.18 was chosen after testing: lower α values (0.05–0.10) smoothed too aggressively and masked real thermal events; higher values (0.30+) let too much noise through. 0.18 gives a 5–6 sample effective window — fast enough to track real motor heating, slow enough to reject single-sample spikes.
The 30% step clamp (`MAX_S=0.30`) addresses a specific failure mode: if a sensor reading jumps more than 30% of its current value in a single tick, the clamp limits the accepted delta before EMA is applied. This prevents a corrupted sensor packet from propagating a large false reading into the smoothed value — even a single NaN or out-of-range reading is rejected before it can trigger a trip.
// EMA filter — exact implementation (SmartMotorX.py)
const EMA_A=0.18, MAX_S=0.30;
function ema(prev, raw) {
if (raw===null || isNaN(raw)) return prev; // NaN guard
const maxStep = prev*MAX_S || 5;
const delta = Math.abs(raw - prev);
const clamped = delta > maxStep && prev > 0
? prev + Math.sign(raw-prev)*maxStep : raw;
return +(prev + EMA_A*(clamped - prev)).toFixed(3);
}
Two distinct fault modes are detected. NAN_FAULT: if a sensor reading is null or NaN (power loss, disconnected probe, ADC failure), the EMA filter returns the last good value but flags the motor with a sensor fault status — the dashboard shows a ⚠ SENSOR badge and the fault is logged to the alarm list. The motor is not auto-tripped on NaN alone (a disconnected sensor shouldn't shut down a motor) but the operator is alerted.
STUCK_SENSOR: if the last 8 consecutive readings are within 0.01 of each other, the sensor is flagged as stuck — a common failure mode where a sensor freezes at its last valid reading. This is more dangerous than NaN because it silently reports a "normal" value while the motor may be overheating. The 8-sample window (`STUCK=8`) was chosen to avoid false flags on stable operating conditions while catching actual stuck sensors within ~8 seconds.
// Sensor fault detection — exact implementation
const STUCK=8; // 8 samples within 0.01 = stuck
function sfault(history, current) {
if (current===null || isNaN(current)) return 'NAN_FAULT';
if (history.length >= STUCK) {
const recent = history.slice(-STUCK);
if (recent.every(v => Math.abs(v - recent[0]) < 0.01))
return 'STUCK_SENSOR';
}
return null; // no fault
}
The system uses a two-zone approach: a warning zone (92% of temp setpoint OR 78% of vib setpoint) and a trip zone (at or above setpoint). Default setpoints are 90°C temperature / 5g vibration, operator-configurable via the Control page. At warning zone, the motor status changes to `warning` and a WARN alarm is raised — no action taken, operator is alerted. At trip zone, the motor is immediately de-energised, status set to `fault`, and a CRIT alarm is auto-generated.
Four trip reasons are tracked in the alarm history: OVER_TEMP, OVER_VIB, ESTOP, SENSOR_FAULT. Each alarm includes timestamp, motor tag, and whether it was an auto-trip or manual. The current live fleet has MTR-003 (COOLING PUMP #2) tripped at 98.7°C on OVER_TEMP, MTR-004 (COMPRESSOR DR.) in warning at 83.5°C / 3.9g — both above the 92% warning threshold.
The IEC 61511 standard requires that safety instrumented functions operate independently of the control system. The auto-trip layer is intentionally separated from the control logic — it cannot be bypassed by any operator command while active, only reset after manual fault acknowledgement.
IEC 62061 requires that safety-related control functions include measures to prevent unintended actuation. In SmartMotorX, every motor control action — START, STOP, RESET, EMERGENCY STOP — is gated by a confirmation overlay before execution. This prevents mis-clicks, accidental touch input on mobile, and operator error under stress. Emergency Stop requires double confirmation because its effect (all drives tripped, system locked) requires manual reset to reverse.
The confirmation gate is implemented as a modal overlay with action-specific warning text. For ESTOP: "This will trip ALL motors immediately. Requires manual reset." For START: "Motor will be energised and start running." The operator must read and confirm the specific consequence — not just click OK on a generic dialog. This is the `reqA()` → `confirmGate()` flow in the codebase, and it cannot be bypassed programmatically.
When the system transitions to offline mode (network loss, cloud unreachable), telemetry continues accumulating locally. The offline buffer is a local queue — readings are not dropped, they are held with their original timestamps. On reconnect, the buffer flushes to the historian/cloud with a `buffered: true` flag, preserving the full data continuity of the time-series record.
The OFFLINE BUFFER status is visible in both the PLC/Network Status panel (Diagnostics page) and the status bar at the bottom of every page. When offline, the status bar shows NET: OFFLINE in amber. All 5 reliability pillars remain active during offline mode — auto-trip, EMA filtering, sensor fault detection, and confirmation logic all operate independently of cloud connectivity. This is a design constraint: the safety layer must not depend on the communication layer.
The AI diagnostics panel calls claude-sonnet-4-20250514 via the Anthropic API with a system prompt that includes the full live telemetry context: all 6 motor states, current temp/vib/health values, active alarms, and current setpoints. The model is instructed to respond in under 120 words, formatted as severity → finding → recommendation.
The Fleet Scan feature sends a structured JSON request and expects a structured JSON response: [{"{"}tag, sev, finding, action{"}"}]. The response is parsed and rendered as a prioritised risk list. The chat interface maintains full conversation history per session, passing all prior turns on each call so the model has context across multi-turn diagnostic sessions.
Offline fallback is implemented: if the API call fails for any reason, the system displays "⚠ AI offline — local protection unaffected (Pillar 3 active)" — making it explicit that AI unavailability does not affect any safety function. The AI layer is advisory only; no safety-critical action is gated on AI response.
// Fleet scan — structured JSON request
{
"model": "claude-sonnet-4-20250514",
"system": "...live telemetry context + setpoints + active alarms...",
"messages": [{
"role": "user",
"content": "Run fleet diagnostic. Top 3 issues by risk. JSON only: [{tag,sev,finding,action}]"
}]
}
IEC 61511 covers Safety Instrumented Systems in the process industry — it defines how safety functions (like auto-trip on over-temperature) must be designed, validated, and operated. IEC 62061 covers safety of machinery control systems. SIL-2 (Safety Integrity Level 2) requires a probability of dangerous failure on demand between 10⁻³ and 10⁻² per hour — meaning the safety function must fail less than once per 100–1000 hours of operation.
In SmartMotorX, compliance is achieved through: independent auto-trip logic that cannot be bypassed by control actions, confirmation gating on all actuations, watchdog timer monitoring all PLCs at 1-second intervals, sensor fault detection with independent flagging, and offline operation maintaining all safety functions without cloud dependency. These are not aspirational targets — they are the designed operating constraints of the system, enforced in code.
During early integration testing, the EMA filter was producing unexpected value spikes on the motor health metric. The symptom: health% would occasionally jump +15 points in a single tick before smoothing back down. Initial suspicion was a simulation noise issue, but the EMA_A=0.18 with MAX_S=0.30 should have clamped any step above 30%.
Root cause: the health metric was being calculated after EMA was applied to temp/vib, using the raw (pre-EMA) noise values in the health formula rather than the smoothed values. The health calculation was reading from the wrong variable. Fix: health is now computed from the EMA-smoothed temp/vib values, not the raw tick values. The spike behaviour disappeared immediately.
This is why the architecture enforces a clear pipeline order: raw reading → EMA filter → fault detection → health calculation → alarm evaluation. Any out-of-order access to raw values produces subtle bugs that look like noise but are actually pipeline ordering errors. The pipeline order is now explicit in the codebase, not implicit in execution sequence.
The current fault detection layer uses static setpoints: temperature above 90°C or vibration above 5g triggers auto-trip. This is v0 — deliberately simple, immediately testable, and correct for a system that doesn't yet have enough operating history to establish per-motor baselines. The existing 60-sample rolling history buffer (`HIST=60`) was designed from day one to support statistical detection once baselines are established.
v1 target — rolling z-score: Each motor maintains a rolling mean and standard deviation over its HIST buffer. An alert fires when a reading deviates more than 3σ from that motor's own recent baseline. MTR-001 (FEED PUMP, 14,320 hours) and MTR-003 (COOLING PUMP, 22,100 hours) will have different normal operating temperatures — per-motor baselines detect anomalies that global thresholds miss.
v2 target — EWMA + bearing FFT: Exponentially weighted moving average on bearing health % for trend projection, combined with FFT analysis of vibration time-series to detect bearing fault harmonics (1× and 2× shaft speed signatures). MTR-004's bearing health at 65% and MTR-006 at 72% are already candidates for this analysis.
The current simulation runs 6 motors at 1-second ticks in a single JS engine — well within browser performance limits. At 50 motors, the JS simulation loop remains fast (50 EMA calculations + 50 health updates per tick is microseconds), but the DOM render — particularly the Motor Fleet grid — becomes a bottleneck. The fix is virtual scrolling or paginating the fleet grid, not the simulation engine.
At 500 motors in a real deployment, the architecture changes fundamentally. The in-browser JS simulation is replaced by real PLC/sensor data via a WebSocket or polling API. The historian server (already in the PLC network status as a real component) handles time-series storage. The SCADA runtime becomes a read-only dashboard consuming from the historian, with the Lambda/DynamoDB pipeline handling write throughput. The current architecture's component boundaries — edge → transport → cloud → dashboard — are already drawn to support this transition without redesign.
PLC scalability: the current 3-PLC design (PLC-01 LINE-A, PLC-02 LINE-B, PLC-03 LINE-C) maps 2 motors per PLC. At 500 motors with 2 motors/PLC, that's ~167 PLCs — standard for a large plant. PROFINET at 100Mbps handles this comfortably; the historian server is the first real bottleneck, addressable with a dedicated time-series database (InfluxDB / TimescaleDB).