mirror of https://github.com/drowe67/phasenn.git
126 lines
3.7 KiB
Python
Executable File
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()
|
|
|