Rachel Sowa
rsowa@umail.ucsb.edu
The goal of this project is to calculate the fundamental frequency of different signals using autocorrelation and compare this result to the one calculated using the FFT method from the previous project.
%pylab inline
from __future__ import print_function
from __future__ import division
from scipy.io import wavfile
import matplotlib.pyplot as plt
Populating the interactive namespace from numpy and matplotlib
# read in the three instrument wav files
glock_sr, glock = wavfile.read('../P4/glockenspiel.wav')
piano_sr, piano = wavfile.read('../P4/piano.wav')
tom_sr, tom = wavfile.read('../P4/tom.wav')
# a function to compare the different peak values coming from the acorrelation and FFT methods
def printSummary(acorr_freq, fft_freq):
print('The fundamental frequency calculated using autocorrelation is '+str(acorr_freq)+' Hz.')
print('The fundamental frequency calculated using the RFFT is '+str(fft_freq)+' Hz.')
print('The difference between the two is '+str(abs(fft_freq - acorr_freq))+' Hz.')
# find the most prominent frequency using the FFT method
def findMaxPeakFFT(source, sample_rate):
source_fft_mag = abs(fft.rfft(source))
max_freq = argmax(source_fft_mag)*(sample_rate / len(source))
return max_freq
# graph the autocorrelation of a signal and find the first lag peak
def findMaxPeakAcorr(name, source, sample_rate):
plt.figure().suptitle(name,fontsize=25)
plt.gcf().set_size_inches(10,15)
subplots_adjust(hspace=0.3)
subplots_adjust(top=0.93)
# plot the original signal in the time domain
plt.subplot(211)
plt.title('Original Signal in Time Domain')
plt.xlabel('Samples')
plt.ylabel('Amplitude')
src, = plt.plot(source)
plt.legend([src],['Source Signal'])
# autocorrelate the signal and plot it
ax = plt.subplot(212)
maxLags = 700
plt.title('Autocorrelation')
plt.xlabel('Lag')
plt.ylabel('Correlation Strength')
lags, c, lines, line = ax.acorr(source.astype('float64'), maxlags=maxLags, usevlines=False, linestyle='-', marker='None')
ax.set_xlim([0,maxLags]) # only show positive lags, since negative lags are just a mirror image
# only consider the positive lags when finding peaks
upper_half = c[int(len(c)/2):]
# find all maxima above a positive threshold
peaks = where((upper_half[:-2] > 0.5)&(upper_half[:-2] < upper_half[1:-1]) & (upper_half[2:] < upper_half[1:-1]))
# consider the first maximum to be our fundamental frequency indicator (but still in units of lag, not Hz)
fund_freq_lag = peaks[0][0]
# plot a vertical line through this peak
mx = plt.axvline(x=fund_freq_lag, linewidth=1, color='#fe9900')
plt.legend([src, mx], ['Correlation', 'First Peak = '+str(int(fund_freq_lag))+' lags'])
# convert the fundamental frequency from units of lags to Hz
fund_freq_lag = sample_rate / fund_freq_lag
return fund_freq_lag
glock_acorr_freq = int(findMaxPeakAcorr('Glockenspiel',glock,glock_sr))
glock_fft_freq = int(findMaxPeakFFT(glock,glock_sr))
printSummary(glock_acorr_freq,glock_fft_freq)
The fundamental frequency calculated using autocorrelation is 1378 Hz. The fundamental frequency calculated using the RFFT is 1323 Hz. The difference between the two is 55 Hz.
piano_acorr_freq = int(findMaxPeakAcorr('Piano',piano,piano_sr))
piano_fft_freq = int(findMaxPeakFFT(piano,piano_sr))
printSummary(piano_acorr_freq,piano_fft_freq)
The fundamental frequency calculated using autocorrelation is 78 Hz. The fundamental frequency calculated using the RFFT is 78 Hz. The difference between the two is 0 Hz.
tom_acorr_freq = int(findMaxPeakAcorr('Tom Tom',tom,tom_sr))
tom_fft_freq = int(findMaxPeakFFT(tom,tom_sr))
printSummary(tom_acorr_freq, tom_fft_freq)
The fundamental frequency calculated using autocorrelation is 94 Hz. The fundamental frequency calculated using the RFFT is 92 Hz. The difference between the two is 2 Hz.
In the piano and tom tom examples, both the fundamental frequencies calculated by the autocorrelation method were very close to their respective fundamental frequencies calculated by the FFT method. However, in the glockenspiel example, the two calculations differed by 55 Hz. Why did this happen?
Let's take a look at the lag value corresponding to 1323 Hz, the fundamental frequency calculated by the FFT method.
print(44100/1323)
33.3333333333
This is only about 1.3 lags away from 32, the original lag value we calculated above in the glockenspiel example. So actually, the two different fundamental frequencies weren't so far off from each other after all. Most likely rounding error contributed to this difference, and it had a bigger effect in the glockenspiel example than the piano or tom tom examples since its first lag peak was significantly lower than those of the piano or tom tom.