3
$\begingroup$

I have a question about signal processing. Experienced with embedded design and code, but DSP is in new territory.

Thus far I am using the CMSIS DSP library functions, which are working well. I am sampling a low frequency signal. Using a timer interrupt, the sampling rate is 40x higher than the highest signal I expect to see. The "buffer" size I process is 2048. I first apply a low pass FIR (arm_fir_f32), and then to the arm_cfft_f32 function so I can then calculate the frequency information. It works well enough to a point where the frequency is +/- 1Hz. However, I am hoping to get this to +/-200mHz.

I understand that I need to reduce the power (noise) at the endpoints, and the Hann window should be the best (better?) choice. Thus my questions:

At which point do I apply the Hann algorithm? (as follows)

$$w[n] = 0.5 - 0.5 \cos \left( \frac{2 \pi n}{N - 1}\right)$$

Should $N$ be the size of my sample block?

EDIT:

Code for windowing function:

(INPUT_SAMPLES=2048) 
for(uint16_t i = 0; i < INPUT_SAMPLES; i++) 
{ 
    ADC_Values[i] = 0.5 - (0.5 * cos ( (2.0 * PI * ADC_Values[i]) / (INPUT_SAMPLES - 1)));
} 

Thank you for any help on this, Roger

EDIT 2:

jojek,

creating the window and changing the calculation as suggested has fixed it. Although the window has not improved resolution as much as I'd like, it's better, and close enough to be quite usable. Fantastic...thanks for all the replies everyone.

$\endgroup$
  • $\begingroup$ Moved your "comment answer" to original question. Please see updated answer. $\endgroup$ – jojek Jun 25 '14 at 22:05
2
$\begingroup$

You should apply window in time domain. The purpose is to make your signal go to zero at boundaries of your frame/sample block. It is necessary because DFT assumes signal to be periodic, and zeroing it at the ends makes it so. Obviously if length of your frame is constant, then precompute window values.

Enough words:

enter image description here

It just occured to me that you want to get the frequency resolution of 0.2 Hz - is that correct? You must keep in mind that frequency resolution is given by: $\Delta f = \frac{f_s}{N} $. So unless your sampling frequency $f_s$ is not lower than approx. 410 Hz (unlikely) you won't achieve the resolution of 200 mHz. You need to extend your observation window. Also padding your signal with zeros will not help too much - this will be only an interpolation of your spectrum points.

EDIT:

If you perform any FIR filtering, then apply the window afterwards. Windowing should be done just before the FFT calculation to make your signal 'disappear' at the ends (especially when filtering produces artifacts for first output samples). Regarding your frequency resolution, with 2kHz of $f_s$ and $N$ equal to 2048 you get approximately 0.98 Hz of a resolution. If you want more than that, then you might think about extending your sample block or decreasing the sampling frequency. Just keep in mind equation I mentioned above.

EDIT 2:

I presume that the function you pasted (and one I moved to your original question) is only for calculation of window. Do I understand you correctly? Or is it function that is performing windowing of your signal (variable ADC_Values[i] is present). Check the following things:

  1. I corrected your equation for window function - notice that it is dependent only on n - there are no signal samples.

  2. If you want to perform windowing within your function then code should look more like:

    ADC_Values[i] = (0.5 - (0.5 * cos ( (2.0 * PI * i) / (INPUT_SAMPLES - 1)))*ADC_Values[i];

Window calculation itself is given by:

`win[i] = (0.5 - (0.5 * cos ( (2.0 * PI * i) / (INPUT_SAMPLES - 1)));`

Therefore I suggest you to precompute the win once and for all, passing it later to your function and performing ADC_Values[i] *= win[i];. This will save some time.

I am assuming that you making typecasting correctly. If you have any doubts, then extract your signal block before and after filtering, together with window samples and windowed signal. This should help you to debug the code.

EDIT 3:

I am afraid that you still do not understand the principle. Changing of window can only remove leakage effects - kind of noise covering your harmonics. It will not increase your frequency resolution. In the matter of fact, it will make it worse - as rectangular window has narrowest main-lobe. Let me repeat once again - if you want to increase your frequency resolution then you must use the appropriate buffer size and sampling frequency, according to equation $\Delta f = \frac{f_s}{N} $.

$\endgroup$
  • $\begingroup$ Here's the rest of my post. The web page didn't let me finish: Hi, thanks for taking the time to answer. The sample block is 2048. This is about 40 times greater than the highest frequency I would measure. About 20 times over the Nyquist rate. Ok, you may need to throw a bone (a bigger one that might hit my head this time) If I apply the Hann to each ADC sample, before the FIR or FFT, is that considered "time domain" window? Thanks... $\endgroup$ – Roger Jun 24 '14 at 20:10
  • $\begingroup$ @Roger: Answer updated. $\endgroup$ – jojek Jun 24 '14 at 20:47
  • $\begingroup$ jojek, thanks for the detailed reply. I'm already doing precisely as you detail: FIR-->WINDOW-->FFT. However, there must be something going amiss in the Window operation. The values look a bit "thin" coming out; and the FFT output buffer is 0. If it's OK, I'll paste the loop that's performing the Window. (INPUT_SAMPLES=2048) for(uint16_t i = 0; i < INPUT_SAMPLES; i++) { ADC_Values[i] = 0.5 - (0.5 * cos ( (2.0 * PI * ADC_Values[i]) / (INPUT_SAMPLES - 1))); } $\endgroup$ – Roger Jun 24 '14 at 22:58
  • $\begingroup$ @Roger: Please see updated post. $\endgroup$ – jojek Jun 24 '14 at 23:22
  • $\begingroup$ jojek, creating the window and changing the calculation as suggested has fixed it. Although the window has not improved resolution as much as I'd like, it's better, and close enough to be quite usable. Fantastic...thanks for all the replies everyone. $\endgroup$ – user10325 Jun 25 '14 at 20:19
0
$\begingroup$

The N parameter for the size of the Hann window should be the size of your FFT (or, if you plan on zero-padding the data to use a longer FFT, the size of the sample block).

$\endgroup$
  • $\begingroup$ Can you clarify that: I'm sampling at 2KHz, collecting a "block" of data that's 2048 samples. So N should be 2048, correct? And n is the sample: sampleADCValue[n] Thanks... $\endgroup$ – Roger Jun 24 '14 at 20:13
  • $\begingroup$ The (small) n depends on whether you are buffering data and/or using any overlap or not. $\endgroup$ – hotpaw2 Jun 24 '14 at 20:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.