Frequency of sampled signal

Thread Starter

Ian0

Joined Aug 7, 2020
9,677
I've been pondering this for a while, but what is the best way to determine the frequency of a sampled signal? (assume it is a sinewave)
As I've always had a comparator and timer in addition to the sampled signal, I have never had to put it into practice.
 

MrChips

Joined Oct 2, 2009
30,720
I've been pondering this for a while, but what is the best way to determine the frequency of a sampled signal? (assume it is a sinewave)
As I've always had a comparator and timer in addition to the sampled signal, I have never had to put it into practice.
Depends on the application.
You can use least squares fit to find a sine wave amplitude, frequency and phase.
If you want a simple measure of the frequency you can count zero-crossing in a given time interval.
You can also shape it with a comparator and measure frequency or period.
 

WBahn

Joined Mar 31, 2012
29,979
I've been pondering this for a while, but what is the best way to determine the frequency of a sampled signal? (assume it is a sinewave)
As I've always had a comparator and timer in addition to the sampled signal, I have never had to put it into practice.
The answer, as usual, is "it depends".

How accurately do you need your estimate of the frequency to be?

How many samples are you getting per period? Several dozen, or just three or four?

How quickly do you need the answer? If your latency can be many cycles, then you can get a pretty good estimate quite easily.

How much processing can you throw at the problem?
 

Thread Starter

Ian0

Joined Aug 7, 2020
9,677
My first thought was to count zero-crossings in a time period.
Fsample = 1600Hz, Fsignal = 40-60Hz.
I counted zero crossings in a second, then averaged the figure with a single-pole IIR filter with a time constant of 4 seconds. That increases the resolution with out much computation.

I also considered counting samples between zero crossings, but that ends with a division to get the final answer.

I just wondered if there were other ways/
 

DickCappels

Joined Aug 21, 2008
10,152
Make the quantity of samples a power of two, that way you only need to right-shift the data the appropriate number of bits to do the division. I've been doing it to average a lot of A-to-D readings (like 256 or even 1024) in the presence of noise.
 

drjohsmith

Joined Dec 13, 2021
852
My first thought was to count zero-crossings in a time period.
Fsample = 1600Hz, Fsignal = 40-60Hz.
I counted zero crossings in a second, then averaged the figure with a single-pole IIR filter with a time constant of 4 seconds. That increases the resolution with out much computation.

I also considered counting samples between zero crossings, but that ends with a division to get the final answer.

I just wondered if there were other ways/
Looks like your looking at mains voltage frequency detection.
Mains has lots of high frequency noise on it
and as mentioned above, it depends,

If its for a frequency meter,
then I'd over sample a lot, and then use a combination of external and software low pass filtering,
then measure the frequency ,

Or one could use an simpler zero cross function,
you would probably want some sort of AGC and threshold moving circuit

For real fun, a FFT is good .. even on a simple Arduino these are practical

https://www.tutorialspoint.com/fast-fourier-transform-fft-on-arduino

A last suggestion,
we used to use of for phone tone detection is may be the Goertzel algorithm
https://www.ti.com/lit/pdf/spra066
https://en.wikipedia.org/wiki/Goertzel_algorithm
 

Thread Starter

Ian0

Joined Aug 7, 2020
9,677
Looks like your looking at mains voltage frequency detection.
Mains has lots of high frequency noise on it
and as mentioned above, it depends,
Close! It’s a generator. The mains frequency is so well regulated that it is hardly is hardly interesting.
My isolation transformer frequency response rolls off above 1kHz, which will take care of the hf noise. With samples 625us apart, I doubt I’ll see very many spurious zero crossings. If I ex-or the latest two samples he MSB will be 1 if there has been a zero crossing in between.

One thing I just realised is that the time interval over which I count zero-crossings, doesn’t have to be longer than a cycle of the waveform to be measured. In fact, I can count the number of zero crossings in a 625us sample period which will be either 0 or 1. If I then decimate and extend the word length, I think I have the frequency. That way all the filters can run in the same interrupt routine (there are other filters that derive rms current and voltage and real power)

Goertzel is interesting. I’ll have a thorough read later.
 

MrSalts

Joined Apr 2, 2020
2,767
Close! It’s a generator. The mains frequency is so well regulated that it is hardly is hardly interesting.
My isolation transformer frequency response rolls off above 1kHz, which will take care of the hf noise. With samples 625us apart, I doubt I’ll see very many spurious zero crossings. If I ex-or the latest two samples he MSB will be 1 if there has been a zero crossing in between.

