Find the frequency of a wave read by Arduino?

Hi,

I have used arduino to take some voltage. I have read the program from this site:

https://www.gammon.com.au/adc

In particolar i have used the one with interrupt.

Now suppone I have only a series of data (of a sine) like:

378
710
899
992
966
827
609
367
159
38
35
147
350
593
817
965
1001
917
733
494
259
88
21
76

Is possible to find the frequency of this sine? I think that we can find something beginning with counting how many points there are in a period.

Nice list of numbers. Can you share your code, so we can help you develop it into what you wish?

const byte adcPin = 0; // A0

const int MAX_RESULTS = 256;

volatile int results [MAX_RESULTS];
volatile int resultNumber;

// ADC complete ISR
ISR (ADC_vect)
{
if (resultNumber >= MAX_RESULTS)
ADCSRA = 0; // turn off ADC
else
results [resultNumber++] = ADC;
} // end of ADC_vect

EMPTY_INTERRUPT (TIMER1_COMPB_vect);

void setup ()
{
Serial.begin (115200);
Serial.println ();

// reset Timer 1
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TCCR1B = bit (CS11) | bit (WGM12); // CTC, prescaler of 8
TIMSK1 = bit (OCIE1B); // WTF?
OCR1A = 39;
OCR1B = 39; // 20 uS - sampling frequency 50 kHz

ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // turn ADC on, want interrupt on completion
ADCSRA |= bit (ADPS2); // Prescaler of 16
ADMUX = bit (REFS0) | (adcPin & 7);
ADCSRB = bit (ADTS0) | bit (ADTS2); // Timer/Counter1 Compare Match B
ADCSRA |= bit (ADATE); // turn on automatic triggering

// wait for buffer to fill
while (resultNumber < MAX_RESULTS)
{ }

for (int i = 0; i < MAX_RESULTS; i++)
Serial.println (results );

  • } // end of setup*
    void loop () { }

If if is a sine, you attempt to identify the peaks by looking for transitions from rising edge to falling edge. Count a number of peaks and divide by the collection time in seconds. You need several samples per wave to make it work.

Thanks, what do you mean with collection time ? The sampling frequency? Instead if it is the time in which arduino acquires these data I don't know, i want to calculate the frequency in order to find it

MementoMori96:
Thanks, what do you mean with collection time ? The sampling frequency? Instead if it is the time in which arduino acquires these data I don't know, i want to calculate the frequency in order to find it

frequency is oscillation with respect to time. in order to calculate frequency you will need to time-stamp each time the microcontroller records a value.

each time the microcontroller rocords a value is the sampling frequency, is it correct?

MementoMori96:
each time the microcontroller rocords a value is the sampling frequency, is it correct?

Let me try to clarify a few things...

  1. y=sin(x) is your library sin function. to have this, we need enough xy pairs in order to see enough of the waveform to make predictions about the waveform.
  2. for Frequency, repetitions per unit of time, x will be time as it elapses, and y will be something else.... Could be a number of things mathematically, but practically, for the ADC, it's measuring a voltage.
  3. In the library sine wave, for each cycle, there is a part of the wave that increases from y=0 to the crest of the wave, there is a part that decreases from the crest of the wave to y=0, there is a part that decreases from y=0 to the trough of the wave, there is a part that increases from the trough of the wave to y=0.
  4. If we have enough samples (y volts at x units of time) we can mathematically place these on respective parts of the wave and pick a place among the plots to measure the wavelength, say crest to crest... to determine a crest, we would have a lower value, then a higher value, then a lower value. The highest value (middle of three) would be as close to the crest as we have sampled. Combined with it's timestamp, we could say it took x units of time to crest, and x more units of time to reach the next crest. trough to trough would be a higher value, then a lower value, then a higher value. These are probably the best places to measure the wavelength.
  5. Crest to crest is 1 cycle, and the second x minus the first x is the time.
  6. first, determine the frequency of each cycle, and store them in an array, then average the array to determine the overall frequency. For twice as many samples, measure crest to crest and trough to trough.

