How to find the mean frequency of a set of samples in an array?

I’m getting an audio wavelet of 300 samples using analogRead() and storing it in an array. I need to calculate the mean frequency of the wavelet. How do I do it?

int a[300];
void setup() {
  pinMode(A0,INPUT);
  for(int i=0;i<300;i++)
  {
    a[i]=analogRead(A0);
  }
}
void loop() {
  //Calculate mean frequency and write it to serial.
}

How do I do it?

Just like you would on a PC. First, you define what "mean" means. It has several different interpretations. Then, you loop through the elements in the array and compute the mean (by whatever definition of mean you come up with).

This really sounds like a homework assignment.

Are you trying to find the mean of the numbers in the array? If so follow Paul's advice.

I wonder, however, if you are trying to infer from the numbers the shape of a wave and then determine the frequency of the wave. If it was a pure sine wave, square wave etc I think I can envisage how to do it but if it's a jumble of audio input I have no idea and I wonder if an Arduino has the power to do it.

...R

Thanks Paul..:slight_smile: pretty funny..:slight_smile:

Well, what I was asking for is a code that would calculate the mean frequency of the audio wave.

Anyway, I'll give it a shot..I'll try writing it myself. But of course I need some help.

I need to know at what speed (precisely) does the analogRead() function read if run continuously in a loop as in my code. My board is arduino Mega 2560.

xpleria:
I need to know at what speed (precisely) does the analogRead() function read if run continuously in a loop as in my code. My board is arduino Mega 2560.

The analogRead reference says it’s 100us per sample, but you’re unlikely to get speeds that high. I would recommend making a test script filling up an array with a few hundred analogRead (in a way that’s representative of how the code will run) and measure the average time for each.

xpleria:
I need to know at what speed (precisely) does the analogRead()

How many decimal places do you “need” for your precision?

Use micros() to time how long the it takes for the analogRead() to complete. Assuming you can spare the 1.2k of RAM, you could even create an array that timestamps each sample.

unsigned long startTime = micros();
int whatever = analogRead(A0);
unsigned long completed = micros() - startTime;

Of course, this all depends on how much precision you need.

Set up one of the timers to provide interrupts at intervals that suit you and do the analogRead when the interrupt triggers. That way you are in charge of the timing. Always best to stay ahead of the ball.

...R

xpleria:
I need to know at what speed (precisely) does the analogRead() function read if run continuously in a loop as in my code. My board is arduino Mega 2560.

Concur with Robin2 - sampling on a timer interrupt is a must.

But anyway, what do you mean by the mean frequency? And how are you planning to extract frequency information from the samples? FFT will get you a spectrum but why you would want to average over that is difficult to fathom.

-br

I think you could get samples quicker if you set up the ADC in free running mode. I don't know if you could even store them that quickly, though. The spec sheet says it takes 13 clock cycles to gather a sample. You might be able to do that in assembly, but you might have to cut it down to 8 bit accuracy. And there's no way you could do it in an interrupt.

Edit:
I was totally missing the prescaler. 13.5 of the ADC clock cycles, with a prescaler of 128 is really close to the 100uS tobyb121 mentioned. Ignore me in this conversation. I don't have enough real experience to know what I'm talking about yet. All I did was read the manual. And build a project where I totally missed the prescaler.

On a positive note, my project is much more accurate now that I set the prescaler bits.

Well, I'm gonna use micros() to find out how long it takes to read n put it up on my LCD.

Another question, I need to clamp the audio signal to above 0V (0-5V) in order to read right?

Is there a way to read the audio signal (+ve and -ve) directly..?

The spec sheet says it takes 13 clock cycles to gather a sample.

That's 13 ADC clock cycles, not CPU clock cycles - there's not much to be gained by going to assembler.

Hmmm..I'll check that out...

But please answer my last question..

i.e., Do I need to clamp the audio signal? Since it is both positive and negative. Or can I read negative in the arduino somehow?

You cannot read negative voltages, but you could bias your signal.

I was sure I had posted a reply to this earlier today - I must have pressed the wrong button somewhere.

In free-running mode you can get an interrupt when every sample is completed and you can control the ADC clock by setting the prescaler. That means you will have full control of the interval between samples.

However I don't think the problem here is harvesting samples - it is what do do with them afterwards. I would be very surprised if the Arduino has the power to do FFT, never mind work out the frequency after the wave form is identified.

It would be a complete waste of time solving the data collection process (including such things as adjusting the voltage range to suit the ADC) if the data can't be processed.

...R

TanHadron:
I think you could get samples quicker if you set up the ADC in free running mode.

The choice between (1) ADC in free-running mode with an interrupt to grab the sample and trigger the next conversion, and (2) grabbing samples on a timer interrupt -- would normally be driven by considerations like "do I need a standard sampling rate" like 8000 samples/sec, vs. sampling as fast as possible in a time-coherent way.

