In a previous log, I covered the hardware part of measuring mains frequency — this time it’s all about the software.
The goal: measure the local 50 Hz mains frequency in near real time, using a Raspberry Pi, a zero-crossing detector, and the pigpio library for precise timing. The Pi counts the signal edges, keeps timestamps in a circular buffer, corrects time drift using a 1 Hz PPS reference from a GPS receiver, and streams the calculated frequency over WebSocket.
The source code is on Github
How It Works
The core idea is simple:
- Each zero-crossing from the mains signal generates an interrupt on a GPIO pin.
- pigpio gives us a timestamp (in microseconds) for every edge.
- We store the last N timestamps (e.g. 1000 samples).
- Once per second (triggered by the GPS PPS), we compute:

- DeltaT : elapsed time between first and last samples
- base_time: correction from the 1 Hz PPS reference
- Division by 2 → because the zero-crossing detector triggers twice per cycle (positive + negative)
- The result (current_frequency) is broadcast as JSON via a WebSocket server.
Core Components
- pigpio handles GPIO interrupts and timestamps (run sudo pigpiod before the script).
- Two GPIO inputs:
- GPIO_INPUT_SIGNAL = 24: the grid frequency signal (from your sensor)
- GPIO_1HZ = 21: the GPS PPS (Pulse-Per-Second) reference
- Circular buffer (deque) keeps the most recent timestamps.
- Callbacks process incoming edges:
- cb_grid_signal: filters noise (debounce ~8 ms) and stores timestamps.
- cb_1Hz: triggered once per second → computes the average frequency using all samples in the buffer.
Key Details
- Debounce filtering on 50Hz input. The callback ignores edges that arrive too close together (less than 8 ms). That prevents false triggers from electrical noise.
- Reference correction (GPS PPS) The 1 Hz signal comes from the GPS receiver’s PPS output, which is accurate to better than one microsecond. This makes the Pi’s local clock drift essentially irrelevant — every second is locked to GPS time, giving you sub-ppm stability for the frequency measurement.
Real-Time Streaming
The script starts a WebSocket server (ws://0.0.0.0:8765) and sends an update once per second:
{
"time_stamp": 1730362540.12,
"last_update_time": 1730362539.89,
"frequency": "50.013"
}
Any WebSocket client (Python, Node.js, browser dashboard, etc.) can subscribe to display or log the frequency over time.
Example Console Output
Base time: 1.000001 seconds (from GPS PPS)
Frequency: 50.012345 Hz (at 1730362540.123456 seconds) [1000 samples; Measured: 100.024690 Hz]
WebSocket server started at ws://0.0.0.0:8765
Client connected from IP: 192.168.1.42
(Measured: 100 Hz = zero-crossings/sec → divide by 2 → ~50 Hz mains frequency.)
Summary
This small Python script combines hardware-level timing from pigpio with a GPS-disciplined PPS reference and asynchronous streaming via WebSocket. It’s a neat way to visualize how the power grid frequency fluctuates in real time — and a solid foundation for any GPS-synchronized power-quality or IoT monitoring setup.
Détourner
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.