Difference between revisions of "MainsFrequency"

From RevSpace
Jump to navigation Jump to search
m (done!)
(Reboot)
(35 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
   {{Project
 
   {{Project
 
   |Name=MainsFrequency
 
   |Name=MainsFrequency
   |Picture=dropper_opto.png
+
   |Picture=netfrequentiemeter.jpg
 
   |Omschrijving=A simple mains frequency counter
 
   |Omschrijving=A simple mains frequency counter
 
   |Status=Completed
 
   |Status=Completed
Line 8: Line 8:
 
   }}
 
   }}
  
 +
== Introduction ==
 +
[[File:power_dip_peak.png|800px|top|dips and peaks on the hour]]
  
== Introduction ==
+
This page is about a simple circuit for measuring the frequency of grid power, publishing it over MQTT.
This page is about creating a simple frequency counter for mains power and publish the frequency over MQTT.
 
  
 
It's based on the Arduino platform, using an ESP8266 to do the wifi/network/MQTT stuff.
 
It's based on the Arduino platform, using an ESP8266 to do the wifi/network/MQTT stuff.
 
 
The frequency measurement principle is to count the number of mains cycles in a fixed period.
 
The frequency measurement principle is to count the number of mains cycles in a fixed period.
To get a resolution of 0.01 Hz, the period is 100 seconds.
+
To get a resolution of 0.01 Hz, we count for approximately 5000 cycles at 100 Hz, so the period is 50 seconds.
 
 
 
To keep the measurement circuit relatively safe, only a part of the electronics is actually connected to mains
 
To keep the measurement circuit relatively safe, only a part of the electronics is actually connected to mains
 
and the low-voltage side is isolated with an optocoupler.
 
and the low-voltage side is isolated with an optocoupler.
  
[https://revspace.nl/grafiekjes/d/3deykmVmz/power?orgId=1 Graph of the AC main frequency as measured at RevSpace]
+
=== Reboot ===
 +
Instead of just counting pulses from zero-crossings, we could sample the actual 50 Hz waveform and do autocorrelation, an FFT (or similar) for example.
  
== Status ==
+
Perhaps get the following stuff out of it:
Received/collected most of the parts:
+
* get more accurate frequency measurement
* 100 nF X2 capacitors.
+
* get more responsive frequency measurement, i.e. instantaneous value, not a running average over 50 seconds.
* piece of breadboard
+
* determine "purity" of the waveform, i.e. how much it deviates from a pure sine wave
* connectors (we have those at the space)
 
* got a polyfuse from [https://revspace.nl/Benadski User:benadski]
 
* optocoupler (forgot the part number)
 
  
== Hardware ==
+
A suitable module for relatively safely sampling the mains voltage could be this
The plan is to use an ESP8266 because it can easily publish the measured value over wifi/MQTT.
+
[https://nl.aliexpress.com/item/1005001499454445.html ZMPT101B] module.
 +
It contains a transformer and an op-amp circuit.
  
I'm looking at various ways of actually getting the mains signal into the microcontroller.
+
More information about this module:
The simplest way appears to be an optocoupler in series with R, C and a diode anti-parallel over the optocoupler's LED.
+
* https://www.electroschematics.com/voltage-sensor/
  
* could be a transformer, like [http://jorisvr.nl/article/grid-frequency shown here]. Safe but bulky.
+
Proposed algorithm for getting accurate instantaneous frequency out of it:
* could be a capacitive/resistive dropper with an optocoupler, like [https://forum.arduino.cc/index.php?PHPSESSID=mbv69trkc089m30l4shlo4cl97&topic=192063.msg1419646#msg1419646 the circuit in this post] (note: this circuit is for 120V!)
+
* Sample the mains frequency waveform at 10 kHz (400 samples per mains cycle nominally) during approximately one second
* <s>could be [https://nl.aliexpress.com/item/ding/32828199766.html this thing] from aliexpress</s>
+
* Determine the median, lower and upper quartiles of the waveform, and shift data so its values are symmetrically around zero
 +
* Calculate zero crossings by doing linear regression to find the zero-crossing of the wave in the region around the zero crossing (in between the quartile values), this gives sub-sample time resolution
 +
* The linear regression can be run as a kind of state machine, just keeping track of sum(x), sum(y), sum(x*x), sum(x*y) is enough to perform a linear regression at any time
 +
* Do this over the approximately 50 cycles contained in the one second data and determine average frequency
 +
-> this should give about 1 millihertz frequency resolution in one second
  
How it's finally built:
+
Implementation I intend to use:
* Used the Aliexpress circuit, removed the capacitor and put heatshrink wrap around it. This makes it a 100 Hz signal.
+
* an STM32 ("blue pill") does the analog stuff, sampling the mains frequency wave form
* Used a nodemcu v3 instead of a Wemos D1 mini (this was what was available at the hacker space)
+
* an ESP8266 handles communication over WiFi, controls the STM32
* pin D4: used by the built-in LED
+
* the STM32 and the ESP8266 communicate over a simple serial line, 3V, TTL, perhaps even simple ASCII so it can be debugged easily during development
* pin D5: mains input
+
* the STM32 samples in a "simple" data capture mode, using a timer driven with crystal accuracy, one interrupt per sample
 +
* the STM32 runs the interpolation algoritm, calculate things to 1 microsecond resolution
  
=== Aliexpress circuit ===
+
== Status ==
[[File:ali_230v_schema.png|thumb|right|https://nl.aliexpress.com/item/ding/32828199766.html circuit]]
+
[[File:blaasop.jpg|thumb|right|oops]]
 +
It works! It blew itself up after being moved to a different casing, but was fixed!
  
The [https://nl.aliexpress.com/item/ding/32828199766.html circuit] as reverse engineered is shown on the right.
+
See [https://revspace.nl/grafiekjes/d/3deykmVmz/power?orgId=1 Live view of the AC main frequency as measured at RevSpace]
Basically, the mains is rectified through a high-value high-power resistor and a bridge rectifier, then stabilized with a zener to 5.1V,
 
which lights the green LED and activates the optocoupler to pull the output low when mains is present.
 
The 47k pull-up makes the signal high when there is no mains power available.
 
  
So this circuit doesn't actually do what I want: the opto is activated all the time when 230V is present, it's not flashing at 50 Hz.
+
Compare it with:
 +
* [https://www.swissgrid.ch/en/home/operation/grid-data/current-data.html#frequency Swiss grid frequency graph]
 +
* [http://www.mainsfrequency.com/ mains frequency]. NOTE: don't leave this site open for too long, it'll ban your IP for 'traffic exceeded' reasons!
  
2018-05-17: If we remove the capacitor from the board, the AC is no longer smoothed and we should see a 100 Hz waveform coming from the optocoupler, maybe worth a try?
+
Possible future enhancements:
 +
* Display the frequency on a nice little OLED screen (or something similar)
  
=== Circuit ===
+
== Hardware ==
[[File:dropper_opto.png|thumb|right|The circuit I plan to use]]
+
[[File:ali_230v_module.jpg|thumb|right|the mains sensing module from Aliexpress]]
The circuit on the right is the one I plan to use.
+
[[File:ali_230v_schema.png|thumb|right|reverse engineered schematic of mains sensing module]]
 +
The microcontroller is an ESP8266 because it can easily publish the measured value over wifi/MQTT.
  
The capacitor drops most of the voltage. It should be an x-rated type, you can tell by the marking "X2".
+
The circuit to sense the frequency is [https://nl.aliexpress.com/item/ding/32828199766.html this mains module] sold on Aliexpress, with a small modification.
The resistor (1k or so) limits the inrush current.
+
The modification is that the smoothing capacitor has been removed, resulting in a 100 Hz signal going into the optocoupler (a pulse during each zero crossing).
The diode (1N4148 probably) protects the optocoupler (4N27 or 4N35) from reverse voltage.
 
The resistor on the right is a pull-up resistor, possibly not even needed if I use the built-in pull-up of the microcontroller.
 
  
The X-capacitor, even though it is designed for connection to mains voltage and referred to as a "safety capacitor", has a failure mode to most likely fail as a short.
+
How things are wired:
This means additional components are needed to make it actually safe to use in this circuit, like a fuse in series that blows when the capacitor fails.
+
* Used the modified Aliexpress circuit.
 
+
* Used a nodemcu v3 for the ESP8266 (this was what was available at the hacker space)
At 50 Hz, the capacitor has a reactance of about 32 kOhm, so the LED current should be something like 230V/32kOhm = 7 mA, well below the maximum of 60 mA mentioned in the data sheet.
+
* Mains power going into the mains detection module (left part of the schematic)
Possibly, a bleeder resistor could be put parallel to the capacitor, to make sure that the capacitor doesn't stay charged when the circuit is powered off.
+
* ESP8266 pin 3.3V: connected to the pull-up on the mains module output (top in schematic - green wire)
Power consumed in the series resistor is R*I*I so about 50 mW, so we can probably use the very common 250 mW type there.
+
* ESP8266 pin D5: connected to the optocoupler output on the mains module output (middle in schematic - brown wire)
 +
* ESP8266 pin GND: connected to the GND pin on the mains module output (bottom in schematic - yellow wire)
 +
* put in a plastic enclosure with warning labels
  
 
== Software ==
 
== Software ==
The Arduino source is available on [https://github.com/bertrik/mainsfreq the github page], but has not been tested on actual hardware yet.
+
The Arduino source is available on [https://github.com/bertrik/mainsfreq the github page].
  
You can build it with platformio ('pio run').
+
An interrupt is generated for each falling edge of the signal coming out of the optocoupler. This happens during the zero crossing, so twice each mains cycle, 100 times per second.
 +
The working principle is that we count the number of interrupts in the past 50 second period, this should nominally be 5000.
 +
An interrupt count is done every second and the result is put in a circular buffer of 50 bins (one for each second).
 +
The sum of these 50 bins divided by 100 then provides the average frequency over the past 50 seconds.
  
The working principle is that we count the number of cycles in a 100 second period, this should nominally be 5000.
+
A simple filter suppresses spurious pulses: when an interrupt occurs, the counter is increased only when more than 8 ms has passed since the previous zero crossing.
A cycle count is done every second and the result is put in a circular buffer of 100 bins.
+
Without this filter, the frequency was typically about 2 Hz too high.
The average of these 100 bins then provides the frequency over the past 100 seconds.
 
The circular buffer is initialized with a value of 50 for each bin.
 
  
 
The accuracy of the frequency count depends on the accuracy of the crystal (among other things).
 
The accuracy of the frequency count depends on the accuracy of the crystal (among other things).
To get 0.01 Hz error at 50 Hz, we need an time reference with at most 0.01 / 50 = 200 ppm frequency deviation.
+
To get 0.01 Hz error at 50 Hz, we need a time reference with at most 0.01 / 50 = 200 ppm frequency deviation.
This is probably doable with the built-in crystal on a typical ESP8266 board (like a Wemos D1 mini).
+
This is doable with the crystal on a typical ESP8266 board (which has an accuracy of 25 ppm or so).
 +
 
 +
You can build the software with platformio ('pio run'), it uses libraries WifiManager and PubSubClient.
  
 
== References ==
 
== References ==
Online [http://www.mainsfrequency.com/ mains frequency]. NOTE: don't leave this site open for too long, it'll ban your IP for 'traffic exceeded' reasons!
 
 
 
Other interesting projects/documents:
 
Other interesting projects/documents:
 
* http://www.palebluedot.nl/jml/projects/arduino/43-measure-mains-power-frequency
 
* http://www.palebluedot.nl/jml/projects/arduino/43-measure-mains-power-frequency

Revision as of 11:32, 6 November 2022

Project MainsFrequency
Netfrequentiemeter.jpg
A simple mains frequency counter
Status Completed
Contact bertrik, Peetz0r
Last Update 2022-11-06

Introduction

dips and peaks on the hour

This page is about a simple circuit for measuring the frequency of grid power, publishing it over MQTT.

It's based on the Arduino platform, using an ESP8266 to do the wifi/network/MQTT stuff. The frequency measurement principle is to count the number of mains cycles in a fixed period. To get a resolution of 0.01 Hz, we count for approximately 5000 cycles at 100 Hz, so the period is 50 seconds. To keep the measurement circuit relatively safe, only a part of the electronics is actually connected to mains and the low-voltage side is isolated with an optocoupler.

Reboot

Instead of just counting pulses from zero-crossings, we could sample the actual 50 Hz waveform and do autocorrelation, an FFT (or similar) for example.

Perhaps get the following stuff out of it:

  • get more accurate frequency measurement
  • get more responsive frequency measurement, i.e. instantaneous value, not a running average over 50 seconds.
  • determine "purity" of the waveform, i.e. how much it deviates from a pure sine wave

A suitable module for relatively safely sampling the mains voltage could be this ZMPT101B module. It contains a transformer and an op-amp circuit.

More information about this module:

Proposed algorithm for getting accurate instantaneous frequency out of it:

  • Sample the mains frequency waveform at 10 kHz (400 samples per mains cycle nominally) during approximately one second
  • Determine the median, lower and upper quartiles of the waveform, and shift data so its values are symmetrically around zero
  • Calculate zero crossings by doing linear regression to find the zero-crossing of the wave in the region around the zero crossing (in between the quartile values), this gives sub-sample time resolution
  • The linear regression can be run as a kind of state machine, just keeping track of sum(x), sum(y), sum(x*x), sum(x*y) is enough to perform a linear regression at any time
  • Do this over the approximately 50 cycles contained in the one second data and determine average frequency

-> this should give about 1 millihertz frequency resolution in one second

Implementation I intend to use:

  • an STM32 ("blue pill") does the analog stuff, sampling the mains frequency wave form
  • an ESP8266 handles communication over WiFi, controls the STM32
  • the STM32 and the ESP8266 communicate over a simple serial line, 3V, TTL, perhaps even simple ASCII so it can be debugged easily during development
  • the STM32 samples in a "simple" data capture mode, using a timer driven with crystal accuracy, one interrupt per sample
  • the STM32 runs the interpolation algoritm, calculate things to 1 microsecond resolution

Status

oops

It works! It blew itself up after being moved to a different casing, but was fixed!

See Live view of the AC main frequency as measured at RevSpace

Compare it with:

Possible future enhancements:

  • Display the frequency on a nice little OLED screen (or something similar)

Hardware

the mains sensing module from Aliexpress
reverse engineered schematic of mains sensing module

The microcontroller is an ESP8266 because it can easily publish the measured value over wifi/MQTT.

The circuit to sense the frequency is this mains module sold on Aliexpress, with a small modification. The modification is that the smoothing capacitor has been removed, resulting in a 100 Hz signal going into the optocoupler (a pulse during each zero crossing).

How things are wired:

  • Used the modified Aliexpress circuit.
  • Used a nodemcu v3 for the ESP8266 (this was what was available at the hacker space)
  • Mains power going into the mains detection module (left part of the schematic)
  • ESP8266 pin 3.3V: connected to the pull-up on the mains module output (top in schematic - green wire)
  • ESP8266 pin D5: connected to the optocoupler output on the mains module output (middle in schematic - brown wire)
  • ESP8266 pin GND: connected to the GND pin on the mains module output (bottom in schematic - yellow wire)
  • put in a plastic enclosure with warning labels

Software

The Arduino source is available on the github page.

An interrupt is generated for each falling edge of the signal coming out of the optocoupler. This happens during the zero crossing, so twice each mains cycle, 100 times per second. The working principle is that we count the number of interrupts in the past 50 second period, this should nominally be 5000. An interrupt count is done every second and the result is put in a circular buffer of 50 bins (one for each second). The sum of these 50 bins divided by 100 then provides the average frequency over the past 50 seconds.

A simple filter suppresses spurious pulses: when an interrupt occurs, the counter is increased only when more than 8 ms has passed since the previous zero crossing. Without this filter, the frequency was typically about 2 Hz too high.

The accuracy of the frequency count depends on the accuracy of the crystal (among other things). To get 0.01 Hz error at 50 Hz, we need a time reference with at most 0.01 / 50 = 200 ppm frequency deviation. This is doable with the crystal on a typical ESP8266 board (which has an accuracy of 25 ppm or so).

You can build the software with platformio ('pio run'), it uses libraries WifiManager and PubSubClient.

References

Other interesting projects/documents: