Some time ago, I saw an article on an old german website that talked about building a field mill to measure atmospheric electricity and other electric fields. I have always wanted to build one since, and I decided it was finally time this month. But since that article is almost as old as I am, I thought there must be some areas in which we can improve the design. Instead of just a box with a voltage output, I turned it into an ESP32-IOT Sensor node. I also published all of the files and an assembly guide on our GitHub, so you can make one yourself if you want to.
Why Would Anyone Even Want to Make This?
I decided to make it because it can measure the static field generated by the weather. Thunderstorms are probably the most obvious ones, but the weather always generates static even if it does not result in lightning strikes. In theory, a grid of them would allow accurate tracking of storm cells and give more accurate warnings about lightning strikes or tell if a thunderstorm is beginning to form. (Though there are some problems with that, as you’ll read later).
It can also do contactless voltage measurements and detect a buildup of static charges, but that has fewer practical uses besides just being cool… at least for what I do in my lab. One thing it can’t detect, is the changing field of a Tesla coil.
How the Field Mill Works
Operating Principle
Looking at the unit of the electric field (Voltage per distance, V/m) might give you the idea that it would be enough to just connect a multimeter to two plates at a fixed distance. But unfortunately, physics says no.
The reason for this becomes obvious when thinking of the sensor as a capacitor and the meter as a load. In a normal capacitor, the act of charging it up creates an electric field between the electrodes, so those two plates are like a pre-charged capacitor. And just like in a normal capacitor, the input impedance of the meter would allow charges to move from one electrode to the other until the voltage between them is zero, discharging it and canceling out any field that we might want to measure. All that means is that a sensor using two plates would always drift to an output of 0V regardless of the field applied and can only be used to measure changes in an electric field.
Satic Fields to Dynamic Fields

So, if the sensor can only measure changes, how do we manage to measure the static field generated by the atmosphere? Simple: we turn the static field into a changing one 😀 This is done with the grounded rotor, which acts as a faraday cage and shields the electric field underneath it. As it turns, it continuously covers and uncovers the electrodes, which results in a constantly changing electric field. Changing field can then sense this with the two plates described above.
As the rotor rotates, it moves charges onto and off the plates, and since the movement of charges is current, we can measure that. That current depends entirely on the external field and the rotor speed, so we can use it to calculate the field the sensor is in.
That current needs to be amplified, turned into a voltage, and read by an ADC, bringing more issues with it.
Field Mill Front End
The first issue is that the electrode current is very, very tiny… Sub-microamp at the highest expected field tiny. We will have to convert that current to a voltage to measure it with our ADC, and just using a resistor in front of the ADC like one usually would not really work. The input bias currents and leakages in the system would probably generate more signal than the sensor itself.
To solve this, we use a high gain transimpedance amplifier. It converts the current from the electrodes to a voltage, while having a near-zero input impedance so we don’t get wrong readings from the voltage drop across the resistor (as even just 100mV across the 1.6mm FR4 would result in a 60V/m offset).

Transimpendance Amplifier Considerations
One thing to keep in mind here is that the OpAmp for the transimpedance amplifier needs to have a low input bias current, as it gets amplified as much as the electrode current. The OpAmp in my plans is a CMOS one with less than 100pA below 70°C.
There is also a low pass filter with a cutoff frequency of around 3kHz in the signal path, limiting the bandwidth of the system to reduce noise. The frequency spectrum of the signal shows how there is pretty much no signal above 1kHz, and in cutting off the signal above that, we are only removing noise.
Sensing the Rotor Position
The last component here is the optical rotor position sensor (IC2) which is required if we want to measure the direction of the field and the strength. When a positive field is applied, the current is >0 when the rotor uncovers the electrodes, but when the field is negative, that happens as the rotor covers them instead. The sensor gives the ESP32 the ability to see where the rotor is and consider it when calculating the sensor reading.
One thing you might have noticed is the use of a 2.5V virtual ground for the entire system. This allows us to use a single 5V supply, as the output from the transimpedance is not mirrored around the 0V rail. That means it will not need to output any negative voltages up to an input current of 250nA.

