I am trying to filter some data based on the the following code using Arduino FFT library for FFT (fast Fourier transform)
/*
fft_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.
*/
#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.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 < 512 ; i += 2) { // 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
fft_input[i] = k; // put real data into even bins
// Serial.print(millis());
// Serial.print("input ");
// Serial.print(i);
// Serial.print(" = ");
Serial.println(k);
fft_input[i+1] = 0; // set odd bins to 0
delay(0.1);
}
fft_window(); // window the data for better frequency response
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
fft_mag_log(); // take the output of the fft
sei();
Serial.println("start");
for (byte i = 0; i < FFT_N/2; i++) {
if(i<10 || i>20)
{
fft_log_out[i] = 0;
}
Serial.println(fft_log_out[i]);
}
}
}
After applying the filter like this:
if(i<10 || i>20)
{
fft_log_out[i] = 0;
}
I then need to Inverse FFT data fft_log_out[]
.
I looked for an Inverse FFT function (in particular in http://wiki.openmusiclabs.com/wiki/FFTFunctions) but can't find it anywhere.
So how can I get the Inverse FFT in Arduino?
The inverse FFT can be obtained by making use of the forward transform:
for (int i = 0 ; i < 512 ; i += 2) {
fft_input[i] = (fft_input[i] >> 8);
fft_input[i+1] = -(fft_input[i+1] >> 8);
}
fft_reorder();
fft_run();
// For complex data, you would then need to negate the imaginary part
// but we can skip this step since you have real data.
Note however that your filtering code has a few issues.
First, the results of the forward FFT are complex numbers which carry both magnitude and phase information. Using fft_mag_log
only takes the magnitude, which alone is not sufficient for recovery of the original signal. You should thus use the complete FFT output left in fft_input
array as input to your filtering code.
Second, the FFT of real valued data results in a spectrum with Hermitian symmetry. To get a real valued filtered output, you must preserve that symmetry. So, you should not completely zero out the values in the upper half of the spectrum:
for (byte i = 0; i < FFT_N; i+=2) {
if (! ((i>=20 && i<=40) || (i>=FFT_N-40 && i<=FFT_N-20)))
{
fft_input[i] = 0;
fft_input[i+1] = 0;
}
}
Third, the filtering would be applied to each block of data independently of each other, always assuming that previous inputs were zeros. This typically results in discontinuities at the block boundaries. To avoid this, you should consider using the overlap-add method.
来源:https://stackoverflow.com/questions/30544456/how-to-inverse-fft-in-arduino