Continue to Site

# [SOLVED]How to apply hann window to unsigned integer ADC

Status
Not open for further replies.

#### lojos

##### Newbie
Hello, I am using Arm-Cortex M3 Microcontroller and CMSIS for FFT, my microcontroller does not support floating point unit therefore I have to use fixed point (Q15 or Q31) for calculation.
Before calculate FFT, I need to apply hanning window on to my data collected from ADC 12-bit (0-4095). My ADC data ranges from 1800 ~ 3200.
Here is a sample code I have tried so far. Did I correctly apply?
C:
double hann[512];
uint32_t ADC[512]; /* data range 1800 ~ 3200 */
q31_t input[512]; /* fixed point */

// Hann window
for (int i = 0; i < 512; i++)
{
hann[i] = 0.5 * (1 - cos(2*PI*i/511));
}

// apply hann window to ADC data
for (int j = 0; j < 512; j++)
{
input[j] = (q31_t)ADC[j] << 19; // convert to fixed point Q31 from 12-bit
}

Hi,

"double" is a floating point. This is what I´d avoid. And why "double"it´s just overkill in precision.

* ADC[] could be signed (or unsigned 16 bit). ... if you want to save RAM.
* Instead of calculating han[] on runtime you could do a 128 tap (x4 quadrants) 16 bit look up table. To avoid overflow problems I´d go up to 32766 only (It´s still a better resolution than your 11 bit input)
The table calculation would then be
--> hann = 16383 * (1 - cos(2*PI*i/511));

I guess the FFT needs signed input. so use 16 bit signed (15 bits positive)

So your ADC uses 12 bits and the hann uses 15 bits.
To do the math with 32 bits precision I´d use a "cast".
Then after the multiplication you get a 12bits + 15 bits (all positive) value.
To fit into a 16 bit signed variable you need to shift 12 bits right. This gives you the best precision for FFT calculation, but needs to be corrected after the FFT.
(But if you want to maintain ADC precision you need to shift 15 bit right)

(from my understanding hanning attenuates all signals by 6dB. Please check on this.)

So in short:
* hann[]: 16 bit signed. range 0...32766
* ADC[]: 16 bit signed. range (0) 1800 ... 3200 (32767)
* Multiplication: signed_16_bit x signed_16_bit = signed_32_bit
* Then shift right to fit into 16 bit signed

****
Generally the hann values don´t need to have more precision than the ADC values. It does not improve the end result. So using values 0...32766 is well enough.
No need to worry about the mathematical error of 32768/32766. The ADC error will be worse.

Klaus

H
Hi,

"double" is a floating point. This is what I´d avoid. And why "double"it´s just overkill in precision.

* ADC[] could be signed (or unsigned 16 bit). ... if you want to save RAM.
* Instead of calculating han[] on runtime you could do a 128 tap (x4 quadrants) 16 bit look up table. To avoid overflow problems I´d go up to 32766 only (It´s still a better resolution than your 11 bit input)
The table calculation would then be
--> hann = 16383 * (1 - cos(2*PI*i/511));

I guess the FFT needs signed input. so use 16 bit signed (15 bits positive)

So your ADC uses 12 bits and the hann uses 15 bits.
To do the math with 32 bits precision I´d use a "cast".
Then after the multiplication you get a 12bits + 15 bits (all positive) value.
To fit into a 16 bit signed variable you need to shift 12 bits right. This gives you the best precision for FFT calculation, but needs to be corrected after the FFT.
(But if you want to maintain ADC precision you need to shift 15 bit right)

(from my understanding hanning attenuates all signals by 6dB. Please check on this.)

So in short:
* hann[]: 16 bit signed. range 0...32766
* ADC[]: 16 bit signed. range (0) 1800 ... 3200 (32767)
* Multiplication: signed_16_bit x signed_16_bit = signed_32_bit
* Then shift right to fit into 16 bit signed

****
Generally the hann values don´t need to have more precision than the ADC values. It does not improve the end result. So using values 0...32766 is well enough.
No need to worry about the mathematical error of 32768/32766. The ADC error will be worse.

Klaus
Hello, thanks for the detailed input. I will try it later when I am free.

Hi,

in line:

you subtract a DC value. May I ask why?
In my eyes it just causes processing power.
The result of the FFT should not differ (besides tap0)

Klaus

Hi,

IEEE documents are not free to read.

Perhaps you could share with us their explanation why DC should be subtracted. Maybe it makes sense .. but I don´t see it now.

Klaus

Having a DC offset before applying the window convolves the DC line with the window function, the DC line is respectively broadened. If you have significant low frequency components, they can be masked.

There's a big difference in bin 1 and a small difference in the next low bins.

Status
Not open for further replies.