@robert-hh Another variant for measuring, which determines the difference between a minimal and maximal value over a window of samples, which should be at least a period of the signal to be tested, e.g. 20 ms for a 50Hz net. More simple than the last example, and immune to offset drifts. Still, the ADC is bad. The noise is a little bit lower if WiFi is switched off, but that only matters at small signals.
#
import math
import array
from machine import ADC, Timer, idle
samples = 600
freq = 50
_BUFFERSIZE = const(64)
#
# acquire ADC values at a fixed rate/s, which is given in
# the constructor. The second argument is the size
# of a ringbuffer, the third a string with the Pin name
#
class Acquire:
def __init__(self, samples, buffersize, pin):
self.put = 0
self.get = 0
self.buffersize = buffersize
self.buffer = array.array("h", 0 for _ in range(self.buffersize))
self.adc = ADC(bits=9)
self.apin = self.adc.channel(pin=pin, attn=ADC.ATTN_11DB)
self._alarm = Timer.Alarm(self.read_adc, 1/samples, periodic=True)
def stop(self):
self._alarm.cancel()
def read_adc(self, alarm):
self.buffer[self.put] = self.apin.value()
self.put = (self.put + 1) % self.buffersize
def next(self, period):
vmin = 4096
vmax = 0
for _ in range(period):
while self.get == self.put:
idle()
# calculate the moving average over the last three values:
value = (self.buffer[self.get] +
self.buffer[(self.get - 1) % self.buffersize] +
self.buffer[(self.get - 2) % self.buffersize]) / 3
vmin = min(value, vmin)
vmax = max(value, vmax)
self.get = (self.get + 1) % self.buffersize
return vmax - vmin
#
# calculate a moving average
# The constructors argument is the window size
#
class Average:
def __init__(self, size):
self.size = size
self.buffer = array.array("f", 0.0 for _ in range (size))
self.put = 0
self.sum = 0.0
def avg(self, value):
self.sum -= self.buffer[self.put]
self.buffer[self.put] = value
self.put = (self.put + 1) % self.size
self.sum += value
return self.sum / self.size
def run(noise=1.2):
acq = Acquire(samples, _BUFFERSIZE, 'P20')
avg_res = Average(freq)
noise_sq = noise * noise
try:
i = 0
while True:
res = avg_res.avg(acq.next(samples/freq))
i += 1
if i == freq:
# remove the noise floor
res = math.sqrt(abs(res*res - noise_sq))
print("{:6.2f} ".format(res/20.2))
i = 0
except KeyboardInterrupt:
acq.stop()
print("Handler stopped")
run()