Go Down

Topic: FFT on Arduino, the audio spectrum is cluttered? (Read 18808 times) previous topic - next topic

el_supremo

@jremington:
I see what you mean now - sorry, my bad.

Pete
Don't send me technical questions via Private Message.

jremington

Quote
BTW: as you can see in the video, the frequency response if VERY good. it recognizes frequencies up to 20 KHz

No, it doesn't. What you are seeing is aliasing and this is very well understood. Any frequencies higher than 4.8 kHz present in the input get "folded" down into the range of 0-4.8 kHz.

pito

#17
Mar 14, 2014, 07:41 pm Last Edit: Mar 14, 2014, 07:46 pm by pito Reason: 1
Code: [Select]
So I connected the Audio signal to A5 instead, and use A0 as noise reference.
Frankly, I can imagine that working when A0 and A5 are sampled simultaneously, but that is not the case with arduino...
PS: As I wrote above, you need an anti-aliasing filter at the ADC input (low-pass), ie when using 20kHz sampling frequency the filter shall cut off everything above 10kHz.

aidvllasaliu


Quote
BTW: as you can see in the video, the frequency response if VERY good. it recognizes frequencies up to 20 KHz

No, it doesn't. What you are seeing is aliasing and this is very well understood. Any frequencies higher than 4.8 kHz present in the input get "folded" down into the range of 0-4.8 kHz.


But how come that when I sweep the tone generator to 20khz it shows up on the arduino's far right side?
And anything beyond 20 khz starts to move to the left again?



Code: [Select]
So I connected the Audio signal to A5 instead, and use A0 as noise reference.
Frankly, I can imagine that working when A0 and A5 are sampled simultaneously, but that is not the case with arduino...


But I AM using an Arduino. An Arduino Uno to be exact, and it Does work, so I don't quite understand what it is that you are saying?

pito

#19
Mar 14, 2014, 07:51 pm Last Edit: Mar 14, 2014, 07:56 pm by pito Reason: 1
Quote
But I AM using an Arduino. An Arduino Uno to be exact, and it Does work, so I don't quite understand what it is that you are saying?

I did not check the noise cancellation code, but in case there is a delay between A0 and A5 sampling, noise cancellation may not work properly.
Quote
it Does work

That could be an illusion, unless you are an experienced dsp guy :)

PS: As I wrote above, you need an anti-aliasing filter at the ADC input (low-pass), ie when using 20kHz sampling frequency the filter shall cut off everything above 10kHz.

jremington

#20
Mar 14, 2014, 07:54 pm Last Edit: Mar 14, 2014, 07:57 pm by jremington Reason: 1
Quote
But how come that when I sweep the tone generator to 20khz it shows up on the arduino's far right side?
And anything beyond 20 khz starts to move to the left again?
You really need to read up on the theory and practice of sampling and FFT calculations. There is plenty of material on line. For example, look at the "sampling sinusoidal functions" and "folding" entries in this article: https://en.wikipedia.org/wiki/Aliasing

Many, many artifacts are introduced by the discrete nature of each procedure and until you understand those, refrain from drawing and publishing unwarranted conclusions. It will only make you look silly.

pito

#21
Mar 14, 2014, 07:59 pm Last Edit: Mar 14, 2014, 08:03 pm by pito Reason: 1
In past I used to use the Maxim's MAX740x low-pass filters, 8pin, 3.3-5V, 8th order, great for your anti- aliasing filter..

http://www.maximintegrated.com/datasheet/index.mvp/id/1899

PS: you must not use the external clock there, a single capacitor (see the datasheet) at CLK against Gnd will clock the filter at specific frequency (internal oscillator).


tmd3

But how come that when I sweep the tone generator to 20khz it shows up on the arduino's far right side?  And anything beyond 20 khz starts to move to the left again?
You're talking about using the Open Music Labs code.  It works up to about 20 kHz because the sampling frequency is about 38.5 kHz.  That code doesn't use analogRead() to get samples; it directly manipulates the ADC.  ADCSRA is set to 0xE5: enable,  start conversion, auto-trigger enable, and prescaler 5.  On a 16 MHz Arduino, that sets the ADC clock to 500 kHz, and, with a conversion every 13 ADC clock cycles, the sample rate is about 38.5 kHz.  The Nyquist frequency is about 19.2 kHz - close to 20 kHz.  You can read about setting up the ADC in the ATMega328 datasheet, Chapter 24.

You've noticed, I'm sure, that you don't get that kind of performance out of your "noise cancelling" code.  That code uses analogRead() to get samples, and leaves the ADC clock at the default setting of 125 kHz, prescaler 7.  The ADC isn't free-running, so samples take 13.5 ADC clock cycles, for a maximum sample rate of about 9.3 kHz, and a Nyquist frequency of about 4.6 kHz.  There'll be some time lost between the end of one conversion and the start of another, so the rate will be a bit less than that.  With sampling controlled by the program, rather than a hardware clock, there'll probably be jitter, but, with interrupts disabled, it may not amount to much.

