def test_butt_bp8_ir(self): # Generate filter. # 8th order bandpass filter # Freq. passed to butterworth is normalized between 0 and 1 # where 1 is the Nyquist frequency fsig = 1000. B = 400. OSR = 64 fphi = B * OSR * 2 w0 = 2 * fsig / fphi B0 = 2 * B / fphi w1 = (np.sqrt(B0**2 + 4 * w0**2) - B0) / 2 w2 = (np.sqrt(B0**2 + 4 * w0**2) + B0) / 2 hz = signal.butter(4, [w1, w2], 'bandpass', output='zpk') ir = impulse_response(hz, db=80) ff = np.logspace(np.log10(w0 / 4), np.log10(w0 * 4), 100) vv1 = evalTF(hz, np.exp(2j * np.pi * ff)) vv2 = evalTF((ir, [1]), np.exp(2j * np.pi * ff)) np.testing.assert_allclose(db(vv1 / vv2), np.zeros_like(vv1), rtol=0, atol=3)
def bench_ntf_fir_weighting_cvxpy_cvxopt(self): try: import cvxpy # analysis:ignore except: raise SkipTest("Modeler 'cvxpy' not installed") print("Benchmarking NTF FIR synthesis with 'cvxpy' modeler + `cvxopt`") tic = time.clock() ntf = ntf_fir_weighting(self.order, self.hz, self.H_inf, modeler='cvxpy', show_progress=False) timing = time.clock()-tic mf = quantization_noise_gain(ntf, self.hz) vv = np.abs(evalTF(ntf, np.exp(2j*np.pi*self.ff))) pe = np.max(vv)-self.H_inf print("Timing: {:6.2f}".format(timing)) print("Accuracy on constraint: {:e}".format(pe)) print("Accuracy on goal: {:e}".format(mf))
def bench_ntf_fir_weighting_cvxpy_cvxopt(self): try: import cvxpy # analysis:ignore except: raise SkipTest("Modeler 'cvxpy' not installed") print("Benchmarking NTF FIR synthesis with 'cvxpy' modeler + `cvxopt`") tic = time.clock() ntf = ntf_fir_weighting(self.order, self.hz, self.H_inf, modeler='cvxpy', show_progress=False) timing = time.clock()-tic mf = quantization_noise_gain(ntf, self.hz) vv = np.abs(evalTF(ntf, np.exp(2j*np.pi*self.ff))) pe = np.max(vv)-self.H_inf print("Timing: {:6.2f}".format(timing)) print("Accuracy on constraint: {:e}".format(pe)) print("Accuracy on goal: {:e}".format(mf))
# Cut off frequency of reconstruction filters # ...set twice as wide as they should to better see artifacts brk1 = B1 / fphi brk2 = 0.5 - B2 / fphi # Create NTF with DELSIG synthesizeNTF ntf_a = synthesizeNTF(order=4, osr=2 * OSR, opt=3, H_inf=np.sqrt(1.5)) ntf_dual_a = mirroredNTF(ntf_a) # Prepare frequency grid ff_log = np.logspace(np.log10(0.5E-5), np.log10(0.5), 4096) ff_lin = np.linspace(0, 0.5, 1024) # Compute magnitude responses of NTF for plotting ntf_a_mag = lambda f: np.abs(evalTF(ntf_a, np.exp(-2j * np.pi * f))) vv_ntf_a_log = ntf_a_mag(ff_log) vv_ntf_a_lin = ntf_a_mag(ff_lin) ntf_dual_a_mag = lambda f: np.abs(evalTF(ntf_dual_a, np.exp(-2j * np.pi * f))) vv_ntf_dual_a_log = ntf_dual_a_mag(ff_log) vv_ntf_dual_a_lin = ntf_dual_a_mag(ff_lin) # Design output filter hz = signal.butter(4, 2 * brk1, btype='low') # Compute magnitude responses of output filter for plotting hz_mag = lambda f: np.abs(evalTF(hz, np.exp(-2j * np.pi * f))) vv_hz_log = hz_mag(ff_log) vv_hz_lin = hz_mag(ff_lin) print("Plotting the noise transfer function...")
# Get the final weighting function as the product of the two def w2(f): return w1(f)*weight2(f) print("... computing optimal NTF...") ntf1 = ntf_fir_weighting(order, w1, quad_opts={'points': [B/fphi]}) ntf2 = ntf_fir_weighting(order, w2, quad_opts={'points': [B/fphi, B/fphi/10]}) # Prepare frequency axis for plotting fmin = 10**np.ceil(np.log10(B/OSR/100)) fmax = fphi/2 ff = np.logspace(np.log10(fmin), np.log10(fmax), 1000) resp_w1 = np.asarray(map(w1, ff/fphi)) resp_ntf1 = np.abs(evalTF(ntf1, np.exp(1j*2*np.pi*ff/fphi))) resp_w2 = np.asarray(map(w2, ff/fphi)) resp_ntf2 = np.abs(evalTF(ntf2, np.exp(1j*2*np.pi*ff/fphi))) ffa = np.logspace(np.log10(0.5E-5), np.log10(0.5), 1024) vv_a2 = dbv(np.abs(evalTF(ntf2, np.exp(1j*2*np.pi*ffa)))) fig0 = plt.figure() l = plt.plot(ff/fphi, dbp(resp_w1), 'b', label='on-off weighting') plt.plot(ff/fphi, dbp(resp_w2), 'r', label='low-dc-noise weighting') l = plt.plot(ff/fphi, dbv(resp_ntf1), 'b--', label='NTF - on-off') plt.plot(ff/fphi, dbv(resp_ntf2), 'r--', label='NTF - low-dc-noise') plt.xlim(1e-5, 1./2) plt.xscale('log', basex=10) plt.gca().set_xticks([1E-5, 1./2]) plt.gca().set_xticklabels(['$10^{-5}$', r'$\frac{1}{2}$'])
# The motor transfer functions to check (at different load/slip) hs0043 = motor.tf_s(0.043) hs02 = motor.tf_s(0.2) hs06 = motor.tf_s(0.6) hz0043 = motor.tf_z(0.043, fphi, True) hz02 = motor.tf_z(0.2, fphi, True) hz06 = motor.tf_z(0.6, fphi, True) # Frequency axis for frequency domain plots (log scale) fmin_log10 = np.ceil(np.log10(fmot / OSR)) fmax_log10 = np.log10(fphi / 2) ff = np.logspace(fmin_log10, fmax_log10, (fmax_log10 - fmin_log10) * 100) # Plot frequency response of the motor yyz0043 = evalTF(hz0043, np.exp(2j * np.pi * ff / fphi)) yyz02 = evalTF(hz02, np.exp(2j * np.pi * ff / fphi)) yyz06 = evalTF(hz06, np.exp(2j * np.pi * ff / fphi)) plt.figure() plt.semilogx(ff, dbv(np.abs(yyz0043)), 'b', label='$\sigma=0.043$') plt.semilogx(ff, dbv(np.abs(yyz02)), 'r', label='$\sigma=0.2$') plt.semilogx(ff, dbv(np.abs(yyz06)), 'g', label='$\sigma=0.6$') plt.xlim(xmax=10**fmax_log10) plt.ylim(ymin=-50) plt.xlabel('$f$ [Hz]') plt.ylabel('[dB]') plt.suptitle("Magnitude response of motor linearized model") plt.legend() plt.ion() plt.show()
# Compute impulse response print("...computing impulse response of filter") hz_ir = impulse_response(hz, db=60) # Compute the optimal NTF print("... computing optimal NTF") q0 = q0_from_filter_ir(order, hz_ir) ntf_opti = ntf_fir_from_q0(q0, H_inf=H_inf) # Determine freq values for which plots are created fmin = 10**np.ceil(np.log10(10)) fmax = 10**np.floor(np.log10(fphi/2)) ff = np.logspace(np.log10(fmin), np.log10(fmax), 1000) # Compute frequency response data resp_filt = np.abs(evalTF(hz, np.exp(1j*2*np.pi*ff/fphi))) resp_opti = np.abs(evalTF(ntf_opti, np.exp(1j*2*np.pi*ff/fphi))) # Plot frequency response plt.figure() plt.semilogx(ff, dbv(resp_filt), 'b', label="Output filter") plt.semilogx(ff, dbv(resp_opti), 'r', label="Optimal NTF") plt.legend(loc="lower right") plt.suptitle("Output filter and NTFs") # Check merit factors ffl = np.linspace(fmin, fmax, 1000) pg_opti = (np.abs(evalTF(ntf_opti, np.exp(1j*2*np.pi*ffl/fphi))) * np.abs(evalTF(hz, np.exp(1j*2*np.pi*ffl/fphi)))) plt.figure() plt.plot(ffl, pg_opti**2, 'r', label="Optimal NTF")
# Clock frequency of modulator fphi = 2*OSR*(B1) # Cut off frequency of reconstruction filter # ...set twice as wide as it should to better see artifacts brk = B1/fphi # Create NTF with DELSIG synthesizeNTF ntf_a = synthesizeNTF(order=4, osr=OSR, opt=3, H_inf=1.5) # Prepare frequency grid ff_log = np.logspace(np.log10(0.5E-5), np.log10(0.5), 4096) ff_lin = np.linspace(0, 0.5, 1024) # Compute magnitude responses of NTF for plotting ntf_a_mag = lambda f: np.abs(evalTF(ntf_a, np.exp(-2j*np.pi*f))) vv_ntf_a_log = ntf_a_mag(ff_log) vv_ntf_a_lin = ntf_a_mag(ff_lin) # Design output filter hz = signal.butter(4, 2*brk, btype='low') # Compute magnitude responses of output filter for plotting hz_mag = lambda f: np.abs(evalTF(hz, np.exp(-2j*np.pi*f))) vv_hz_log = hz_mag(ff_log) vv_hz_lin = hz_mag(ff_lin) print("Plotting the noise transfer function...") # Plot magnitude responses with log scale - same as Fig. 5a plt.figure()
plt.figure() plt.plot(ff, vv) plt.xlim(1e-5, 1. / 2) plt.ylim(0, 1.1) plt.xscale('log', basex=10) plt.gca().set_xticks([1E-5, 1. / 2]) plt.gca().set_xticklabels(['$10^{-5}$', r'$\frac{1}{2}$']) plt.xlabel('$f$', x=1.) plt.ylabel('$w(f)$', y=0.9) plt.grid(True, 'both') plt.suptitle('Weighting function') plt.tight_layout(rect=[0, 0, 1, 0.98]) print("... computing optimal NTF") ntf_opti = ntf_fir_weighting(order, w1, H_inf=H_inf) ntf_opti_mag = lambda f: np.abs(evalTF(ntf_opti, np.exp(-2j * np.pi * f))) print("... computing delsig NTF") ntf_delsig = synthesizeNTF(delsig_order, OSR, 3, H_inf, 0) ntf_delsig_mag = lambda f: np.abs(evalTF(ntf_delsig, np.exp(-2j * np.pi * f))) print("... plotting optimal NTF amplitude response") vv_mag = dbv(ntf_opti_mag(ff)) vv_mag_delsig = dbv(ntf_delsig_mag(ff)) plt.figure() plt.plot(ff, vv_mag, label='Proposed') plt.plot(ff, vv_mag_delsig, 'r-o', linewidth=0.5, markevery=24,
H_inf=H_inf, normalize=1E3, cvxopt_opts={ 'reltol': 1E-12, 'abstol': 1E-10, 'feastol': 1E-2 }) dunn_ntf = ntf_dunn(3, osr, H_inf) fmin = 10 fmax = fphi / 2 ff = np.logspace(np.log10(fmin), np.log10(fmax), 1000) resp_w = f_weighting(ff) resp_opti = np.abs(evalTF(opti_ntf, np.exp(1j * 2 * np.pi * ff / fphi))) resp_ref = np.abs(evalTF(dunn_ntf, np.exp(1j * 2 * np.pi * ff / fphi))) # First figure. This provides the weighting function and the NTFs fig0 = plt.figure() plt.plot(ff / fphi, dbp(resp_w), 'b', label='audio weighting') plt.plot(ff / fphi, dbv(resp_opti), 'r', label='proposed NTF') l = plt.plot(ff / fphi, dbv(resp_ref), 'g', label="Dunn's NTF") plt.suptitle('Audio weighting and NTF magnitude response') plt.xlim(10E-5, 1. / 2) plt.ylim(-140, 20) plt.xscale('log', basex=10) plt.gca().set_xticks([1E-5, 1. / 2]) plt.gca().set_xticklabels(['$10^{-5}$', r'$\frac{1}{2}$']) plt.xlabel('$f$', x=1.) plt.ylabel((r'$w(f)$, ' +
plt.figure() plt.plot(ff, vv) plt.xlim(1e-5, 1./2) plt.ylim(0, 1.1) plt.xscale('log', basex=10) plt.gca().set_xticks([1E-5, 1./2]) plt.gca().set_xticklabels(['$10^{-5}$', r'$\frac{1}{2}$']) plt.xlabel('$f$', x=1.) plt.ylabel('$w(f)$', y=0.9) plt.grid(True, 'both') plt.suptitle('Weighting function') plt.tight_layout(rect=[0, 0, 1, 0.98]) print("... computing optimal NTF") ntf_opti = ntf_fir_weighting(order, w1, H_inf=H_inf) ntf_opti_mag = lambda f: np.abs(evalTF(ntf_opti, np.exp(-2j*np.pi*f))) print("... computing delsig NTF") ntf_delsig = synthesizeNTF(delsig_order, OSR, 3, H_inf, 0) ntf_delsig_mag = lambda f: np.abs(evalTF(ntf_delsig, np.exp(-2j*np.pi*f))) print("... plotting optimal NTF amplitude response") vv_mag = dbv(ntf_opti_mag(ff)) vv_mag_delsig = dbv(ntf_delsig_mag(ff)) plt.figure() plt.plot(ff, vv_mag, label='Proposed') plt.plot(ff, vv_mag_delsig, 'r-o', linewidth=0.5, markevery=24, markersize=3, label='Reference') plt.xlim(1e-5, 1./2) # plt.ylim(0,1.1) plt.xscale('log', basex=10)
# Compute the optimal NTF print("... computing optimal NTF") q0 = q0_from_filter_ir(order, hz_ir) ntf_opti = ntf_fir_from_q0(q0, H_inf=H_inf) # Compute an NTF with DELSIG, for comparison print("... computing delsig NTF") ntf_delsig = synthesizeNTF(4, OSR, 3, H_inf, 0) # Determine freq values for which plots are created fmin = 10**np.ceil(np.log10(2 * B / OSR)) fmax = 10**np.floor(np.log10(fphi / 2)) ff = np.logspace(np.log10(fmin), np.log10(fmax), 1000) # Compute frequency response data resp_filt = np.abs(evalTF(hz, np.exp(1j * 2 * np.pi * ff / fphi))) resp_opti = np.abs(evalTF(ntf_opti, np.exp(1j * 2 * np.pi * ff / fphi))) resp_delsig = np.abs(evalTF(ntf_delsig, np.exp(1j * 2 * np.pi * ff / fphi))) # Plot frequency response plt.figure() plt.semilogx(ff, dbv(resp_filt), 'b', label="Output filter") plt.semilogx(ff, dbv(resp_opti), 'r', label="Optimal NTF") plt.semilogx(ff, dbv(resp_delsig), 'g', label="Delsig NTF") plt.legend(loc="lower right") plt.suptitle("Output filter and NTFs") # Check merit factors ffl = np.linspace(fmin, fmax, 1000) pg_opti = (np.abs(evalTF(ntf_opti, np.exp(1j * 2 * np.pi * ffl / fphi))) * np.abs(evalTF(hz, np.exp(1j * 2 * np.pi * ffl / fphi))))
return w1(f) * weight2(f) print("... computing optimal NTF...") ntf1 = ntf_fir_weighting(order, w1, quad_opts={'points': [B / fphi]}) ntf2 = ntf_fir_weighting(order, w2, quad_opts={'points': [B / fphi, B / fphi / 10]}) # Prepare frequency axis for plotting fmin = 10**np.ceil(np.log10(B / OSR / 100)) fmax = fphi / 2 ff = np.logspace(np.log10(fmin), np.log10(fmax), 1000) resp_w1 = np.fromiter(list(map(w1, ff / fphi)), np.double) resp_ntf1 = np.abs(evalTF(ntf1, np.exp(1j * 2 * np.pi * ff / fphi))) resp_w2 = np.fromiter(list(map(w2, ff / fphi)), np.double) resp_ntf2 = np.abs(evalTF(ntf2, np.exp(1j * 2 * np.pi * ff / fphi))) ffa = np.logspace(np.log10(0.5E-5), np.log10(0.5), 1024) vv_a2 = dbv(np.abs(evalTF(ntf2, np.exp(1j * 2 * np.pi * ffa)))) fig0 = plt.figure() l = plt.plot(ff / fphi, dbp(resp_w1), 'b', label='on-off weighting') plt.plot(ff / fphi, dbp(resp_w2), 'r', label='low-dc-noise weighting') l = plt.plot(ff / fphi, dbv(resp_ntf1), 'b--', label='NTF - on-off') plt.plot(ff / fphi, dbv(resp_ntf2), 'r--', label='NTF - low-dc-noise') plt.xlim(1e-5, 1. / 2) plt.xscale('log', basex=10) plt.gca().set_xticks([1E-5, 1. / 2]) plt.gca().set_xticklabels(['$10^{-5}$', r'$\frac{1}{2}$'])
# The motor transfer functions to check (at different load/slip) hs0043 = motor.tf_s(0.043) hs02 = motor.tf_s(0.2) hs06 = motor.tf_s(0.6) hz0043 = motor.tf_z(0.043, fphi, True) hz02 = motor.tf_z(0.2, fphi, True) hz06 = motor.tf_z(0.6, fphi, True) # Frequency axis for frequency domain plots (log scale) fmin_log10 = np.ceil(np.log10(fmot/OSR)) fmax_log10 = np.log10(fphi/2) ff = np.logspace(fmin_log10, fmax_log10, (fmax_log10-fmin_log10)*100) # Plot frequency response of the motor yyz0043 = evalTF(hz0043, np.exp(2j*np.pi*ff/fphi)) yyz02 = evalTF(hz02, np.exp(2j*np.pi*ff/fphi)) yyz06 = evalTF(hz06, np.exp(2j*np.pi*ff/fphi)) plt.figure() plt.semilogx(ff, dbv(np.abs(yyz0043)), 'b', label='$\sigma=0.043$') plt.semilogx(ff, dbv(np.abs(yyz02)), 'r', label='$\sigma=0.2$') plt.semilogx(ff, dbv(np.abs(yyz06)), 'g', label='$\sigma=0.6$') plt.xlim(xmax=10**fmax_log10) plt.ylim(ymin=-50) plt.xlabel('$f$ [Hz]') plt.ylabel('[dB]') plt.suptitle("Magnitude response of motor linearized model") plt.legend() plt.ion() plt.show()