This is a pure sine wave, captured by the ADC + DMA code, as described previously:
The plot above consists of 800 samples, sampled 40 µs apart, i.e. at 25 kHz - for a total of 32 ms. A quick calculation would seem to indicate that we’re seeing 1.6 cycles of a 50 Hz sine wave.
Except that it’s not… the incoming signal used here was a 24,950 Hz sine wave!
There is no way to tell what the frequency of a sampled signal is without further information. The reason for this is aliasing, an important aspect in any situation where continuous signals are sampled - as in the case of an ADC. We’ll get the same result with 25050/49950/50050/… Hz.
The math behind all this is locked up inside the Niquist-Shannon sampling theorem, but the intuition for this phenomenon is actually quite easy to pick up.
Here is a high-frequency pure sine wave, sampled at a - too low - rate (SVG from Wikipedia):
Each successive sample is picking up a slightly earlier piece of the sine wave. Unfortunately, when you drop the real signal (the red line) and look at only the sampled value (the black dots), it all ends up suggesting an aliased sine wave of a much lower frequency (the blue line). Yet this last waveform is totally fake - it is not present in the original signal!
When sampling at frequency X, signals of frequency Y
, X-Y
, X+Y
, 2*X-Y
,
2*X+Y
, … all look the same - no matter how fast that ADC circuit is, or
how clean and noise-free that input signal is.
The fact that the 24,950 Hz capture above looked so much like a 50 Hz signal is in fact a tribute to the accuracy of the sampling obtained by running our ADC off a hardware timer. If you think about it: any jitter in the timing of the sampling interval would lead to a highly distorted sample in the case of 24,950 Hz, since the real input signal varies much more quickly than with 50 Hz.
When X is 25,000 Hz, any frequency from 12,501 Hz to 24,999 Hz will “flip over” and alias back into our sampled data as if they were signals of 12,499 Hz to 1 Hz, respectively. And the same will happen over and over again for any frequency above X.
This also points to a solution: if we filter out high frequencies before
sampling, then all is well. As long as we keep all frequencies > X/2
out of
the ADC. This is called the Nyquist
frequency.
Ideally, we’d need a perfect low pass, which passes all signals under X/2
as
is, and suppresses everything above. In the real world, such a filter does not
exist, but we can choose a filter which starts filtering at X/4
or even
X/10
, and rely on the roll-off of a
simple RC filter to do the job. With a sample and
hold capacitor on the input of
an ADC, a well-chosen resistor can also work.
There is also another approach to avoid aliasing: assume that we know that
frequencies > Z are not present in our signal. Perhaps the properties of the
input circuit are such that they already limit the frequency response. Then we
could oversample at a higher rate
2*Z
, perform some digital filtering, and then throw away the extra samples to
end up with exactly the data rate we need. This last step is called
decimation.
This doesn’t change the fact that sampling should never see frequencies above
half the sampling rate - we’ve merely moved part of the work over to
DSP.
For the JeeLabs Energy Monitor prototype, the plan is to sample at 25 KHz - so we have to block all signals above 12.5 KHz. What this means for the actual circuit still needs to be determined…