-1
$\begingroup$

I'm trying to calculate the spectral density of a signal. What I'm expecting is a scale in dbFS where 0 dbFS would be the maximal theorical energy if all my signal is concentrated in a single frequency (without clipping, of course).

So, I'll calculate a ratio :

float dbfs = 20.Math.log10(freq_energy/max_theorical_energy);

As an example, I'm using a 16 bits signal sampled at 44100 Hz with 2048 samples for each "sound packet". To get that maximal theorical energy, I suppose I generate a signal at 44100/2048 Hz (around 21 Hz). So, in one "sound packet", I will get one single complete sine cycle. And, as temporal_energy = frequency_energy (Parseval Theorem), I used that routine to find that max_theorical_energy, based on the energy of that theorical temporal signal :

double max_energy
for (int i=0 ; i<2048 ; i++) {
    max_energy+=Math.pow( Math.abs ( Math.sin(2*Math.Pi/2048) * Math.pow(2, 15) ), 2);
    //2^15 = 32000 = maximum absolute value of a 16 bit signal
}

Then, I generated signals at a given frequencie (210 Hz for example) and compared the energy of that signal to my theorical result. As the values for each frequencies are complex, I used that routine to get the energy of my signal (still generating 2048 samples for each "sound packet) :

double signal_energy = 0d;
// datas[] represent the values of my signal after a FFT
for (int i = 0 ; i<datas.length ; i++) {
    signal_energy+= Math.pow(datas[i].getReal(), 2) + Math.pow(datas[i].getImaginary(), 2)
}

So, now, if I calculate the ratio signal_energy / max_theorical_energy, I'm expecting something around 1. But the result is 1.xxxxE8 ! It's very far from 1...

So, what's wrong ? Where are my mistakes ?

Thank you for your help.

$\endgroup$
  • $\begingroup$ How is your FFT algorithm normalized? Are you using a window function? $\endgroup$ – endolith Dec 21 '18 at 16:19
  • $\begingroup$ No, I'm not using any window function. And for my FFT, I'm using a classical "reordering then butterfly" function. I tested my FFT algorythm with few examples (like the one I found on wikipedia) and it seems working. I'm sure it's a "small nothing" which is the cause of my problem but, the smallest it is, the harder it is to find it... $\endgroup$ – Dr_Click Dec 21 '18 at 16:27
  • $\begingroup$ So if you have a 0 dBFS sine wave that fits perfectly into a single bin, with FFT of length N, the amplitude at that bin is 0.5 * N? This is my note to self to remember: gist.github.com/endolith/236567 $\endgroup$ – endolith Dec 21 '18 at 16:33
  • $\begingroup$ @endolith : thank you for your answers and for your help. I will keep your link for future explorations of signal processing. Merry Christmas $\endgroup$ – Dr_Click Dec 21 '18 at 16:34
1
$\begingroup$

Ok, I finally got it !

There were two mistakes in my code.
First one : when calculating the max_energy, I just "forgot" to index "i" (when I was talking about a "small nothing"...)

double max_energy
for (int i=0 ; i<2048 ; i++) {
    max_energy+=Math.pow( Math.abs ( Math.sin(i*2*Math.Pi/2048) * Math.pow(2, 15) ), 2);
    //2^15 = 32000 = maximum absolute value of a 16 bit signal
}

And second mistake : when I'm calculating the maximal energy with frequencies, I have to divide by the number of samples. So, my routine is becoming :

double signal_energy = 0d;
// datas[] represent the values of my signal after a FFT
for (int i = 0 ; i<datas.length ; i++) {
    signal_energy+= Math.pow(datas[i].getReal(), 2) + Math.pow(datas[i].getImaginary(), 2)/datas.length
}

And, now, it works. The ratio is 1.00000xxx

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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