Perehama:
Let me try to clarify a few things…

  1. y=sin(x) is your library sin function. to have this, we need enough xy pairs in order to see enough of the waveform to make predictions about the waveform.
  2. for Frequency, repetitions per unit of time, x will be time as it elapses, and y will be something else… Could be a number of things mathematically, but practically, for the ADC, it’s measuring a voltage.
  3. In the library sine wave, for each cycle, there is a part of the wave that increases from y=0 to the crest of the wave, there is a part that decreases from the crest of the wave to y=0, there is a part that decreases from y=0 to the trough of the wave, there is a part that increases from the trough of the wave to y=0.
  4. If we have enough samples (y volts at x units of time) we can mathematically place these on respective parts of the wave and pick a place among the plots to measure the wavelength, say crest to crest… to determine a crest, we would have a lower value, then a higher value, then a lower value. The highest value (middle of three) would be as close to the crest as we have sampled. Combined with it’s timestamp, we could say it took x units of time to crest, and x more units of time to reach the next crest. trough to trough would be a higher value, then a lower value, then a higher value. These are probably the best places to measure the wavelength.
  5. Crest to crest is 1 cycle, and the second x minus the first x is the time.
  6. first, determine the frequency of each cycle, and store them in an array, then average the array to determine the overall frequency. For twice as many samples, measure crest to crest and trough to trough.

Hi, thanks for the answer. I have read the message right now but Yesterday I have had an idea (that maybe is what you are saying or not, i’m not sure). I have the sampling frequency, so I can count how much point there are in a period of sine, multiply them for 1/(sampling frequency) = and then make the inverse of that result to obtain the frequency of sine. Is this correct?
N.B. this is correct only if sampling frequncy is < than adc clock frequency

MementoMori96:
Hi, thanks for the answer. I have read the message right now but Yesterday I have had an idea (that maybe is what you are saying or not, i’m not sure). I have the sampling frequency, so I can count how much point there are in a period of sine, multiply them for 1/(sampling frequency) = and then make the inverse of that result to obtain the frequency of sine. Is this correct?
N.B. this is correct only if sampling frequncy is < than adc clock frequency

I keep trying to spell this out for you, but your hung up on the sampling frequency. Forget the sampling frequency. It is only important to satisfy the requirement of obtaining enough samples to accurately measure the waveform. Higher sampling frequency = more samples for the same amount of time. But, you MUST tie each sample to a time irrespective of the sampling frequency. You can do it another way… sample for a specific interval of time, then count the crests within that interval of time. It’s not going to be as accurate this way, but it will be easier for a novice.

I don’t know if I understand your thought correctly, but i can’t do this, i have only that data, i have not timestamp and i can’t redo the “experiment”

MementoMori96:
I don’t know if I understand your thought correctly, but i can’t do this, i have only that data, i have not timestamp and i can’t redo the “experiment”

If you have some idea how long it took you to take those samples, you will have some idea of the frequency. If you cannot go back and obtain data you did not collect, there is no way to fix this. You have essentially 1 full wave, maybe, from value 966 to value 965 or 1001. If you tell me how much time elapsed from 966 to 965, I can tell you the frequency. If you can’t, no.

Ok thanks, no i can’t tell you. But why we can’t do anything woth sampling frequency, why is my idea not correct?

MementoMori96:
Ok thanks, no i can’t tell you. But why we can’t do anything woth sampling frequency, why is my idea not correct?

Ok, we will try. If the sampling frequency is 50 kHz, That is 50,000 samples per second, so the time between each sample is 20 μs. Between 966 and 965, there are 11 intervals (12 to 1001). That's 220 μs (240 μs) or 4,545 Hz (4166 Hz). Using this same logic, your ordered pairs are: (378, 0), (710, 20), (899, 40), (992, 60), (992, 80), (966, 100), (827, 120), (609, 140), (367, 160), (159, 180), (38, 200),(35, 220), (147, 240), (350, 260), (593, 280), (817, 300), (965, 320), (1001, 340), (917, 360), (733, 380), (494, 400), (259, 440), (88, 460), (21, 480), (76, 500)

That is "close" to the real one (4000 Hz), so is this method correct?

MementoMori96:
That is "close" to the real one (4000 Hz), so is this method correct?

Is it correct for future use, no. Is it as close as you can get on a previously ran data set? I think so. Why are you cross-posting? Or do you have to separate projects plagued by the same misunderstanding?