The results shown in the first post, with a bipolar sine signal directly coupled to the analog input, look about right.  I'd expect the ADC to read zero for the entire negative half-cycle, and to track the input signal for the positive half-cycle, if it wasn't destroyed outright.  Here's a link to a table of Fourier series, showing the coefficients for a half-wave rectified sine signal: http://people.clarkson.edu/~jsvoboda/Syllabi/EE221/Fourier/FourierSeriesTable.pdf.  It has a DC component, a component at the fundamental, and decreasing components at even harmonics.  That corresponds qualitatively with the initial results.

aidvllasaliu


I did not check the noise cancellation code, but in case there is a delay between A0 and A5 sampling, noise cancellation may not work properly.
......
That could be an illusion, unless you are an experienced dsp guy :)

PS: As I wrote above, you need an anti-aliasing filter at the ADC input (low-pass), ie when using 20kHz sampling frequency the filter shall cut off everything above 10kHz.


Haha no I am definately not experienced. But it does seem to work.

When I do not use analogRead to get the data there is more delay it seems, so the noise cancellation does not work
that well. But still most of the unwanted signal is being leaked so it works pretty good for my application.



Quote
But how come that when I sweep the tone generator to 20khz it shows up on the arduino's far right side?
And anything beyond 20 khz starts to move to the left again?
You really need to read up on the theory and practice of sampling and FFT calculations. There is plenty of material on line. For example, look at the "sampling sinusoidal functions" and "folding" entries in this article: https://en.wikipedia.org/wiki/Aliasing

Many, many artifacts are introduced by the discrete nature of each procedure and until you understand those, refrain from drawing and publishing unwarranted conclusions. It will only make you look silly.


I will read for sure. This stuff is interesting!


In past I used to use the Maxim's MAX740x low-pass filters, 8pin, 3.3-5V, 8th order, great for your anti- aliasing filter..

http://www.maximintegrated.com/datasheet/index.mvp/id/1899

PS: you must not use the external clock there, a single capacitor (see the datasheet) at CLK against Gnd will clock the filter at specific frequency (internal oscillator).




I will get one of those chips!


You're talking about using the Open Music Labs code.  It works up to about 20 kHz because the sampling frequency is about 38.5 kHz.  That code doesn't use analogRead() to get samples; it directly manipulates the ADC.  ADCSRA is set to 0xE5: enable,  start conversion, auto-trigger enable, and prescaler 5.  On a 16 MHz Arduino, that sets the ADC clock to 500 kHz, and, with a conversion every 13 ADC clock cycles, the sample rate is about 38.5 kHz.  The Nyquist frequency is about 19.2 kHz - close to 20 kHz.  You can read about setting up the ADC in the ATMega328 datasheet, Chapter 24.

You've noticed, I'm sure, that you don't get that kind of performance out of your "noise cancelling" code.  That code uses analogRead() to get samples, and leaves the ADC clock at the default setting of 125 kHz, prescaler 7.  The ADC isn't free-running, so samples take 13.5 ADC clock cycles, for a maximum sample rate of about 9.3 kHz, and a Nyquist frequency of about 4.6 kHz.  There'll be some time lost between the end of one conversion and the start of another, so the rate will be a bit less than that.  With sampling controlled by the program, rather than a hardware clock, there'll probably be jitter, but, with interrupts disabled, it may not amount to much.

The results shown in the first post, with a bipolar sine signal directly coupled to the analog input, look about right.  I'd expect the ADC to read zero for the entire negative half-cycle, and to track the input signal for the positive half-cycle, if it wasn't destroyed outright.  Here's a link to a table of Fourier series, showing the coefficients for a half-wave rectified sine signal: http://people.clarkson.edu/~jsvoboda/Syllabi/EE221/Fourier/FourierSeriesTable.pdf.  It has a DC component, a component at the fundamental, and decreasing components at even harmonics.  That corresponds qualitatively with the initial results.


I see.

However despite using analogRead(), by adding "ADCSRA = 0xc5;" to the code, I still get the same amount of noise reductions
while still having around 20kHz freq range.
15.5kHz to be almost exact!

What's going on here?

aidvllasaliu

So here are the results that I attached.
Including the Arduino Sketch!

