Closed TerelleM closed 4 years ago
Hi @TerelleM , it is a little bit difficult to know what is going on without more details or code. I suspect there might be some confusion with how the data is organized in the FFT output buffer. This is explained in the README here.
If you are using a real FFT, then only FFT bins from 0 to N / 2 (i.e. N/2 = 32 in your case) are produced. In addition, the output data is complex valued, but stored as floating point real values in interleaved format, that is real and imaginary parts of the complex number alternate in the array.
... Re[X_k], Im[X_k], Re[X_{k+1}], Im[X_{k+1}], ...
Let's say that you have N = 64, use a real FFT and want to check the squared magnitude of the 5th FFT coefficient,
float X_5_r = plan->output[10]; // real part: 2 * 5 th element
float X_5_i = plan->output[11]; // imag part: 2 * 5 + 1 th element
float sq_mag = X_5_r * X_5_r + X_5_i * X_5_i;
If you are using a real FFT, please also note that we use a special format to be able to use a shorter buffer. For N=64, we have
[X_0, X_32, Re[X_1], Im[X_1], Re[X_2], Im[X_2], ..., Re[X_31], Im[X_31]]
This is a real array of length 64.
I hope this help. Please let me know if this solves your problem or not :)
Thanks @fakufaku for the response, I should be more specific in just what i'm trying to do here with this code. I am trying to create a spectrum analyzer and want all of the processing to be fast on a single core. I am feeding my ESP32 an audio signal from my phone with a max peak-peak of about 2.5 V, after computing the FFT I convert the values from complex to magnitude and keep them in an array called 'Magnitude' for easy processing.
The problem is I am unsure how the scaling works with the output FFT or how to control it. Say If I fed a frequency of 500Hz-1kHz I'd expect the max peak to appear in the first few indexes of the 'Magnitude' array, similarly if I were to feed a larger frequency of 10kHz-20kHz i'd expect the peak to appear in the last couple of indexes of the 'Magnitude' array. I'd like to have the 'Magnitude' array be scaled properly for frequencies ranging from 50Hz-22kHz (as this is the frequency range of of my phones audio output).
I guess a few of my questions are: What is the frequency range of this FFT?, How does the scaling of the output array adjust with different frequency's? If there are any details I left out please let me know, i'd love to hear your advice as I am not an expert in FFT and am relatively new in C programming.
int task_adc1() {
ESP_LOGD(tag, ">> adc1");
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_0db);
int value = adc1_get_raw(ADC1_CHANNEL_6);
ESP_LOGD(tag, "value: %d", value);
return value;
}
void rfft_test_task()
{
int k;
int NFFT = 32;
// Create fft plan and let it allocate arrays
fft_config_t *fft_analysis = fft_init(NFFT, FFT_REAL, FFT_FORWARD, NULL, NULL);
fft_config_t *fft_synthesis = fft_init(NFFT, FFT_REAL, FFT_BACKWARD, fft_analysis->output, NULL);
// Fill array with some dummy data
for (k = 0 ; k < fft_analysis->size ; k++){
fft_analysis->input[k] = (float)task_adc1();
printf("bin=%d input=%f \n", k, fft_analysis->input[k]);
}
// Calculate FFT
fft_execute(fft_analysis);
fft_execute(fft_synthesis);
// Test accuracy
int n_errors = 0;
for (k = 0 ; k < fft_analysis->size ; k++)
if (abs(fft_analysis->input[k] - fft_synthesis->output[k]) > 1e-5)
{
// Report Errors
printf("bin=%d input=%.4f output=%.4f\n err=%f",
k, fft_analysis->input[k], fft_synthesis->output[k],
fabsf(fft_analysis->input[k] - fft_synthesis->output[k]));
n_errors++;
}
int location =0;
float max = 0;
float Magnitude [((fft_analysis->size)/2)];
for (k = 1 ; k < ((fft_analysis->size)/2) ; k++){
Magnitude [k] = sqrt(pow((float)fft_analysis->output[2*k],2)+ pow((float)fft_analysis->output[2*k+1],2));
if (Magnitude [k] > max){
max = Magnitude [k];
location = k;
}
}
printf("max: %f , ", max);
printf("location: %d \n", location);
fft_destroy(fft_analysis);
fft_destroy(fft_synthesis);
}
Hi @TerelleM , thanks for providing more details!
The frequency range of the FFT is determined entirely by the sampling frequency of the input signal. Let the sampling frequency of the input signal be Fs
, then, the center frequency of the kth bin of the FFT is: f_k = k * Fs / NFFT
. So in this sense your intuition is correct.
Now, in your code, it is not explicit what the sampling frequency of the input signal is. I can imagine a few problems that might be happening. For example (potential problem, I don't know if this is what is happening here):
Fs/2
will wrap around and appear as low-frequency components.task_adc1
until the buffer is full, then run the FFT. For most applications, one wants instead to have the samples accumulate at regular intervals "in the background", and then a full buffer be returned. I think in ESP32-IDF this is implemented by making use of the I2S DMA together with the ADC, see the doc here.@fakufaku, Worked like a charm! Thanks for the help.
Hey there,
I've tested out your code and it works very fast and I am confident in the values however, when testing using a function generator i'd increase the frequency ranging from 100Hz->22kHz and the index of the max output does not match to what i'd expect. For example using a 64 sample size and a test range of 1kHz->6kHz, the index would increase consecutively (5, 6, 7, 8 ,9) but for other increasing frequency ranges it would bounce around (21, 38, 18, 50). Shouldn't the indexes be scaled to the range of frequency?