import numpy as np
import numpy.random as random
from numpy.fft import fft
from scipy.io import wavfile
import matplotlib.pyplot as plt
import seaborn as sns
import os
%matplotlib inline
sns.set()
sns.set(font_scale=1.5)
data_dir = './recordings/'
# determine digits of interest (0 to 9)
digits = [1,2] # change here to load more digits
# dictionary that will store our values
signals = {d:[] for d in digits}
file_names = {d:[] for d in digits}
# import files
for filename in os.listdir(data_dir):
# iterate over digits
for d in digits:
if filename.startswith(str(d)+'_'):
wav = wavfile.read(data_dir+filename)[1]
if len(wav.shape)<2:
signals[d].append(wav)
file_names[d].append(filename)
# find maximum of vector length
N = max([len(v) for d in digits for v in signals[d]])
# next we split our dataset in train and test
# we will use a 80/20 random split.
# create train/test split
ix = np.arange(100)
random.shuffle(ix)
# select train entries
ix_train = ix[:80]
#select test entries
ix_test = ix[80:]
# next we compute the average spectrum of each spoken digit in the training set.
# we will consider a window up to 1.5 KHz
# sampling rate is 8kHz
Ts = 1.0/8000
ix_cut = int(np.ceil(1500*Ts*N))
# initialize dictionary for storing transforms
transforms = {}
# initialize dictionary for storing mean transforms
mean_transforms = {}
# compute mean transform of each digit and in the training set.
# Make sure to only keep the spectrum up to 1.5kHz
# Code Solution to Q1 Here
transforms = {d:[] for d in digits}
mean_transforms = {d:[] for d in digits}
for d in digits:
for ind in ix_train:
transforms[d].append(np.fft.fft(signals[d][ind], n = N))
for d in digits:
for i in range(80):
transforms[d][i] = transforms[d][i][:ix_cut]
for d in digits:
mean_transforms[d] = np.sum(np.abs(transforms[d]), axis = 0)/80
mean_transforms[d] /= np.linalg.norm(mean_transforms[d])
# In this next part, plot the average spectral magnitude of each digit.
# Code Solution to Q2 here
avg_spec_mag = {d:[] for d in digits}
for d in digits:
avg_spec_mag[d] = np.sum(np.abs(transforms[d]), axis = 0)/80
plt.title("Avg. Spectral Magnitude d="+ str(d))
plt.xlabel("Frequency (Hz)")
plt.ylabel("Magnitude")
plt.plot(np.fft.fftfreq(N, Ts)[:ix_cut],avg_spec_mag[d])
plt.show()
# classifier function
# receives a vector, computes the product with average digits, and returns the max inner product
# Input: sample x (vector)
def mean_classifier(x):
# Code Q3a Here
xft = np.fft.fft(x)[:ix_cut]
max_similarity = 0
highest = 0
for d in digits:
similarity = np.inner(np.abs(xft), np.abs(mean_transforms[d]))
if similarity > max_similarity:
max_similarity = similarity
highest = d
return highest
# Write anser for Q3b here
#The classifier performs pretty poorly, categorizing only about 1/4 of samples correctly, a lower accuracy than guessing at random.
# Code 3b Here
tests = 0
correct = 0
for d in digits:
for ind in ix_test:
if mean_classifier(signals[d][ind]) == d:
correct += 1
tests += 1
print(correct/tests)
# Write answer for Q4 here
#The accuracy is now very close to the accuracy I would predict had classifications been given at random.
# Code Q4 here
# determine digits of interest (0 to 9)
digits = [0,1,2,3,4,5,6,7,8,9] # change here to load more digits
# dictionary that will store our values
signals = {d:[] for d in digits}
file_names = {d:[] for d in digits}
# import files
for filename in os.listdir(data_dir):
# iterate over digits
for d in digits:
if filename.startswith(str(d)+'_'):
wav = wavfile.read(data_dir+filename)[1]
if len(wav.shape)<2:
signals[d].append(wav)
file_names[d].append(filename)
# find maximum of vector length
N = max([len(v) for d in digits for v in signals[d]])
transforms = {d:[] for d in digits}
mean_transforms = {d:[] for d in digits}
for d in digits:
for ind in ix_train:
transforms[d].append(np.fft.fft(signals[d][ind], n = N))
for d in digits:
for i in range(80):
transforms[d][i] = transforms[d][i][:ix_cut]
for d in digits:
mean_transforms[d] = np.sum(np.abs(transforms[d]), axis = 0)/80
mean_transforms[d] /= np.linalg.norm(mean_transforms[d])
tests = 0
correct = 0
for d in digits:
for ind in ix_test:
if mean_classifier(signals[d][ind]) == d:
correct += 1
tests += 1
print(correct/tests)
# Code Q5 here