First picture shows us the "Medium Res Mode" (I didn't know what to call it), which has a 15.6 kHz range and very good Noise Reduction.

The second picture shows us the "High Res Mode", which has a 20 kHz range and not so good Noise Reduction.

Both modes were fed with a Sin Wave at 15.6 kHz.

I know that most of you don't agree with me because of aliasing and this and that.
But hey, if it works, it works. There's no need to go deeper than this. I am not planning on becoming a rocket scientist anytime soon anyways.

Just the same way that you don't need to be an engineer just because you're gonna build a car, by definition.

Hope you enjoy the sketch :D

jremington

tmd3 (reply #22) has it right. I haven't tried out the Open Music Labs code, but 8 bit sampling certainly does allow you to span the nominal audio range. As pointed out several times already, in all cases you really need an anti-aliasing filter preceding the input, so that frequencies greater than (ADC sampling frequency)/2 are greatly diminished in the input.

tmd3


However despite using analogRead(), by adding "ADCSRA = 0xc5;" to the code, I still get the same amount of noise reductions while still having around 20kHz freq range.
What's going on here?

What's going on is this:  by executing "ADCSRA = 0xc5,", you change the ADC settings, and change the way it works.  The ADC prescaler is set to 5, selecting a system clock divider of 32, an ADC clock of 500 kHz, and a sample time of 13.5 ADC clock cycles, 27 microseconds.  That corresponds to a maximum sample rate of about 37 kHz, and a Nyquist frequency of about 18.5 kHz.  Because the ADC conversions are triggered by the program, rather than hardware, you'll lose some time in loop overhead and function calls, so the actual sample rate and Nyquist frequency, will be something less.  You measured 15.5 kHz - something less than 18.5 kHz, as expected.  That suggests that you're losing about 5 microseconds per conversion in software, or about 80 system clock cycles.  That's probably not unreasonable.

Your posted code didn't manipulate ADCSRA, so it uses the default prescaler of 7, didviding the system clock by 128, for an ADC clock of 125 kHz, and a maximum sample rate of about 9.3 kHz.  It aliases at something like 4 kHz.  As expected.

If you want to know how the ADC control registers affect the way the ADC works,
You can read about setting up the ADC in the ATMega328 datasheet, Chapter 24.

krass76

try using a battery instead of your pc's 5V to power the arduino (I used a 7.2V racing pack). That did it for me.

aidvllasaliu


tmd3 (reply #22) has it right. I haven't tried out the Open Music Labs code, but 8 bit sampling certainly does allow you to span the nominal audio range. As pointed out several times already, in all cases you really need an anti-aliasing filter preceding the input, so that frequencies greater than (ADC sampling frequency)/2 are greatly diminished in the input.


I will do that!



However despite using analogRead(), by adding "ADCSRA = 0xc5;" to the code, I still get the same amount of noise reductions while still having around 20kHz freq range.
What's going on here?

What's going on is this:  by executing "ADCSRA = 0xc5,", you change the ADC settings, and change the way it works.  The ADC prescaler is set to 5, selecting a system clock divider of 32, an ADC clock of 500 kHz, and a sample time of 13.5 ADC clock cycles, 27 microseconds.  That corresponds to a maximum sample rate of about 37 kHz, and a Nyquist frequency of about 18.5 kHz.  Because the ADC conversions are triggered by the program, rather than hardware, you'll lose some time in loop overhead and function calls, so the actual sample rate and Nyquist frequency, will be something less.  You measured 15.5 kHz - something less than 18.5 kHz, as expected.  That suggests that you're losing about 5 microseconds per conversion in software, or about 80 system clock cycles.  That's probably not unreasonable.

Your posted code didn't manipulate ADCSRA, so it uses the default prescaler of 7, didviding the system clock by 128, for an ADC clock of 125 kHz, and a maximum sample rate of about 9.3 kHz.  It aliases at something like 4 kHz.  As expected.

If you want to know how the ADC control registers affect the way the ADC works,
You can read about setting up the ADC in the ATMega328 datasheet, Chapter 24.



I did read a little bit, hence I added "ADCSRA = 0xc5", but I guess I'll have to go a little bit more in depth in this area!


try using a battery instead of your pc's 5V to power the arduino (I used a 7.2V racing pack). That did it for me.


What or who are you referring to? Please re-formulate :)



Now I have another weird problem.

I am trying to show the FFT on an Adafruit SSD1306 OLED display.

The FFT:ing is working OK in a separate sketch, the OLED:ing is working OK in a separate sketch, but when I combine the two
the OLED:ing does not work.

However when I comment out the FFT code in void setup(), the OLED:ing works perfectly fine.

Does anyone have any idea on what's going on here?

Logically thinking, the OLED:ing part does not have anything to do with the FFT:ing at all purely computation-wise, or pin-wise.

All I'm doing is plotting out the resulting FFT values to the OLED, but the OLED isn't even working once the FFT part of the sketch is running.

Out of RAM?
The sketch size is well below the chip limit.

aydingulgun

hi guys, i read most of the conversation here and i find it very informing, thank you for that. i want to input a sound signal to arduino and output it as PWM signal. what i m trying to do is, controlling some water jets to create a visual of a graphic equalizer. i hope i can explain correctly. what i understand from this topic is that i need to use fft transformation on the computer and a low-pass filter on the output signal from the computer and then i can use it as an analog input to an arduino. this looks and sounds complex but i think i can manage that. My question is: if i understand the parts till now what i need to do next? if i m mistaking what is the mistake? and finally can i do this with a some sort of bord (without using a laptop)? i m sorry for my english ty for your answers.

Go Up