One thing I just realised is that the time interval over which I count zero-crossings, doesn’t have to be longer than a cycle of the waveform to be measured. In fact, I can count the number of zero crossings in a 625us sample period which will be either 0 or 1. If I then decimate and extend the word length, I think I have the frequency. That way all the filters can run in the same interrupt routine (there are other filters that derive rms current and voltage and real power)

Goertzel is interesting. I’ll have a thorough read later.
I have a frequency counter that counts for 8-seconds, and I shift three binary places to get Hz, or for higher frequency, I use 1 second as is, or for high frequencies, I use 1/8 or 1/64th second and so on from my precision time source.
 

BobaMosfet

Joined Jul 1, 2009
2,110
I've been pondering this for a while, but what is the best way to determine the frequency of a sampled signal? (assume it is a sinewave)
As I've always had a comparator and timer in addition to the sampled signal, I have never had to put it into practice.
Offset DC to AC and time how frequently it crosses zero. There's your frequency. Or simply convert to a square-wave and time the leading edges.
 

MrAl

Joined Jun 17, 2014
11,396
I've been pondering this for a while, but what is the best way to determine the frequency of a sampled signal? (assume it is a sinewave)
As I've always had a comparator and timer in addition to the sampled signal, I have never had to put it into practice.
Hi,

The way the old time frequency counters worked was they would first run the signal through a Schmitt trigger which squared up the signal, then use that to clock a number of digital counters. The counters were allowed to count for exactly 1 second with gating, then the counters were stopped. The counters then repressented the frequency.
If you used BCD counters you didnt have to do anything else except use them to drive a set of BCD to 7 segment decoder drivers that that would display the entire count on the multiple digit 7 segment display. The front end may contain an amplifier.

In the modern world you could use a microcontroller to count the number of changes on a digital pin and stop after 1 second.
Alternately, if your ADC is fast enough, you can sample the input many times over and decide what is positive and what is negative, then count those pulses the same way. The ADC should be able to pick up lower level signals than the digital inputs. The ADC has to be fast enough though in order to catch every input change.
The old time frequency counters did not average, but you can add that function if you like and take the advice of using a power of 2 for the oversampling so you can use digital word shifts instead of an actual divide.
If you can get away without shifting you can implement BCD counters in registers so you can display it without any further processing.

If you need frequency spectra then it gets more complicated. You need to implement something like an FFT.
 

MrChips

Joined Oct 2, 2009
30,720
Calculating the FFT is the classic way of finding the frequency content of any random waveform.
The signal could be a square wave with any arbitrary DC offset, distorted sine wave, voice, music, etc.

The frequency resolution is the reciprocal of the total sample period.
Thus if the want a resolution of 1Hz, you need to sample for 1 second.
If you want a resolution of 0.1Hz, you need to sample for 10 seconds.

Your maximum displayed frequency is one-half the sampling frequency. This is known as the sampling theorem or Nyquist theorem.
You need an anti-aliasing filter, i.e. a low pass filter, that attenuates all frequencies greater than one-half the sampling frequency.
 

Thread Starter

Ian0

Joined Aug 7, 2020
9,677
The problem with that is the complexity.
Assuming I need to measure to 0.1Hz, I have to sample for 10 seconds. My sampling frequency is 1600Hz. That's 16000 samples. The FFT doesn't produce a single value which is the frequency of the signal, it produces 16000 data points which form the spectrum of the signal. Then it has to be processed to find the fundamental.

I've tried the method of counting the number of zero-crossings in each sample period and averaging and it works very well.
Two cascaded single-order filters with a cutoff frequency of 6Hz worked best. I suppose that is a 2nd order critically damped filter with Q=0.5 and f=8.5Hz, or a 2nd order Linkwitz-Riley filter. It settled MUCH faster than a first order filter, and had much less residual "noise" than a 2nd order Bessel filter implented as a BiQuad, and it con be implemented in 6 instructions in ARM assembler.

I will note that my signal only has 2 zero crossings per cycle (one in each direction). It won't work for complex signals with lots of harmonics and multiple zero-crossings per cycle.
 

WBahn

Joined Mar 31, 2012
29,979
Are you using hysteresis in determining your zero crossings? Your low pass filters can reduce the need for this, but it doesn't take much noise at all around those zero crossings to result in extra counts if you don't.
 

Thread Starter

Ian0

Joined Aug 7, 2020
9,677
Are you using hysteresis in determining your zero crossings? Your low pass filters can reduce the need for this, but it doesn't take much noise at all around those zero crossings to result in extra counts if you don't.
It seems not to be a problem. The signal is 7020 counts peak on a 14-bit A/D - it varies by ±10% at most in amplitude.
That is 1378 counts/sample at 1600 samples/second as it crosses zero. I doubt there would be much chance of jitter.
There is also some low-pass filtering on the way in but only the leakage inductance of a small transformer, but there is very little energy above 800Hz, so sufficient anti-aliasing is achieved.
 

