Hi,
I changed the CMSIS-DSP frequency bin example to Q15 format (or at least I'm trying to do so), but I'm getting wrong results. My changed code:
/* =================================================================================================
for(testIndex = 0; testIndex < TEST_LENGTH_SAMPLES; testIndex++)
testInput_f32_10khz_cfft[testIndex] /= 6.2f; //divide the example test data by 6.2 to get it in the range -1...+1
testIndex = 0;
arm_float_to_q15(testInput_f32_10khz_cfft, testInput_q15_10khz_cfft, TEST_LENGTH_SAMPLES); //convert the data to Q15
/* Process the data through the CFFT/CIFFT module */
arm_cfft_q15(&arm_cfft_sR_q15_len1024, testInput_q15_10khz_cfft, ifftFlag, doBitReverse);
/* Process the data through the Complex Magnitude Module for calculating the magnitude at each bin */
arm_cmplx_mag_q15(testInput_q15_10khz_cfft, testOutput_q15_cfft, fftSize); //output 2.14
arm_shift_q15(testOutput_q15_cfft, 1, testOutput_q15_cfft, fftSize); //convert to 1.15
arm_q15_to_float(testOutput_q15_cfft, testOutput_q15_to_f32_cfft, 2048); //for better readability in debug view
The output of this is:
0.0110473633, 0.000000000, 0.000000000, 0.000000000, 0.000000000, 0.000000000, 0.0110473633, 0.000000000,
0.000000000, 0.0110473633, 0.0110473633, 0.000000000, 0.000000000, 0.0110473633, 0.0191040039, 0.000000000,
0.000000000, 0.0110473633, 0.0191040039, 0.0110473633, 0.000000000, 0.0110473633, 0.000000000, 0.000000000,
0.0110473633, 0.000000000, 0.000000000, 0.000000000, 0.000000000, 0.000000000, 0.000000000, 0.000000000,
...
The output of the frequency bin example is:
89.4459534, 26.1034775, 35.7469597, 34.7221146, 49.2430763, 55.420784, 89.1215439, 20.6131191,
37.0284195, 98.7423096, 93.8422165, 63.7021141, 61.6773682, 84.585701, 123.891975, 25.0829983,
52.0468674, 74.8693924, 134.225296, 76.7762985, 16.0060749, 94.5713272, 65.412468, 24.5386391,
77.5796204, 56.8698654, 28.9609737, 18.5632, 26.0725956, 17.7821369, 24.5758419, 5.75964499,
I don't get where my error is. Except of the Q15 shift after the magnitude calculation, I (think I) do the same as in the frequency bin example. I know that I can't expect the same values since Q15 is in the range of -1...+1, but as the output shows, there are many zero values and most of the other values are identical. I expected to have values with the same ratios.
Any ideas what I'm doing wrong? I really don't see my error
Regards,
Ralf
I replaced the arm_cmplx_mag_q15() with arm_cmplx_mag_squared_q15(). Result compared to the output of the f32 CFFT is a ratio between ~980 and ~1061 for the two outputs - so it seems this is working, with a reduced precision and a varying ratio.
So, why do I have to use the squared magnitude function for Q15? The floating point implementation uses the normal magnitude function.
And the magnitude function for Q15 seems to destroy the buffer - why? Is this a bug?
The fixed point ffts downshift the data in order to prevent overflow. In order to properly interpret the output, you'll have to multiply it by a scale factor after it's been converted to floating point. Some documentation about it here Complex FFT Functions . I think you'll just have to multiply by the fft length, but I could be off by a bit. However, this won't fix those zeros you're seeing obviously. Maybe the divide by 6.2 makes the input values too small and it's losing precision? Hard to say. When you show the normal frequency bin example output, try changing the input to that to be /= 6.2 as well to get a more direct comparison of outputs. Could you post those expected results too please? I'm curious to see
I'm not sure what to say about mag vs squared mag.
Hi Daniel,
Daniel White schrieb: The fixed point ffts downshift the data in order to prevent overflow. In order to properly interpret the output, you'll have to multiply it by a scale factor after it's been converted to floating point. Some documentation about it here Complex FFT Functions . I think you'll just have to multiply by the fft length, but I could be off by a bit. However, this won't fix those zeros you're seeing obviously. Maybe the divide by 6.2 makes the input values too small and it's losing precision?
Daniel White schrieb:
The fixed point ffts downshift the data in order to prevent overflow. In order to properly interpret the output, you'll have to multiply it by a scale factor after it's been converted to floating point. Some documentation about it here Complex FFT Functions . I think you'll just have to multiply by the fft length, but I could be off by a bit. However, this won't fix those zeros you're seeing obviously. Maybe the divide by 6.2 makes the input values too small and it's losing precision?
changing from /= 6.2 (double) to /= 6.2f (float) doesn't make a difference. You might be right that the output could be scaled by the FFT size. I'll check if the scaling factor depends on the FFT size.
I don't have a problem keeping the output in the range of +/- 1, this might be helpful later when showing the data on a display as graphs.
The main problem for me is that the data gets corrupted when using arm_cmplx_mag_q15() and I don't know if this is a bug. For my understanding the steps to achieve the example results with Q15 should be the exactly the same as with the float type.
Interestingly, doing the same steps with the CMSIS RFFT Q15 implementation works (of course using a real data only input array) with arm_cmplx_mag_q15(), so it can't be a bug.
So, it's as follows:
CFFT float type works with arm_cmplx_mag_f32()
CFFT Q15 type works(?) with arm_cmplx_mag_squared_Q15()
RFFT Q15 type works with arm_cmplx_mag_Q15()
I'm just a beginner in FFT and how it works. I'd understand if the CFFT f32/Q15 versions would need arm_cmplx_mag_xxx() and the RFFT would need arm_cmplx_mag_squared_xxx(), because the output of the RFFT might be different, but this is not the case...
Daniel White schrieb: When you show the normal frequency bin example output, try changing the input to that to be /= 6.2 as well to get a more direct comparison of outputs. Could you post those expected results too please? I'm curious to see
When you show the normal frequency bin example output, try changing the input to that to be /= 6.2 as well to get a more direct comparison of outputs. Could you post those expected results too please? I'm curious to see
The f32 CFFT output shown above is already done with a scaled down input, please look at the first loop in the code posted above (and please ignore the double for() loop, the forum software seems to have a different behaviour than other applications when using copy/cut/paste shortcuts).
So, it seems that for a CFFT Q15, the input has to be downscaled in combination with an upscale of the output to get directly comparable results.
Another idea, instead of doing
Handle this in floating point. You might be cutting off the top bit of the results of complex mag.
Daniel White schrieb:Another idea, instead of doingarm_shift_q15(testOutput_q15_cfft, 1, testOutput_q15_cfft, fftSize); //convert to 1.15Handle this in floating point. You might be cutting off the top bit of the results of complex mag.
I checked this by setting a breakpoint at this line and looked in the testOutput_q15_cfft array - the contents are already corrupted before the Q15 shift.
I also compared the values of the input buffer after the CFFT/RFFT and before the mag calculation - they're identical except of the ratios.
Currently I'm investigating what happens inside the arm_cfft_q15() function. I identified a difference between the Q15 CFFT and RFFT: for the RFFT it's clearly stated that the output must be downscaled. However, the CFFT Q15 documentation doesn't mention any scaling, therefore my code currently doesn't scale the CFFT result before calculating the magnitude. Maybe this is the problem...
For anyone still looking for this answer, and for my sanity:-
1. input buffer is N samples
2. output buffer is N*2 results (real + imag)
3. before Mag calc you must scale depending on FFTSize (N) N=32 :<<4, 64:<<5,128:<<6, ... you get the idea (don't forget 2*N)
4. length to pass to Mag calc is FFTSize (N) but output will be N/2 (me thinks)
4. RFFT will eat your input buffer ;) Mmmm bits.
5. RFFT ifftFlagR =0(forward transform [time -> Freq]), bitReverseFlag =1 (go figure)