I found out why I am getting aliasing. (bins 2-256 all get activated from anything more than 145hz)
in said post, jremington says I need a low pass filter. I am relatively new to arduino what does he mean by a low pass filter, and how can I do it cost-effectively.
I'm not an expert on this, but the FFT/FHT algorithm has to "know" the sample rate so if there's not a function in the FFT library I'd expect it to be in the library documentation.
Well I can but I am not sure heaping more detail is going to help only confuse but here we go.
The A/D converter is clocked from the main system clock through a frequency divider circuit. A single stage divides the input frequency by two. Basically this is just an edge triggered D-type flip flop with the inverted output wired to the D input. Two stages in cascade will result in a division of four and each additional stage doubled the frequency division achieved.
There are three bits in an internal memory of the processor chip address 0x7A which is called the ADPS2 register that control the division ratio you get, as shown here:-
To change the division this divider gives you simply change those bits. The Arduino compiler knows about these register names and what address they correspond to so you can change them simply by writing to the three bits of the register without changing any of the other bits. So first you make just these three bits zero by using a logic AND operation on the contents of the register and then you use a logic OR to set these bits to what you want.
So to make the A/D faster you make the division of the prescaler smaller, but if it is too small then you loose accuracy on the resultant value. A division of 16 is a good compromise which means setting those bits to 0x04. This is done by the code
Note that while that makes your analogRead faster that is not the only factor in determining the sample rate. The time for storing of the sample also adds to the time it takes to acquire a sample.
The only way to get a true measure of the sample rate is to set a digital pin at the start of you acquiring N samples and clear it when you have finished. Then measure the time this pin is high using an oscilloscope and divide that time by N. This gives the sample time, to get the sample rate then take the reciprocal of this.
Yon need the sample rate to make sense of the FFT results.
I don't know if that is a typo but I am using fht.
I don't need a super accurate decibel reading. I just need a relative sense of volume. I am comparing each frequency bin between left and right.
Have you looked at what the other bits do in that register? It is all in the processor’s data sheet, the way I showed you how to do it preserved bits in the register that you did not need or want to change.
i put the top line into my code (replacing ADCSRA = 0xe5; // set the ADC to free-running mode)
but then i get no results at all.
i am currently getting aliasing. (any sound over 145 hz and bins 2-64 go crazy)
here is my code (slightly modified example from fht library)
/*
fht_adc.pde
guest openmusiclabs.com 9.5.12
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. there is a pure data patch for
visualizing the data.
*/
#define LOG_OUT 1 // use the log output function
#define FHT_N 128 // set to 256 point fht
int fht_left[128];
int fht_right[128];
#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
ADMUX = 0x40; // use adc0
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;
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();
for (int i = 0 ; i < FHT_N ; i++) { //fht_left = fht_output
fht_left[i] = fht_log_out[i];
};
};
for (int i=0; i< FHT_N/2; i++) {
Serial.println(fht_log_out[i]);
};
}
if I'm honest, I have no idea what an adcsra register is. But based on your response, I'm guessing that i need to put the top line under adcsra=0xe5, instead of replacing
There is actually no need to replace that line at all, or make any other changes to the code. As it is, it sets the ADC sample rate to 38 kHz.
If your input has signals with frequency higher that 19 kHz, you will have signal aliasing, which may make it impossible to interpret the results. A good low pass filter is the solution, or change the signal source.
Unfortunately this is a technical hobby, and if you want to get anywhere with it, you must learn to read the processor data sheet, and something about circuits.
It is as almost I never posted reply #8, or you never read it.
Find that piece of the table I posted from the data sheet in reply #8 and above it will be what all the other bits are. If you want to change the free running mode you will have to change both the mask of 0xf8 and the value of 0x04.
Try and understand what this line is doing. The first number 0xf8 is being anded with the value in the register. This means that all the bits in 0xf8 that are zero will result in those same bits in the ADCSRA register being zero. Then the OR with 0x04 results in all the bits with a one in them being set, then the resulting bit pattern is being placed back into the ADCSRA register.
0xf8 is the binary bit pattern 11111000
0x04 is the binary bit pattern 00000100