def denormalize_one_pole(self, pole): # cambio de variable: s -> q*(s/wo+wo/s) = q*(s^2+wo^2)/(s*wo) # 1/(s-p) -> (wo*s)/(q*s^2 - p*s*wo + q*wo^2) # entonces por cada polo REAL tengo: if pole.imag == 0: [denorm_zeroes, denorm_poles, gain_factor] = \ signal.tf2zpk([self.denormalized_template.w0, 0], [self.q, -pole * self.denormalized_template.w0, self.q * self.denormalized_template.w0**2]) # 1/( (s-p)*(s-conj(p)) ) -> # ((-wo^2)*s^2)/((-q^2)*s^4 + q*wo*(conj(p) + p) *s^3 + (- 2*q^2*wo^2 - p*conj(p)*wo^2)*s^2 + (p*q*wo^3 + q*wo^3*conj(p))*s - q^2*wo^4) # ((-wo^2)*s^2)/(a*s^4 + b *s^3 + c *s^2 + d *s + e) # entonces por cada polo IMAGINARIO tengo: else: a = -self.q**2 b = self.q * self.denormalized_template.w0 * 2 * np.real(pole) c = -(2 * self.q**2 + abs(pole)**2) * self.denormalized_template.w0**2 d = 2 * np.real(pole) * self.q * self.denormalized_template.w0**3 e = -self.q**2 * self.denormalized_template.w0**4 [denorm_zeroes, denorm_poles, gain_factor ] = signal.tf2zpk([-self.denormalized_template.w0**2, 0, 0], [a, b, c, d, e]) return [list(denorm_poles), list(denorm_zeroes), gain_factor]
def plot_zp(self): zd, pd, kd = signal.tf2zpk(self.b_num_dig, self.a_den_dig) za, pa, ka = signal.tf2zpk(self.b_num, self.a_den) Pza, Ppa, Pka = signal.tf2zpk(self.Pb_num, self.Pa_den) plt.figure(figsize=(5760 / 300, 3240 / 300), dpi=300) plt.subplot(131) plt.xlabel('Imaginary') plt.ylabel('Real') plt.grid(True) plt.xlim(-1.2, 1.2) plt.ylim(-1, 1) plt.plot(np.real(zd), np.imag(zd), 'or') plt.plot(np.real(pd), np.imag(pd), 'xr') x = np.linspace(-2, 2, 400) y = np.linspace(-2, 2, 400) x, y = np.meshgrid(x, y) z = x * x + y * y plt.contour(x, y, z, [1]) plt.subplot(132) plt.xlabel('Imaginary') plt.ylabel('Real') plt.grid(True) plt.plot(np.real(za), np.imag(za), 'ob') plt.plot(np.real(pa), np.imag(pa), 'xb') plt.subplot(133) plt.xlabel('Imaginary') plt.ylabel('Real') plt.grid(True) plt.plot(np.real(Pza), np.imag(Pza), 'og') plt.plot(np.real(Ppa), np.imag(Ppa), 'xg') plt.savefig(str(self.low_f_Hz) + '-' + str(self.high_f_Hz) + 'zp.png') plt.close()
def test_real_summation_partition(): # F = 1 / (z + 0.5) F = Fz, Fp, Fk = tf2zpk([1.], [1., 0.5]) L, R = rf.real_summation_partition(F) assert isreal(L) and isreal(R) Sz, Sp, Sk = rf.add(L, R) assert_almost_equal(np.sort(Fz), np.sort(Sz)) assert_almost_equal(np.sort(Fp), np.sort(Sp)) assert_almost_equal(Fk, Sk) # F = (z^2 - 2) / (z^3 + 2 * z^2 + 2 * z + 1) F = Fz, Fp, Fk = tf2zpk([1, 0, -2], [1, 2, 2, 1]) L, R = rf.real_summation_partition(F) assert isreal(L) and isreal(R) Sz, Sp, Sk = rf.add(L, R) assert_almost_equal(np.sort(Fz), np.sort(Sz)) assert_almost_equal(np.sort(Fp), np.sort(Sp)) assert_almost_equal(Fk, Sk) # F = (z^4 + 1) / (z^4 + 2 * z^3 + 2 * z^2 + 1) F = Fz, Fp, Fk = tf2zpk([1, 0, 0, 0, 1], [1, 2, 2, 0, 1]) L, R = rf.real_summation_partition(F) assert isreal(L) and isreal(R) Sz, Sp, Sk = rf.add(L, R) assert_almost_equal(np.sort(np.around(Fz, decimals=15)), np.sort(np.around(Sz, decimals=15))) assert_almost_equal(np.sort(np.around(Fp, decimals=15)), np.sort(np.around(Sp, decimals=15))) assert_almost_equal(Fk, Sk)
def convert_forward_euler(pa, Tsampling=0.01): # if isintance(pa, TransferFunction): if isinstance(pa, lti): #reviso primero el valor final s = Symbol('s') pa_sympy = lti_to_sympy(pa) final_value_analog = pa_sympy.subs(s, 0).evalf() # print (' Final value: ' + str(final_value_analog)) #convierto backward euler num_d, den_d, td = cont2discrete((pa.num, pa.den), Tsampling, method='euler') zd, pd, kd = tf2zpk(num_d, den_d) #agrego zeros infinitos while (np.shape(zd) < np.shape(pd)): zd = np.append(zd, [-1]) #normalizo los zeros planta_d = ZerosPolesGain(zd, pd, kd) planta_d = planta_d.to_tf() zd, pd, kd = tf2zpk(planta_d.num, planta_d.den) #convierto a sympy para evaluar el valor final y ajustarlo planta_d_sympy = lti_to_sympy(planta_d) z = Symbol('z') planta_d_sympy = planta_d_sympy.subs(s, z) final_value_d = planta_d_sympy.subs(z, 1).evalf() #ahora ajusto la ganancia para que me coincidan los dos valores finales kd = kd * final_value / final_value_d # print ('Ceros digital: ' + str(zd)) # print ('Polos digital: ' + str(pd)) # print ('K digital: ' + str(kd)) #normalizo por ultima vez planta_d, ya agregue los zeros #y ajuste la ganancia con los valores finales planta_d = ZerosPolesGain(zd, pd, kd) planta_d = planta_d.to_tf() # print ('planta_d ' + str(planta_d)) #muestro el valor final planta_d_sympy = lti_to_sympy(planta_d) z = Symbol('z') planta_d_sympy = planta_d_sympy.subs(s, z) final_value_d = planta_d_sympy.subs(z, 1).evalf() # print ('planta_d final value: ' + str(final_value_d)) #reconvierto planta_d a dlti planta_d = dlti(planta_d.num, planta_d.den, dt=td) return planta_d else: raise ValueError('planta_analog is not instance of TransferFunction!')
def test_multiply(): # F = (z + 1) / (z^3 - 3 * z^2 + 10 * z + 1) F = tf2zpk([1, 1], [1, -3, 10, 1]) # G = 1 / (z^2 - z + 3) G = tf2zpk([1], [1, -1, 3]) # H = F * G = \ # (z + 1) / # (z^5 - 4 * z^4 + 16 * z^3 - 18 * z^2 + 29 * z + 3) Hz, Hp, Hk = tf2zpk([1, 1], [1, -4, 16, -18, 29, 3]) Mz, Mp, Mk = rf.multiply(*F, *G) assert_almost_equal(np.sort(Hz), np.sort(Mz)) assert_almost_equal(np.sort(Hp), np.sort(Mp)) assert_almost_equal(Hk, Mk)
def test_add(): # F = (z + 1) / (z^3 - 3 * z^2 + 10 * z + 1) F = tf2zpk([1, 1], [1, -3, 10, 1]) # G = 1 / (z^2 - z + 3) G = tf2zpk([1], [1, -1, 3]) # H = F + G = \ # (2 * z^3 - 3 * z^2 + 12 * z + 4) / # (z^5 - 4 * z^4 + 16 * z^3 - 18 * z^2 + 29 * z + 3) Hz, Hp, Hk = tf2zpk([2, -3, 12, 4], [1, -4, 16, -18, 29, 3]) Sz, Sp, Sk = rf.add(*F, *G) assert_almost_equal(np.sort(Hz), np.sort(Sz)) assert_almost_equal(np.sort(Hp), np.sort(Sp)) assert_almost_equal(Hk, Sk)
def test_product(): # F = (z + 1) / (z^3 - 3 * z^2 + 10 * z + 1) F = tf2zpk([1, 1], [1, -3, 10, 1]) # G = 1 / (z^2 - z + 3) G = tf2zpk([1], [1, -1, 3]) # H = (-5 * z^2 + 10) / 2 H = tf2zpk([-5, 0, 10], [2]) # J = F * G * H = \ # (-5 * z^3 - 5 * z^2 + 10 z + 10) / # (2 * z^5 - 8 * z^4 + 32 * z^3 - 36 * z^2 + 58 * z + 6) Jz, Jp, Jk = tf2zpk([-5, -5, 10, 10], [2, -8, 32, -36, 58, 6]) Mz, Mp, Mk = rf.product([F, G, H]) assert_almost_equal(np.sort(Jz), np.sort(Mz)) assert_almost_equal(np.sort(Jp), np.sort(Mp)) assert_almost_equal(Jk, Mk)
def mirroredNTF(ntf): """Creates a symmetric noise transfer function from a prototype. This function takes a prototype single band NTF for a LP modulator and returns a symmetric NTF with signal bands at the bottom and at the top of the available frequency ranges. Note that the way in which the mirroring happens make the resulting NTF peak at about the squared value as the peak of the original prototype. Hence the prototype should be designed with an H_inf value that is the square root of the desired one. Parameters ---------- ntf : tuple input noise tranfer function in zpk form Returns ------- ntf2 : tuple output noise transfer function in zpk form """ zpk_mode = True if len(ntf) != 3: zpk_mode = False ntf = tf2zpk(*ntf) # Take the opposite of poles and zeros to get an HP filter ntf_flipped = (-ntf[0], -ntf[1], ntf[2]) # Take the product of the two ntf_mirrored = (np.hstack((ntf[0], ntf_flipped[0])), np.hstack((ntf[1], ntf_flipped[1])), 1) if not zpk_mode: ntf_mirrored = zpk2tf(*ntf_mirrored) return ntf_mirrored
def _transform(b, a, Wn, analog, output): """ Shift prototype filter to desired frequency, convert to digital with pre-warping, and return in various formats. """ Wn = np.asarray(Wn) if not analog: if np.any(Wn < 0) or np.any(Wn > 1): raise ValueError("Digital filter critical frequencies " "must be 0 <= Wn <= 1") fs = 2.0 warped = 2 * fs * tan(pi * Wn / fs) else: warped = Wn # Shift frequency b, a = lp2lp(b, a, wo=warped) # Find discrete equivalent if necessary if not analog: b, a = bilinear(b, a, fs=fs) # Transform to proper out type (pole-zero, state-space, numer-denom) if output in ('zpk', 'zp'): return tf2zpk(b, a) elif output in ('ba', 'tf'): return b, a elif output in ('ss', 'abcd'): return tf2ss(b, a) elif output in ('sos'): raise NotImplementedError('second-order sections not yet implemented') else: raise ValueError('Unknown output type {0}'.format(output))
def check_minphase(self, ): zeros, poles, _ = signal.tf2zpk(self.b, self.a) print(zeros) print(poles) for kai in np.concatenate([zeros, poles]): if not np.abs(kai) < 1.0: print('This is not min phase')
def stabilityPlot(transferFunction): pyplot.figure(figsize=(6, 3)) maxIteration = 1024 nK2 = 256 data = [] for idx, k2 in enumerate(np.linspace(0.1, 1, nK2)): k1 = 65536 delta = k1 / 2 jdx = 0 while jdx < maxIteration: b, a = transferFunction(k1, k2) _, pole, gain = signal.tf2zpk(b, a) if np.max(np.abs(pole * gain)) >= 1: k1 -= delta else: k1 += delta jdx += 1 delta *= 0.5 data.append((k1, k2)) print(idx, k1, k2) k1, k2 = zip(*data) pyplot.scatter(k2, k1, s=4, zorder=2) k1Array, k2Array = zip(*data) # with open("k1_k2.json", "w") as fi: # json.dump({"k1": k1Array, "k2": k2Array}, fi, indent=2) pyplot.title("k1-k2 Plot") pyplot.ylabel("k1") pyplot.xlabel("k2") pyplot.grid(zorder=1) pyplot.tight_layout() pyplot.show()
def _check_coefficients(b, a): """Check for filter stability""" z, p, k = signal.tf2zpk(b, a) if np.any(np.abs(p) > 1.0): raise RuntimeError('Filter poles outside unit circle, filter will be ' 'unstable. Consider using different filter ' 'coefficients.')
def filterResponse2zeros(vandermondeMatrixSuperSet): """ This function takes in a Vandermonde matrix and generates the zeros of each column of the matrix. This function can be used to generate the zeros of a vandermonde matrix upfront and then store them inputs: 1. vandermondeMatrixSuperSet: Matrix of sinusoids stacked as columns outputs: 1. zerosFilterResponseSuperSet: Zeros of each column of filterResponseSuperSet stacked again as columns. Note: # rows of zerosFilterResponseSuperSet = # of rows of filterResponseSuperSet -1 (Since the number of zeros is 1 less than the filter tap length) This function uses the inbuilt scipy.signal.tf2zpk """ filterResponseSuperSet = np.conj( vandermondeMatrixSuperSet ) ## This has to have a conjugation effect to enhance the true tone numResponses = filterResponseSuperSet.shape[1] numZeros = filterResponseSuperSet.shape[0] - 1 zerosFilterResponseSuperSet = np.zeros((numZeros, numResponses), dtype=np.complex64) for ele in np.arange(numResponses): zerosFilterResponseSuperSet[:, ele], _, _ = sig.tf2zpk( filterResponseSuperSet[:, ele], 1) return zerosFilterResponseSuperSet
def ss_to_zpk(A, B, C): """Convert a state-space system to sets of Zero-Pole-Gain objects. Parameters ---------- A: (n,n) array_like State-space dynamics matrix B: (n,m) array_like Input matrix. C: (n,m) array_like Output matrix """ zpks = [] for im in range(B.shape[1]): zpks.append([]) for ip in range(C.shape[0]): try: num, den = signal.ss2tf( A, B[:, im].reshape((-1, 1)), C[ip, :].reshape((1, -1)), np.zeros((1, 1))) nu2 = num # strip leading (close to zeros) from num while np.allclose(nu2[:, 0], 0, 1e-14) and \ nu2.shape[-1] > 1: nu2 = nu2[:, 1:] # to zpk z, p, k = signal.tf2zpk(nu2, den) zpks[-1].append(ZPK(z, p, k)) except ValueError: raise RuntimeWarning("cannot analyse state-space") return zpks
def lab6_ex4(): # set parameters of system fs = 2000 #sampling frequency (Hz) fn = fs/2.0 #nyqvist frequency wp = array([200/fn,400/fn]) #band-pass in normalized corner frequencies ws = array([1/fn,100/fn,500/fn,5000/fn]) #band-stop in normalized corner frequencies gstop = 40 #minimum attenuation in stopband gpass = 1 #maximum loss in passband # create remez filter, frequency response, and plot b,a = iirdesign(wp,ws,gpass,gstop,analog=0) w,h = freqz(b,a) plot(w/pi, 20*log10(abs(h)),'b-') title('IIR of given frequency response') xlabel('normalized frequency (1 = fn)') ylabel('magnitude (dB scale)') grid() show() print("\nBoth designs achieve the desired response at the desired attenuation, but the IIR design's response attenuates and gains more quickly than the 46th-order remez FIR design.") z,p,k = tf2zpk(b,a) zplane(z,p) title('zplane of IIR of given frequency response') show() print('\nZ-plane analysis shows that the IIR design uses an 8th degree polynomial, while the remez FIR uses a 46th order polynomial (and thus far more components) to achieve the same desired response. This is because the IIR filter is able to use both zeros and poles (i.e. feedback) to achieve the desired frequency response at the desired attenuation and loss, whereas the remez FIR must use only zeros (no feedback).')
def test_sine(self): rate = 2000 t = np.linspace(0, 1.0, rate + 1) # A signal with low frequency and a high frequency. xlow = np.sin(5 * 2 * np.pi * t) xhigh = np.sin(250 * 2 * np.pi * t) x = xlow + xhigh b, a = butter(8, 0.125) z, p, k = tf2zpk(b, a) # r is the magnitude of the largest pole. r = np.abs(p).max() eps = 1e-5 # n estimates the number of steps for the # transient to decay by a factor of eps. n = int(np.ceil(np.log(eps) / np.log(r))) # High order lowpass filter... y = filtfilt(b, a, x, padlen=n) # Result should be just xlow. err = np.abs(y - xlow).max() assert_(err < 1e-4) # A 2D case. x2d = np.vstack([xlow, xlow + xhigh]) y2d = filtfilt(b, a, x2d, padlen=n, axis=1) assert_equal(y2d.shape, x2d.shape) err = np.abs(y2d - xlow).max() assert_(err < 1e-4) # Use the previous result to check the use of the axis keyword. # (Regression test for ticket #1620) y2dt = filtfilt(b, a, x2d.T, padlen=n, axis=0) assert_equal(y2d, y2dt.T)
def lab6_ex3(): # set parameters of system fs = 2000 #sampling frequency (Hz) fn = fs/2 #nyqvist frequency fc = array([0,100,200,400,500,1000]) #corner frequencies fb = array([0,1.0,0]) #desired band gains for each pair of corner frequencies deg = 46 #degree of polynomial nt = deg + 1 #number of taps = degree + 1 a = array([1.0,0]) #(no feedback (FIR), poles at origin reduced to 1 for simplification) # create remez filter, frequency response, and plot b = remez(nt,fc,fb,Hz=fs) w,h = freqz(b,a) plot(w/pi*fn, 20*log10(abs(h)),'b-') title('FIR of given frequency response using remez algo') xlabel('frequency') ylabel('magnitude (dB scale)') grid() show() print('\nFilter requires 47 taps for stop-band attenuation of at least -40 dB') z,p,k = tf2zpk(b,a) zplane(z,p) title('zplane of remez-FIR of given frequency response (47 taps)') show()
def pzmap(filters): try: iter(filters) except TypeError: filters = [filters] fig, ax = plt.subplots() ax.ticklabel_format(useOffset=False) ax.set_ylabel('rad/sec') ax.set_xlabel('rad/sec') ax.grid(True) title = 'pzmap' fig.suptitle(title) fig.canvas.set_window_title(title) r = 1.5 for filt in filters: z, p, k = sig.tf2zpk(filt.num, filt.den) poles = ax.plot(p.real, p.imag, 'x', markersize=9, alpha=0.5) rx = 1.5 * np.amax(np.concatenate((abs(z), abs(p)))) r = rx if rx > r else r ax.plot(z.real, z.imag, 'o', color='none', markersize=9, alpha=0.5, markeredgecolor=poles[0].get_color()) ax.axis('scaled') ax.axis([-r, r, -r, r])
def save_fil(fil_dict, arg, out_format, sender, DEBUG = False): """ Convert between poles / zeros / gain, filter coefficients (polynomes) and second-order sections and store all available formats in the passed dictionary 'fil_dict'. """ if DEBUG: print("saveFil: arg = ",arg) if out_format == 'zpk': # arg = [z,p,k] (b, a) = sig.zpk2tf(arg[0], arg[1], arg[2]) zpk = arg elif out_format == 'ba': # arg = [b,a] if np.ndim(arg) == 1: # print(len(arg)) b = np.asarray(arg) a = np.zeros(len(arg)) a[0] = 1 else: b = arg[0] a = arg[1] # print("saveFil: b, a = ",b , a) zpk = sig.tf2zpk(b, a)#[np.roots(arg), [1, np.zeros(len(arg)-1)],1] else: raise ValueError("Unknown output format {0:s}".format(out_format)) fil_dict['ba'] = [b, a] fil_dict['zpk'] = [zpk[0], zpk[1], zpk[2]]#zpk fil_dict['sos'] = None fil_dict['creator'] = (out_format, sender)
def zplane(b, a): z, p, k = signal.tf2zpk(b, a) # plt.figure() plt.title("Pole-zero placement of EQ Filters") plt.plot(z.real, z.imag, 'ko', fillstyle='none', ms=10) plt.plot(p.real, p.imag, 'kx', fillstyle='none', ms=10) unit_circle = patches.Circle( (0, 0), radius=1, fill=False, color='black', ls='solid', alpha=0.9) plt.gca().add_patch(unit_circle) plt.axvline(0, color='0.7') plt.axhline(0, color='0.7') plt.grid() plt.ylim([-1, 1]) plt.xlim([-1, 1]) plt.gca().set_aspect('equal', adjustable='box') plt.ylabel('Imaginary') plt.xlabel('Real')
def filter_char(b, a, show=True): # Pole-zero characteristics zero, pole, __ = sp.tf2zpk(b, a) if (pole.shape < zero.shape): pole = np.concatenate( (pole, np.zeros(zero.shape[0] - pole.shape[0], dtype=complex))) zp = [zero, pole] # Magnitude and Phase Characteristics w1, H = sp.freqz(b, a, 1024, whole=True) # Time domain sequence (= Coefficients for given filter since it is FIR) h = ifft(H) ii = np.where(abs(h) > 1e-4) h = np.real( h[ii]) # remove noisy imaginary components- h is a real FIR filter # Group Delay of Filter w2, gd = sp.group_delay((b, a), whole=True) if show == True: plt.figure("Pole-Zero Plot") plt.polar(np.angle(zp[0]), np.abs(zp[0]), 'bo') plt.polar(np.angle(zp[1]), np.abs(zp[1]), 'gx') plt.polar(np.linspace(0, 2 * pi, 360), np.ones(360), 'k-') plt.title("Pole-Zero Plot") plt.figure("Mag-Phase Characteristics") plt.subplot(211) plt.plot(w1, abs(H)) plt.title("Mag-Phase Characteristics of FIR filter") plt.subplot(212) plt.plot(w1, np.unwrap(np.angle(H))) plt.figure("h[n]") plt.plot(h, "ro") plt.title("Time Domain: FIR Filter") plt.figure("Group Delay of Filter") plt.plot(w2, gd) plt.title("Group Delay of Filter") return zp, H, h, gd
def test_summation_decomposition(): # F = 1 / (z + 0.5) F = Fz, Fp, Fk = tf2zpk([1.], [1., 0.5]) terms = rf.summation_decomposition(*F, nterms=2) S = Sz, Sp, Sk = rf.summation(terms) assert_almost_equal(np.sort(Sz), np.sort(Fz)) assert_almost_equal(np.sort(Sp), np.sort(Fp)) assert_almost_equal(Sk, Fk) # F = (z^2 - 2) / (z^4 + 2 * z^3 + 2 * z^2 + 1) F = Fz, Fp, Fk = tf2zpk([1, 0, -2], [1, 2, 2, 1]) terms = rf.summation_decomposition(*F, nterms=2) S = Sz, Sp, Sk = rf.summation(terms) assert_almost_equal(np.sort(Sz), np.sort(Fz)) assert_almost_equal(np.sort(Sp), np.sort(Fp)) assert_almost_equal(Sk, Fk)
def test_summation(): # F = (z + 1) / (z^3 - 3 * z^2 + 10 * z + 1) F = tf2zpk([1, 1], [1, -3, 10, 1]) # G = 1 / (z^2 - z + 3) G = tf2zpk([1], [1, -1, 3]) # H = (-z^2 + 1) / 1 H = tf2zpk([-1, 0, 1], [1]) # J = F + G + H = \ # (-z^7 + 4 * z^6 - 15 * z^5 + 14 * z^4 - 13 * z^3 - 21 * z^2 + 29 * z + 3) / # (z^5 - 4 * z^4 + 16 * z^3 - 18 * z^2 + 29 * z + 3) Jz, Jp, Jk = tf2zpk([-1, 4, -15, 14, -11, -24, 41, 7], [1, -4, 16, -18, 29, 3]) Sz, Sp, Sk = rf.summation([F, G, H]) assert_almost_equal(np.sort(Jz), np.sort(Sz)) assert_almost_equal(np.sort(Jp), np.sort(Sp)) assert_almost_equal(Jk, Sk)
def lab6_ex2(): # set parameters of system fn = 1.0 nt = 50 #number of taps freq = array([0,0.1,0.2,0.5,1.0]) #frequency sampling points gain = array([1.0,1.0,0.01,0.001,0]) b = firwin2(nt,freq,gain,nyq=fn) #calc FIR coefficients with given frequency response a = array([1.0,0]) #(no feedback (FIR), poles at origin reduced to 1 for simplification) # calc frequency response of filter and plot w,h = freqz(b,a) plot(w/pi, 20*log10(abs(h)),'b-') title('FIR of given frequency response') xlabel('normalized frequency (1 = fn)') ylabel('magnitude (dB scale)') grid() show() print('\nResponses in dB scale (all frequencies are relative to fn):\nf = 0, gain = 0 dB\nf = 0.1, gain = -1.05 dB\nf = 0.2, gain = -18.25 dB\nf = 0.5, gain = -56.4 dB\nf = 1.0, gain =~ -92 dB (filter tries to approach -inf and goes off the scale around f = 0.999)') print('\nThe filter has 49 zeros (the same as number of taps - 1)') print('The filter should also have 49 poles (all at the origin) so that it is causal. However, in this implementation (firwin2) there are no poles (except those added by the user)') # calc and show zeros and poles on zplane z,p,k = tf2zpk(b,a) zplane(z,p) title('zplane of FIR of given frequency response (50 taps)') show() print('\nFrom the zplane diagram, we can see pairs of conjugate pairs of zeros that follow along the unit circle. For each pair of conjugate pairs, one conjugate pair is inside of the unit circle and one is on the outside. As the frequency increases to fn, each pair of zeros generally gets closer and closer to the unit circle, thus attenuating the signal even further, up to a gain of 0 @ f = fn)')
def print_zpk(num, den): z, p, k = sig.tf2zpk(num, den) print('Poles:') print_pole_or_zero_info(p) if z.size: print('Zeros:') print_pole_or_zero_info(z) print('K = {}'.format(k))
def frequency_response(tf, w_in=[0.01, 100], plot=0): w = linspace(w_in[0], w_in[1], 10000) wi = w * 1j g = 20 * log10(abs(polyval(tf.num[0][0], wi))) - 20 * log10( abs(polyval(tf.den[0][0], wi))) zero, pole, gain = tf2zpk(tf.num[0][0], tf.den[0][0]) m = count_nonzero(zero == 0) n = count_nonzero(pole == 0) zero = zero[zero != 0] pole = pole[pole != 0] real_zero = zero[imag(zero) == 0] real_pole = pole[imag(pole) == 0] p_real_zero = 0 p_real_pole = 0 for zi in real_zero: p_real_zero += rad2deg(arctan2(w, -real(zi))) for ip in real_pole: p_real_pole += rad2deg(arctan2(w, -real(ip))) imag_zero = zero[imag(zero) != 0] imag_pole = pole[imag(pole) != 0] n_pairs_zero = len(imag_zero) / 2 n_pairs_pole = len(imag_pole) / 2 p_imag_zero = 0 p_imag_pole = 0 for ii in range(0, int(n_pairs_zero)): char_equ = real(polymul([1, -imag_zero[0]], [1, -imag_zero[1]])) w_n = sqrt(char_equ[2]) zeta = char_equ[1] / (2 * w_n) p_imag_zero += rad2deg( arctan2((2 * zeta * w / w_n), (1 - (w / w_n)**2))) imag_zero = delete(imag_zero, [0, 1]) for jj in range(0, int(n_pairs_pole)): char_equ = real(polymul([1, -imag_pole[0]], [1, -imag_pole[1]])) w_n = sqrt(char_equ[2]) zeta = char_equ[1] / (2 * w_n) p_imag_pole += rad2deg( arctan2((2 * zeta * w / w_n), (1 - (w / w_n)**2))) imag_pole = delete(imag_pole, [0, 1]) p = 90 * m - 90 * n + p_real_zero - p_real_pole + p_imag_zero - p_imag_pole if plot: plt.figure() plt.subplot(2, 1, 1) plt.plot(w, g) plt.xscale('log') plt.grid() plt.subplot(2, 1, 2) plt.plot(w, p) plt.xscale('log') plt.grid() plt.show() return g, p, w
def test_real_product_decomposition(): # F = 1 / (z + 0.5) F = Fz, Fp, Fk = tf2zpk([1.], [1., 0.5]) terms = rf.real_product_decomposition(*F, nterms=2) assert all(isreal(term) for term in terms) Pz, Pp, Pk = rf.product(terms) assert_almost_equal(np.sort(Fz), np.sort(Pz)) assert_almost_equal(np.sort(Fp), np.sort(Pp)) assert_almost_equal(Fk, Pk) # F = (z^2 - 2) / (z^4 + 2 * z^3 - 2 * z^2 + 2 * z + 1) F = Fz, Fp, Fk = tf2zpk([1, 0, -2], [1, 2, -2, 2, 1]) terms = rf.real_product_decomposition(*F, nterms=2) assert all(isreal(term) for term in terms) Pz, Pp, Pk = rf.product(terms) assert_almost_equal(np.sort(Fz), np.sort(Pz)) assert_almost_equal(np.sort(Fp), np.sort(Pp)) assert_almost_equal(Fk, Pk)
def get_APower(file): fs, data = read(file) data = data.astype("float32") b, a = A_weighting(fs) z, p, k = tf2zpk(b, a) IRLen = getIRLen(p) filtData = filtfilt(b, a, data, padlen=IRLen) power = (filtData*filtData).sum() return power
def find_zeros_poles(numerator, denominator): # calculate zeros, poles and gain zeros, poles , gain = signal.tf2zpk(numerator, denominator) # rounding to 2 decimal place zeros = np.round(zeros, 3) poles = np.round(poles, 3) return zeros, poles
def lab6_ex1(): # set parameters of system fs = 5000 #sampling frequency (Hz) fn = fs/2 #nyqvist frequency fc1 = 0.1*fn #corner frequency1 fc2 = 0.2*fn #corner frequency2 fc3 = array([fc1,fc2]) #corner frequency3 (as an array of two corner frequencies) deg = 18 #degree of polynomial nt = deg + 1 #number of taps = degree + 1 a = array([1.0,0]) #(no feedback (FIR), poles at origin reduced to 1 for simplification) # calc FIR filter coefficients b1 = firwin(nt,fc1,pass_zero=1,nyq=fn) #low-pass b2 = firwin(nt,fc2,pass_zero=0,nyq=fn) #high-pass b3 = firwin(nt,fc3,pass_zero=0,nyq=fn) #band-pass # calc and show freq response w,h = freqz(b1,a) plot(w/pi, 20*log10(abs(h)),'b-') w,h = freqz(b2,a) plot(w/pi, 20*log10(abs(h)),'r-') w,h = freqz(b3,a) plot(w/pi, 20*log10(abs(h)),'g-') legend(('low-pass, fc = 0.1*fn','high-pass, fc = 0.2*fn','band-pass, fc = 0.1*fn, 0.2*fn'), loc=3) title('firwin filters') xlabel('normalized frequency (1.0 = fn)') ylabel('magnitude (dB scale)') show() # calc and show zeros and poles on zplane z,p,k = tf2zpk(b1,a) zplane(z,p) title('zplane of low-pass, fc = 0.1*fn') show() z,p,k = tf2zpk(b2,a) zplane(z,p) title('zplane of high-pass, fc = 0.2*fn') show() z,p,k = tf2zpk(b3,a) zplane(z,p) title('zplane of band-pass, fc = 0.1*fn, 0.2*fn') show()
def freqz_plot(line, cell): # line, cellをparse N, FS = [float(v) for v in line.split()] ba = cell.split("\n") b = [float(v) for v in ba[0].split(",")] a = [float(v) for v in ba[1].split(",")] # 時間特性、周波数特性、位相特性、群遅延特性等を計算 w, h = sg.freqz(b, a, worN=int(N)) f = w * FS / (2.0 * np.pi) z, p, k = sg.tf2zpk(b, a) _, gd = sg.group_delay((b, a), w=w) # 上記パラメータをプロット fig = plt.figure(1, figsize=(8, 12)) ax = fig.add_subplot(321) ax.plot(b, "o-") ax.plot(a, "x-") ax.grid() ax.set_xlabel("time [pt]") ax.set_ylabel("amplitude") ax = fig.add_subplot(322) ax.semilogx(f, 20.0 * np.log10(np.abs(h))) ax.grid() ax.set_xlabel("frequency [Hz]") ax.set_ylabel("power [dB]") ax.set_xlim([10.0, FS/2.0]) ax.set_ylim([-40.0, 10.0]) ax = fig.add_subplot(323) ax.semilogx(f, np.angle(h)) ax.grid() ax.set_xlim([10.0, FS/2.0]) ax.set_ylim([-np.pi, np.pi]) ax.set_xlabel("frequency [Hz]") ax.set_ylabel("phase [rad]") ax = fig.add_subplot(324) ax.semilogx(f, gd) ax.grid() ax.set_xlabel("frequency [Hz]") ax.set_ylabel("group delay [pt]") ax.set_xlim([10.0, FS/2.0]) ax.set_ylim([-40.0, 40.0]) ax = fig.add_subplot(325) ax.add_patch(plt.Circle((0.0, 0.0), 1.0, fc="white")) ax.plot(np.real(z), np.imag(z), "o", mfc="white") ax.plot(np.real(p), np.imag(p), "x", mfc="white") ax.grid() ax.set_xlim([-1.5, 1.5]) ax.set_ylim([-1.5, 1.5]) plt.show()
def denormalize_one_pole(self, pole): # cambio de variable: s-> s/wp # 1/(s-p) -> (wp) /(s - wp*p) # entonces por cada polo REAL en poles tengo: wp = self.denormalized_template.wp if pole.imag == 0: [denorm_zeroes, denorm_poles, gain_factor] = signal.tf2zpk([wp], [1, -wp * pole]) # 1/( (s-p)*(s-conj(p))) = 1/(s^2 -2*real(p)*s + abs(p)^2) -> # (wp)^2 / (s^2 - 2*real(p)*wp *s + wp^2*abs(p)^2) # entonces por cada polo IMAGINARIO tengo: else: [denorm_zeroes, denorm_poles, gain_factor] = \ signal.tf2zpk([wp**2], [1, - 2 * np.real(pole)*wp, wp**2 * abs(pole)**2]) return [list(denorm_poles), list(denorm_zeroes), gain_factor]
def set_band_pass(self): self.num = [1, 0] self.den = [1, 1, 1] self.sys = signal.TransferFunction([1, 0], [1, 1, 1]) self.w, self.mag, self.phase = signal.bode(self.sys) self.stepT, self.stepMag = signal.step(self.sys) self.impT, self.impMag = signal.impulse(self.sys) self.pzg = signal.tf2zpk(self.sys.num, self.sys.den) self.GDfreq, self.gd = signal.group_delay((self.num, self.den)) self.plotMag()
def denormalize_one_pole(self, pole): # cambio de variable: s -> 1/ ( q*(s/wo+wo/s) ) == s*wo / (q * (s^2 + wo^2) ) # 1/(s-p) -> (- q*s^2 - q*wo^2)/(p*q*s^2 - s*wo + p*q*wo^2) # entonces por cada polo REAL tengo: if pole.imag == 0: [denorm_zeroes, denorm_poles, gain_factor] = signal.tf2zpk( [-self.q, 0, -self.q * self.denormalized_template.w0**2], [ pole * self.q, -self.denormalized_template.w0, pole * self.q * self.denormalized_template.w0**2 ]) # (q^2*s^4 + 2*q^2*s^2*wo^2 + q^2*wo^4) / # ((p*q^2*conj(p))*s^4 + (- q*wo*conj(p) - p*q*wo)*s^3 + (2*p*conj(p)*q^2*wo^2 + wo^2)*s^2 + (- p*q*wo^3 - q*wo^3*conj(p))*s + p*q^2*wo^4*conj(p)) # que se puede escribir como # (a*s^4 + c*s^2 + e) / # (f*s^4 + g*s^3 + h *s^2 + i *s + j) # entonces por cada polo IMAGINARIO tengo: else: # numerador a = self.q**2 c = 2 * self.q**2 * self.denormalized_template.w0**2 e = self.q**2 * self.denormalized_template.w0**4 # denominador f = np.absolute(pole)**2 * self.q**2 g = -self.q * self.denormalized_template.w0 * 2 * pole.real h = (2 * np.absolute(pole)**2 * self.q**2 * self.denormalized_template.w0**2 + self.denormalized_template.w0**2) i = -self.denormalized_template.w0**3 * self.q * 2 * pole.real j = np.absolute( pole)**2 * self.q**2 * self.denormalized_template.w0**4 [denorm_zeroes, denorm_poles, gain_factor] = signal.tf2zpk([a, 0, c, 0, e], [f, g, h, i, j]) return [list(denorm_poles), list(denorm_zeroes), gain_factor]
def ex4_1(): wp = 0.2*np.pi ws = 0.3*np.pi fs = 4000.0 T = 1/fs Wp = wp/T Ws = ws/T n, x = signal.buttord(Wp, Ws, 2, 40, analog=True) b, a = signal.butter(n, x, analog=True) z, p, k = signal.tf2zpk(b, a) print z, p, k
def plot_cont2(self, b2, c2): self.z2, self.p2, self.k2 = signal.tf2zpk(b2, c2) plt.plot(numpy.real(self.z2), numpy.imag(self.z2), 'oy', label='Zeros of TF3') plt.plot(numpy.real(self.p2), numpy.imag(self.p2), 'xk', label='Poles of TF3') plt.legend(loc=1, numpoints=1)
def test_bad_filter(self): """Regression test for #651: better handling of badly conditioned filter coefficients.""" warnings.simplefilter("error", BadCoefficients) try: b, a = bessel(20, 0.1) z, p, k = tf2zpk(b, a) raise AssertionError("tf2zpk did not warn about bad "\ "coefficients") except BadCoefficients: pass finally: warnings.simplefilter("always", BadCoefficients)
def pole_zero(sys, xlim=None, ylim=None, figax=None, rcParams=None): if len(sys) == 2: z, p, k = signal.tf2zpk(*sys) elif len(sys) == 3: z, p, k = sys elif len(sys) == 4: z, p, k = signal.ss2zpk(*sys) else: ValueError("""\ sys must have 2 (transfer function), 3 (zeros, poles, gain), or 4 (state space) elements. sys is: {}""".format(sys)) return _pole_zero(z, p, k, xlim=xlim, ylim=ylim, figax=figax, rcParams=rcParams)
def poleZeroPlot(b,a, phone): a[1:len(a)] = -a[1:len(a)]; b=[b] z, p, k = signal.tf2zpk(b, a) p = p[p!=0] fig = plt.figure() plt.plot(np.real(z), np.imag(z), 'xb') plt.plot(np.real(p), np.imag(p), 'or') plt.ylim((-2.0, 2.0)) plt.xlim((-2.0,2.0)) plt.legend(['Zeros', 'Poles'], loc=2) plt.title('Pole / Zero Plot for /'+phone+'/ for order '+str(len(p))) plt.ylabel('Real') plt.xlabel('Imaginary') plt.grid()
def test_simple(self): z_r = np.array([0.5, -0.5]) p_r = np.array([1.j / np.sqrt(2), -1.j / np.sqrt(2)]) # Sort the zeros/poles so that we don't fail the test if the order # changes z_r.sort() p_r.sort() b = np.poly(z_r) a = np.poly(p_r) z, p, k = tf2zpk(b, a) z.sort() p.sort() assert_array_almost_equal(z, z_r) assert_array_almost_equal(p, p_r)
def polosyzeros(b, a): (zeros,poles,gain) = tf2zpk(b, a) angle = np.linspace(-np.pi,np.pi,50) cirx = np.sin(angle) ciry = np.cos(angle) l, = pl.plot(poles.real, poles.imag, 'x') pl.plot(zeros.real, zeros.imag, 'o',color=l.get_color()) pl.plot(cirx,ciry, 'k-') pl.grid() pl.xlim((-2, 2)) pl.xlabel('Real') pl.ylim((-1.5, 1.5)) pl.ylabel('Imag') return (zeros,poles,gain)
def PlotFilterCharacteristics(b,a,figname): w, h = sig.freqz(b,a) z, p, k = sig.tf2zpk(b, a) plt.figure(num=figname) plt.subplot(211) plt.plot(np.real(z), np.imag(z), 'xb') plt.plot(np.real(p), np.imag(p), 'or') # plot unit circle phis=np.arange(0, 2*np.pi, 0.01) plt.plot( np.cos(phis), np.sin(phis), c='b') plt.grid() plt.xlim([-3,3]) plt.ylim([-1.2, 1.2]) plt.legend(['Zeros', 'Poles'], loc=2) plt.subplot(212) plt.plot(np.abs(h))
def test_evalTF(): """Test function for evalTF() """ from scipy.signal import tf2zpk from ._utils import empty num, den = np.poly([3, 0.3, 1]), np.poly([2, 0.5, .25]) H = (num, den) tstr1 = empty() tstr1.form, tstr1.num, tstr1.den = 'coeff', num, den tstr2 = empty() tstr2.form = 'zp' tstr2.zeros, tstr2.poles, tstr2.k = tf2zpk(num, den) z = np.exp(1j*np.linspace(0, 2*np.pi, num=129, endpoint=True)) h1 = evalTF(tstr1, z) h2 = evalTF(tstr2, z) h3 = evalTF(H, z) assert np.allclose(np.abs(h1), np.abs(h2), atol=1e-8, rtol=1e-5) assert np.allclose(h1, h3, atol=1e-8, rtol=1e-5)
def test_dstep(self): a = np.asarray([[0.9, 0.1], [-0.2, 0.9]]) b = np.asarray([[0.4, 0.1, -0.1], [0.0, 0.05, 0.0]]) c = np.asarray([[0.1, 0.3]]) d = np.asarray([[0.0, -0.1, 0.0]]) dt = 0.5 # Because b.shape[1] == 3, dstep should result in a tuple of three # result vectors yout_step_truth = (np.asarray([0.0, 0.04, 0.052, 0.0404, 0.00956, -0.036324, -0.093318, -0.15782348, -0.226628324, -0.2969374948]), np.asarray([-0.1, -0.075, -0.058, -0.04815, -0.04453, -0.0461895, -0.0521812, -0.061588875, -0.073549579, -0.08727047595]), np.asarray([0.0, -0.01, -0.013, -0.0101, -0.00239, 0.009081, 0.0233295, 0.03945587, 0.056657081, 0.0742343737])) tout, yout = dstep((a, b, c, d, dt), n=10) assert_equal(len(yout), 3) for i in range(0, len(yout)): assert_equal(yout[i].shape[0], 10) assert_array_almost_equal(yout[i].flatten(), yout_step_truth[i]) # Check that the other two inputs (tf, zpk) will work as well tfin = ([1.0], [1.0, 1.0], 0.5) yout_tfstep = np.asarray([0.0, 1.0, 0.0]) tout, yout = dstep(tfin, n=3) assert_equal(len(yout), 1) assert_array_almost_equal(yout[0].flatten(), yout_tfstep) zpkin = tf2zpk(tfin[0], tfin[1]) + (0.5,) tout, yout = dstep(zpkin, n=3) assert_equal(len(yout), 1) assert_array_almost_equal(yout[0].flatten(), yout_tfstep) # Raise an error for continuous-time systems system = lti([1], [1, 1]) assert_raises(AttributeError, dstep, system)
def test_dimpulse(self): a = np.asarray([[0.9, 0.1], [-0.2, 0.9]]) b = np.asarray([[0.4, 0.1, -0.1], [0.0, 0.05, 0.0]]) c = np.asarray([[0.1, 0.3]]) d = np.asarray([[0.0, -0.1, 0.0]]) dt = 0.5 # Because b.shape[1] == 3, dimpulse should result in a tuple of three # result vectors yout_imp_truth = (np.asarray([0.0, 0.04, 0.012, -0.0116, -0.03084, -0.045884, -0.056994, -0.06450548, -0.068804844, -0.0703091708]), np.asarray([-0.1, 0.025, 0.017, 0.00985, 0.00362, -0.0016595, -0.0059917, -0.009407675, -0.011960704, -0.01372089695]), np.asarray([0.0, -0.01, -0.003, 0.0029, 0.00771, 0.011471, 0.0142485, 0.01612637, 0.017201211, 0.0175772927])) tout, yout = dimpulse((a, b, c, d, dt), n=10) assert_equal(len(yout), 3) for i in range(0, len(yout)): assert_equal(yout[i].shape[0], 10) assert_array_almost_equal(yout[i].flatten(), yout_imp_truth[i]) # Check that the other two inputs (tf, zpk) will work as well tfin = ([1.0], [1.0, 1.0], 0.5) yout_tfimpulse = np.asarray([0.0, 1.0, -1.0]) tout, yout = dimpulse(tfin, n=3) assert_equal(len(yout), 1) assert_array_almost_equal(yout[0].flatten(), yout_tfimpulse) zpkin = tf2zpk(tfin[0], tfin[1]) + (0.5,) tout, yout = dimpulse(zpkin, n=3) assert_equal(len(yout), 1) assert_array_almost_equal(yout[0].flatten(), yout_tfimpulse) # Raise an error for continuous-time systems system = lti([1], [1, 1]) assert_raises(AttributeError, dimpulse, system)
def setUp(self): num = np.poly([3, 0.3, 1]) den = np.poly([2, 0.5, .25]) H = (num, den) tstr1 = empty() (tstr1.form, tstr1.num, tstr1.den) = ('coeff', num, den) tstr2 = empty() tstr2.form = 'zp' (tstr2.zeros, tstr2.poles, tstr2.gain) = tf2zpk(num, den) z = np.exp(1j * np.linspace(0, 2*np.pi, num=129, endpoint=True)) self.h1 = ds.evalTF(tstr1, z) self.h2 = ds.evalTF(tstr2, z) self.h3 = ds.evalTF(H, z) self.h4 = ds.evalTF(lti(tstr2.zeros, tstr2.poles, tstr2.gain), z) h5tf = lti(tstr2.zeros, tstr2.poles, tstr2.gain) self.h5 = ds.evalTF((h5tf.A, h5tf.B, h5tf.C, h5tf.D), z) h6tf = np.vstack((np.hstack((h5tf.A, h5tf.B)), np.hstack((h5tf.C, np.atleast_2d(h5tf.D))))) self.h6 = ds.evalTF(h6tf, z)
def _c2dmatched(sysC, Ts): # Pole-zero match method of continuous to discrete time conversion szeros, spoles, sgain = tf2zpk(sysC.num[0][0], sysC.den[0][0]) zzeros = [0] * len(szeros) zpoles = [0] * len(spoles) pregainnum = [0] * len(szeros) pregainden = [0] * len(spoles) for idx, s in enumerate(szeros): sTs = s*Ts z = exp(sTs) zzeros[idx] = z pregainnum[idx] = 1-z for idx, s in enumerate(spoles): sTs = s*Ts z = exp(sTs) zpoles[idx] = z pregainden[idx] = 1-z zgain = np.multiply.reduce(pregainnum)/np.multiply.reduce(pregainden) gain = sgain/zgain sysDnum, sysDden = zpk2tf(zzeros, zpoles, gain) return TransferFunction(sysDnum, sysDden, Ts)
def __init__(self, num, den, dt=0.01, maxt=5.0, myvar='s', label='G'): """num and den are either scalar constants or lists that are passed to scipy.poly1d to create a list of coefficients.""" #print('in TransferFunction.__init__, dt=%s' % dt) if _realizable(num, den): num = atleast_1d(num) den = atleast_1d(den) start_num_ind = nonzero(num)[0][0] start_den_ind = nonzero(den)[0][0] num_ = num[start_num_ind:] den_ = den[start_den_ind:] signal.lti.__init__(self, num_, den_) else: z, p, k = signal.tf2zpk(num, den) self.gain = k self.num = poly1d(num) self.den = poly1d(den) self.dt = dt self.myvar = myvar self.maxt = maxt self.label = label
def trigonometric_filter_zeros(zeros): """ function return the zeros of trigonometric polynomial L(w)""" v = [] z = [] for i in range(zeros): v.append(calculate_combinations(zeros - 1, i)) v = np.array(v, float) result = np.zeros(2 * zeros - 1) for k in range(zeros): result = result + v[k] * sinp(k, zeros - 1) den = np.zeros(len(result)) den[len(den) - 1] = 1 # convertize the transfer function to pole zero representation z1, p, k = tf2zpk(result, den) z = np.append(z, unique_real_zeros(z1)) z = np.append(z, stable_zeros(z1)) return z
def poles_zeros(self): """Computing and plotting POLES-ZEROS of the filter""" pyplot.figure(figsize=(6, 6)) (p, z, k) = signal.tf2zpk(self.b, self.a) if self.ftype == 'butter': z = -(z / min(real(z))) circle = Circle((0, 0), radius=abs(max(z)), linestyle='dotted', fill=False) try: p = -(p / min(real(p))) except ValueError: pass else: circle = Circle((0, 0), radius=1, linestyle='dotted', fill=False) #Plotting Poles-zeros #pyplot.scatter(real(p), imag(p), marker='o', s=50) pyplot.scatter(real(z), imag(z), marker='x', s=100) pyplot.xlabel('Real Part') pyplot.ylabel('Imaginary Part') pyplot.title('Pole-zeros' + "\n" + str(self.ord) + "th order " + self.btype + " " + self.ftype_plot + " filter") #Formatting plot. pyplot.gca().add_patch(circle) limits = [] limits.append(max(pyplot.gca().get_xlim())) limits.append(max(pyplot.gca().get_ylim())) max_limit = max(limits) if max_limit < 1.2: max_limit = 1.2 pyplot.axis([-max_limit, max_limit, -max_limit, max_limit]) pyplot.vlines(0, -max_limit, max_limit, color='k', linestyles='dotted') pyplot.hlines(0, -max_limit, max_limit, color='k', linestyles='dotted')
import numpy as np import scipy.signal as signal import matplotlib.pyplot as plt b, a = signal.iirdesign(wp=100, ws=200, gpass=2.0, gstop=40., analog=True) w, h = signal.freqs(b, a) plt.title('Analog filter frequency response') plt.plot(w, 20*np.log10(np.abs(h))) plt.ylabel('Amplitude Response [dB]') plt.xlabel('Frequency') plt.grid() plt.show() z, p, k = signal.tf2zpk(b, a) plt.plot(np.real(z), np.imag(z), 'xb') plt.plot(np.real(p), np.imag(p), 'or') plt.legend(['Zeros', 'Poles'], loc=2) plt.title('Pole / Zero Plot') plt.ylabel('Real') plt.xlabel('Imaginary') plt.grid() plt.show()
For BPF when the transformation is applied to 1/(s-root) we get Numerator = Bs Denominator = s^2+omega_0^2-B*c*s Using this basic result and finding numerator and denominator to get the bandpass transfer function ''' analog_numer = chebyshev_k.real analog_denom = 1+0.j for c in poles: if(c.real<= 0): analog_numer = np.poly1d([f_B,0],r=0)*analog_numer analog_denom = np.poly1d([1,-f_B*c,omega_z_s],r=0)*analog_denom print "Analog numerator\n",analog_numer print "\nAnalog denominator\n",analog_denom # Converting back to digital domain from transfer function z,p,k=sg.tf2zpk(analog_numer,analog_denom) plt.figure(5) plt.grid(True) plt.scatter(p.real,p.imag,s=50,c='b',marker='x') plt.scatter(z.real,z.imag,s=50,c='b',marker='o') plt.title('Pole Zero plot of Analog Bandpass filter') plt.ylabel('Imaginary') plt.xlabel('Real') ''' For converting the bandpass filter to digital domain using s = (1-z^-1)/(1+z^-1) Numerator = B(z^2-1) Denominator = (omega_0^2-B+1)z^2+(2*omega_0^2-2)z+(omega_0^2+B+1) Using this basic result and finding numerator and denominator to get the bandpass transfer function
print dec_lo print dec_hi print recon_lo print recon_hi w = pywt.Wavelet("db3") print w.rec_lo print w.rec_hi print w.dec_lo print w.dec_hi figure() z, p, k = tf2zpk(w.rec_lo, [1]) zplane(z, p) show() ddddddddd # print "constrains",np.sum(h1),np.sum(h1**2) print np.mean((w.rec_lo - h1) ** 2), "estimation error" show() ddddddd asdasd c = np.convolve(w.dec_lo, np.flipud(w.dec_lo)) print c
rptpole = figure("Frequency Response") fft_N = 32768 mag_p = rptpole.add_subplot(2,1,1) ang_p = rptpole.add_subplot(2,1,2) rep_array = arange(6) + 0 color_list = ['r', 'k', 'b', 'm', 'g', 'y'] for i in rep_array: ply = poly(ones(i + 1) * root_r) gfiltpak.gfreqz(b, ply, fft_N, Fs=1e6, color = color_list[i], magfig = mag_p, angfig = ang_p, logx = True, threedb = True, ylimmag = [-10, 0]) hold(True) ########################################## # Residues = Partial fraction expansion z, p, k = si.tf2zpk(b, a) #figure("Scatter plot") #scatter(real(p), imag(p), vmin = -0.5, vmax = 0.5) #scatter(real(z), imag(z), vmin = -0.5, vmax = 0.5) #figure("Zplane plot") #gfiltpak.zplane(b, a) ########################################## # Residues b = [0.5, 0.5, 0.25] a = [1, 0.5, 0.5, 0.75] ylims = [-50, 0]
#Lowpass filter transfer function #Find gain for Chebyshev K_butter=omega_c**N #print "GAIN:",K_butter #print "omega_c:",omega_c numer=K_butter denom=1+0.j for c in poles_a: if(c.real<= 0): numer=np.poly1d([1,0,omega_z_s],r=0)*numer denom=np.poly1d([-c,f_B,-c*omega_z_s],r=0)*denom #print "analog numerator\n",numer #print "\nanalog denominator\n",denom z,p,k=sg.tf2zpk(numer,denom) #print "Check",z,p,k plt.figure(5) plt.grid(True) plt.scatter(p.real,p.imag,s=50,marker='x') plt.scatter(z.real,z.imag,s=50,marker='o') plt.title('Pole Zero plot of Analog Bandstop filter') plt.ylabel('Imaginary') plt.xlabel('Real') #Tedious still basic version #Need to try convolution #Numerator= (omega_0^2+1)z^2+2*(omega_0^2-1)z+(omega_0^2+1) #Denominator= (-B-c-c*omega_0^2)z^2+(2*c-2*c*omega_0^2)z+(-c*omega_0^2-c+B) numer=K_butter
def lab6_ex5(): # set parameters of system fs = 2000 #sampling frequency (Hz) fn = fs/2 #nyqvist frequency fc = array([0,200,300,1000]) #corner frequencies (assuming typo in lab, putting pass-band @ 0-200 and stop-band @ 300-1000) fb = array([1.0,0]) #desired band gains for each pair of corner frequencies deg = 19 #degree of polynomial nt = deg + 1 #number of taps = degree + 1 a = array([1.0,0]) #(no feedback (FIR), poles at origin reduced to 1 for simplification) # create remez filter, frequency response, and plot b1 = remez(nt,fc,fb,Hz=fs) w,h = freqz(b1,a) subplot(211) plot(w/pi*fn, 20*log10(abs(h)),'b-') title('Remez algo FIRs (20 taps)') ylabel('magnitude (dB scale)') grid() # change to high-pass (switch desired band gains) fb = array([0,1.0]) #desired band gains for each pair of corner frequencies b2 = remez(nt,fc,fb,Hz=fs) w,h = freqz(b2,a) plot(w/pi*fn, 20*log10(abs(h)),'r-') # change to band-stop (add pair of corner frequencies: need at least 3 pairs to produce stopband between 200-300Hz) fc = array([0,199,200,300,301,1000]) #corner frequencies fb = array([1.0,0,1.0]) #desired band gains for each pair of corner frequencies b3 = remez(nt,fc,fb,Hz=fs) w,h = freqz(b3,a) plot(w/pi*fn, 20*log10(abs(h)),'g-') legend(("low-pass","high-pass","band-stop"),loc='best') # redo all 3 filters using firwin2 instead of remez algorithm # low-pass fc = array([0,200,300,fn-1,fn]) #frequency sampling points fb = array([1.0,1.0,0,0,0]) #gains for each sampling point b4 = firwin2(nt,fc,fb,nyq=fn) #calc FIR coefficients with given frequency response a = array([1.0,0]) #(no feedback (FIR), poles at origin reduced to 1 for simplification) w,h = freqz(b4,a) subplot(212) plot(w/pi*fn, 20*log10(abs(h)),'b-') title('Firwin2 algo FIRs (20 taps)') xlabel('frequency') ylabel('magnitude (dB scale)') # high-pass fb = array([0,0,1,1,0]) b5 = firwin2(nt,fc,fb,nyq=fn) w,h = freqz(b5,a) plot(w/pi*fn, 20*log10(abs(h)),'r-') # band-stop (200-300Hz) fc = array([0,200,300,fn-1,fn]) fb = array([1.0,0,0,1.0,0]) b6 = firwin2(nt,fc,fb,nyq=fn) w,h = freqz(b6,a) plot(w/pi*fn, 20*log10(abs(h)),'g-') legend(("low-pass","high-pass","band-stop"),loc='best') show() z,p,k = tf2zpk(b1,a) zplane(z,p) title('low-pass remez FIR') show() z,p,k = tf2zpk(b4,a) zplane(z,p) title('low-pass firwin2 FIR') show() z,p,k = tf2zpk(b2,a) zplane(z,p) title('high-pass remez FIR') show() z,p,k = tf2zpk(b5,a) zplane(z,p) title('high-pass firwin2 FIR') show() z,p,k = tf2zpk(b3,a) zplane(z,p) title('band-stop remez FIR') show() z,p,k = tf2zpk(b6,a) zplane(z,p) title('band-stop firwin2 FIR') show() print("\nHere we see that a 20-tap FIR system is limited in performance, whether its algorithm is Remez or Firwin2 (window method):") print("\nRemez:\nThe low-pass Remez does attenuate rapidly at 300Hz, but the high-pass's response at higher frequencies oscillates above and below 0dB, meaning it both amplifies and attenuates high frequencies. The band-stop FIR has the same issue at both low and high frequency bands that should be passed.") print("\nFirwin2:\nThe low-pass and high-pass Firwin2 filters attenuate slowly at their corner frequencies, but at least they attenuate. The band-stop filter shows the weakness of this response, however, as it looks to be attenuating just about every frequency available, not just those within the 200-300Hz range") print("\nClearly, these FIRs require much higher numbers of taps (e.g. at least 40-50 taps, as in earlier exercises) to perform adequately in many situations")