2018-02-26 04:32 PM
Hello,
I am doing a project in which I am using the FFT to do some calculations for a determined signal. I get real data from the ADC and then process it with the FFT.
I noticed that the FFt give me an incorrect output, meaning that whenever I use the FFT to calculate magnitude, or RMS value, or anything I get incorrect values and the problem is not due to scaling since a DC signal give me an RMS value of 0.48 and a 60Hz sine wave that is 3.3V peak to peak gives me a result of 0.5. Because of that I decided to do the following:
- Take the raw data from the ADC and graph it (I got a pretty albeit noisy sign wave);
- Create a sine wave in real time and the perform the FFT
var = 0.0625 * arm_sin_f32(2 * PI * i / 128 + PI/2) + 0.0625;
arm_float_to_q15(&var, &buffer, 1);
I performed the float, q31 and q15 FFT and got the expected result for RMS value of the sine wave.
- I compared both the runtime sinusoidal wave and the acquired wave from the ADC, both were very similar only the ADC sine wave was noisier.
- I decided to convert the data from the ADC to float and then do the float CFFT and the results were correct. I injected varying amplitude signals and all the time I got the correct output (after doing some scaling).
Has anyone faced this problem as well? Is this a bug or am I doing something wrong? Of course I gave the function a complex array, where the even indices were the raw ADC data and the odd indices were 0 (zero). Please help, I'd rather use the q15 version of the CFFT because then I don't have to spend time converting the entire buffer before processing
PS: The ADC buffer is filled by DMA @10kHz
Also, If I use the arm_rms_q15 function on the output of arm_cfft_q15 the result is ALWAYS zero.
#fft-stm32f4 #cmsis-dsp #q15_fft2018-02-26 11:53 PM
- I decided to convert the data from the ADC to float and then do the float CFFT and the results were correct. I injected varying amplitude signals and all the time I got the correct output (after doing some scaling).
Are you aware what q15 is ?
It seems you have a scaling/accuracy problem.
The q15 data type has no real advantage compared to q31, halfword access is not faster than word access.
2018-02-27 12:40 AM
Cross post:
2018-02-27 04:04 AM
But the result of the q31 is not that great either, I decided on using q15 CFFT because the ADC data is 12 bits. I have just tried using the arm_cfft_q31, but I can't just use the data as is formthe ADC, I have to do arm_q15_t_q31 or else it always gives zero as a result for the RMS value.
Are you aware what q15 is ?Yes. I think I might have expressed myself incorrectly, when I said that I converted the raw ADC data to float and executed the CFFT, I meant to say that I converted the data and performed the arm_cfft_f32 and not the arm_cfft_q15.
As I said in my original post, I don't want to have to convert data before using it, that's why I wanted to use the q15 CFFT
2018-02-27 05:14 AM
The 12 bit ADC data are neither q15.
If you don't scale your input data to the format range, you are losing accuracy.
For proper magnitude (phase) values, your 0dB input value should be scaled to the data range (q15, q31).
I utilized M4F cores when using FFT, either F3, F4 or F7 MCUs. And I think the runtime requirements are not significantly higher, compared to integer.
With a STM32F407 at 168MHz core clock, I got about 2.5 ms for a 2048 CFFT using float, with maximal optimization.
Just the compiler builtin optimization, nothing else.
2018-02-27 05:25 AM
AvaTar wrote:
I utilized M4F cores when using FFT, either F3, F4 or F7 MCUs. And I think the runtime requirements are not significantly higher, compared to integer.
I saw a report from ARM a while back showing that floating-point using a hardware FPU was significantly faster than doing scaled integers.
I can't find it now, but it's hinted at in the penultimate page of this:
2018-02-27 05:45 AM
Ok, I'll do that. I'll simply use q31 FFT, since I really do get great results with it, but how was I wrong to assume that ADC data is already in q15 format?
I mean ... it's a value that varies between 0 and 4095, and when I created the FFT in runtime varying from 0 to 4095 i actually got the expected result when calculating the RMS value (I still couldn't use the CMSIS RMS function, I had to implement it on my own) and when I compared both waves they were practically identical, except for the phase offset and the noise, but it still should've worked, but it didn't.
I always assumed that the ADC data received is just a q15 down scaled by a facor of 8 (15 bits - 12 bits = 3 bits ... 2 ^ 3=8).
2018-02-27 06:05 AM
The Q number formats can actually represent an integer part (0 bits for q15) and fractional parts (15 for q15 ...).
So the 12 bit unsigned short blends well into q15, but uses just a fraction of it's possible range and accuracy.
Real DSPs have such formats natively supported in hardware, that's (supposedly) why it found its way in the CMSIS code.
2018-02-27 06:20 AM
Yeah that's why I assumed it would work directly. I still don't know what I did wrong, I can see that I'm using just a fraction of of the range and accuracy that q15 offers, but I still can't understand what I'm doing wrong ... the created sine wave gives me a correct output (a fraction of what I expected), but the 'same' real wave gives me a completely incorrect value, which is very odd to me, I even tried adding a phase offset to the created wave but it still gave me the correct output ...
Well ... it's not like it's crucial for me to use the q15 CFFT, but it would be nice to understand what I'm doing wrong.
PS: I just noticed your avatar, Dilbert rules. And also, thank you very much for taking time from your day to help me with my question
2018-02-27 07:28 AM
Since q15 and q31 are just 'integer' (and calculations like the fft amount to 'scaled math' to avoid loss of precision), I think there is a scaling factor missing.
... the created sine wave gives me a correct output (a fraction of what I expected), ...
With the input signal scaled to 1 (or 0dB), the magnitude tells you directly the portion of energy the corresponding spectral component has.
When 'scaling down' the time-domain signal amplitude, you need to take this into account.
Second thing (I guess you know) is the 'bin effect'.
The sampling frequency and the FFT block size (number of points) define the number resulting spectral components you get.
This does not reflect the reality, since usually (much) more components are present.
Their 'energy' (magnitude) is allotted to the next FFT 'bin' present, i.e. a component actually calculated in the FFT.
Here, just higher resolution, i.e. more points per FFT and thus more effort helps ...