For today you should:
1) Work on exercises.
2) Progress report.
3) Consider case study ideas.
Today:
1) Autocorrelation (the missing chapter 5)
2) Sawtooth chirp and trombone
3) One more thing about noise
For next time:
1) Read Chapter 6 (DCT)
2) Work on exercises.
In statistics, correlation is the tendency of two variables to vary together; that is, when one is high, the other is high, and vice versa.
You can think of X and Y as vectors or signals. If X and Y are unbiased signals, the means are 0 and we can simplify the numerator.
If they are normalized so the standard deviation is 1, we can simplify the denominator... a lot.
So in the context of signals, correlation is usually written:
\sum_i X_i Y_i
NumPy provides corrcoef, and thinkdsp.Wave provides corr:
def corr(self, other):
"""Correlation coefficient.
other: Wave
returns: float
"""
corr = numpy.corrcoef(self.ys, other.ys)[0, 1]
return corr
See chap05.ipynb for an example.
Things that vary in time usually exhibit serial correlation: each value is correlated with its predecessor (and successor).
A simple way to compute serial correlation is to shift the signal and then compute correlation:
y1 = wave.ys[lag:]
y2 = wave.ys[:n-lag]
corr = numpy.corrcoef(y1, y2)[0, 1]
When lag=0, y1 and y2 are the same and the correlation is perfect.
When lag=1, y1 and y2 are very similar, so the correlation is high.
If a signal is periodic with period t, and the framerate is r, what happens when lag = t r?
See chap05.ipynb for an example.
So let's take this idea to the next step and compute corrcoef for all (relevant) values of lag:
def autocorr(wave):
n = len(wave.ys)
corrs = []
lags = range(n//2)
for lag in lags:
y1 = wave.ys[lag:]
y2 = wave.ys[:n-lag]
corr = numpy.corrcoef(y1, y2)[0, 1]
corrs.append(corr)
return lags, corrs
See chap05.ipynb for an example.
Cross-correlation is defined as
f* is the complex conjugate of f, but since we are working with real signals, we can ignore that for now.
When f and g are the same (and real), this is autocorrelation.
If f and g are similar but out of phase, you can find the lag that maximizes their correlation.
numpy provides correlate, which computes cross-correlation, but we can use it to compute autocorrelation:
corrs = numpy.correlate(ys, ys, mode='same')
Let's see if we can figure out the result :)
Why would we want to use cross-correlation instead of just computing autocorrelation?
Because cross-correlation can be "reduced to" DFT, and we have a fast algorithm for DFT.
Where "reduced to" means
1) Mangle the inputs,
2) Apply FFT
3) Unmangle the outputs.
Since autocorrelation and DFT are both doing something like spectral analysis, it is not surprising that there is a mathematical connection.
But in practice, reducing to FFT is not always the best way to compute autocorrelation.
Exercises:
1) Think about better ways to extract the first peak.
2) What happens if you miss the first peak.
3) Make a version of Wave.make_spectrogram that breaks the wave array into segments and uses autocorrelation to find the fundamental pitch of each segment.
5) Apply this analysis to the saxophone sample and see if it sheds any light on the missing fundamental phenomenon.
5) Which is better for pitch tracking, FFT or autocorrelation?
6) What can we infer about human pitch perception?