phasenn/phasenn_test5.py

126 lines
3.7 KiB
Python
Executable File

#!/usr/bin/python3
# phasenn_test5.py
#
# David Rowe Oct 2019
# Sparse model like test4 but with non-linear layers (activation functions) as
# these will be required later when we add amplitude information.
import numpy as np
import sys
from keras.layers import Dense
from keras import models,layers
from keras import initializers
import keras.backend as K
import matplotlib.pyplot as plt
# constants
N = 80 # number of time domain samples in frame
nb_samples = 100000
nb_batch = 32
nb_epochs = 50
width = 256
pairs = 2*width
fo_min = 50
fo_max = 400
Fs = 8000
# Generate training data. Given the phase at the start of the frame,
# and the frequency, determine the phase at the end of the frame
# phase encoded as cos,sin pairs
phase_start = np.zeros((nb_samples, pairs))
phase_end = np.zeros((nb_samples, pairs))
Wo = np.zeros(nb_samples)
L = np.zeros(nb_samples, dtype=int)
# Map 0...width-1 to 0...pi
for i in range(nb_samples):
r = np.random.rand(1)
fo = fo_min + (fo_max-fo_min)*r[0]
Wo[i] = fo*2*np.pi/Fs
L[i] = int(np.floor(np.pi/Wo[i]))
for m in range(1, L[i]):
wm = m*Wo[i]
bin = int(np.round(wm*width/np.pi))
# Quantise frequency to this bin, this step is important to
# match results of test3. Without it we are adding +/- 0.5 bin
# uncertainty in the frequency, which will randomise phase shifts
# across bins
wm = bin*np.pi/width
r = np.random.rand(1)
phase_start_pol = -np.pi + r[0]*2*np.pi
phase_start[i,2*bin] = np.cos(phase_start_pol)
phase_start[i,2*bin+1] = np.sin(phase_start_pol)
phase_end_pol = phase_start_pol + N*wm
phase_end[i,2*bin] = np.cos(phase_end_pol)
phase_end[i,2*bin+1] = np.sin(phase_end_pol)
print(phase_start.shape)
print(phase_end.shape)
# note most of these weights whould end up being 0, as we only need
# two wieghts to map each phase rotation
model = models.Sequential()
model.add(layers.Dense(pairs, activation='relu', input_dim=pairs))
model.add(layers.Dense(pairs, input_dim=pairs))
model.summary()
import keras.backend as K
# Compile and fit our model
from keras import optimizers
sgd = optimizers.SGD(lr=0.02, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='mse', optimizer=sgd)
history = model.fit(phase_start, phase_end, batch_size=nb_batch, epochs=nb_epochs)
# measure error over non-zero samples
phase_end_est = model.predict(phase_start)
ind = np.nonzero(phase_start)
err = (phase_end_est[ind] - phase_end[ind])
var = np.var(err)
std = np.std(err)
print("rect var: %f std: %f" % (var,std))
#print(err[:5,:])
# approximation if error is small
err_angle = np.arctan2(err[1::2], 1)
#print(err[:5,:])
print(err_angle.shape)
var = np.var(err_angle)
std = np.std(err_angle)
print("angle var: %f std: %f" % (var,std))
print("angle var: %4.2f std: %4.2f degs" % (var*180/np.pi,std*180/np.pi))
plot_en = 1;
if plot_en:
plt.figure(1)
plt.plot(history.history['loss'])
plt.title('model loss')
plt.xlabel('epoch')
plt.figure(2)
plt.hist(err_angle, bins=20)
plt.title('phase angle error')
plt.figure(3)
r = 0
phase = np.zeros(width)
phase_est = np.zeros(width)
for m in range(1,L[r]):
wm = m*Wo[r]
bin = int(np.round(wm*width/np.pi))
#print("bin: %d %f %f" % (bin, phase_end[r,2*bin], phase_end[r,2*bin+1]))
phase[m] = np.arctan2(phase_end[r,2*bin+1], phase_end[r,2*bin])
phase_est[m] = np.arctan2(phase_end_est[r,2*bin+1], phase_end_est[r,2*bin])
plt.plot(phase[1:L[r]+1],'g')
plt.plot(phase_est[1:L[r]+1],'r')
plt.show()