def iir_bandstops(fstops, fs, order=4): import numpy as np from scipy.signal import iirdesign, zpk2tf, freqz nyq = 0.5 * fs # Zeros zd, poles pd, and gain kd for the digital filter zd = np.array([]) pd = np.array([]) kd = 1 # Notches for fstopData in fstops: fstop = fstopData[0] df = fstopData[1] df2 = fstopData[2] low = (fstop - df) / nyq high = (fstop + df) / nyq low2 = (fstop - df2) / nyq high2 = (fstop + df2) / nyq z, p, k = iirdesign([low,high], [low2,high2], gpass=1, gstop=6, ftype='ellip', output='zpk') zd = np.append(zd,z) pd = np.append(pd,p) # Set gain to one at 100 Hz...better not notch there bPrelim,aPrelim = zpk2tf(zd, pd, 1) outFreq, outg0 = freqz(bPrelim, aPrelim, 100/nyq) # Return the numerator and denominator of the digital filter b,a = zpk2tf(zd,pd,k) return b, a
def ITU_R_468_weighting(fs): """ Return ITU-R 468 digital weighting filter transfer function fs : float Sampling frequency Example: >>> from scipy.signal import freqz >>> import matplotlib.pyplot as plt >>> fs = 200000 >>> b, a = ITU_R_468_weighting(fs) >>> f = np.logspace(np.log10(10), np.log10(fs/2), 1000) >>> w = 2*pi * f / fs >>> w, h = freqz(b, a, w) >>> plt.semilogx(w*fs/(2*pi), 20*np.log10(abs(h))) >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both') >>> plt.axis([10, 100e3, -50, 20]) """ z, p, k = ITU_R_468_weighting_analog() # Use the bilinear transformation to get the digital filter. try: # Currently private but more accurate from scipy.signal.filter_design import _zpkbilinear zz, pz, kz = _zpkbilinear(z, p, k, fs) return zpk2tf(zz, pz, kz) except ImportError: b, a = zpk2tf(z, p, k) return bilinear(b, a, fs)
def iir_bandstops(fstops, fs, order=4): """ellip notch filter fstops is a list of entries of the form [frequency (Hz), df, df2] where df is the pass width and df2 is the stop width (narrower than the pass width). Use caution if passing more than one freq at a time, because the filter response might behave in ways you don't expect. """ nyq = 0.5 * fs # Zeros zd, poles pd, and gain kd for the digital filter zd = np.array([]) pd = np.array([]) kd = 1 # Notches for fstopData in fstops: fstop = fstopData[0] df = fstopData[1] df2 = fstopData[2] low = (fstop - df) / nyq high = (fstop + df) / nyq low2 = (fstop - df2) / nyq high2 = (fstop + df2) / nyq z, p, k = iirdesign([low,high], [low2,high2], gpass=1, gstop=6, ftype='ellip', output='zpk') zd = np.append(zd,z) pd = np.append(pd,p) # Set gain to one at 100 Hz...better not notch there bPrelim,aPrelim = zpk2tf(zd, pd, 1) outFreq, outg0 = freqz(bPrelim, aPrelim, 100/nyq) # Return the numerator and denominator of the digital filter b,a = zpk2tf(zd,pd,k) return b, a
def prepare_video_filters(): # TODO: test these CLV+innerCAV parameters. Should be same on PAL+NTSC t1 = 25 t2 = 13.75 [tf_b, tf_a] = sps.zpk2tf(-t2*(10**-8), -t1*(10**-8), t1 / t2) SP['f_emp'] = sps.bilinear(tf_b, tf_a, 1/(freq_hz/2)) # RF BPF and analog audio cut filters SP['f_videorf_bpf'] = sps.butter(1, [SP['vbpf'][0]/(freq_hz/2), SP['vbpf'][1]/(freq_hz/2)], btype='bandpass') if SP['analog_audio'] == True: SP['f_aleft_stop'] = sps.butter(1, [(SP['audio_lfreq'] - 750000)/(freq_hz/2), (SP['audio_lfreq'] + 750000)/(freq_hz/2)], btype='bandstop') SP['f_aright_stop'] = sps.butter(1, [(SP['audio_rfreq'] - 750000)/(freq_hz/2), (SP['audio_rfreq'] + 750000)/(freq_hz/2)], btype='bandstop') # standard post-demod LPF lowpass_filter_b, lowpass_filter_a = sps.butter(SP['vlpf_order'], SP['vlpf_freq']/(freq_hz/2), 'low') # post-demod deemphasis filter [tf_b, tf_a] = sps.zpk2tf(-SP['deemp'][1]*(10**-8), -SP['deemp'][0]*(10**-8), SP['deemp'][0] / SP['deemp'][1]) SP['f_deemp'] = sps.bilinear(tf_b, tf_a, 1/(freq_hz/2)) # if AC3: #SP['f_arightcut'] = sps.butter(1, [(2650000)/(freq_hz/2), (3150000)/(freq_hz/2)], btype='bandstop') # prepare for FFT: convert above filters to FIR using FDLS techniques first forder = 256 forderd = 0 [Bbpf_FDLS, Abpf_FDLS] = fdls.FDLS_fromfilt(SP['f_videorf_bpf'][0], SP['f_videorf_bpf'][1], forder, forderd, 0, phasemult = 1.00) [Bemp_FDLS, Aemp_FDLS] = fdls.FDLS_fromfilt(SP['f_emp'][0], SP['f_emp'][1], forder, forderd, 0) [Bdeemp_FDLS, Adeemp_FDLS] = fdls.FDLS_fromfilt(SP['f_deemp'][0], SP['f_deemp'][1], forder, forderd, 0) [Bplpf_FDLS, Aplpf_FDLS] = fdls.FDLS_fromfilt(lowpass_filter_b, lowpass_filter_a, forder, forderd, 0) Fbpf = np.fft.fft(Bbpf_FDLS, blocklen) Femp = np.fft.fft(Bemp_FDLS, blocklen) SP['fft_video'] = Fbpf * fft_hilbert if SP['analog_audio'] == True: [Bcutl_FDLS, Acutl_FDLS] = fdls.FDLS_fromfilt(SP['f_aleft_stop'][0], SP['f_aleft_stop'][1], forder, forderd, 0, phasemult = 1.00) [Bcutr_FDLS, Acutr_FDLS] = fdls.FDLS_fromfilt(SP['f_aright_stop'][0], SP['f_aright_stop'][1], forder, forderd, 0, phasemult = 1.00) Fcutl = np.fft.fft(Bcutl_FDLS, blocklen) Fcutr = np.fft.fft(Bcutr_FDLS, blocklen) SP['fft_video'] *= (Fcutl * Fcutr) SP['fft_video_inner'] = SP['fft_video'] * Femp # Post processing: lowpass filter + deemp Fplpf = np.fft.fft(Bplpf_FDLS, blocklen) Fdeemp = np.fft.fft(Bdeemp_FDLS, blocklen) SP['fft_post'] = Fplpf * Fdeemp # determine freq offset and mult for output stage hz_ire_scale = (SP['videorf_100ire'] - SP['videorf_0ire']) / 100 minn = SP['videorf_0ire'] + (hz_ire_scale * -60) SP['output_minfreq'] = sminn = minn / (freq_hz / tau) out_scale = 65534.0 / (SP['ire_max'] - SP['ire_min']) SP['output_scale'] = (freq_hz / tau) * (out_scale / hz_ire_scale)
def find_sysd_prew(sys,f,Ts): #Find the discrete-time transfer function for the Bilinear transform with prewarping #Convert the continuous time system to a form so we can substitute s with factor*(z-1)/(z+1) s = Symbol('s') zer = sys.zero() pol = sys.pole() teller = 1 noemer = 1 for k in range(len(zer)): teller = teller * (s-zer[k]) for k in range(len(pol)): noemer = noemer*(s-pol[k]) sys_cont = teller/noemer val1 = sys.horner(0)[0][0] val2 = sys_cont.subs(s,0) K = val1/val2 sys_cont = simplify(K*teller/noemer) #Substitute s z = Symbol('z') factor = float(f)/(math.tan(float(f)*Ts/2)) ssys = simplify(sys_cont.subs(s,factor*(z-1)/(z+1))) omgekeerd = simplify(1/ssys) #Compute zeros and poles zeros = solve(ssys, z) poles = solve(omgekeerd,z) #Compute gain num,den = signal.zpk2tf(zeros,poles,1) num = num.tolist() den = den.tolist() for k in range(len(num)): try: num[k] = float(num[k]) except: num[k] = num[k] for k in range(len(den)): try: den[k] = float(den[k]) except: den[k] = den[k] system = TransferFunction(num,den,Ts) gain = sys.horner(0)[0][0]/(system.horner(1)[0][0]) #Convert it to a transferfunction num,den = signal.zpk2tf(zeros,poles,gain) num = num.tolist() den = den.tolist() for k in range(len(num)): try: num[k] = float(num[k]) except: num[k] = num[k] for k in range(len(den)): try: den[k] = float(den[k]) except: den[k] = den[k] system = TransferFunction(num,den,Ts) return system
def prepare_video_filters(SP): # TODO: test these CLV+innerCAV parameters. Should be same on PAL+NTSC t1 = 25 t2 = 13.75 [tf_b, tf_a] = sps.zpk2tf(-t2 * (10 ** -8), -t1 * (10 ** -8), t1 / t2) Femp = filtfft(sps.bilinear(tf_b, tf_a, 1 / (freq_hz / 2))) # RF BPF and analog audio cut filters Fbpf = filtfft(sps.butter(1, [SP["vbpf"][0] / (freq_hz / 2), SP["vbpf"][1] / (freq_hz / 2)], btype="bandpass")) # standard post-demod LPF Fplpf = filtfft(sps.butter(SP["vlpf_order"], SP["vlpf_freq"] / (freq_hz / 2), "low")) # post-demod deemphasis filter [tf_b, tf_a] = sps.zpk2tf( -SP["deemp"][1] * (10 ** -8), -SP["deemp"][0] * (10 ** -8), SP["deemp"][0] / SP["deemp"][1] ) Fdeemp = filtfft(sps.bilinear(tf_b, tf_a, 1.0 / (freq_hz / 2))) SP["fft_video"] = Fbpf * fft_hilbert if SP["analog_audio"] == True: Fcutl = filtfft( sps.butter( 1, [(SP["audio_lfreq"] - 750000) / (freq_hz / 2), (SP["audio_lfreq"] + 750000) / (freq_hz / 2)], btype="bandstop", ) ) Fcutr = filtfft( sps.butter( 1, [(SP["audio_rfreq"] - 750000) / (freq_hz / 2), (SP["audio_rfreq"] + 750000) / (freq_hz / 2)], btype="bandstop", ) ) # if AC3: # SP['f_arightcut'] = sps.butter(1, [(2650000)/(freq_hz/2), (3150000)/(freq_hz/2)], btype='bandstop') SP["fft_video"] *= Fcutl * Fcutr SP["fft_video_inner"] = SP["fft_video"] * Femp # Post processing: lowpass filter + deemp SP["fft_post"] = Fplpf * Fdeemp # determine freq offset and mult for output stage hz_ire_scale = (SP["videorf_100ire"] - SP["videorf_0ire"]) / 100 minn = SP["videorf_0ire"] + (hz_ire_scale * -60) SP["output_minfreq"] = sminn = minn / (freq_hz / tau) out_scale = 65534.0 / (SP["ire_max"] - SP["ire_min"]) SP["output_scale"] = (freq_hz / tau) * (out_scale / hz_ire_scale)
def iir(c,N,fs,fc=0,wc=0,fc1=0,fc2=0,wc1=0,wc2=0): if c==1: b,a = signal.butter(N,wc,btype = 'low',analog=True,output='ba')#Design an Nth order digital or analog Butterworth filter and return the filter coefficients in (B,A) or (Z,P,K) form. za,pa,ka = signal.butter(N,wc,btype = 'low',analog=True,output='zpk') num,den = signal.zpk2tf(za,pa,ka) elif c==2: b,a = signal.butter(N,wc,btype = 'high',analog=True,output='ba')#Design an Nth order digital or analog Butterworth filter and return the filter coefficients in (B,A) or (Z,P,K) form. za,pa,ka = signal.butter(N,wc,btype = 'high',analog=True,output='zpk') num,den = signal.zpk2tf(za,pa,ka) elif c==3: b,a = signal.butter(N,[wc1,wc2],btype = 'bandpass',analog=True,output='ba')#Design an Nth order digital or analog Butterworth filter and return the filter coefficients in (B,A) or (Z,P,K) form. za,pa,ka = signal.butter(N,[wc1,wc2],btype = 'bandpass',analog=True,output='zpk') num,den = signal.zpk2tf(za,pa,ka) elif c==4: b,a = signal.butter(N,[wc1,wc2],btype = 'bandstop',analog=True,output='ba')#Design an Nth order digital or analog Butterworth filter and return the filter coefficients in (B,A) or (Z,P,K) form. za,pa,ka = signal.butter(N,[wc1,wc2],btype = 'bandstop',analog=True,output='zpk') num,den = signal.zpk2tf(za,pa,ka) #Compute frequency response of analog filter. w, h = signal.freqs(b,a)#h->frequency response plt.semilogx(w, 20 * np.log10(abs(h))) plt.xlabel('Frequency') plt.ylabel('Amplitude response [dB]') plt.grid() plt.show() fig = plt.figure() ax1 = fig.add_subplot(1, 1, 1) ax1.set_title('Analog filter frequency response') ax1.plot(w, 20 * np.log10(abs(h)), 'b') ax1.set_ylabel('Amplitude [dB]', color='b') ax1.set_xlabel('Frequency [Hz]') ax1.grid() ax2 = ax1.twinx() angles = np.unwrap(np.angle(h)) ax2.plot(w, angles, 'g') ax2.set_ylabel('Angle [radians]', color='g') plt.axis('tight') plt.show() #to plot the poles and zeros in z-plane plt.figure() plt.plot(np.real(za), np.imag(za), 'xb') plt.plot(np.real(pa), np.imag(pa), 'or') plt.legend(['Zeros', 'Poles'], loc=2) plt.title('Pole / Zero Plot') plt.ylabel('Real') plt.xlabel('Imaginary') plt.grid() plt.show() print("Num: ");print(num) print("Den: ");print(den)
def prepare_video_filters(SP): # TODO: test these CLV+innerCAV parameters. Should be same on PAL+NTSC t1 = 25 t2 = 13.75 [tf_b, tf_a] = sps.zpk2tf(-t2 * (10**-8), -t1 * (10**-8), t1 / t2) Femp = filtfft(sps.bilinear(tf_b, tf_a, 1 / (freq_hz / 2))) # RF BPF and analog audio cut filters Fbpf = filtfft( sps.butter( 1, [SP['vbpf'][0] / (freq_hz / 2), SP['vbpf'][1] / (freq_hz / 2)], btype='bandpass')) # standard post-demod LPF Fplpf = filtfft( sps.butter(SP['vlpf_order'], SP['vlpf_freq'] / (freq_hz / 2), 'low')) # post-demod deemphasis filter [tf_b, tf_a] = sps.zpk2tf(-SP['deemp'][1] * (10**-8), -SP['deemp'][0] * (10**-8), SP['deemp'][0] / SP['deemp'][1]) Fdeemp = filtfft(sps.bilinear(tf_b, tf_a, 1.0 / (freq_hz / 2))) SP['fft_video'] = Fbpf * fft_hilbert if SP['analog_audio'] == True: Fcutl = filtfft( sps.butter(1, [(SP['audio_lfreq'] - 750000) / (freq_hz / 2), (SP['audio_lfreq'] + 750000) / (freq_hz / 2)], btype='bandstop')) Fcutr = filtfft( sps.butter(1, [(SP['audio_rfreq'] - 750000) / (freq_hz / 2), (SP['audio_rfreq'] + 750000) / (freq_hz / 2)], btype='bandstop')) # if AC3: #SP['f_arightcut'] = sps.butter(1, [(2650000)/(freq_hz/2), (3150000)/(freq_hz/2)], btype='bandstop') SP['fft_video'] *= (Fcutl * Fcutr) SP['fft_video_inner'] = SP['fft_video'] * Femp # Post processing: lowpass filter + deemp SP['fft_post'] = Fplpf * Fdeemp # determine freq offset and mult for output stage hz_ire_scale = (SP['videorf_100ire'] - SP['videorf_0ire']) / 100 minn = SP['videorf_0ire'] + (hz_ire_scale * -60) SP['output_minfreq'] = sminn = minn / (freq_hz / tau) out_scale = 65534.0 / (SP['ire_max'] - SP['ire_min']) SP['output_scale'] = (freq_hz / tau) * (out_scale / hz_ire_scale)
def __init__(self, Gp, Time, Input): while (True): # Try random parameter values self.DP1 = np.random.uniform(0, DAMPING_MAX) self.WN1 = np.random.uniform(0, WN_MAX) self.DP2 = np.random.uniform(0, DAMPING_MAX) self.WN2 = np.random.uniform(0, WN_MAX) # Compute location of zeros (self.Z1, self.Z2) = np.roots([1, 2 * self.DP1 * self.WN1, self.WN1**2]) (self.Z3, self.Z4) = np.roots([1, 2 * self.DP2 * self.WN2, self.WN2**2]) # Create test PI controller (used to calculate the maximum K for closed loop stable) (self.Gc_num, self.Gc_den) = zpk2tf( [self.Z1, self.Z2, self.Z3, self.Z4], [0], 1) # Controller with one pole in origin and 2 pair of zeros self.Gc = ctrl.tf(self.Gc_num, self.Gc_den) # Evaluate closed loop stability self.gm, self.pm, self.Wcg, self.Wcp = ctrl.margin(self.Gc * Gp) # Dischard solutions with no gain margin if self.Wcg == None or (self.Wcp != None and self.Wcg >= self.Wcp): continue if self.gm == None: # None = inf self.gm = K_MAX # If K < gm => closed loop stable (gm > 0dB) self.K = np.random.uniform(0, self.gm) # Create PI controller for closed loop stable system (self.Gc_num, self.Gc_den) = zpk2tf( [self.Z1, self.Z2, self.Z3, self.Z4], [0], self.K ) # Controller with one pole in origin and 2 pair of zeros self.Gc = ctrl.tf(self.Gc_num, self.Gc_den) # Closed loop system self.M = ctrl.feedback(self.Gc * Gp, 1) # Closed loop step response self.y, self.t, self.xout = ctrl.lsim(self.M, Input, Time) # Evaluate fitness self.fitness = evaluate(Input, self.y) break
def step_resp_SecondOrder2(t=None, Q=None, w0=None, Amp=None): if t is None: tt = np.array([]) y_out = np.array([]) else: if Q is None: tt = np.array([]) y_out = np.array([]) else: if w0 is None: # w0 = 1 [rad/seg] "Normalizado" NUM = [1] DEN = [1, 1 / Q, 1] else: z = np.array([]) p = np.roots([1, w0 / Q, w0**2]) k = w0**2 NUM, DEN = sig.zpk2tf(z, p, k) if Amp is None: u = 1 * esc(t) else: u = Amp * esc(t) tt, y_out, x = sig.lsim2((NUM, DEN), u, t) return tt, y_out
def fitness_calc(self, Gp, Time, Input): # Compute location of zeros (self.Z1, self.Z2) = np.roots([1, 2 * self.DP1 * self.WN1, self.WN1**2]) (self.Z3, self.Z4) = np.roots([1, 2 * self.DP2 * self.WN2, self.WN2**2]) # Create PI controller (self.Gc_num, self.Gc_den) = zpk2tf( [self.Z1, self.Z2, self.Z3, self.Z4], [0], self.K) # Controller with one pole in origin and 2 pair of zeros self.Gc = ctrl.tf(self.Gc_num, self.Gc_den) # Evaluate closed loop stability self.gm, self.pm, self.Wcg, self.Wcp = ctrl.margin(self.Gc * Gp) # Dischard solutions with no gain margin if self.gm == None or self.gm <= 1: self.fitness = 999 return # Closed loop system self.M = ctrl.feedback(self.Gc * Gp, 1) # Closed loop step response self.y, self.t, self.xout = ctrl.lsim(self.M, Input, Time) # Evaluate fitness self.fitness = evaluate(Input, self.y)
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 _design_iir(wp, ws, sample_rate, gpass, gstop, analog=False, ftype='cheby1', output='zpk'): # pylint: disable=invalid-name nyq = sample_rate / 2. wp = numpy.atleast_1d(wp) ws = numpy.atleast_1d(ws) if analog: # convert Hz to rad/s wp *= TWO_PI ws *= TWO_PI else: # convert Hz to half-cycles / sample wp /= nyq ws /= nyq z, p, k = signal.iirdesign(wp, ws, gpass, gstop, analog=analog, ftype=ftype, output='zpk') if analog: # convert back to Hz z /= -TWO_PI p /= -TWO_PI k *= TWO_PI ** z.size / -TWO_PI ** p.size if output == 'zpk': return z, p, k elif output == 'ba': return signal.zpk2tf(z, p, k) elif output == 'sos': return signal.zpk2sos(z, p, k) else: raise ValueError("'%s' is not a valid output form." % output)
def integrate(data, sample_frequency, integration_time): """Integrate the sound pressure squared using exponential integration. :param data: Energetic quantity, e.g. :math:`p^2`. :param sample_frequency: Sample frequency. :param integration_time: Integration time. :returns: Time weighting is applied by applying a low-pass filter with one real pole at :math:`-1/\\tau`. .. note:: Because :math:`f_s \\cdot t_i` is generally not an integer, samples are discarded. This results in a drift of samples for longer signals (e.g. 60 minutes at 44.1 kHz). """ integration_time = np.asarray(integration_time) sample_frequency = np.asarray(sample_frequency) samples = data.shape[-1] b, a = zpk2tf([1.0], [1.0, integration_time], [1.0]) b, a = bilinear(b, a, fs=sample_frequency) #b, a = bilinear([1.0], [1.0, integration_time], fs=sample_frequency) # Bilinear: Analog to Digital filter. n = np.floor(integration_time * sample_frequency).astype(int) data = data[..., 0:n*(samples//n)] newshape = list(data.shape[0:-1]) newshape.extend([-1, n]) data = data.reshape(newshape) #data = data.reshape((-1, n)) # Divide in chunks over which to perform the integration. return lfilter(b, a, data)[...,n-1] / integration_time # Perform the integration. Select the final value of the integration.
def zpk_tf1(zeros_tf, poles_tf, gain): zeros = getzeros(zeros_tf) poles = getzeros(poles_tf) num, den = zpk2tf(zeros, poles, gain) # sys = matlab.zpk(zeros, poles, gain) sys = matlab.tf(num, den) return sys
def _design_iir(wp, ws, sample_rate, gpass, gstop, analog=False, ftype='cheby1', output='zpk'): nyq = sample_rate / 2. wp = atleast_1d(wp) ws = atleast_1d(ws) if analog: wp *= TWO_PI ws *= TWO_PI else: wp /= nyq ws /= nyq z, p, k = signal.iirdesign(wp, ws, gpass, gstop, analog=analog, ftype=ftype, output='zpk') if analog: z /= -TWO_PI p /= -TWO_PI if output == 'zpk': return z, p, k elif output == 'ba': return signal.zpk2tf(z, p, k) elif output == 'sos': return signal.zpk2sos(z, p, k) else: raise ValueError("'%s' is not a valid output form." % output)
def for_matti(kirjain, tyyppi, fs): F = np.array( formantit2.formantit[tyyppi][kirjain][0:4]) #4 ensimmäistä formanttia Ba = np.array([20, 30, 50, 60]) #Bandwith formanteille dur = formantit2.formantit[tyyppi][kirjain][4] #kesto nsamps = int(math.floor(dur * fs)) #Näytteiden määrä R = np.exp(-np.pi * Ba / fs) #naparadius theta = (2 * np.pi * F) / fs #napakulma poles = R * np.exp(1j * theta) #Navat [B, A] = sg.zpk2tf(0, poles, 1) #Kontrolli f0 = 105 #pitch w0T = 2 * np.pi * f0 / fs #normalisoitu nharm = int(math.floor((fs / 2) / f0)) sig = np.zeros(nsamps) n = np.arange(nsamps) if F[0] != 0 and F[1] != 0 and F[2] != 0 and F[3] != 0: for i in range(nharm): #sig += np.sin(i*w0T*n) sig += sg.sawtooth(i * w0T * n) sig = sig / np.max(sig) speech = sg.lfilter(np.array([1.0]), A, sig) return speech
def return_trans_func(f, sensor_name, coil_name, sample_rate, nd=16, debug=0): try: sk, sp, sz, Afit, Bfit, np, nz = get_hdf5values(f, sensor_name, coil_name, nd, debug=debug) print 'obtained hdf data' data_found = 1 except: print 'failed to get data - coupling not recorded because its too weak?' data_found = 2 return 0, 0, 0 #convert zero-pole-gain representation to polynomial representation b_s, a_s = scipy_signal.zpk2tf(sz,sp,sk) if debug==1: print 'b_s:', ['%.2e'%(i_tmp) for i_tmp in b_s] print 'a_s:', ['%.2e'%(i_tmp) for i_tmp in a_s] print 'zpk2tf finished' #convert from s-domain -> z-domain using bilinear transform #note this uses a modified version of the scipy function #b_z, a_z = scipy_signal.bilinear(b_s, a_s,fs=sample_rate) b_z, a_z = bilinear(b_s, a_s, fs=sample_rate) if debug==1: print 'b_z:', ['%.2e'%(i_tmp) for i_tmp in b_z] print 'a_z:', ['%.2e'%(i_tmp) for i_tmp in a_z] print 'bz and az found' return a_z, b_z, 1
def butter_test(order, range, capacity): range = numpy.core.numeric.asarray(range) z, p = compute_butterworth(order) fs = 2.0 warped = 2 * fs * numpy.tan(numpy.pi * range / fs) if capacity in ('lowpass', 'highpass'): if capacity == 'lowpass': z, p, k = capacity_filters._zpklp2lp(z, p, 1, wo=warped) elif capacity == 'highpass': z, p, k = capacity_filters._zpklp2hp(z, p, 1, wo=warped) elif capacity in ('bandpass', 'bandstop'): bw = warped[1] - warped[0] wo = numpy.sqrt(warped[0] * warped[1]) if capacity == 'bandpass': z, p, k = capacity_filters._zpklp2bp(z, p, 1, wo=wo, bw=bw) elif capacity == 'bandstop': z, p, k = capacity_filters._zpklp2bs(z, p, 1, wo=wo, bw=bw) z, p, k = capacity_filters._zpkbilinear(z, p, 1, fs=fs) return signal.zpk2tf(z, p, k)
def make_biquads(filterset, fs=FS): ZPK = list(generate_filter_coeffs(filterset, fs, output='zpk')) biquads = [] singles = [] # pair off zeros/poles from each filter set and convert to transfer func for Z, P, K in ZPK: zeros = sorted(Z, key=lambda x: -abs(x.imag)) poles = sorted(P, key=lambda x: -abs(x.imag)) for zz, pp in zip(grouper(2, zeros), grouper(2, poles)): ba = sig.zpk2tf(zz, pp, K) if len(zz) == 2: biquads.append(ba) else: singles.append(ba) # convolve the spare singles together to make biquads for BA in grouper(2, singles): (b1, a1), (b2, a2) = BA b = sig.convolve(b1, b2) a = sig.convolve(a1, a2) biquads.append((b, a)) return np.array(biquads)
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 iir_bp(fstops, fs, order=4): """ the opposite of a notch filter: return coefficients to add a spectral line """ nyq = 0.5 * fs # Zeros zd, poles pd, and gain kd for the digital filter zd = np.array([]) pd = np.array([]) # Lines for fstopData in fstops: fstop = fstopData[0] df = fstopData[1] df2 = fstopData[2] low = (fstop - df) / nyq high = (fstop + df) / nyq low2 = (fstop - df2) / nyq high2 = (fstop + df2) / nyq z, p, k = sig.iirdesign([low2, high2], [low, high], gpass=1, gstop=6, ftype='ellip', output='zpk') zd = np.append(zd, z) pd = np.append(pd, p) # Return the numerator and denominator of the digital filter b, a = sig.zpk2tf(zd, pd, k) return b, a
def _normalize_gain(self): """ Normalize the gain factor so that the maximum of |H(f)| stays 1 or a previously stored maximum value of |H(f)|. Do this every time a P or Z has been change. Called by _copy_item() """ if not np.isfinite(self.zpk[2]): self.zpk[2] = 1. norm = self.cmbNorm.currentText() if norm != "None": b, a = zpk2tf(self.zpk[0], self.zpk[1], self.zpk[2]) [w, H] = freqz(b, a) Hmax = max(abs(H)) if not np.isfinite(Hmax) or Hmax > 1e4 or Hmax < 1e-4: Hmax = 1. if norm == "1": self.zpk[2] = self.zpk[2] / Hmax # normalize to 1 elif norm == "Max": if norm != self.norm_last: # setting has been changed -> 'Max' self.Hmax_last = Hmax # use current design to set Hmax_last self.zpk[2] = self.zpk[2] / Hmax * self.Hmax_last self.norm_last = norm # store current setting of combobox self._restore_gain()
def filter_arma(data, rate, verbose=False): """Filter using a preset ARMA system""" #Place poles by hand, it doesn't matter much. Values should be in hz #I can't be bothered playing with the radius. zeros = np.array([100, 2000, 400, 412, 2500, 3500, 4000]) poles = np.array([200, 2000, 3000, 8000]) z = 0.99 * np.exp(2j * np.pi * (zeros / (2 * rate))) p = 0.99 * np.exp(2j * np.pi * (poles / (2 * rate))) #Make the filter use real transfer function values! z = np.append(z, z.conj()) p = np.append(p, p.conj()) if (verbose): plt.figure() plt.title("Zero locations") plt.scatter(z.real, z.imag) print("Zero freqs as multiple of pi", np.angle(z) / np.pi) print("Zero mags", np.abs(z)) plt.figure() plt.title("Pole locations") plt.scatter(p.real, p.imag) print("Pole freqs as multiple of pi", np.angle(p) / np.pi) print("Pole mags", np.abs(p)) b, a = sig.zpk2tf(z, p, 1) output = sig.lfilter(b, a, data) if (verbose): h, w = sig.freqz(b, a, fs=rate) plt.figure() plt.title("test_function") plt.plot(h) plt.plot(w) return output
def _normalize_gain(self): """ Normalize the gain factor so that the maximum of |H(f)| stays 1 or a previously stored maximum value of |H(f)|. Do this every time a P or Z has been changed. Called by setModelData() and when cmbNorm is activated """ norm = qget_cmb_box(self.ui.cmbNorm, data=False) self.ui.ledGain.setEnabled(norm == 'None') if norm != self.norm_last: qstyle_widget(self.ui.butSave, 'changed') if not np.isfinite(self.zpk[2]): self.zpk[2] = 1. self.zpk[2] = np.real_if_close(self.zpk[2]).item() if np.iscomplex(self.zpk[2]): logger.warning("Casting complex to real for gain k!") self.zpk[2] = np.abs(self.zpk[2]) if norm != "None": b, a = zpk2tf(self.zpk[0], self.zpk[1], self.zpk[2]) [w, H] = freqz(b, a, whole=True) Hmax = max(abs(H)) if not np.isfinite(Hmax) or Hmax > 1e4 or Hmax < 1e-4: Hmax = 1. if norm == "1": self.zpk[2] = self.zpk[2] / Hmax # normalize to 1 elif norm == "Max": if norm != self.norm_last: # setting has been changed -> 'Max' self.Hmax_last = Hmax # use current design to set Hmax_last self.zpk[2] = self.zpk[2] / Hmax * self.Hmax_last self.norm_last = norm # store current setting of combobox self._restore_gain()
def integrate(data, sample_frequency, integration_time): """Integrate the sound pressure squared using exponential integration. :param data: Energetic quantity, e.g. :math:`p^2`. :param sample_frequency: Sample frequency. :param integration_time: Integration time. :returns: Time weighting is applied by applying a low-pass filter with one real pole at :math:`-1/\\tau`. .. note:: Because :math:`f_s \\cdot t_i` is generally not an integer, samples are discarded. This results in a drift of samples for longer signals (e.g. 60 minutes at 44.1 kHz). """ integration_time = np.asarray(integration_time) sample_frequency = np.asarray(sample_frequency) samples = data.shape[-1] b, a = zpk2tf([1.0], [1.0, integration_time], [1.0]) b, a = bilinear(b, a, fs=sample_frequency) #b, a = bilinear([1.0], [1.0, integration_time], fs=sample_frequency) # Bilinear: Analog to Digital filter. n = np.floor(integration_time * sample_frequency).astype(int) data = data[..., 0:n * (samples // n)] newshape = list(data.shape[0:-1]) newshape.extend([-1, n]) data = data.reshape(newshape) #data = data.reshape((-1, n)) # Divide in chunks over which to perform the integration. return lfilter( b, a, data )[..., n - 1] / integration_time # Perform the integration. Select the final value of the integration.
def zpk_120qa(flat=True): ''' Trillium 120QA TransferFunction Transfer function from Velocity to Voltage. Retrun ------ H : matlab.tf ''' z = np.array([0, 0, -31.63, -160, -350, -3177]) # rad/sec p = np.array([ -0.03661 + 0.037059j, -0.03661 - 0.037059j, -32.55, -142, -364 + 404j, -364 - 404j, -1260, -4900 + 5200j, -4900 - 5200j, -7100 + 1700j, -7100 - 1700j ]) # rad/sec k = 8.31871 * 10e17 # f=1Hzで1202.5になるように規格化した。だめだけども。 S = 1202.5 / 9.99999845 if False: z, p, k = trillium.zpk_120qa() num, den = zpk2tf(z, p, k) w, h = freqs(num, den, worN=np.logspace(-2, 3, 1e5)) f = w / np.pi / 2.0 df = f[1] - f[0] idx = np.where(np.isclose(f, 1.0, atol=df) == True)[0] print(abs(h[idx])) plt.loglog(f, abs(h)) plt.savefig('hoge.png') return z, p, k * S
def _process_waveforms(self, waveforms): """Process the waveforms with the DataLogger information.""" # Correcting electric Field with actual length of dipole for runid in self.runlist: try: mask = ((waveforms.index > self.runinfo[runid]['Start']) & (waveforms.index < self.runinfo[runid]['End'])) waveforms["QN"].loc[mask] *= (100.0/self.runinfo[runid]['Ex']) # mV/km waveforms["QE"].loc[mask] *= (100.0/self.runinfo[runid]['Ey']) # mV/km # If there's no info about length, then use default length. except KeyError: pass if self.zpk is None: return waveforms # Filtering waveforms by NIMS system response for channel in waveforms: # loop for FE, FN, FZ, QN, QE for filt in self.zpk[channel]: # loop for filter zval = self.zpk[channel][filt]['z'] pval = self.zpk[channel][filt]['p'] kval = self.zpk[channel][filt]['k'] # convert analog zpk to digital filter zval, pval, kval = bilinear_zpk(zval, pval, kval, self.samplingrate) b, a = zpk2tf(zval, pval, kval) waveforms[channel] = filtfilt(b, a, waveforms[channel].interpolate()) return waveforms
def frequency_response_analog(poles, zeros): k = 1. poles = map(freq2omega, poles) zeros = map(freq2omega, zeros) ac = sigpy.zpk2tf(zeros, poles, k) w, h = sigpy.freqs(ac[0], ac[1], 2**20) w = w / (2 * np.pi) return w, h
def calcFiltros(A1,A2,Wc,Wp): plt.figure() Nb, Wnb = signal.buttord(Wp,Wc,A1,A2,True) Nc, Wnc = signal.cheb1ord(Wp,Wc,A1,A2,True) Ne, Wne = signal.ellipord(Wp,Wc,A1,A2,True) print('Butterbord Wp =' + str(Wp)) print("N = "+ str(Nb) ) print("Wn = "+ str(Wnb) ) Zb,Pb,Kb = signal.buttap(Nb) ab,bb = signal.zpk2tf(Zb,Pb,Kb) print("H(s) = ") strFunTrans = funTrans([ab,bb]) print(strFunTrans) print("\n") wb, hb = freqs(ab, bb) plt.semilogx(wb, abs(hb)) print('Chebychev Wp =' + str(Wp)) print("N = "+ str(Nc) ) print("Wn = "+ str(Wnc) ) Zc,Pc,Kc = signal.buttap(Nc) ac,bc = signal.zpk2tf(Zc,Pc,Kc) print("H(s) = ") strFunTrans = funTrans([ac,bc]) print(strFunTrans) print("\n") wc, hc = freqs(ac, bc) plt.semilogx(wc, abs(hc)) print('Eliptica Wp =' + str(Wp)) print("N = "+ str(Ne) ) print("Wn = "+ str(Wne) ) Ze,Pe,Ke = signal.buttap(Ne) ae,be = signal.zpk2tf(Ze,Pe,Ke) print("H(s) = ") strFunTrans = funTrans([ae,be]) print(strFunTrans) print("\n") we, he = freqs(ae, be) plt.semilogx(we, abs(he)) plt.xlabel('Frequency') plt.ylabel('Amplitude response') plt.grid()
def test_filter(self): array = self.create() a2 = array.filter([100], [1], 1e-2) self.assertIsInstance(a2, type(array)) self.assertArraysEqual(a2.frequencies, array.frequencies) # manually rebuild the filter to test it works b, a, = signal.zpk2tf([100], [1], 1e-2) fresp = abs(signal.freqs(b, a, array.frequencies.value)[1]) nptest.assert_array_equal(a2.value, fresp * array.value)
def test_filter(self, array): a2 = array.filter([100], [1], 1e-2) assert isinstance(a2, type(array)) utils.assert_quantity_equal(a2.frequencies, array.frequencies) # manually rebuild the filter to test it works b, a, = signal.zpk2tf([100], [1], 1e-2) fresp = abs(signal.freqs(b, a, array.frequencies.value)[1]) utils.assert_array_equal(a2.value, fresp * array.value)
def crossCalib(monitor_trace, response_trace, **kwargs): m_trace=monitor_trace.copy() r_trace=response_trace.copy() if 'demean' in kwargs and kwargs['demean']: m_trace.detrend('demean') r_trace.detrend('demean') if 'taper' in kwargs and kwargs['taper']: m_trace.taper(0.05) r_trace.taper(0.05) #Paramètres des PSD if 'nfft' in kwargs: n_fft=kwargs['nfft'] else: n_fft=1024 if 'npad' in kwargs: n_pad=kwargs['npad'] else: n_pad=n_fft*4 if 'noverlap' in kwargs: n_overlap=kwargs['noverlap'] else: n_overlap=int(n_fft*0.90) #paz par défaut: chaine générique if 'paz' in kwargs: paz=kwargs['paz'] else: paz=dict() paz['zeros']=np.array([]) paz['poles']=np.array([]) paz['gain']=1 paz['seismometer_gain']=1 paz['datalogger_gain']=1 paz['sensitivity']=paz['seismometer_gain']*paz['datalogger_gain']*paz['gain'] fs=m_trace.stats.sampling_rate (P00,f)=mlab.psd(m_trace.data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,pad_to=n_pad,detrend=mlab.detrend_mean,window=mlab.window_hanning) (P01,f)=mlab.csd(m_trace.data,r_trace.data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,pad_to=n_pad,detrend=mlab.detrend_mean,window=mlab.window_hanning) (C,f)=mlab.cohere(m_trace.data,r_trace.data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,pad_to=n_pad,detrend=mlab.detrend_mean,window=mlab.window_hanning) (b,a)=sp.zpk2tf(paz['zeros'],paz['poles'],paz['sensitivity']) (_w,H0)=sp.freqs(b,a,f*2*np.pi) H1=P01*H0/P00 H1=H1[1:] C=C[1:] f=f[1:] return (H1,C,f)
def get_fitted_tf(omega_measured,tf_measured,coh_measured,_exc,dof): _tf = control.tf(*zpk2tf([],[],0)) print(_exc,dof) for i in range(5): try: w0,Q0,k0 = params[_exc][dof][i] __tf = control.tf(*zpk2tf([],p(w0,Q0),k0)) _tf += __tf except: pass # if dof not in _exc: _tf = _tf*(blend(lp='low')+blend(lp='high')) #_tf = _tf*(blend(lp='low')) mag, phase, omega = _tf.freqresp(omega_measured) _w = omega h = mag*np.exp(1j*phase)#*np.exp(1j*10) h = np.squeeze(h) return _w,h
def emphasis_iir(t1, t2, fs): """Generate an IIR filter for 6dB/octave pre-emphasis (t1 > t2) or de-emphasis (t1 < t2), given time constants for the two corners.""" # Convert time constants to frequencies, and pre-warp for bilinear transform w1 = 2 * fs * np.tan((1 / t1) / (2 * fs)) w2 = 2 * fs * np.tan((1 / t2) / (2 * fs)) # Zero at t1, pole at t2 tf_b, tf_a = sps.zpk2tf([-w1], [-w2], w2 / w1) return sps.bilinear(tf_b, tf_a, fs)
def random_arma(p, q, k = 1, z_radius = 1, p_radius = 0.75): ''' Returns a random ARMA(p, q) filter. The parameters p and q define the order of the filter where p is the number of AR coefficients (poles) and q is the number of MA coefficients (zeros). k is the gain of the filter. The z_radius and p_radius paramters specify the maximum magnitude of the zeros and poles resp. In order for the filter to be stable, we should have p_radius < 1. The poles and zeros will be placed uniformly at random inside a disc of the specified radius. We also force the coefficients to be real. This is done by ensuring that for every complex pole or zero, it's recipricol conjugate is also present. If p and q are even, then all the poles/zeros could be complex. But if p or q is odd, then one of the poles and or zeros will be purely real. The filter must be causal. That is, we assert p >= q. Finally, note that in order to generate complex numbers uniformly over the disc we can't generate R and theta uniformly then transform them. This will give a distribution concentrated near (0, 0). We need to generate u uniformly [0, 1] then take R = sqrt(u). This can be seen by starting with a uniform joint distribution f(x, y) = 1/pi, then applying a transform to (r, theta) with x = rcos(theta), y = rsin(theta), calculating the distributions of r and theta, then applying inverse transform sampling. ''' assert(p >= q), 'System is not causal' P = [] Z = [] for i in range(p % 2): pi_r = stats.uniform.rvs(loc = -p_radius, scale = 2*p_radius) P.append(pi_r) for i in range((p - (p % 2)) / 2): pi_r = sqrt(stats.uniform.rvs(loc = 0, scale = p_radius)) pi_ang = stats.uniform.rvs(loc = -np.pi, scale = 2*np.pi) P.append(cmath.rect(pi_r, pi_ang)) P.append(cmath.rect(pi_r, -pi_ang)) for i in range(q % 2): zi_r = stats.uniform.rvs(loc = -z_radius, scale = 2*z_radius) Z.append(zi_r) for i in range((q - (q % 2)) / 2): zi_r = stats.uniform.rvs(loc = 0, scale = z_radius) zi_ang = stats.uniform.rvs(loc = -np.pi, scale = 2*np.pi) Z.append(cmath.rect(zi_r, zi_ang)) Z.append(cmath.rect(zi_r, -zi_ang)) b, a = signal.zpk2tf(Z, P, k) return b, a
def setRandomFIR(self, order=2): """ generates minimum-phase FIR filters with random zeros for each neuron order = nr of zeros in one filter """ size = self.getSize() zeros = (N.random.rand(size, order) * 2 - 1) + (N.random.rand(size, order) * 2 - 1) * 1j k = 1.0 self.B = N.zeros((size, order + 1)) self.A = N.zeros((size, order + 1)) for n in range(size): self.B[n], self.A[n] = signal.zpk2tf(zeros[n], [], k)
def test_ITU_R_468_weight(fs=None): """ Test that frequency response meets tolerance from Rec. ITU-R BS.468-4 """ import numpy as np import matplotlib.pyplot as plt from scipy.signal import freqz frequencies = np.array(( 31.5, 63, 100, 200, 400, 800, 1000, 2000, 3150, 4000, 5000, 6300, 7100, 8000, 9000, 10000, 12500, 14000, 16000, 20000, 31500 )) responses = np.array(( -29.9, -23.9, -19.8, -13.8, -7.8, -1.9, 0, +5.6, +9.0, +10.5, +11.7, +12.2, +12.0, +11.4, +10.1, +8.1, 0, -5.3, -11.7, -22.2, -42.7 )) upper_limits = np.array(( +2.0, +1.4, +1.0, +0.85, +0.7, +0.55, +0.5, +0.5, +0.5, +0.5, +0.5, +0.01, # Actually 0 tolerance, but specified as "+12.2" dB +0.2, +0.4, +0.6, +0.8, +1.2, +1.4, +1.6, +2.0, +2.8 )) lower_limits = np.array(( -2.0, -1.4, -1.0, -0.85, -0.7, -0.55, -0.5, -0.5, -0.5, -0.5, -0.5, -0.01, # Actually 0 tolerance, but specified as "+12.2" dB -0.2, -0.4, -0.6, -0.8, -1.2, -1.4, -1.6, -2.0, -float('inf') )) if fs is None: z, p, k = ITU_R_468_weighting_analog() b, a = zpk2tf(z, p, k) w, h = freqs(b, a, 2*pi*frequencies) else: # Passes if fs >= 180000 Hz but not at typical audio fs b, a = ITU_R_468_weighting(fs) w = 2*pi * frequencies / fs w, h = freqz(b, a, w) levels = 20 * np.log10(abs(h)) plt.semilogx(frequencies, levels) plt.semilogx(frequencies, responses + upper_limits, 'r--') plt.semilogx(frequencies, responses + lower_limits, 'r--') assert all(np.less_equal(levels, responses + upper_limits)) assert all(np.greater_equal(levels, responses + lower_limits))
def dcgain(*args): ''' Compute the gain of the system in steady state. The function takes either 1, 2, 3, or 4 parameters: Parameters ---------- A, B, C, D: array-like A linear system in state space form. Z, P, k: array-like, array-like, number A linear system in zero, pole, gain form. num, den: array-like A linear system in transfer function form. sys: LTI (StateSpace or TransferFunction) A linear system object. Returns ------- gain: ndarray The gain of each output versus each input: :math:`y = gain \cdot u` Notes ----- This function is only useful for systems with invertible system matrix ``A``. All systems are first converted to state space form. The function then computes: .. math:: gain = - C \cdot A^{-1} \cdot B + D ''' #Convert the parameters to state space form if len(args) == 4: A, B, C, D = args return ss(A, B, C, D).dcgain() elif len(args) == 3: Z, P, k = args num, den = zpk2tf(Z, P, k) return tf(num, den).dcgain() elif len(args) == 2: num, den = args return tf(num, den).dcgain() elif len(args) == 1: sys, = args return sys.dcgain() else: raise ValueError("Function ``dcgain`` needs either 1, 2, 3 or 4 " "arguments.")
def test_identity(self): """Test the identity transfer function.""" z = [] p = [] k = 1. b, a = zpk2tf(z, p, k) b_r = np.array([1.]) # desired result a_r = np.array([1.]) # desired result # The test for the *type* of the return values is a regression # test for ticket #1095. In the case p=[], zpk2tf used to # return the scalar 1.0 instead of array([1.0]). assert_array_equal(b, b_r) assert_(isinstance(b, np.ndarray)) assert_array_equal(a, a_r) assert_(isinstance(a, np.ndarray))
def A_weighting(fs, output='ba'): """ Design of a digital A-weighting filter. Designs a digital A-weighting filter for sampling frequency `fs`. Warning: fs should normally be higher than 20 kHz. For example, fs = 48000 yields a class 1-compliant filter. Parameters ---------- fs : float Sampling frequency output : {'ba', 'zpk', 'sos'}, optional Type of output: numerator/denominator ('ba'), pole-zero ('zpk'), or second-order sections ('sos'). Default is 'ba'. Examples -------- Plot frequency response >>> from scipy.signal import freqz >>> import matplotlib.pyplot as plt >>> fs = 200000 >>> b, a = A_weighting(fs) >>> f = np.logspace(np.log10(10), np.log10(fs/2), 1000) >>> w = 2*pi * f / fs >>> w, h = freqz(b, a, w) >>> plt.semilogx(w*fs/(2*pi), 20*np.log10(abs(h))) >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both') >>> plt.axis([10, 100e3, -50, 20]) Since this uses the bilinear transform, frequency response around fs/2 will be inaccurate at lower sampling rates. """ z, p, k = ABC_weighting('A') # Use the bilinear transformation to get the digital filter. z_d, p_d, k_d = _zpkbilinear(z, p, k, fs) if output == 'zpk': return z_d, p_d, k_d elif output in {'ba', 'tf'}: return zpk2tf(z_d, p_d, k_d) elif output == 'sos': return zpk2sos(z_d, p_d, k_d) else: raise ValueError("'%s' is not a valid output form." % output)
def _save(self, fil_dict, arg): """ First design initial elliptic filter meeting sqRoot Amp specs; - Then create residue vector from poles/zeros; - Then square filter (k,p,z and dc,p,r) to get zero phase filter; - Then Convert results of filter design to all available formats (pz, pr, ba, sos) and store them in the global filter dictionary. Corner frequencies and order calculated for minimum filter order are also stored to allow for an easy subsequent manual filter optimization. """ fil_save(fil_dict, arg, self.FRMT, __name__) # For min. filter order algorithms, update filter dict with calculated # new values for filter order N and corner frequency(s) F_PBC fil_dict['N'] = self.N if str(fil_dict['fo']) == 'min': if str(fil_dict['rt']) == 'LP' or str(fil_dict['rt']) == 'HP': # HP or LP - single corner frequency fil_dict['F_PB'] = self.F_PBC / 2. else: # BP or BS - two corner frequencies fil_dict['F_PB'] = self.F_PBC[0] / 2. fil_dict['F_PB2'] = self.F_PBC[1] / 2. # Now generate poles/residues for custom file save of new parameters if (not self.manual): z = fil_dict['zpk'][0] p = fil_dict['zpk'][1] k = fil_dict['zpk'][2] n = len(z) gain, residues = self._partial (k, p, z, n) pA, zA, gn, pC, rC = self._sqCausal (k, p, z, gain, residues, n) fil_dict['rpk'] = [rC, pC, gn] # save antiCausal b,a (nonReciprocal) also [easier to compute h(n) try: fil_dict['baA'] = sig.zpk2tf(zA, pA, k) except Exception as e: logger.error(e) # 'rpk' is our signal that this is a non-Causal filter with zero phase # inserted into fil dictionary after fil_save and convert # sig_tx -> select_filter -> filter_specs self.sig_tx.emit({'sender':__name__, 'filt_changed':'ellip_zero'})
def compute_coeffs(z, z1): """ function computes the filter coefficients of decomposition low pass filter given zeros at pi and zeros of trigonmonetric polynomial for daubach filter """ # adding poles for causal system zeros = len(z) p = np.zeros(zeros - 1) p = np.array(p) z = np.append(z, z1) h = zpk2tf(z, p, [1]) h = np.array(h[0]) # normalizing the filter coefficients h = h / math.sqrt(np.sum(h ** 2)) return h, z, p
def ITU_R_468_weighting_analog(): """ Return ITU-R 468 analog weighting filter zeros, poles, and gain """ z = [0] p = [-25903.70104781628, +36379.90893732929j-23615.53521363528, -36379.90893732929j-23615.53521363528, +62460.15645250649j-18743.74669072136, -62460.15645250649j-18743.74669072136, -62675.1700584679] # Normalize to +12.2 dB at 6.3 kHz, numerically b, a = zpk2tf(z, p, 1) w, h = freqs(b, a, 2*pi*6300) k = 10**(+12.2/20) / abs(h[0]) return z, p, k
def test_mapCtoD_1(self): """Test function for mapCtoD() 1/6""" # The first test comes straight from the DSToolbox doc # We map the standard continuous time DS modulator to its DT counterpart # and we check whether the TF is (1 - 1/z)**2 LFc = (np.array([[0., 0.], [1., 0.]]), np.array([[1., -1.], [0., -1.5]]), np.array([[0., 1.]]), np.array(([[0., 0.]])) ) tdac = [0, 1] LF, Gp = ds.mapCtoD(LFc, tdac) ABCD = np.vstack((np.hstack((LF[0], LF[1])), np.hstack((LF[2], LF[3])) )) H = ds.calculateTF(ABCD) num, den = zpk2tf(*H[0]) self.assertTrue(np.allclose(num, [ 1., -2., 1.], atol=1e-8, rtol=1e-5)) self.assertTrue(np.allclose(den, [1., 0., 0.], atol=1e-8, rtol=1e-5))
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, source, gain=1, **kwds): # Automatically duplicate mono input to fit the desired output shape gain = np.atleast_1d(gain) if len(gain) != source.nchannels and len(gain) != 1: if source.nchannels != 1: raise ValueError('Can only automatically duplicate source ' 'channels for mono sources, use ' 'RestructureFilterbank.') source = RestructureFilterbank(source, len(gain)) samplerate = source.samplerate zeros = np.array([-200, -200]) poles = np.array([-250 + 400j, -250 - 400j, -2000 + 6000j, -2000 - 6000j]) # use an arbitrary gain here, will be normalized afterwards b, a = signal.zpk2tf(zeros, poles * 2 * np.pi, 1.5e9) # normalize the response at 1000Hz (of the analog filter) resp = np.abs(signal.freqs(b, a, [1000*2*np.pi])[1]) # response magnitude b /= resp bd, ad = signal.bilinear(b, a, samplerate) bd = (np.tile(bd, (source.nchannels, 1)).T * gain).T ad = np.tile(ad, (source.nchannels, 1)) LinearFilterbank.__init__(self, source, bd, ad, **kwds)
def ITU_R_468_weighting(fs, output='ba'): """ Return ITU-R 468 digital weighting filter transfer function Parameters ---------- fs : float Sampling frequency Examples -------- >>> from scipy.signal import freqz >>> import matplotlib.pyplot as plt >>> fs = 200000 >>> b, a = ITU_R_468_weighting(fs) >>> f = np.logspace(np.log10(10), np.log10(fs/2), 1000) >>> w = 2*pi * f / fs >>> w, h = freqz(b, a, w) >>> plt.semilogx(w*fs/(2*pi), 20*np.log10(abs(h))) >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both') >>> plt.axis([10, 100e3, -50, 20]) """ z, p, k = ITU_R_468_weighting_analog() # Use the bilinear transformation to get the digital filter. zz, pz, kz = _zpkbilinear(z, p, k, fs) if output == 'zpk': return zz, pz, kz elif output in {'ba', 'tf'}: return zpk2tf(zz, pz, kz) elif output == 'sos': return zpk2sos(zz, pz, kz) else: raise ValueError("'%s' is not a valid output form." % output)
z, p, k = tf2zpk(c, [1]) zplane(z, p) c = np.convolve(c, np.flipud(c)) print c figure() z, p, k = tf2zpk(c, [1]) zplane(z, p) print z s1 = math.sqrt(2) s2 = 1.0 / s1 z = [s1, s2, -s1, -s2] h = zpk2tf(z, p, k) print h, k show() dd dim = 2 + w.vanishing_moments_psi dim1 = w.vanishing_moments_psi + 1 print dim, dim1, w.dec_lo, w.vanishing_moments_psi A = np.zeros((dim, dim1)) c = np.zeros(dim1) P = 2 * np.eye(dim) P[dim - 1, dim - 1] = -2 q = np.zeros(dim)
def filter(self, *filt): """Apply the given filter to this `TimeSeries`. All recognised filter arguments are converted either into cascading second-order sections (if scipy >= 0.16 is installed), or into the ``(numerator, denominator)`` representation before being applied to this `TimeSeries`. .. note:: All filters are presumed to be digital (Z-domain), if you have an analog ZPK (in Hertz or in rad/s) you should be using `TimeSeries.zpk` instead. .. note:: When using `scipy` < 0.16 some higher-order filters may be unstable. With `scipy` >= 0.16 higher-order filters are decomposed into second-order-sections, and so are much more stable. Parameters ---------- *filt one of: - :class:`scipy.signal.lti` - `MxN` `numpy.ndarray` of second-order-sections (`scipy` >= 0.16 only) - ``(numerator, denominator)`` polynomials - ``(zeros, poles, gain)`` - ``(A, B, C, D)`` 'state-space' representation Returns ------- result : `TimeSeries` the filtered version of the input `TimeSeries` See also -------- TimeSeries.zpk for instructions on how to filter using a ZPK with frequencies in Hertz scipy.signal.sosfilter for details on the second-order section filtering method (`scipy` >= 0.16 only) scipy.signal.lfilter for details on the filtering method Raises ------ ValueError If ``filt`` arguments cannot be interpreted properly """ sos = None # single argument given if len(filt) == 1: filt = filt[0] # detect LTI if isinstance(filt, signal.lti): filt = filt a = filt.den b = filt.num # detect SOS elif isinstance(filt, numpy.ndarray) and filt.ndim == 2: sos = filt # detect taps else: b = filt a = [1] # detect TF elif len(filt) == 2: b, a = filt elif len(filt) == 3: try: sos = signal.zpk2sos(*filt) except AttributeError: b, a = signal.zpk2tf(*filt) elif len(filt) == 4: try: zpk = signal.ss2zpk(*filt) sos = signal.zpk2sos(zpk) except AttributeError: b, a = signal.ss2tf(*filt) else: raise ValueError("Cannot interpret filter arguments. Please " "give either a signal.lti object, or a " "tuple in zpk or ba format. See " "scipy.signal docs for details.") if sos is not None: new = signal.sosfilt(sos, self, axis=0).view(self.__class__) else: new = signal.lfilter(b, a, self, axis=0).view(self.__class__) new.__dict__ = self.copy_metadata() return new
def test_detector(): fitSamples = 100 # Prepare detector zero_1 = -5.56351644e+07 pole_1 = -1.38796386e+04 pole_real = -2.02559385e+07 pole_imag = 9885315.37450211 gain = 2./1e-8 zeros = [zero_1,0. ] poles = [ pole_real+pole_imag*1j, pole_real-pole_imag*1j, pole_1] system = signal.lti(zeros, poles, gain ) system.to_tf() num = system.num den = system.den print "original num: " + str(num) print "original den" + str(den) system.to_zpk() print "back to the zpk" print system.zeros print system.poles print system.gain # num = np.array((3478247474.8078203, 1.9351287044375424e+17, 6066014749714584.0)) # den = [1, 40525756.715025946, 508584795912802.44, 7.0511687850000589e+18] # system = signal.lti(num, den) # # zeros = system.zeros # poles = system.poles # gain = system.gain new_num, new_den, dt = signal.cont2discrete((num, den), 1E-8, method="bilinear") # new_num /= 1.05836038e-08 print "new discrete tf representation" print new_num print new_den print dt new_z, new_p, new_k, dt = signal.cont2discrete((zeros, poles, gain), 1E-8, method="bilinear" ) print "new discrete zpk representation" print new_z print new_p print new_k print dt print "...and back to tf" dis_num, dis_den = signal.zpk2tf(new_z, new_p, new_k) print dis_num print dis_den tempGuess = 77.89 gradGuess = 0.0483 pcRadGuess = 2.591182 pcLenGuess = 1.613357 #Create a detector model detName = "conf/P42574A_grad%0.2f_pcrad%0.2f_pclen%0.2f.conf" % (0.05,2.5, 1.65) det = Detector(detName, temperature=tempGuess, timeStep=10., numSteps=fitSamples, ) det.LoadFields("P42574A_fields_v3.npz") det.SetFields(pcRadGuess, pcLenGuess, gradGuess) print "time steps out number is %d" % det.siggenInst.GetSafeConfiguration()['ntsteps_out'] print "time steps calc number is %d" % det.siggenInst.GetSafeConfiguration()['time_steps_calc'] print "step size out is %f" % det.siggenInst.GetSafeConfiguration()['step_time_out'] print "step size calc is %f" % det.siggenInst.GetSafeConfiguration()['step_time_calc'] sig_array = det.GetRawSiggenWaveform( 0.174070, 0.528466, 10.755795) t, sig_array2, x = signal.lsim(system, sig_array, det.time_steps, interp=False) sig_array1 = signal.lfilter(new_num[0], new_den, sig_array) sig_array4 = signal.lfilter(dis_num, dis_den, sig_array) # dissystem = system.to_discrete(1E-8) # ## new_k = dissystem.zeros ## new_p = dissystem.poles ## new_k = dissystem.gain ## dis_num, dis_den = signal.zpk2tf(new_z, new_p, new_k) ## sig_array5 = signal.lfilter(dis_num, dis_den, sig_array) # # plt.figure() plt.plot(sig_array1, "b:") plt.plot(sig_array2, color="black") plt.plot(sig_array4, "r:") # plt.plot(sig_array5, "g:") plt.figure() plt.plot(sig_array2-sig_array1, color="b") plt.plot(sig_array2-sig_array4, color="r") # plt.plot(sig_array2-sig_array5, color="g") #plt.ylim(-0.05, 1.05) plt.xlabel("Time [ns]") plt.ylabel("Charge [arb.]") plt.show()