FHT processing appears VERY noisy

I downloaded the FHT library, hooked up my function generator to A0 and watched the serial port data from the standard fht_adc_serial example (after adding a delay (5):wink: and the data didn't look right. To test the FHT program, I grounded A0 with a 1k resistor straight to arduino ground and was hoping to see straight zeros. I posted some of what I got below. Why is this not zero? The output of FHT does change when I hook up different signals, but grounding the input should be a flatline. Is this a noise problem? And if so is it possible to quiet the arduino enough to get a reasonable FHT?

start
232
216
80
60
47
42
38
32
33
19
27
27
19
19
19
19
8
19
19
27
16
19
19
19
19
19
19
16
19
19
19
19
0
8
8
16
16
0

To help with this, we'll need these:

  • A schematic of your circuit. If we can't get that, we need a clear description. In particular, we need to know pretty precisely how you're connecting the analog input signal.
  • Your code. You mention adding a delay(5). We need to know where you added it. Please post your whole sketch.
  • A link to the library that you're using. Please be specific. If you're using the Open Music Labs FHT library, note that there are three libraries available.

The test circuit is just a 1k ohm resistor plugged in directly from A0 to the GND plug next to Vin on my Arduino UNO. I assume that should give straight zeros for the FHT, but it doesn't.

The code is as follows:

/*
fht_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 256 // set to 256 point fht

#include <FHT.h> // include the library

void setup() {
  Serial.begin(115200); // use the serial port
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
  while(1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      delay(5);
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    sei();
    Serial.println("start");
    for (byte i = 0 ; i < FHT_N/2 ; i++) {
      Serial.println(fht_log_out[i]); // send out the data
    }
  }
}

To be honest, I'm not sure which library I downloaded, I didn't know there was more than one. Hopefully, the comments in the top of the code help to decipher that...

MODERATOR ADDED [code]...[/code] TAGS

OK. I'll suggest that you eliminate the "delay(5)" that you added. It will only add confusion later as you get this setup working.

Based on what you've posted so far, my impressions are that you don't have much experience in acquiring audio data with an analog input, and that you're not particularly familiar with the Fourier transform. I also think that you're using an Uno, and that you're a skilled English speaker. Are those impressions correct?

I'd also like to know what your objectives are with this post. Are you hoping to gain insight into the Arduino and the Fourier transform, or are you in a hurry to just get it working? For now, I'm going to take it that you yearn for knowledge for its own sake, and progress slowly, with you doing work and analysis at each step. If that doesn't suit your goals, please say so.

And, I'd like to get an idea of your familiarity with the concept of a logarithm, and an idea of your level of skill at designing and analyzing electrical circuits.

I'll strongly recommend that you refrain from using an audio signal as your input for now. An audio signal goes both positive and negative, and the Arduino's analog inputs are only able to deal with positive signals that are less than 5 volts. If you connect an audio signal directly to an analog input, or even through a resistor, the negative voltage that exists during part of the audio cycle can damage or destroy the analog input. Shortly, we'll work out some simple hardware that will let you safely connect an audio source to your Arduino.

My experience tells me that destruction is unlikely if the signal voltage isn't particularly high and the source isn't particularly powerful - maybe it comes from an iPod, as opposed to, say, the speaker output of a 100-watt amplifier - and it hasn't been connected for a long time. Odds are that your Arduino is fine. If you want to test it, you can write a sketch to read the analog input, print its value to the terminal, delay for a bit, and do it all again. Then run the sketch while you connect the analog input to GND, 3.3V, and 5V, and observe that the readings are what you'd expect.

Back to your question. I'd recommend that you examine the analog data that you've acquired, before it's processed, to determine whether the data is what you think it is. An easy way to do that is to print the contents of the array fht_input[] right after the acquisition is complete, and before fht_window() is executed. Please tell us what you see, and what you expected.

That may be a bit tricky, since the sketch you posted will run continuously, and will scroll data on the screen quickly and without limit. You can make it stop after one execution by inserting this line at the point where you'd like the processor to stop:

   while(1) {}

In this case, that might be right after you print the input data. That'll make the processor wait until the value 1 evaluates as false; it'll never happen, so this bit of code is the equivalent of halting the processor.

Finally, I see that the moderator has added [ code ]...[ /code ] tags to your post. That suggests to me that you haven't read the sticky post, "How to use this forum - please read.", found at the top of the topic listings in each section of the forum. Please read that post. It describes some housekeeping details that will make your posts clearer, and clarity will help you garner more and better responses.

If you remove the call to the fht_window() function you will get all zeroes except in the first bin (the DC component).

Pete

Pete,

Thanks for the response! I tried your suggestion and did see the data go to all zero except the first bin. Why does blocking that function help?

To explain my situation a little further, I'm interested in using the FHT for evaluating frequency components of an analog signal between 8 and 60 Hz and figured the delay would help focus in on this frequency range. If I'm using the following equation correctly:

Frequency(k) = (k)*(sample_rate)/(FHT_N)

the 5ms delay (+ ~3ms processing time) should make the sample rate ~125Hz so the bin frequencies should be:

Frequency(k) = k*(125)/256

So to verify the FHT was working I tried a new test case running a 2.5 volt ~50Hz square wave into A0 with the modified code (eliminating the fht_window) and the output data did not look correct in this case. I know my square wave doesn't have a perfect duty cycle (it's a 555 timer) but still I would expect to see frequency components that should start around 50 Hz (which should be somewhere past bin 50), but this appears to give a lot of low frequency components. I want to verify that the FHT works with simple sample cases before assuming it will work on my complicated signal. Any additional thoughts? (tmd3, thanks for the idea on checking the input stream! I should have a chance to do that shortly just to verify that's not the problem.) Data below:

start
176
215
210
198
174
155
179
181
172
139
155
169
168
155
79
154
162
158
139
127
152
156
149
115
136
150
150
138
80
139
148
144
125
116
141
145
137
101
127
141
141
128
80
132
140
136
116
111
134
138
130
91
121
135
135
122
81
126
134
130
109
107
129
133
125
82
117
130
130
116
83
123
130
126
103
105
126
129
121
72
115
128
127
112
83
121
128
123
99
104
124
127
118
63
114
126
125
110
85
119
126
121
96
104
123
125
116
49
113
124
123
107
87
119
125
120
92
104
122
124
114
30
113
124
122
106
89
119

I don't know why removing the windowing does that. Windowing is supposed to improve the frequency response but when I've used it, it seems to smear a clean signal across bins on either side.

One thing you should try is to print out the input array and see if it looks like a reasonable square wave going in to the FHT.

I don't know if you can get a decent result when using such a small range of low frequencies. I've only used audio frequencies, although I have been able to decode the 100Hz date/time code on the WWV AM station.

Pete

A 50 Hz square wave has many frequency components, much higher than 50 Hz. If it has 50% duty cycle, then the components are odd multiples of the fundamental (150, 250, 350, etc.). If not 50% duty cycle, then both even and odd multiples of the fundamental frequency are present.

All of those frequencies will show up in your output, confused by aliasing with the sample frequency. Google "fft aliasing" for more info.

If you are interested only in the spectrum between 8 and 60 Hz, you must have an antialiasing filter between the signal source and the Arduino input that effectively eliminates all frequencies above (sample frequency)/2, and the sample frequency should be rather higher than twice the maximum frequency of interest.

Finally, the FHT processing itself is not very noisy. Look to your data instead.

I understand that you should see a lot of frequency components above the 50 Hz frequency of the square wave, but there should be a sharp cutoff in the FHT data below ~50Hz. I checked the ADC signal into the analog port and it looks like a square wave.

Just to clarify, I ran the basic FHT code listed above without the delay and without the windowing. The first bin should be at 1.22Hz and since that frequency is well below 50Hz, it should be close to zero with a 50Hz square wave input. The data should start to appear around the 40th bin (~50Hz) with bins 1-39 all approximately 0, but that's not what I'm seeing on the FHT output.

skaght:
The data should start to appear around the 40th bin (~50Hz) with bins 1-39 all approximately 0, but that's not what I'm seeing on the FHT output.

OK, so that's what it's not doing. Really, though, we need to know what it does do, and that fairly specifically, if we hope to help here.

Maybe you could show us the values of fht_input[] immediately after they're loaded, the values of fht_input[] immediately after fht_run() is executed, and the values of fft_log_out[] after processing is complete.

show us the values

And please put them in code tags so that they don't require a huge amount of scrolling to get to the next message.

Pete

el_supremo:
... please put them in code tags so that they don't require a huge amount of scrolling ...

Or, attach the data as text files.

Posting the actual code you used to get the data would be helpful, too. These two statements seem to me to be inconsistent:

skaght:
... ran the basic FHT code listed above without the delay and without the windowing.

The first bin should be at 1.22Hz ...

Without the delay - I presume that's the 5 millisecond delay you added earlier - the sample frequency is set to one sample every 26 microseconds, nearly 38.5 kHz, by the assignment to ADCSRA in setup() and again in loop(). That corresponds to a bin #1 frequency of about 150 Hz. Seeing the code would clear up this dichotomy, for me at least.

but there should be a sharp cutoff in the FHT data below ~50Hz.

Not true. Obviously, you have not yet read up on aliasing.

If you sample a perfect 50 Hz square wave using 120 Hz sample frequency, there will be a strong component in the FHT spectrum at 150-120 Hz, or 30 Hz. If it is not a perfect square wave, there will also be signals in the spectrum at 120-100 = 20 Hz, etc.

I'll repeat that "FHT processing" is NOT noisy. The true noise is due to limited precision of the calculation, which is on the order of a few parts in 10,000.

However, there can be very large artifacts due to sampling, windowing and lack of appropriate input filtering that you must learn about, if you hope to make sense of your calculations. I recommend starting with the FFT instead of the FHT because the theory is simpler.

I'm actually working with the same library right now.

The reason I was getting noise was

  1. the circuit between the Analog Input 5 (which I am using) and the audio jack was with other components than described from the diagram I was using.

Correcting that, and building the correct circuit eliminated some noise.

  1. The other problem was that I was using the stock code presented in the FHT library,
    which apparently is using the ADC directly.

I changed that code a bit so it reads data from the Analog Input using the standard AnalogRead() function
and that eliminated the noise COMPLETELY.

Please read my previous (very old) post for some info: FFT on Arduino, the audio spectrum is cluttered? - Audio - Arduino Forum

The diagram I am using for the circuit between the Analog Input and the Audio Jack can be found here: http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-realtime-audio-processing/

Or more specifically here:

Build that circuit, and change the code so the samples are taken from AnalogRead(), and your noise level should be very close to 0 if not spot on 0.

Why is noise introduced when using Open Music Labs original code?

I have no idea, and their documentation is very poor.

Good Luck!

EDIT:

Make sure that the 4.7nF capacitor is a Ceramic Capacitor.
You know the little brown:ish ones?

AnalogRead() does nothing other than take the input from the ADC directly, so it is very hard to see how that could possibly yield any different result than the method used the OpenMusicLabs code.

I can't think of any reason that using analogRead(), as opposed to the hardware-clock-triggered free-running ADC, would improve the results of the FFT. analogRead() triggers each conversion in software, and it's therefore vulnerable to latency while some ISR finishes executing. At best, it won't have as accurate a timebase as the ADC's hardware clock. The FFT needs a series of samples very evenly-spaced in time in order to provide accurate results.

aidvllasaliu:
Why is noise introduced when using Open Music Labs original code?

I'm still waiting for something quantitative to support that assertion. Like, some input data and output data, showing a noisy result for a clean input.

tmd3:
I can't think of any reason that using analogRead(), as opposed to the hardware-clock-triggered free-running ADC, would improve the results of the FFT. analogRead() triggers each conversion in software, and it's therefore vulnerable to latency while some ISR finishes executing. At best, it won't have as accurate a timebase as the ADC's hardware clock. The FFT needs a series of samples very evenly-spaced in time in order to provide accurate results.
I'm still waiting for something quantitative to support that assertion. Like, some input data and output data, showing a noisy result for a clean input.

Please read the old post I made, I have screenshots and videos posted there.

A lot of people seem to get noise.

I did read that old thread, and in fact contributed to it.

As far as I can see, nothing useful was gained from that long discussion. Many people misuse FFT routines, fail to use proper input filtering techniques or make other mistakes, then abandon the project and leave other people confused.

In particular, it was NOT shown in that thread that for a clean, properly filtered signal, use of AnalogRead() is "less noisy" than the analog read code built into the OpenMusicLabs routine.

aidvllasaliu:
A lot of people seem to get noise.

Maybe. I still haven't seen anything quantitative and repeatable.

A lot of people seem to think that they get noise, because they:

  • Don't notice that the output data from the example code is logarithmic, rather than linear. Low values show up a lot better on a logarithmic scale. I think that users sometimes misinterpret the logarithmic representation of very low values as noise.
  • Don't notice that the example code applies a Hann window to the input data before performing the FFT. The Hann window reduces spectral leakage for samples whose periods don't fit neatly into the sample frame, at the expense of some sharpness of spectral peaks.
  • Eliminate the windowing function to get sharp peaks, and then interpret spectral leakage in the FFT output as noise.
  • Don't know what spectral leakage is.
  • Think that a single-pole filter with a corner frequency at half the sampling frequency is adequate to eliminate aliasing.
  • Interpret aliased signals as noise.
  • Don't know what aliasing is.
  • Have an understanding of the FFT, the DFT, and the Fourier transform that's based more on folklore than on analysis.

My experience tells me that the Open Music Labs Fourier libraries work well, and provide accurate results within the limits of the fixed-point math they use. If those libraries are faulty, I'd like to know, and I think that the rest of the community would like to know, too. Show us unprocessed input data and faulty output output data, and describe what's wrong. The community will repeat the experiment and verify your results.