# Best way to evaluate “quality” of autocorrelation?

This is a side-trip from my snoring app.

I had a crack at producing an autocorrelation of the audio signal, to see if that "correlates" with snoring/breathing very well. I have a simple algorithm going (produces 1.0 as the zeroth element, which is a good sign), but I'm wondering how to evaluate the result to determine if the autocorrelation is strong, and, perhaps further, how to use it to separate various possible sound sources.

Question #1: Is the RMS of the autocorrelation (skipping element zero) as good a "quality" metric as any, or is there something better?

To elaborate: I simply want a numerical way (vs "looking" at a chart) to distinguish a highly autocorrelated signal from a less well autocorrelated one.

(I don't really know enough to know what other questions to ask.)

Some early results: In some cases autocorrelation (either RMS or peak) shows a dramatic jump on a snore -- precisely the response I'd like to see. In other cases there is no apparent movement at all in these measures (and this can be two successive snores with the two responses), and in high-noise situations the measurements actually dip (slightly) during a snore.

Update -- 22 May: I finally got some time to work on this some more. (I was pulled off on another app that is literally a pain.) I fed the output of the autocorrelation into an FFT and the output is somewhat interesting -- it shows a fairly dramatic peak near the origin when a snore starts.

So now I'm faced with the problem of quantizing this peak somehow. Oddly, the highest peaks, in terms of absolute magnitude, occur at other times, but I tried the ratio of peak to arithmetic mean and that tracks pretty well. So what are some good ways to measure the "peakedness" of the FFT. (And please don't say that I need to take an FFT of it -- this thing is already close to swallowing its own tail. :) )

Also, it occurred to me that the quality of the FFT might be improved somewhat if I mirror-reflected the autocorrelation results being fed in, with zero (which is by definition 1.0 magnitude) in the middle. This would put the "tails" on both ends. Is this (possibly) a good idea? Should the mirror image be upright or inverted? (Of course, I'll try it regardless of what you say, but I thought maybe I might get some hints on the details.)

Tried flatness--

My test cases can be divided roughly into the "well-behaved" category and the "problem children" category.

For the "well-behaved" test cases the flatness of the FFT of the autocorrelation dips dramatically and the ratio of peak to average autocorrelation climbs during a snore. The ratio of those two number (peak ratio divided by flatness) is particularly sensitive, exhibiting a 5-10x climb during a breath/snore.

For the "problem children", however, the numbers head in exactly the opposite direction. The peak/average ratio dips slightly while the flatness actually increases by 50-100%

The difference between these two categories are (mostly) threefold:

1. Noise levels are (usually) higher in the "problem children"
2. Audio levels are (pretty much always) lower in the "problem children"
3. The "problem children" tend to consist of more breathing and less actual snoring (and I need to detect both)

Any ideas?

Update -- 5/25/2012: It's a little premature to have a victory dance, but when I reflected the autocorrelation about a point, took the FFT of that, and then did spectral flatness, my combined ratio scheme showed a good jump in several different environments. Reflecting the autocorrelation seems to improve the quality of the FFT.

One minor point, though, is that, since the "DC component" of the reflected "signal" is zero, the zeroth FFT result is always zero, and this kinda breaks a geometric mean that includes zero. But skipping the zeroth element seems to work.

The result I'm getting is far from sufficient to identify snores/breaths by itself, but it seems to be a fairly sensitive "confirmation" -- if I don't get the "jump" then it's probably not a snore/breath.

I haven't analyzed it closely, but I suspect that what's happening is that a whistling sound occurs somewhere during the breath/snore, and that whistle is what's being detected.

• As far as the 'strength' measure of correlation, what you need to do is normalize your two signals being correlated, before doing a correlation. (After normalization, each signals' sum should be 1). Then the correlation peak will always exist between -1 and 1. This is your strength. I am not sure about the rest of your question, perhaps you can edit a little. – Spacey May 18 '12 at 16:13
• I'm dealing with autocorrelation, so the two signals are one and the same, and are, by definition "normalized" relative to each other. By "strength" I mean how much autocorrelation there is. – Daniel R Hicks May 18 '12 at 16:47
• I don't understand what you want, but I would think you'd want to measure the maximum value of the autocorrelation peak, not the RMS value of the whole thing. – endolith May 18 '12 at 17:37
• @endolith I think he might be asking about a measure of 'peakiness' of your autocorrelation function, it order to distinguish a signal with one delta, (autocorrelation of noise) from a signal of many peaks? (autocorrelation of signal with harmonics). Perhaps using the spectral-flatness measure can also be used here... – Spacey May 18 '12 at 17:57
• It sounds like spectral flatness is what he wants. Daniel: Do you want to determine how different the signal is from white noise? – Emre May 18 '12 at 19:21

## Preliminaries

This demonstration is easier with the MATLAB package audioread, which enables reading/writing MP3 files. Alternatively, you can convert the MP3 file in the example to WAV manually.

## Easy case

Before we examine your problematic file, let's head over to SoundCloud and grab a decent snore so we know what to expect when the SNR is high. This is a 52s stereo 44.1KHz MP3. Download it to a folder in MATLAB's path.

Now let's calculate the spectrogram (I chose a 8192-sample Hann window) and the spectral flatness:

[snd1,fs1]=mp3read('snoring - brobar.mp3'); % use wavread if you converted manually
[s1,f,t,p1]=spectrogram(mean(snd1,2),hann(8192));
sf1=10*log10(geomean(p1)./mean(p1)); % spectral flatness
plot(linspace(0,length(snd1)/fs1,length(sf1)),sf1); axis tight


The huge dips in the spectral flatness (i.e., deviation from white noise) scream "I am snoring". We can easily classify it by looking at the deviation from the baseline (median):

stem(linspace(0,length(snd1)/fs1,length(sf1)),median(sf1)-sf1>2*std(sf1)); axis tight


We had more than two standard deviations of headroom. The standard variation itself, for reference, is 6.8487.

## Hard case

Now let's take a look at your file. It's a 10 minute, 8KHz WAV file. Since the level is so low, it helps to compand the signal.

[snd,fs]=wavread('recordedFile20120408010300_first_ten_minutes');
cmp=compand(snd,255,1);
wavwrite(cmp,'companded'); % used for listening purposes
[s,f,t,p]=spectrogram(snd,hann(8192));
sf=10*log10(geomean(p)./mean(p));
plot(linspace(0,600,length(sf)),sf);


See those nice dips accompanying each snore? Neither do I. How about the nice peaks? They're not snoring, but the sound of the subject moving. The standard deviation is a paltry 0.9388

# Conclusion

You need to acquire a cleaner signal if you want to rely on the spectral flatness! I had compand it just to hear anything. If a low SNR is detected, prod the user to place the phone closer or use a microphone like the phone that comes with the headset.

The good news is that it is possible to detect snoring in even the problematic case. However, since this question was not just about snore detection I will stop here, and explain how to do that in your other question.

• Now you've got a sense of what I'm up against. That sample was "medium" quality among the samples I have to work with -- there are much worse. And I can read that sample pretty well with my existing algorithms. – Daniel R Hicks May 24 '12 at 12:11
• What algorithms are those? – Emre May 24 '12 at 12:19
• In brief: The sound is run through FFT 8 times a second, the spectrum is sliced into 5 frequency bands, the power and spectral difference for each band is calculated, then the results are scored in a way that gives more weight to bands which appear to be varying at the right rate. – Daniel R Hicks May 24 '12 at 17:21