Hi I tested arm_rfft_fast_f32 function from CMSIS-DSP 1.4.4 with generated 50hz sine wave at 1000Hz sample rate using 1024 samples, but i get peek value at 102, not 51 which i should get 1000/1024 ~0,97 * 51 = 50Hz:
uint16_t i;
float32_t khz10[1024];
float32_t maxvalue;
uint32_t maxindex;
//float32_t output2[1024];
arm_rfft_fast_instance_f32 S;
arm_rfft_fast_init_f32(&S, 1024);
printf("Input=[");
for(i=0; i<1024; i++){
khz10[i] = 1.2f*arm_sin_f32(2*3.1415926f*50*i/1000)+1;
printf("%f,",khz10[i]);
}
printf("]\r\n");
arm_rfft_fast_f32(&S, khz10,khz10,0);
arm_abs_f32(khz10, khz10, 1024);
arm_max_f32(khz10+1, 1023, &maxvalue, &maxindex);
printf("Max:[%ld]:%f Output=[",maxindex,maxvalue);
I later tested this function with real data from adc and I can only get 1/4 of frequency spectrum
not about 1/2 as I expected. Can anyone could me explain this ?
Hi gregoryk,
Try replacing this block of code
with
arm_cmplx_mag_f32(khz10, khz10, 512); /**/
arm_max_f32(khz10[1], 511, &maxvalue, &maxindex); /**/
for(i=0; i<512; i++){ /**/
The altered lines are marked with /**/ and the changes are in red.
If you are using MATLAB, its function abs distinguishes between a real and a complex parameter.
The CMSIS function arm_abs_f32 computes the absolute value of a real number(s). The output samples of FFT are always complex numbers. "Real FFT" means the input samples are real-valued but the output samples are still complex-valued. Hence, you should use arm_cmplx_mag_f32 instead.
I'm not sure if that is the solution to the problem, I ran out of time and I also cannot make the necessary explanations for all the changes. I would just encourage you to post the result of those modifications.
Regards,
Goodwin
There were errors in the modified code in my previous reply:
The newly revised code is below
arm_max_f32(&khz10[1], 511, &maxvalue, &maxindex); /**/
maxindex++; /**/
&khz10[1] is just an alternative to khz10+1 so it's more appropriate to give it a different color other than red. I chose blue, to mean the original can be preserved.
goodwin >The output samples of FFT are always complex numbers.
Yes you are right,but the code of this function is like this:
/* Calculation of RFFT of input */
arm_cfft_f32( Sint, p, ifftFlag, 1);
/* Real FFT extraction */
stage_rfft_f32(S, p, pOut);
After your modification my result is even stranger mirror value are bigger:
The output samples of FFT are always complex numbers.
This statement is generally correct with only one exception. I forgot that in CMSIS-DSP, the real FFT functions pack the DC and Nyquist frequency data at the beginning of the array. The code must be modified for this fact but in the meantime I'll ignore it.
There is no mirror here. The frequency bins from 0 to 511 are all below the Nyquist frequency. In fact, real FFT functions do not compute the frequency samples above the Nyquist.
What is your input data for this graph, the software-generated or that acquired from the ADC?
What are the bin numbers of those two spikes?
goodwin napisał(-a):What is your input data for this graph, the software-generated or that acquired from the ADC?What are the bin numbers of those two spikes?
goodwin napisał(-a):
Input data comes from sin function which I post in first post. All this is generated by stm32f4 discovery board and send by USB serial and next plot in octave:
i=0:511;
plot(i,Output)
Bins are on 51(that should be) and 460 ?
If output from this function is complex numbers what real FFT extraction do ?
Those information will help but I cannot work with your main problem yet.
When the real input data is preprocessed and applied to the complex FFT function the output of complex FFT is not yet the frequency spectrum of the input data. Postprocessing is needed to recover the spectrum from the intermediate result, that's what "real FFT extraction" does. Postprocessing involves additional operations on the intermediate result but it cannot convert the final output to real numbers. Of course some of the output have their imaginary component equal to zero; in general, however, they are complex numbers.
For your main problem, this is what we can do in the meantime:
Create this new program (this is just for troubleshooting so keep the previous file).
float32_t output2[1024];
for(i=0; i<1024; i+=2){
khz10[i>>1]=khz10[i];
output2[i>>1]=khz10[i+1];
for(i=0; i<512; i++){
printf("%f,",output2[i]);
Temporarily, I enabled the declaration of output2. I want to see the output of arm_rfft_fast_f32 before additional operation is done to the samples. The real and imaginary components will be segregated and output2 is used for this. Now plot khz10 and output2, the range should be 0 to 511 for both arrays.
Ok this is how plots looks like after you sugestion:
Real part:
Imaginary part:
Hi, i find what was wrong. We can't just use the same buffer for input and output in function arm_rfft_fast_f32
So the correct version looks like this:
float32_t output[1024];
arm_rfft_fast_f32(&S, khz10,output,0);
arm_cmplx_mag_f32(output,output, 512);
arm_max_f32(&output[1], 511, &maxvalue, &maxindex);
maxindex++;
printf("Max Value:[%ld]:%f Output=[",maxindex,maxvalue);
printf("%f,",output[i]);
I have aditional qestion about appling window functions
In book Joseph Yiu The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors
there example with using Hannning window
defined like:
// Create the Hanning window. This is usually done once at the
// start of the program.
for(i=0; i<L; i++) {
hanning_window_q31[i] =
(q31_t) (0.5f * 2147483647.0f * (1.0f - cosf(2.0f*PI*i / L)));
Why there is max integer value multiplied by 0.5. is this related with fixed point data type they use.
Can I just use max integer value from ADC which equals 4095 in stm32f4 ?
If i understand correctly in other windows function like Hamming we must also multiply equation by max value which can be obtained from ADC to suppress signal at the edges of buffer ?
Why he divide by L and not by L-1 ?
Horrible and thorny!
If these are the real and imaginary parts of the real FFT function output, then the problem existed even before my suggested modifications. As you can see in the code used to generate these two graphs, the modified portions are not there anymore. I know you can easily understand what I am trying to point out now, that there is a spurious output at bin 460 right after arm_rfft_fast_f32 returned. It's now more difficult to troubleshoot this problem but we still have options to try.
Again I would suggest a simple modification to your program and we will observe its effect in the output of arm_rfft_fast_f32. I want to temporarily modify the sampling rate to 800, later on you can restore your preferred sampling rate. I've shown the block containing the line and the modification
khz10[i] = 1.2f*arm_sin_f32(2*3.1415926f*50*i/800)+1;
Be careful that you enter 800, not 8000. You will do this in the latest code (where I separated the real and imaginary parts) I posted. Again plot khz10 and output2, the range is 0 to 511.
My previous reply is for your previous post containing the plot for the real and imaginary parts. I wonder why I didn't see your follow-up post and prior to my posting of this reply, it was your post that was shown as latest in the welcome page.
I pondered if it is possible to use the same buffer in arm_rfft_fast_f32. My attention was diverted from it because the signal and the spur has an interesting relationship. The frequency bin of the spur, 460, is equal to 511 - 51. Fortunately, you decided to restore the output buffer and found the trouble.
There is still a minor problem with the output spectrum. Earlier I stated that the CMSIS-DSP real FFT functions pack the data for frequency bins 0 (DC) and N/2 (Nyquist frequency) at the beginning of the output array. So if the output array is passed to arm_cmplx_mag_f32 right after arm_rfft_fast_f32, the magnitude for DC will be erroneous and the Nyquist frequency will be missing in the spectrum. We can have it corrected in two ways.
First, we use a temporary variable to save the Nyquist frequency data, later the saved data will be reinserted to the output array.
float32_t saveNyquist; // Variable for saving the Nyquist frequency data
// Take the absolute value of the Nyquist frequency data and save it to saveNyquist
arm_abs_f32(output+1, &saveNyquist, 1);
// Convert real DC data to complex number with imaginary part = 0,
// this 0 obliterates the Nyquist frequency data at index=1
// so it was saved in the preceding function call
output[1] = 0;
// Append the saved Nyquist frequency data
output[512] = saveNyquist;
// There are now 513 frequency bins because of the Nyquist frequency
// and it should be included in the search for the bin with maximum magnitude
arm_max_f32(output+1, 512, &maxvalue, &maxindex);
for(i=0; i<513; i++){
Second, instead of using a temporary variable, we extend the length of the output array to hold one more complex number. The Nyquist frequency data will be copied into the extended location.
float32_t output[1026];
// Unpack the DC and Nyquist frequency data
//
// Copy the Nyquist frequency data to the end of the buffer
output[1024] = output[1];
// Convert the DC and Nyquist frequency data to complex numbers
// with imaginary parts = 0
output[1] = output[1025] = 0;
arm_cmplx_mag_f32(output,output, 513);
Note: The corrections are with respect to the latest code that you posted, the one which you described as correct version.
Regarding the window functions, I'll just request that you post your questions in a new thread since the current discussion is already lengthy.