phasenn/phasenn_test8.py

168 lines
5.1 KiB
Python
Executable File

#!/usr/bin/python3
# phasenn_test8.py
#
# David Rowe Oct 2019
# Estimate phase spectra from amplitude spectra for a 2nd order IIR
# filter, just like a Hilbert Transform.
import numpy as np
import sys
import matplotlib.pyplot as plt
from scipy import signal
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
# make tensorflow less verbose ....
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
# custom loss function
def sparse_loss(y_true, y_pred):
mask = tf.cast( tf.not_equal(y_pred, 0), dtype='float32')
n = tf.reduce_sum(mask)
return tf.reduce_sum(tf.square((y_pred - y_true)*mask))/n
'''
# testing custom loss function
x = layers.Input(shape=(None,))
y = layers.Input(shape=(None,))
loss_func = K.Function([x, y], [sparse_loss(x, y)])
assert loss_func([[[1,1,1]], [[0,2,0]]]) == np.array([1])
assert loss_func([[[0,1,0]], [[0,2,0]]]) == np.array([1])
'''
# constants
N = 80 # number of time domain samples in frame
nb_samples = 400000
nb_batch = 32
nb_epochs = 25
width = 256
pairs = 2*width
fo_min = 50
fo_max = 400
Fs = 8000
# Generate training data.
filter_amp = np.zeros((nb_samples, width))
# phase as an angle
filter_phase = np.zeros((nb_samples, width))
# phase encoded as cos,sin pairs:
filter_phase_rect = np.zeros((nb_samples, pairs))
Wo = np.zeros(nb_samples)
L = np.zeros(nb_samples, dtype=int)
for i in range(nb_samples):
# distribute fo randomly on a log scale, gives us more training
# data with low freq frames which have more harmonics and are
# harder to match
r = np.random.rand(1)
log_fo = np.log10(fo_min) + (np.log10(fo_max)-np.log10(fo_min))*r[0]
fo = 10 ** log_fo
Wo[i] = fo*2*np.pi/Fs
L[i] = int(np.floor(np.pi/Wo[i]))
# sample 2nd order IIR filter with random peak freq
r = np.random.rand(2)
alpha = 0.1*np.pi + 0.4*np.pi*r[0]
gamma = 0.9 + 0.09*r[1]
w,h = signal.freqz(1, [1, -2*gamma*np.cos(alpha), gamma*gamma], range(1,L[i])*Wo[i])
for m in range(1,L[i]):
bin = int(np.round(m*Wo[i]*width/np.pi))
mWo = bin*np.pi/width
filter_amp[i,bin] = np.log10(abs(h[m-1]))
filter_phase[i,bin] = np.angle(h[m-1])
filter_phase_rect[i,2*bin] = np.cos(filter_phase[i,bin])
filter_phase_rect[i,2*bin+1] = np.sin(filter_phase[i,bin])
model = Sequential()
model.add(Dense(pairs, activation='relu', input_dim=width))
model.add(Dense(4*pairs, activation='relu'))
model.add(Dense(pairs))
model.summary()
sgd = keras.optimizers.SGD(lr=0.08, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss=sparse_loss, optimizer=sgd)
history = model.fit(filter_amp, filter_phase_rect, batch_size=nb_batch, epochs=nb_epochs)
# measure error in rectangular coordinates over all samples
filter_phase_rect_est = model.predict(filter_amp)
ind = np.nonzero(filter_phase_rect)
err = (filter_phase_rect[ind] - filter_phase_rect_est[ind])
var = np.var(err)
std = np.std(err)
print("rect var: %f std: %f" % (var,std))
c1 = filter_phase_rect[ind]; c1 = c1[::2] + 1j*c1[1::2]
c2 = filter_phase_rect_est[ind]; c2 = c2[::2] + 1j*c2[1::2]
err_angle = np.angle(c1 * np.conj(c2))
var = np.var(err_angle)
std = np.std(err_angle)
print("angle var: %4.2f std: %4.2f rads" % (var,std))
print("angle var: %4.2f std: %4.2f degs" % (var*180/np.pi,std*180/np.pi))
def sample_model(r):
phase = np.zeros(width, dtype=complex)
phase_est = np.zeros(width, dtype=complex)
phase_err = np.zeros(width, dtype=complex)
phase_filt = np.zeros(width)
amp_filt = np.zeros(width)
for m in range(1,L[r]):
wm = m*Wo[r]
bin = int(np.round(wm*width/np.pi))
phase[m] = filter_phase_rect[r,2*bin] + 1j*filter_phase_rect[r,2*bin+1]
phase_est[m] = filter_phase_rect_est[r,2*bin] + 1j*filter_phase_rect_est[r,2*bin+1]
phase_err[m] = phase[m] * np.conj(phase_est[m])
amp_filt[m] = filter_amp[r,bin]
return phase, phase_err, amp_filt
plot_en = 1;
if plot_en:
plt.figure(1)
plt.plot(history.history['loss'])
plt.title('model loss')
plt.xlabel('epoch')
plt.show(block=False)
plt.figure(2)
plt.subplot(211)
plt.hist(err_angle*180/np.pi, bins=50)
plt.subplot(212)
plt.hist(Wo*(Fs/2)/np.pi, bins=20)
plt.title('phase angle error (deg) and fo (Hz)')
plt.show(block=False)
plt.figure(3)
plt.title('sample vectors and error')
for r in range(12):
plt.subplot(3,4,r+1)
phase, phase_err, amp_filt = sample_model(r)
plt.plot(np.angle(phase[1:L[r]])*180/np.pi,'g')
plt.plot(np.angle(phase_err[1:L[r]])*180/np.pi,'r')
plt.ylim(-180,180)
plt.show(block=False)
plt.figure(4)
plt.title('filter amplitudes')
for r in range(12):
plt.subplot(3,4,r+1)
phase, phase_err, amp_filt = sample_model(r)
plt.plot(amp_filt[1:L[r]],'g')
plt.show(block=False)
# click on last figure to close all and finish
plt.waitforbuttonpress(0)
plt.close()