0
$\begingroup$

I have a set of audio files for which I would like to determine a SNR metric. I tried to implement in Matlab as follows:

% Calculate the FFT and PSD of each of the signals in the signal vector.
afftvectors = {};
hfftvectors = {};
psdvectors = {};
halffreqvectors = {};
powdbvectors = {};
signalpeaks = {};
signalpeaklocs = {};
noisepsd = {};

for k = 1:numel(signalvectors)
    afy = abs(fft(signalvectors{k}));
    afftvectors{k} = afy;
    % Due to the symmetric nature of FFT, only half the spectrum is actually required.
    hfy = afy(1:length(afy)/2+1);
    hfftvectors{k} = hfy;
    
    py = (1/(freqarray{k} * length(signalvectors{k}))) * abs(hfftvectors{k}).^2;
    % since we take only half of the spectrum, we can conserve the energy by multiplying 
    % by 2. Zero frequency (DC) (index 1) and the Nyquist frequency (last index, i.e, end) 
    % do not occur twice so, we'll skip the multiplication operation on them.
    py(2:end-1) = 2 * py(2:end-1);
    psdvectors{k} = py;
    halffreqvectors{k} = 0:freqarray{k}/length(signalvectors{k}):freqarray{k}/2;
    powdbvectors{k} = 10 * log10(psdvectors{k});
    
    % Find peaks
    [signalpeaks{k},signalpeaklocs{k}] = findpeaks(psdvectors{k});
    noisepsd{k} = psdvectors{k} - signalpeaks{k};
end

So, the idea was to get the peaks of Power Spectral Density vector. I hit a dead end when I got the output where 'signalpeaks{1}' is a vector of size 13235x1 but my 'psdvectors{1}' itself is a vector of size 36001x1. All the elements in cell array 'signalvectors' has a sample size of 72000. What exactly is going wrong here? Am I using the wrong function in findpeaks() or something else needs to be done?

$\endgroup$
2
  • $\begingroup$ Why are you subtracting the peaks from the PSD? Your PSD has 36001 points, findpeaks has found 13235 peaks in it. So of course you cannot subtract the two as the vectors have differnt lengths. I wouldn't know what to suggest how to fix it, since I don't understand why you subtract the two. NB: This does not give you a noise PSD as you were hoping... $\endgroup$
    – Florian
    Oct 13, 2020 at 7:52
  • $\begingroup$ Oh. I got the idea from the link here. Maybe my understanding is wrong? Would you suggest a different approach for a SNR metric? $\endgroup$ Oct 13, 2020 at 8:00

1 Answer 1

1
$\begingroup$

Firstly, here is how you can fix what you are tryin to do:

noisepsd{k} = psdvectors{k};
noisepsd{k}(signalpeaklocs{k}) = noisepsd{k}(signalpeaklocs{k}) - signalpeaks{k};

Secondly, here is why I think it is not the greatest idea: You are finding the peaks and subtracting them from the spectrum. This is actually equivalent to setting the points where you have local peaks to zero. In effect, you will have a spectrum that is equal to zero at all points where you have local peaks and equal to signal plus noise at all other points. I fail to see why this could be a good estimate of the noise power spectral density.

Thirdly, if you ask me how to do better, well... finding the SNR of a signal is like asking how to get A and B from C = A+B. You cannot! The problem is not unique. If we have a noisy signal, how would we know what is signal and what is noise, how to even properly define "noise" here? In general you cannot, because both could be stochastic. You can only find an approximation and this approximation will only work well if you know something about your signal. For instance, if you had a pure tone in noise, the problem becomes solvable. We can estimate the tone parameters (frequency, amplitude, phase) form the signal, remove it and treat the remaining part as noise. It works in this case because we know how to differentiate signal and noise, the signal should be tone-like. However, in general audio signals need not be tone-like at all.

The only answer I can give is studying your signals closely and trying to come up with some heuristic that describes them well. Maybe your signals are bandlimited, i.e., you have some regions in the frequency range where you expect no signals. Then you could use those to estimate the noise floor. You would need to assume thought that the noise floor is constant (i.e., the noise is white).

All this will only work if you know a thing or two about your signals. If you know nothing it's back to guessing A and B from C = A+B.

$\endgroup$
3
  • $\begingroup$ I get it. Like you said, I'm getting noisepsd{k} as a 0x0 cell array. I guess this may not be a good approach. Will have to change the direction now. Thanks for the pointers. $\endgroup$ Oct 13, 2020 at 8:45
  • $\begingroup$ Huh, a 0x0 cell array still should not happen ^^ what is the size of psdvectors{k}? They should have the same size. $\endgroup$
    – Florian
    Oct 13, 2020 at 8:52
  • $\begingroup$ psdvectors{k} is a 1x1 cell array. Strange I know. I too expected a 1x1 for noisepsd{k}. $\endgroup$ Oct 13, 2020 at 9:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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