MrChips

Joined Oct 2, 2009
30,720
The problem with that is the complexity.
Assuming I need to measure to 0.1Hz, I have to sample for 10 seconds. My sampling frequency is 1600Hz. That's 16000 samples. The FFT doesn't produce a single value which is the frequency of the signal, it produces 16000 data points which form the spectrum of the signal. Then it has to be processed to find the fundamental.
It is still doable without a lot of effort. I did an FFT voice app on MATLAB for a class demonstration, straight from the mic input into MATLAB. You could sing or whistle into the mic and see the fundamental note.

In fact, there are a number of free apps off the web that you can download into your PC to do FFT and tone recognition from mic input.
 

WBahn

Joined Mar 31, 2012
29,979
It seems not to be a problem. The signal is 7020 counts peak on a 14-bit A/D - it varies by ±10% at most in amplitude.
That is 1378 counts/sample at 1600 samples/second as it crosses zero. I doubt there would be much chance of jitter.
There is also some low-pass filtering on the way in but only the leakage inductance of a small transformer, but there is very little energy above 800Hz, so sufficient anti-aliasing is achieved.
It's not jitter I was concerned with, but noise. But your right, you sampling rate is slow enough that you shouldn't have a problem. I hadn't run the numbers to realize that you are only getting about 30 Sa/period.

Another question: In an early post you said that the signal frequency was 40 Hz to 60 Hz. But an a recent post you said that you were filtering the signal with two first-order filters at 6 Hz. I assumed that these were low-pass filters to remove high frequency noise. Are they actually high-pass filters to remove any DC offset?
 

Thread Starter

Ian0

Joined Aug 7, 2020
9,677
It's not jitter I was concerned with, but noise. But your right, you sampling rate is slow enough that you shouldn't have a problem. I hadn't run the numbers to realize that you are only getting about 30 Sa/period.

Another question: In an early post you said that the signal frequency was 40 Hz to 60 Hz. But an a recent post you said that you were filtering the signal with two first-order filters at 6 Hz. I assumed that these were low-pass filters to remove high frequency noise. Are they actually high-pass filters to remove any DC offset?
My "light bulb" moment was realising that I didn't have to count zero crossings in a period that was LONGER than the period of the signal. I could even count them in my 625us sample period, and I would get an figure that is either 1 or 0, with a 1 occurring once in every 16 samples. I filter that series of 1s and 0s at 6Hz (effectively, decimation) and the output from the filter is a number that represents the frequency. It settles to an accuracy of 0.1Hz in about 3 seconds, and no division is involved. It's much the same process as turning PDM from microphones into PCM for I2S.
[Edit] just a thought - what I have done digitally emulates a LM2917.
 
Last edited:

MrAl

Joined Jun 17, 2014
11,396
The problem with that is the complexity.
Assuming I need to measure to 0.1Hz, I have to sample for 10 seconds. My sampling frequency is 1600Hz. That's 16000 samples. The FFT doesn't produce a single value which is the frequency of the signal, it produces 16000 data points which form the spectrum of the signal. Then it has to be processed to find the fundamental.

I've tried the method of counting the number of zero-crossings in each sample period and averaging and it works very well.
Two cascaded single-order filters with a cutoff frequency of 6Hz worked best. I suppose that is a 2nd order critically damped filter with Q=0.5 and f=8.5Hz, or a 2nd order Linkwitz-Riley filter. It settled MUCH faster than a first order filter, and had much less residual "noise" than a 2nd order Bessel filter implented as a BiQuad, and it con be implemented in 6 instructions in ARM assembler.

I will note that my signal only has 2 zero crossings per cycle (one in each direction). It won't work for complex signals with lots of harmonics and multiple zero-crossings per cycle.
Yes as you get lower in frequency it takes longer to get a measurement. That's life i guess. If you dont know when the wave will change polarity after 1 second, then you have to wait longer, 2 seconds, then maybe 3 seconds, then 4, etc., etc. If you had a pure sinusoidal wave you could make some assumptions and get a faster reading, but if the waveshape changes for any reason it will be inaccurate.
Maybe you can hire a psychic advisor to predict the frequency before the first half cycle is complete :)
 

Thread Starter

Ian0

Joined Aug 7, 2020
9,677
That could be really useful. Do you know many psychic advisors that are familiar with Nyquist’s sampling theory?
 
Top