Polling for samples in loop() will generate enough phase noise due to sampling jitter that it should be avoided.

There is an FFT library that works on Arduino, but without a definition of "mean frequency" it's hard to know whether it helps the OP toward his objective.

-br

What's the nature of the data you're collecting? If it's audio data an fft of 300 samples 100us/sample, will give a frequency range of 5kHz, and a frequency resolution of 33Hz. 5 kHz is quite low for audio data, but you won't get much better without a dedicated audio adc.
Is the data you're collecting made up from many frequencies? what kind of frequency range is it? is it noisy?

Well, right now, I’m working on 300 samples. Once I complete the code of my processing, I’m planning to move the analogRead() to the loop().

Definition of data I’m collecting:
It’s a speech signal, with some noise (a small amplitude white noise).
And yes, I need to collect this data at specific intervals.
A sampling frequency of 5kHz is enough for my project. (not really bothered much about the audio quality)
PS: I don’t understand whats FFT, free running mode, ADC with interrupt… Pretty new to these stuffs

Definition of mean frequency:
The signal I’ll be receiving is an audio signal. This will have an irregular waveform. So what I do is, read 300 samples, and find the frequency of each wavelet (basically a wave starting zero going positive then negative and back to zero). then get the mean of it.

for eg. if I get four wavelets (just for example sake, but will be getting many wavelets) of frequencies like 1.8kHz 2.2kHz 1.6kHz 2.4kHz, then mean frequency of those 300 samples is 2kHz. Mean frequency > 1kHz, hence reject these samples. If less than1kHz, then write those samples to a Port.

The choice between (1) ADC in free-running mode with an interrupt to grab the sample and trigger the next conversion, and (2) grabbing samples on a timer interrupt

Also, dint find these things on the arduino site. Trying to read n understand from others.

I’ve not yet completed my code, but here’s how it would look

int a[300];
int b[300];
char j = 0;
char flag = 0;
analogReadResolution(8);
void setup() {
  //read first 300 samples
  for(int i=0;i<300;i++) {
    a[i] = analogRead(0); //read from pin A0
  }
  //calculate mean frequency of samples of 'a'
  //if freq<1kHz, flag = 1; else flag = 0;
}
void loop() {
  if(j==0) {
    for(int i=0;i<300;i++) {
      b[i] = analogRead(0); //read from pin A0
      if(flag) PORTA = a[i]; //from which it will be converted using DAC
    }
  //calculate mean frequency of samples of 'b'
  //if freq<1kHz, flag = 1; else flag = 0;
  }
  else {
    for(int i=0;i<300;i++) {
      a[i] = analogRead(0); //read from pin A0
      if(flag) PORTA = b[i]; //from which it will be converted using DAC
    }
  //calculate mean frequency of samples of 'a'
  //if freq<1kHz, flag = 1; else flag = 0;
  }
  j = ~j;
}

an FFT converts a number of samples in a time series and gives you the set of frequencies that make up that signal. For measuring speech an FFT going up to 5kHz
5kHz is the maximum frequency you'll get, and for speech that's not bad. Implementing an FFT algorithm is quite complex though for what you are trying to do though.
A simple method is to count the number of times that the signal crosses 0, and use the average as the average time period, which you can use to find the frequency.
You'll still want to do a bit of filtering to remove high frequency noise, but this can be as simple as ignoring time between zero-crossings smaller than a few samples.

BTW. Not sure what you mean here:

if(flag) PORTA = a[i];

I may be wrong and I hope I am not causing offence but I can't help feeling you may be a little out of your depth.

The way you describe it I think you believe that every time the speech waveform crosses from positive to negative the gap from that point to the previous similar point is a wave of some frequency and the average of those things would mean something. As far as I know it's not like that at all. What you receive from any sound other than a pure sine wave sound is a very complex jumble of several, perhaps dozens, of different frequencies. Fourier analysis (FFT) is the mathematical process of separating that jumble into a number of sine waves which, if "played" at the same time and in the correct phase would create the complex wave of the original sound. This does not mean that the original sound had any of those sine waves in it. For example a square wave can be represented as a collection of sine waves.

Perhaps it would help if you explained what you intend to do with the "mean frequency" if you can determine it.

PS I have no idea how to do Fourier analysis but they have a wonderful mechanical machine in the Science Museum in London that can do it.

...R

xpleria:
It's a speech signal, with some noise (a small amplitude white noise).

Definition of mean frequency:
The signal I'll be receiving is an audio signal. This will have an irregular waveform. So what I do is, read 300 samples, and find the frequency of each wavelet (basically a wave starting zero going positive then negative and back to zero). then get the mean of it.

@Robin2: I agree that zero-crossing methods are pretty crude, but if you've got a significant dominant frequency though you should pick it out, but that seems to be what he wants to get from the FFT, so it's not too bad a method.