The ESP32 Board
This contains all the digital stuff needed, which is really just a differential ADC, the ESP32 dev board, and some miscellaneous power stuff. The ADC is a differential one to give the system common-mode noise immunity. This will remove both the 2.5V offset and any other signals received by the electrodes caused by the rotor. Mains interference from a cable next to the field mill would, for example, be eliminated by this.
Since the ESP32 does all the signal processing in software, we don’t need any analog switches and logic gates used in some of the older schematics for field mill amplifiers on the web. The signal from the front end goes straight into the ADC, and the ESP does the rest. The one issue that we have is that the performance of the ESP32s ADC is pretty miserable and not suitable for this application. That is why I chose to use a dedicated differential ADC chip instead.
To give the measurements a stable reference, we use a voltage reference IC that is more stable and lower noise than either the 5V or 3.3V rails. The 2.5V from this is divided down by a factor of 5 to give the ADC a reference of 500mV.
Field Mill Code
I won’t be going into any detail about the user interface or its back-end because it isn’t really relevant to this project. All it is is a web server that serves either the webpage or the data from the sensor in the form of a .json file. No idea if that is the best or even a good way to do it since I have little experience doing web dev stuff, but it works 😛
The two other tasks the code has are controlling the motor and calculating the field from the ADC reading.
The motor rpm is regulated with a simple PID loop (but without the P). It needs to be well regulated as the electrode current is linearly proportional to the speed of the motor, which means that any inaccuracy here will directly impact the reading. The PID also corrects for slight variations in the motors and the mechanical assembly of the sensor.
ADC Operation
The ADC is set to sample at a fixed 10KHz, and the task automatically ignores all values within a specified dead time around the zero-crossing point. This is because the rotor does not perfectly shield only the area it covers because the field lines aren’t straight at the edges. This results in the soft-ish edges you see, which we ignore.

The value then gets digitally rectified by inverting it when the optical interrupter outputs a 1 (which is every time the A electrodes get uncovered) and averaged to eliminate the last bit of noise and leave us with the DC content of the signal. We then use the calibration data to calculate the applied field from the measured value.
And because I can, I added a task that periodically sends the data to an MQTT server if desired so that it can be processed further and logged in a database like InfluxDB.
Problems You May Have Building This Field Mill
The biggest thing to keep in mind is how crazy sensitive this thing is. I had issues with it not working the first time I assembled it because there was some flux residue with caused enough leakage to overpower the signal completely. Make sure to clean the board with some IPA or ethanol and an old toothbrush to prevent this.
Another problem you might run into is a high reading even without any field applied. If this happens, you should make sure that there is absolutely no exposed plastic near the sensor anywhere, that all of the top part is covered in copper tape and that the tape is electrically connected to the tape on the middle piece.
What To Improve

As it stands, the performance of the sensor is acceptable but not stellar. The signal we are trying to measure is tiny, even after the high gain transimpedance amp, so the signal-to-noise ratio is quite poor. To improve this, I could add a lock-in amplifier, which is extremely narrow band and would eliminate almost all noise from the system. I could also increase the gain from the Transimpedance amplifier and decrease the effect of the noise caused by the ADC, but since the ADC is pretty low noise, it would really only increase the effective number of bits we get from it (right now, the reading is not full range).
The one other issue is that the field mill does not have a lid. The rotor and circuitry are completely exposed, so it couldn’t really be used in the rain, which greatly limits its potential as a meteorological instrument.
Conclusion
My plan initially was to make a bunch of them and spread them all over the place to gather data but without a lid, they’d last maybe a week if I’m lucky. The problem with a lid is that it must not impact the measurement. A plastic one would get charged up and create a field of its own (I tested it and got a reading 10x larger than the external field), and a wood one is conductive enough to shield the field that we want to measure completely. The only option I could think of would be something ceramic, but that might get conductive enough to cause issues once it gets dirty. That is all to say that I could not think of a way to cover it properly. If you have any good ideas, I’d love to hear them 🙂