def butterworth_plot(fig=None, ax=None): """ Plot of frequency response of the Butterworth filter with different orders. """ if fig is None: fig, ax = plt.subplots(1, 2, figsize=(10, 4)) b1, a1 = signal.butter(1, 10, 'low', analog=True) w, h1 = signal.freqs(b1, a1) ang1 = np.rad2deg(np.unwrap(np.angle(h1))) h1 = 20 * np.log10(abs(h1)) b2, a2 = signal.butter(2, 10, 'low', analog=True) w, h2 = signal.freqs(b2, a2) ang2 = np.rad2deg(np.unwrap(np.angle(h2))) h2 = 20 * np.log10(abs(h2)) b4, a4 = signal.butter(4, 10, 'low', analog=True) w, h4 = signal.freqs(b4, a4) ang4 = np.rad2deg(np.unwrap(np.angle(h4))) h4 = 20 * np.log10(abs(h4)) b6, a6 = signal.butter(6, 10, 'low', analog=True) w, h6 = signal.freqs(b6, a6) ang6 = np.rad2deg(np.unwrap(np.angle(h6))) h6 = 20 * np.log10(abs(h6)) w = w/10 # PLOT ax[0].plot(w, h1, 'b', w, h2, 'r', w, h4, 'g', w, h6, 'y', linewidth=2) ax[0].axvline(1, color='black') # cutoff frequency ax[0].scatter(1, -3, marker='s', edgecolor='0', facecolor='1', s=400) #ax1.legend(('1', '2', '4', '6'), title='Filter order', loc='best') ax[0].set_xscale('log') fig.suptitle('Bode plot for low-pass Butterworth filter with different orders', fontsize=16, y=1.05) #ax1.set_title('Magnitude', fontsize=14) ax[0].set_xlabel('Frequency / Critical frequency', fontsize=14) ax[0].set_ylabel('Magnitude [dB]', fontsize=14) ax[0].set_xlim(0.1, 10) ax[0].set_ylim(-120, 10) ax[0].grid(which='both', axis='both') ax[1].plot(w, ang1, 'b', w, ang2, 'r', w, ang4, 'g', w, ang6, 'y', linewidth=2) ax[1].axvline(1, color='black') # cutoff frequency ax[1].legend(('1', '2', '4', '6'), title='Filter order', loc='best') ax[1].set_xscale('log') #ax2.set_title('Phase', fontsize=14) ax[1].set_xlabel('Frequency / Critical frequency', fontsize=14) ax[1].set_ylabel('Phase [degrees]', fontsize=14) ax[1].set_yticks(np.arange(0, -300, -45)) ax[1].set_ylim(-300, 10) ax[1].grid(which='both', axis='both') plt.tight_layout(w_pad=1) axi = plt.axes([.115, .4, .15, .35]) # inset plot axi.plot(w, h1, 'b', w, h2, 'r', w, h4, 'g', w, h6, 'y', linewidth=2) #ax11.set_yticks(np.arange(0, -7, -3)) axi.set_xticks((0.6, 1, 1.4)) axi.set_yticks((-6, -3, 0)) axi.set_ylim([-7, 1]) axi.set_xlim([.5, 1.5]) axi.grid(which='both', axis='both')
def __init__(self, fp, fs, gpass, gstop, ftype, btype): #Variables init. self.fp = fp self.fs = fs self.gpass = gpass self.gstop = gstop self.ftype = ftype self.btype = btype #Filter type for plot's title. types_dict = {"butter":"Butterworth", "cheby1":"Chebyshev I", "cheby2":"Chebyshev II", "ellip": "Cauer"} self.ftype_plot = types_dict[ftype] self.__wsk() self.__filter_order() #Designing filter. (self.b, self.a) = signal.iirfilter(self.ord, self.wn, rp=self.gpass, rs=self.gstop, btype=self.btype, analog=True, output='ba', ftype=ftype) #Frequency response of analog filter. (self.w, self.h) = signal.freqs(self.b, self.a, worN=1000) #Denormalizing variabels for ploting. Pulsation to frequency. self.w = (self.w * (self.sampling_w / 2)) / (2 * pi) self.wn = (self.wn * (self.sampling_w / 2)) / (2 * pi)
def filterba(self, b, a, inplace=False): """Apply a filter to this `Spectrum` in numerator-denominator format. Parameters ---------- b : :class:`~numpy.ndarray` Numerator of a linear filter a : :class:`~numpy.ndarray` Decnominator of a linear filter inplace : `bool`, optional, default: `False` modify this `Spectrum` in-place Returns ------- Spectrum either a view of the current `Spectrum` with filtered data, or a new `Spectrum` with the filtered data """ fresp = abs(signal.freqs(b, a, self.frequencies)[1]) if inplace: self *= fresp return self else: new = self * fresp return new
def FilterResponse(self): """ Gives the response of the filter y frequency-amplitude """ self.w, self.h = SGN.freqs(self.ba, self.aa) return self.w, self.h
def compute_frequencies(self, N=None): if hasattr(self, 'sample_rate'): try: self.W, self.H = signal.freqz(self.B, self.A) except: self.W, self.H = signal.freqz(self.B) else: self.W, self.H = signal.freqs(self.B, self.A, N)
def plot_H(b, a): ws = np.linspace(2*np.pi*3.7, 2*np.pi*8.6, 200) w, h = signal.freqs(b, a, ws) plt.semilogx(w/(2*np.pi), 20 * np.log10(abs(h))) plt.title('Butterworth filter frequency response') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.show()
def make_ctle(rx_bw, peak_freq, peak_mag, w, dc_offset=0): """ Generate the frequency response of a continuous time linear equalizer (CTLE), given the: - signal path bandwidth, - peaking specification, and - list of frequencies of interest. We use the 'invres()' function from scipy.signal, as it suggests itself as a natural approach, given our chosen use model of having the user provide the peaking frequency and degree of peaking. That is, we define our desired frequency response using one zero and two poles, where: - The pole locations are equal to: - the signal path natural bandwidth, and - the user specified peaking frequency. - The zero location is chosen, so as to provide the desired degree of peaking. Inputs: - rx_bw The natural (or, unequalized) signal path bandwidth (Hz). - peak_freq The location of the desired peak in the frequency response (Hz). - peak_mag The desired relative magnitude of the peak (dB). (mag(H(0)) = 1) - w The list of frequencies of interest (rads./s). - dc_offset The d.c. offset of the CTLE gain curve (dB). Outputs: - w, H The resultant complex frequency response, at the given frequencies. """ p2 = -2. * pi * rx_bw p1 = -2. * pi * peak_freq z = p1 / pow(10., peak_mag / 20.) if(p2 != p1): r1 = (z - p1) / (p2 - p1) r2 = 1 - r1 else: r1 = -1. r2 = z - p1 b, a = invres([r1, r2], [p1, p2], []) w, H = freqs(b, a, w) H *= pow(10., dc_offset / 20.) / abs(H[0]) # Enforce d.c. offset. return (w, H)
def grp_delay_ana(b, a, w): """ Calculate the group delay of an anlog filter. """ w, H = sig.freqs(b, a, w) H_angle = np.unwrap(np.angle(H)) # tau_g = np.zeros(len(w)-1) tau_g = (H_angle[1:]-H_angle[:-1])/(w[0]-w[1]) return tau_g, w[:-1]
def butter_filter(): N = 8 #order wn = 0.5 #frequency in the transition band when gain drops below -3dB type = 'low' #filter type b, a = signal.butter(N,wn,'low',analog=False) w, h = signal.freqs(b, a) return (b,a,w,h)
def band_stop(self, low_f, high_f, axis='x', order=6): f_nyq = self.rate / 2 band_low = low_f / f_nyq band_high = high_f / f_nyq b, a = sig.butter(order, [band_low, band_high], btype='bandstop') w, h = sig.freqs(b, a) vdata = self.ts[axis] filtered = sig.lfilter(b,a,vdata) return filtered
def test_sos_phys2filter(): b, a = sos_phys2filter(S0, delta, f0) H = freqs(b, a, 2 * np.pi * fe5)[1] indmax = np.abs(H).argmax() assert np.round(np.abs(f0 - fe5[indmax])) <= 0.01 * f0 assert np.abs(H[0]) == approx(S0) bmulti, amulti = sos_phys2filter(S0 * np.ones(K), delta * np.ones(K), f0 * np.ones(K)) assert len(bmulti[0]) == K assert amulti.shape == (K, 3)
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 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 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 plot_filter_response(b, a): w, h = signal.freqs(b, a) plt.plot(w, 20 * np.log10(abs(h))) plt.xscale('log') plt.title('Chebyl1 filter frequency response') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(100, color='green') # cutoff frequency plt.show()
def FDLS_fromfilt(B, A, N, D, shift = 0.0, phasemult = 1.0, analog = False): if analog: w, h = sps.freqs(B, A) else: w, h = sps.freqz(B, A, worN = 1024) Am = np.absolute(h) Th = np.angle(h) * phasemult return FDLS(N, D, w, Am = Am, Th = Th, shift = shift)
def Rule_7(w_start, w_end): # Rule 7 determining the phase of GGm at -180deg # this is solved visually from a plot w = np.logspace(w_start, w_end, 1000) Pz = np.polymul(G()[0], Gm()[0]) Pp = np.polymul(G()[1], Gm()[1]) [w, h] = scs.freqs(Pz, Pp, w) plt.semilogx(w, (180 / np.pi) * (phase(h) + w * Time_Delay())) plt.show()
def elliptical_filter(): #Design an elliptical filter with some predefined parameters N = 8 #order rp = 1 #max ripple below unity in passband [dB] rs = 10 #max attenuation in the stop band [dB] wn = 0.5 #frequency in the transition band when gain drops below rp (for ellip) type = 'low' #filter type b, a = signal.ellip(N,rp,rs,wn,'low',analog=False) w, h = signal.freqs(b, a) return (b,a,w,h)
def __method(self): # TODO Check CPU time ''' low pass filtering for mode estimation function array must be declared and passed through the function ''' # step 1 vedran, design filter ''' Wn= length-2 sequence giving the critical frequencies - Fp, Fst parameters from matlab fdesign.lowpass(Fp,Fst,Ap,Ast) rp: maximum ripple in the pass band. (dB) - Ap parameter from matlab fdesign.lowpass(Fp,Fst,Ap,Ast) rs: minimum attenuation in the stop band. (dB) - Ast parameter from matlab fdesign.lowpass(Fp,Fst,Ap,Ast) ''' b, a= signal.iirfilter(self.__order, Wn=[2/25,2.5/25], rp=0.1, rs=50, btype='lowpass', analog=True, ftype='cheby2') # step 2 vedran, apply filter simsignalFilter= signal.lfilter(b, a, self.__simulationsSignal) # step 3 vedran, downsample the signal simsignalsampled = signal.decimate(simsignalFilter, 10, ftype='iir') # step 4 with signal.freqs(b,a,y) we obtain frequency response of the signal freqHz, amplitude = signal.freqs(b, a, simsignalsampled) print 'angular frequency ', freqHz print 'amplitude response ', amplitude for vfreq, vdamp in zip(freqHz, amplitude): mode= EigenValue(vfreq,vdamp) self.__simulationModes.append(mode) # step 2 vedran, apply filter maessignalFilter= signal.lfilter(b, a, self.__measurementSignal) # step 3 vedran, downsample the signal maessignalsampled = signal.decimate(maessignalFilter, 10, ftype='iir') # step 4 with signal.freqs(b,a,y) we obtain frequency response of the signal freqHz, amplitude = signal.freqs(b, a, maessignalsampled) print 'angular frequency ', freqHz print 'amplitude response ', amplitude for vfreq, vdamp in zip(freqHz, amplitude): mode= EigenValue(vfreq,vdamp) self.__simulationModes.append(mode) # step 4 vedran, armax, _signal.real or signal.magnitude and signal.sampling data sys_ident= smapi.tsa.ARMA(simsignalsampled, order=(self.__order,self.__order)).fit() print sys_ident sys_ident= smapi.tsa.ARMA(maessignalsampled, order=(self.__order,self.__order)).fit() print sys_ident
def draw_frequency_response(b,a): from scipy.signal import freqs w, h = freqs(b, a) plt.figure(figsize=(8, 6), dpi=100) plt.plot(w, 20 * np.log10(abs(h))) plt.xscale('log') plt.title('Butterworth filter frequency response') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(100, color='green') # cutoff frequency plt.savefig('frequency_response.png',dpi=500)
def butterplot(fs, fc): """ https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.butter.html """ b, a = signal.butter(4, 100, 'low', analog=True) w, h = signal.freqs(b, a) ax = figure().gca() ax.semilogx(fs*0.5/np.pi*w, 20*np.log10(abs(h))) ax.set_title('Butterworth filter frequency response') ax.set_xlabel('Frequency [Hz]') ax.set_ylabel('Amplitude [dB]') ax.grid(which='both', axis='both') ax.axvline(fc, color='green') # cutoff frequency ax.set_ylim(-50, 0)
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 _response_prototype_and_filters(self, freqs): freqs = num.asarray(freqs, dtype=num.float) iomega = 1.0j * 2. * num.pi * freqs trans = iomega * self._prototype_response_velocity(iomega) for (order, corner) in self.filters: if order < 0. or corner < 0.: b,a = signal.butter(abs(order), [abs(corner)], btype='high', analog=1) else: b,a = signal.butter(order, [corner], btype='low', analog=1) trans *= signal.freqs(b,a, freqs)[1] return trans
def chebyshevplot(fs): """ https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.cheby1.html#scipy.signal.cheby1 """ b, a = signal.cheby1(4, 5, 100, 'high', analog=True) w, h = signal.freqs(b, a) ax = figure().gca() ax.semilogx(w, 20*np.log10(abs(h))) ax.set_title('Chebyshev Type I frequency response (rp=5)') ax.set_xlabel('Frequency [radians / second]') ax.set_ylabel('Amplitude [dB]') ax.grid(which='both', axis='both') ax.axvline(100, color='green') # cutoff frequency ax.axhline(-5, color='green') # rp
def compute_response(freqlist, paz, mode='vel'): if isinstance(freqlist, float) or isinstance(freqlist, int): freqlist = array([freqlist]) b, a = zpk2tf(paz.zeros(units='rad', mode=mode), paz.poles(units='rad', mode=mode), paz.h0) # a has to be a list for the scipy.signal.freqs() call later but zpk2tf() # strangely returns it as an integer. if not isinstance(a, ndarray) and a == 1.0: a = [1.0] _, h = freqs(b, a, freqlist * 2 * pi) return h
def Rule_4(w_star, w_end, wr): # this is rule 4 on pg-207 for input constraint check towards reference changes wr = 10 ** wr w = np.logspace(w_star, w_end, 1000) [w, h] = scs.freqs(G()[0], G()[1], w) plt.loglog(w, abs(h), "b") plt.loglog([w[0], w[-1]], [(R() - 1), (R() - 1)], "r") plt.loglog([wr, wr], [0.8 * np.min([(R() - 1), np.min(abs(h))]), 1.2 * np.max([(R() - 1), np.max(abs(h))])], "g") print "The blue line needs to be larger than the red line up to the freqeuncy where control is needed" print "This plot is done up to the wr" print "The green vertical line is the wr" plt.show()
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 add_filter(self, filter_, frequencies=None, dB=True, **kwargs): """Add a linear time-invariant filter to this BodePlot Parameters ---------- filter_ : `~scipy.signal.lti`, `tuple` the filter to plot, either as a `~scipy.signal.lti`, or a `tuple` with the following number and meaning of elements - 2: (numerator, denominator) - 3: (zeros, poles, gain) - 4: (A, B, C, D) frequencies : `numpy.ndarray`, optional list of frequencies (in Hertz) at which to plot db : `bool`, optional, default: `True` if `True`, display magnitude in decibels, otherwise display amplitude. **kwargs any other keyword arguments accepted by :meth:`~matplotlib.axes.Axes.plot` Returns ------- mag, phase : `tuple` of `lines <matplotlib.lines.Line2D>` the lines drawn for the magnitude and phase of the filter. """ if frequencies is None: w = None else: w = frequencies * 2. * pi if not isinstance(filter_, signal.lti): filter_ = signal.lti(*filter_) w, h = signal.freqs(filter_.num, filter_.den, w) w /= (2. * pi) mag = numpy.absolute(h) if dB: mag = 2 * to_db(mag) phase = numpy.degrees(numpy.unwrap(numpy.angle(h))) lm = self.maxes.plot(w, mag, **kwargs) lp = self.paxes.plot(w, phase, **kwargs) return lm, lp
def frequency_response(self, f_min=20.0, f_max=300.0): """ Calculate frequency response of the speaker (box/driver combination) Calculate system response of a certain driver in a vented box, according to Small [1]_. Parameters ---------- f_min : Lower frequency f_max : Upper frequency EReturns ------- freqs : ndarray the frequencies at which h was computed amplitude : ndarray the frequency response References ---------- .. [1] Richard H. Small, "Vented-Box Loudspeaker Systems -- Part I" """ start = np.log10(2*np.pi*f_min) stop = np.log10(2*np.pi*f_max) frequencies = np.logspace(start, stop, num=100) a = self.a b = self.b b[0] *= self.T_0**4 a[0] *= self.T_0**4 a[1] *= self.T_0**3 a[2] *= self.T_0**2 a[3] *= self.T_0 w, h = signal.freqs(self.b, self.a, worN=frequencies) freqs = w / (2*np.pi) amplitude = 20.0*np.log10(h) return (freqs, amplitude)
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 plot_response(w, h, *args, **kwargs): plt.semilogx(w, 20 * np.log10(np.abs(h)), *args, **kwargs) # inverse notch filter # s^2 + s/Q + 1 # H(s) = --------------- # s^2 + 1 def inverse_notch_s(freq, Q): w = freq return [1.0 / w**2, 1.0 / w / Q, 1], [1.0 / w**2, 0, 1] b_s, a_s = inverse_notch_s(100, 0.5) w, h = signal.freqs(b_s, a_s, worN=worN) plot_response(w, h) def inverse_notch_z(freq, Q, fs): wc = 2 * np.pi * freq / fs wS = np.sin(wc) wC = np.cos(wc) alpha = wS / (2.0 * Q) a0 = 1.0 + alpha return [a0, -2.0 * wC, (1.0 - alpha)], [1.0, -2.0 * wC, 1.0] b_z, a_z = inverse_notch_z(100, 0.5, FS) w, h = signal.freqz(b_z, a_z, worN=worN, fs=FS)
def ABC_weighting(curve='A'): """ Design of an analog weighting filter with A, B, or C curve. Returns zeros, poles, gain of the filter. Examples -------- Plot all 3 curves: >>> from scipy import signal >>> import matplotlib.pyplot as plt >>> for curve in ['A', 'B', 'C']: ... z, p, k = ABC_weighting(curve) ... w = 2*pi*logspace(log10(10), log10(100000), 1000) ... w, h = signal.freqs_zpk(z, p, k, w) ... plt.semilogx(w/(2*pi), 20*np.log10(h), label=curve) >>> plt.title('Frequency response') >>> plt.xlabel('Frequency [Hz]') >>> plt.ylabel('Amplitude [dB]') >>> plt.ylim(-50, 20) >>> plt.grid(True, color='0.7', linestyle='-', which='major', axis='both') >>> plt.grid(True, color='0.9', linestyle='-', which='minor', axis='both') >>> plt.legend() >>> plt.show() """ if curve not in 'ABC': raise ValueError('Curve type not understood') # ANSI S1.4-1983 C weighting # 2 poles on the real axis at "20.6 Hz" HPF # 2 poles on the real axis at "12.2 kHz" LPF # -3 dB down points at "10^1.5 (or 31.62) Hz" # "10^3.9 (or 7943) Hz" # # IEC 61672 specifies "10^1.5 Hz" and "10^3.9 Hz" points and formulas for # derivation. See _derive_coefficients() z = [0, 0] p = [ -2 * pi * 20.598997057568145, -2 * pi * 20.598997057568145, -2 * pi * 12194.21714799801, -2 * pi * 12194.21714799801 ] k = 1 if curve == 'A': # ANSI S1.4-1983 A weighting = # Same as C weighting + # 2 poles on real axis at "107.7 and 737.9 Hz" # # IEC 61672 specifies cutoff of "10^2.45 Hz" and formulas for # derivation. See _derive_coefficients() p.append(-2 * pi * 107.65264864304628) p.append(-2 * pi * 737.8622307362899) z.append(0) z.append(0) elif curve == 'B': # ANSI S1.4-1983 B weighting # Same as C weighting + # 1 pole on real axis at "10^2.2 (or 158.5) Hz" p.append(-2 * pi * 10**2.2) # exact z.append(0) # TODO: Calculate actual constants for this # Normalize to 0 dB at 1 kHz for all curves b, a = zpk2tf(z, p, k) k /= abs(freqs(b, a, [2 * pi * 1000])[1][0]) return np.array(z), np.array(p), k
def filter_function(self, freqs): b, a = signal.butter(self.order, 2 * np.pi * self.fc, 'lowpass', analog=True) return self.gain * np.abs(signal.freqs(b, a, 2 * np.pi * freqs)[1])
################### Calculate roots ############################# nulls = np.roots(bb) # zeros of H(s) poles = np.roots(aa) # poles of H(s) #nulls = [0,0] #poles = [-1,-2] #bb = np.poly(nulls #aa = np.poly(poles) print("aa, bb =", aa,bb) print("P, N =", np.roots(aa), np.roots(bb)) print("Angle(P) = ", angle(np.roots(aa))/ pi * 180) W_max = 2 # normalized circular frequency; W = 2 pi f tau W = np.linspace(0, W_max, 201) # start, stop, step. endpoint is included [W,H] = sig.freqs(bb, aa, W) # Calculate H(w) at the frequency points w1 #[w,H]=sig.freqs(bb,aa) # calculate H(w) at 200 frequencies "around the # interesting parts of the response curve" f = W H_abs = abs(H) H_max = max(H_abs); H_max_dB = 20*log10(H_max) W_max = W[np.argmax(H_abs)] # frequency where |H(Omega)| is max. H_angle = np.unwrap(angle(H)) #==================================================== figure(1) dsp.zplane(bb, aa, analog=True, style = 'square', anaCircleRad=W_c, mzc = (0,0.5,0) ) axzp = plt.gca() axzp.set_xlabel(r'$\sigma \, / \,\omega_n \; \rightarrow$',fontsize=18) axzp.set_ylabel(r'$j \omega \, / \,\omega_n \; \rightarrow$',fontsize=18)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Thu Nov 21 16:56:44 2019 @author: bassem """ import numpy as np from scipy import signal import matplotlib.pyplot as plt b, a = signal.butter(4, 5000, 'low', analog=True) w, h = signal.freqs(b, a) plt.figure(figsize=(6, 6)) plt.semilogx(w, 20 * np.log10(abs(h))) plt.title('Butterworth filter frequency response') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(5000, color='green') plt.axvline(20000, color='green') b1, a1 = signal.butter(4, 10000, 'High', analog=True) w1, h1 = signal.freqs(b1, a1) plt.semilogx(w1, 20 * np.log10(abs(h1))) plt.show() '''notre signale''' ''' for the path in this script ,you have to download the file in the main repository named "signaljour1.txt" and make the necessary changes to run the code below''' from scipy import signal import pandas as pd
# -*- coding: utf-8 -*- """ Created on Fri Sep 18 12:30:50 2020 @author: anavr """ import numpy as np from scipy import signal import matplotlib.pyplot as plt order = 10 normal_cutoff = 15 b, a = signal.butter(order, normal_cutoff, 'low', analog=True) w, h = signal.freqs(b, a) #fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True) plt.subplot(2, 1, 1) plt.title('Butterworth filter frequency response') plt.semilogx(w, 20 * np.log10(abs(h))) plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(normal_cutoff, color='green') # cutoff frequency plt.tight_layout() t = np.linspace(0, 1, 1000, False) # 1 second sig = np.sin(2 * np.pi * 10 * t) + np.sin(2 * np.pi * 20 * t) sos = signal.butter(10, 15, 'hp', fs=1000, output='sos')
def fft_integration(data, fs, fc=None, order=-1): """Intergration of a signal in the frequency domain using FFT. This function implements the integration in the time domain by means of the Fast Fourier Transform. It also performs a band pass filter, removing all the unwanted frequencies. Args: signal (array): Numpy 1d-array with the data. fs (float or int): Sampling frequency. fc (float or tuple): This is the cut-off frequency. If fc is floating or integer a lowpass filter is performed. If fc is a list a band pass-pass filter is made between the two given frequencies. order (integer): Indicates the order of the integration. Negative number indicates integration while positive indicates differentiontion (not implemented yet). Return (array): Signal integrated. """ # check for nans if more than 10 percents nans = np.isnan(data) if len(nans.nonzero()[0]) / len(data) < 0.1: data[nans] = np.nanmean(data[~nans]) else: return data * np.nan # if order == 0 do nothing if order == 0: return data # if order > 0 raise an error if order > 0: raise ValueError("Order must be a negative integer") # get frequency array N = len(data) freqs = np.fft.fftfreq(N, 1 / fs) # the first element of freqs array is zero, so we have # to discard it to avoid division by zero # the factor of integration is iw factor = 1j * 2 * np.pi * freqs[1:] # compute fft of the signal for the non-zero frequencies # and apply integration factor fft = np.zeros(len(freqs), 'complex') fft[1:] = np.fft.fft(data)[1:] * factor**order # high pass filter if fc is None: return np.fft.ifft(fft).real # elif isinstance(fc, float) or isinstance(fc, int): # if False: # <-- ideal filter just in case ix = abs(freqs) <= fc fft[ix] = 0. # else: # <- freqs response of a 3th order butterworth filter b, a = signal.butter(3, fc, 'high', analog=True) w, h = signal.freqs(b, a, worN=freqs) fft = fft * abs(h) return np.fft.ifft(fft).real
def create_coeffs_ts9(alpha): R1 = 1e3 R2 = 10e3 R3 = 1e3 R4 = 220 C1 = 0.022e-6 C2 = 0.022e-6 P = 22e3 return (0, alpha * C2 * R2 * R3 + alpha * (1-alpha) * C2 * P * R2 + R2 * R4 * C2, R2), (C2 * R4 * C1 * R2 * R1 + (1-alpha) * C2 * R1 * P * C1 * R2, (1-alpha) * C2 * (alpha * P * R2 + R1 * alpha * P + R1 * R2) + R4 * C2 * (R2 + R1) + R1 * C1 * R2, R2 + R1) b0, a0 = create_coeffs_sd1(0) b1, a1 = create_coeffs_sd1(1) b, a = create_coeffs_sd1(0.5) sd10 = signal.freqs(b0, a0, worN=np.logspace(1, 4.5, 1000)) sd11 = signal.freqs(b1, a1, worN=np.logspace(1, 4.5, 1000)) sd1 = signal.freqs(b, a, worN=np.logspace(1, 4.5, 1000)) fig = plt.figure() plt.title('Analog filter frequency response (SD1 tone circuit)') ax1 = fig.add_subplot(111) plt.loglog(sd10[0], np.abs(sd10[1]), 'b', label="alpha=0") plt.loglog(sd11[0], np.abs(sd11[1]), 'g', label="alpha=1") plt.loglog(sd1[0], np.abs(sd1[1]), 'r', label="alpha=0.5") plt.xlabel("Frequency (Hz)") plt.ylabel("Amplitude (dB)") plt.legend() b0d, a0d = signal.bilinear(b0, a0, 44100)
def frequencyResponse(self, *args, **kwargs): return freqs(*self.butter, *args, **kwargs)[1]
m = loadmat('s5d2nap_justdata.mat') # In[3]: matrix = m['s5d2nap'] low = 0.3 high = 30 fs = 1000 lowcut = low / (0.5 * fs) highcut = high / (0.5 * fs) #bandpass b3, a3 = signal.butter(2, [lowcut, highcut], 'band') w3, h3 = signal.freqs(b3, a3) new_matrix = [] for index, row in enumerate(matrix): new_matrix.append(row[100000:460000]) # print len(new_matrix[0]) eeg = np.array(new_matrix) # In[7]: # In[8]: s = pd.DataFrame(new_matrix).transpose() # print s # plt.subplot(8,8) fig1 = plt.figure() fig2 = plt.figure() fig3 = plt.figure()
from scipy.signal import butter, lfilter, freqs import numpy as np import FeatureExtractorUtils as fe import scipy data = pd.read_csv('../METAWEAR_cap_sensor_accel.csv') data = data.iloc[:,0:4] data = data.values dataTime = data[:, 0] dataX, dataY, dataZ = data[:,1], data[:,2], data[:,3] plt.figure(1) plt.clf() b, a = butter(3, 0.3, 'low' , analog = 'True') w, h = freqs(b, a, worN=2000) plt.plot((100 * 0.5 / np.pi) * w, abs(h), label="order = %d" % 3) plt.figure(2) plt.clf() #plt.plot(dataTime[20000:30000], dataY[20000:30000], label = 'Noisy signal') y = lfilter(b,a, dataY[20000:30000]) #plt.plot(dataTime[20000:30000], y, label = 'Filtered Signal') # #b, a = butter(9, 0.3, 'high' , analog = 'True') #yhigh = lfilter(b,a, dataY[20000:]) # #plt.plot(dataTime[20000:], yhigh, label = 'body Signal') #plt.show()
#---Filter Parameters-----------------------------------------------------------------------# Rs = R6 + t * Rt a4 = Rs * C3 * C4 * C5 * C6 * R4 * R7 * R8 a3 = C3 * C5 * C6 * R4 * R7 * R8 + Rs * C4 * C5 * C6 * R7 * R8 + Rs * C3 * C4 * C6 * R4 * R8 + Rs * C3 * C4 * C5 * R4 * R7 a2 = C5 * C6 * R7 * R8 + C3 * C6 * R4 * R8 + Rs * C4 * C6 * R8 + C3 * C5 * R4 * R7 + Rs * C4 * C5 * R7 + Rs * C3 * C4 * R4 a1 = C6 * R8 + C5 * R7 + C3 * R4 + Rs * C4 a0 = 1 b4 = a4 b3 = C3 * C5 * C6 * R4 * R7 * R8 + Rs * C3 * C4 * C6 * R4 * R8 + Rs * C3 * C4 * C5 * R4 * R7 + Rs * C3 * C5 * C6 * R4 * R7 + Rs * C3 * C5 * C6 * R4 * R8 b2 = C3 * C6 * R4 * R8 + C3 * C5 * R4 * R7 + Rs * C3 * C4 * R4 + Rs * C3 * C5 * R4 + Rs * C3 * C6 * R4 b1 = C3 * R4 b0 = 0 B = [b4, b3, b2, b1, b0] A = [a4, a3, a2, a1, a0] #---Frequency response of tone control analog circuit---------------------------------------# w, h = sig.freqs(B, A) plt.semilogx(w, abs(h)) plt.title('Magnitude response of first stage analog circuit') plt.ylabel('Magnitude(linear scale)') plt.xlabel('Frequency(Hz)') plt.savefig('MagResAnaCir.png') plt.show() #---Frequency response of digitized tone control circuit------------------------------------# targetFreq = 20540 alpha = targetFreq * 2 * np.pi / np.tan(targetFreq * np.pi * T) B0 = alpha**4 * b4 + alpha**3 * b3 + alpha**2 * b2 + alpha * b1 B1 = -4 * alpha**4 * b4 - 2 * alpha**3 * b3 + 2 * alpha * b1 B2 = 6 * alpha**4 * b4 - 2 * alpha**2 * b2 B3 = -4 * alpha**4 * b4 + 2 * alpha**3 * b3 - 2 * alpha * b1 B4 = alpha**4 * b4 - alpha**3 * b3 + alpha**2 * b2 - alpha * b1 A0 = alpha**4 * a4 + alpha**3 * a3 + alpha**2 * a2 + alpha * a1 + a0
def run(): fs = 44100.0 # Define frecuencia de muestreo lowcut = 3000.0 # define frecuencia corte bajo highcut = 5000.0 # define frecuencia de corte alto ftype = 'cheby2' # Aqui se define el tipo de filtro que se usara btype = 'highpass' # Aqui se decide que tipo de bandas se dejaran pasar T = 0.5 # Se define la longitud en segundos de la señal de ruido nsamples = T * fs # Obtiene el numero de muestras t = np.linspace(0, T, nsamples, endpoint=False) x, f = ruido_gen(t) # Genera señal aleatoria analog = False orders = [1, 5, 10, 15] plt.figure(1) plt.clf() # Itera para graficar las funciones de filtro segun su orden for order in orders: b, a = filter(fs, x, lowcut=lowcut, highcut=highcut, order=order, btype=btype, ftype=ftype, graph=True, analog=True) w, h = signal.freqs(b, a) plt.semilogx(w, 20 * np.log10(np.abs(h)), label="Orden = %d" % order) plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.xlabel('Frecuencia (Hz)') plt.ylabel('Ganancia (dB)') plt.grid(True) plt.legend(loc='best') plt.figure(2) plt.clf() plt.plot(t, 0 * x - .5) plt.plot(t, x - 2.25, label='Señal con ruido') n = 100 yHz = [] f = np.fft.fftfreq(len(t), 1 / fs) # Filtra la señal aleatoria segun el filtro ordn = 0 for order in orders: y = filter(fs, data=x, lowcut=lowcut, highcut=highcut, btype=btype, ftype=ftype, analog=analog) yHz.append( np.abs(1.0 / len(t) * np.fft.fft(y))) # obtiene muestra de espectro de cada señal label = label_gen(btype, lowcut, highcut, orders, ordn) plt.plot(t, y - .5 * n, label=label) n = n + 100 ordn = ordn + 1 plt.xlabel('Tiempo (segundos)') plt.grid(True) plt.axis('tight') plt.legend(loc='upper left') plt.figure(3) plt.clf() x = np.abs(1.0 / len(t) * np.fft.fft(x)) plt.plot(f, 0 * x - .5) plt.plot(f, x - 1.00, label='Señal con ruido') n = 3 ordn = 0 for y in yHz: label = label_gen(btype, lowcut, highcut, orders, ordn) plt.plot(f, y - .5 * n, label=label) n = n + 1 ordn = ordn + 1 plt.xlabel('Frecuencia (Hz)') plt.grid(True) plt.axis('tight') plt.legend(loc='upper left') plt.show()
import numpy as np import scipy.signal as signal import matplotlib.pyplot as plt from matplotlib import style ''' Can filter any noisy signals Input for Lowpass Filter 1. Order of the filter 3. Cutoff Frequency 4. High or low pass filter 5. Digital or Analog ''' bessel_coeff_y, bessel_coeff_x = signal.bessel(4, 100, 'low', analog=True) #Frequency Response of the Filter w, h = signal.freqs(bessel_coeff_y, bessel_coeff_x) plt.plot(w, 20 * np.log10(abs(h))) plt.xscale('log') plt.title('Bessel Filter Frequency Response') plt.xlabel('Frequency (rad/second') plt.ylabel('Amplitude (dB)') plt.margins(0, 0.1) plt.grid() plt.axvline(100, color='green') plt.show()
def analysis(self, show=False): """perform a PDM analysis on each lightcurve""" from matplotlib import rcParams from functions import sigma_clip, phase print 'Analysis' fig_width = 18.3/2.54 # width in inches, was 7.48in fig_height = 23.3/2.54 # height in inches, was 25.5 fig_size = [fig_width,fig_height] #set plot attributes params = {'backend': 'Agg', 'axes.labelsize': 12, 'axes.titlesize': 12, 'font.size': 12, 'xtick.labelsize': 12, 'ytick.labelsize': 12, 'figure.figsize': fig_size, 'savefig.dpi' : 300, 'font.family': 'sans-serif', 'axes.linewidth' : 0.5, 'xtick.major.size' : 2, 'ytick.major.size' : 2, } rcParams.update(params) for starid in self.stars: star = NGC2236Star(starid) print '%-24s '% starid, lc = star.lightcurve() meanflux = np.nanmean(lc.flux) lc.flux /= meanflux lc.flux *= meanflux lc.rebin(0.0125) lc.interpolate() lc.normalize() raw_time, raw_flux = (lc.time, lc.flux) lc.medfilter() lc.jmpflt() lc.detrend() time, flux = (lc.time, lc.flux) time -= min(time) # convert to magnitudes mag = -2.512*np.log10(meanflux*flux) + 24 # remove the mean so we are around 0.0 magnitudes mag -= np.mean(mag) # perform a 3sigma clipping time, mag = sigma_clip(time, mag) # calculate fourier spectrum with zero padding n = len(mag) n2 = 8*n ft = np.fft.rfft(mag, n2) #amp = abs(ft)/n power = abs(ft)**2/n freq = np.fft.fftfreq(n2, d=lc.dt()) # apply a bessel filter to eliminate runlength artifacts from scipy import signal b, a = signal.butter(4, 2./max(time), 'high', analog=True) _, h = signal.freqs(b, a, worN=freq[1:n]) filt_pwr = abs(ft[1:n]*h)**2/n i = np.argmax(filt_pwr)+1 maxfreq = freq[i] period = 1./maxfreq from pdm import pdm #refine period using pdm pdm_periods, pdm_thetas = pdm(time, mag, period/1.5, period*1.5, 0.0125) i = np.argmin(pdm_thetas) period = pdm_periods[i] print 'P = %5.2f' % period, star['period'] = period periods = 1./freq[1:n] periods = periods[::-1] filt_pwr = filt_pwr[::-1] norm = np.mean(filt_pwr) print '%.1f' % (max(filt_pwr)/norm) power[1:n] /= norm filt_pwr /= norm star['amp'] = max(filt_pwr)/norm ph_time, ph_mag = phase(time, mag, period) num = len(ph_time)/round(max(time)/period) rph_mag, _ = signal.resample(ph_mag, num, t = ph_time) rph_time = np.linspace(min(ph_time),max(ph_time),num) bv = star['bv'] if bv is None: bv=-99 plt.subplot(411) ################################################## plt.title('%s (%d) B-V=%.2f' % (starid, star['corotid'], bv)) plt.scatter(raw_time-min(raw_time), raw_flux, edgecolor='none', alpha=0.5, s=3, color='k') plt.ylim(min(raw_flux),max(raw_flux)) plt.xlim(0,max(time)) plt.subplot(412) ################################################## plt.plot(time, -mag, 'k') plt.ylim(min(-mag),max(-mag)) plt.xlim(0,max(time)) plt.subplot(413) ################################################## plt.plot(1./freq[1:n], power[1:n], 'k') plt.plot(1./freq[1:n], filt_pwr, 'g') #plt.plot(1./w, 20 * np.log10(abs(h))) plt.axvline(period) #plt.axhline(np.mean(filt_pwr[1:n])) plt.xlim(0.1, max(time)) plt.subplot(414) ################################################## plt.plot(rph_time, -rph_mag,color='k') plt.plot(rph_time+period, -rph_mag,color='k') #plt.plot(phased_time, phased_mag, 'g') #plt.plot(phased_time+period, phased_mag, 'g') plt.axvline(period, linestyle='--') plt.xlabel('P = %.2f' % period) plt.xlim(0., period*2) #plt.grid() if show: plt.show() else: plt.savefig(config.plotpath+'%s(%d).pdf' % (starid,star['corotid'])) plt.close()
#%% from scipy import signal import matplotlib.pyplot as plt import numpy as np #%% f1 = 1.1E6 f2 = 0.9e6 w1 = 2 * np.pi * f1 w2 = 2 * np.pi * f2 #%% B, A = signal.iirfilter(2, [w1, w2], btype='band', analog=True, ftype='butter', output='ba') w, h = signal.freqs(B, A) plt.plot(w / 2 / 3.14, 20 * np.log10(abs(h)), color='red', linewidth=2) plt.xscale('log') plt.title('Butterworth band pass filter frequency response', fontsize=20) plt.xlabel('Frequency [Hz]', fontsize=20) plt.ylabel('Amplitude [dB]', fontsize=20) plt.margins(0, 0.01) plt.grid(which='both', axis='both') plt.yticks(size=20) plt.xticks(size=20) plt.axvline(f1, color='green', linewidth=2) # cutoff frequency plt.axvline(f2, color='blue', linewidth=2) # cutoff frequency plt.show() print("a=", A) print("b=", B) i = 0
b, a = signal.butter(2, 1.0, analog=1) # 低通->带通的频率变换函数 w1 = 1.0 # 低通带频率 w2 = 2.0 # 高通带频率 dw = w2 - w1 # 通带宽度 w0 = np.sqrt(w1 * w2) # 通带中心频率 # 产生10**-2到10**2的频率点 w = np.logspace(-2, 2, 1000) # 使用频率变换公式计算出转换之后的频率 nw = np.imag(w0 / dw * (1j * w / w0 + w0 / (1j * w))) _, h = signal.freqs(b, a, worN=nw) h\ = 20 * np.log10(np.abs(h)) pl.figure(figsize=(8, 5)) pl.subplot(221) pl.semilogx(w, nw) # X轴使用log坐标绘图 pl.xlabel(u"变换前圆频率(弧度/秒)") pl.ylabel(u"变换后圆频率(弧度/秒)") pl.subplot(222) pl.plot(h, nw) pl.xlabel(u"低通滤波器的频率响应(dB)") pl.subplot(212)
f = 4.7e-6 #%% b_4 = a**2 * d**2 * b * c * e * f b_3 = a**2 * d**2 * (b * e + b * f + c * f) b_2 = a**2 * d**2 b_1 = 0 b_0 = 0 a_3 = a * b * c * d * e * f a_2 = (b * c * e * f) + (a * c * d * f) - (a * b * d * f) + (a * b * d * e) a_1 = a * d + b * e + c * f a_0 = 1 #%% w, H = signal.freqs([b_4, b_3, b_2, b_1, b_0], [a_3, a_2, a_1, a_0]) plt.figure() plt.semilogx(w / 2 / np.pi, 20 * np.log10(np.abs(H))) plt.xlim(20, 30000) plt.ylim(-100, 50) #%% def myBilinear(b, a, fs): z = np.zeros(5) # numerator p = np.zeros(5) # denominator c = 2 * fs # no warping (for now) b_0 = b[0] * c**4 b_1 = b[1] * c**3
def filter_ecog_signal(signalArray, sampFq, filtFqs=[60, 120, 180], filtBandwidths=[4, 4, 4], filtOrder=2, plotSpectrogram=False, plotFilter=False): """ Performs notch filtering of input frequencies (filtFqs with bandwidth filtBandwidths) Option to plot spectrogram and filter Returns filtered signals """ NyquistFq = float(sampFq/2) filtRanges = [[0 for j in range(2)] for i in range(len(filtFqs))] for p in range(len(filtRanges)): filtRanges[p][0] = (filtFqs[p] - filtBandwidths[p]/2)/NyquistFq filtRanges[p][1] = (filtFqs[p] + filtBandwidths[p]/2)/NyquistFq signalArrayFiltered = np.zeros_like(signalArray) # Check if signalArray is multidimensional, or just corresponds to a single electrode: if len(np.shape(signalArray)) > 1: nElectrode = 0 for electrode in signalArray: for filtRange in filtRanges: if filtRange[1] < 1: filtNume, filtDenom = signal.butter( filtOrder, filtRange, btype='bandstop') electrode = signal.filtfilt(filtNume, filtDenom, electrode) if plotFilter: # Only want to plot filter once in the loop: if nElectrode == 0: w, h = signal.freqs(filtNume, filtDenom, 1000) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(w, 20 * np.log10(abs(h))) ax.set_xscale('log') ax.set_title('Filter frequency response') ax.set_xlabel('Frequency [radians / second]') ax.set_ylabel('Amplitude [dB]') #ax.axis((10, 1000, -100, 10)) ax.grid(which='both', axis='both') plt.show() if plotSpectrogram: fig = plt.figure() plt.specgram(electrode, NFFT=512, Fs=sampFq) plt.title('Filtered spectrogram for electrode '+str(nElectrode)) plt.xlabel('Time [sec]') plt.ylabel('Frequency [Hz]') # plt.xlim(0, (header['edfInfo']['nRecords']-2)) plt.ylim(0, sampFq/2.) cbar = plt.colorbar() cbar.set_label('Power spectral density [W/Hz]') plt.show() signalArrayFiltered[nElectrode] = electrode nElectrode = nElectrode+1 # if signalArray is one dimensional vector (single electrode) elif len(np.shape(signalArray)) == 1: nElectrode = 0 electrode = signalArray for filtRange in filtRanges: if filtRange[1] < 1: filtNume, filtDenom = signal.butter( filtOrder, filtRange, btype='bandstop') electrode = signal.filtfilt(filtNume, filtDenom, electrode) if plotFilter: w, h = signal.freqs(filtNume, filtDenom, 1000) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(w, 20 * np.log10(abs(h))) ax.set_xscale('log') ax.set_title('Filter frequency response') ax.set_xlabel('Frequency [radians / second]') ax.set_ylabel('Amplitude [dB]') #ax.axis((10, 1000, -100, 10)) ax.grid(which='both', axis='both') plt.show() if plotSpectrogram: fig = plt.figure() plt.specgram(electrode, NFFT=512, Fs=sampFq) plt.title('Filtered spectrogram for electrode '+str(nElectrode)) plt.xlabel('Time [sec]') plt.ylabel('Frequency [Hz]') # plt.xlim(0, (header['edfInfo']['nRecords']-2)) plt.ylim(0, sampFq/2.) cbar = plt.colorbar() cbar.set_label('Power spectral density [W/Hz]') plt.show() signalArrayFiltered = electrode return signalArrayFiltered
# w is the maximum frequency which is f2 which is 5. # dx <= 1/10 <-> dx > 10 Hz # all sampling frequencies lower (and inclusive) than 10 Hz lead to aliasing. # ------------------------------ # ex2.3 # sc.signal.butter() # generate Butterworth low-pass filter coefficients: # select an appropriate cutoff frequency # work on the 10 Hz example b, a = sig.butter(4, 100, 'low', analog=True) plt.plot(b, a) w, h = sig.freqs(b, a) plt.plot(w, 20 * np.log10(abs(h))) # check out the sample functions and forum! down_freq = 10 indices = np.arange(0, down_freq * 10, 1) * (10000 // (down_freq * 10)) indices.shape[0] == down_freq * 10 # power spectrum values t_down_sampled = scfft.fft(samples[indices]) t_down_sampled = np.sqrt(np.power(t_down_sampled.imag, 2) + np.power(t_down_sampled.real, 2)) t_freqs = np.linspace(0, down_freq, 10*down_freq, endpoint=False) # plot both spaces plt.subplot(1, 2, 1) plt.plot(fs, samples) plt.plot(fs[indices], samples[indices], 'ro') plt.plot(fs[indices], samples[indices])
def make_ctle(rx_bw, peak_freq, peak_mag, w, mode='Passive', dc_offset=0): """ Generate the frequency response of a continuous time linear equalizer (CTLE), given the: - signal path bandwidth, - peaking specification - list of frequencies of interest, and - operational mode/offset. We use the 'invres()' function from scipy.signal, as it suggests itself as a natural approach, given our chosen use model of having the user provide the peaking frequency and degree of peaking. That is, we define our desired frequency response using one zero and two poles, where: - The pole locations are equal to: - the signal path natural bandwidth, and - the user specified peaking frequency. - The zero location is chosen, so as to provide the desired degree of peaking. Inputs: - rx_bw The natural (or, unequalized) signal path bandwidth (Hz). - peak_freq The location of the desired peak in the frequency response (Hz). - peak_mag The desired relative magnitude of the peak (dB). (mag(H(0)) = 1) - w The list of frequencies of interest (rads./s). - mode The operational mode; must be one of: - 'Off' : CTLE is disengaged. - 'Passive': Maximum frequency response has magnitude one. - 'AGC' : Automatic gain control. (Handled by calling routine.) - 'Manual' : D.C. offset is set manually. - dc_offset The d.c. offset of the CTLE gain curve (dB). (Only valid, when 'mode' = 'Manual'.) Outputs: - w, H The resultant complex frequency response, at the given frequencies. """ if (mode == 'Off'): return (w, ones(len(w))) p2 = -2. * pi * rx_bw p1 = -2. * pi * peak_freq z = p1 / pow(10., peak_mag / 20.) if (p2 != p1): r1 = (z - p1) / (p2 - p1) r2 = 1 - r1 else: r1 = -1. r2 = z - p1 b, a = invres([r1, r2], [p1, p2], []) w, H = freqs(b, a, w) if (mode == 'Passive'): H /= max(abs(H)) elif (mode == 'Manual' or mode == 'AGC'): H *= pow(10., dc_offset / 20.) / abs(H[0]) # Enforce d.c. offset. else: raise RunTimeException( "pybert_util.make_ctle(): Unrecognized value for 'mode' parameter: {}." .format(mode)) return (w, H)
from scipy import signal import matplotlib.pyplot as plt import numpy as np # References : Scipy.org, buttord.html #An analog bandpass filter with passband within 3 dB from 20 to 50 rad/s, while rejecting at least -40 dB below 14 and above 60 rad/s. # Expt1 : Run the program as is and observe the output # Expt2 : Comment line 15 and uncomment line 16, to visualise bandstop filter N, Wn = signal.buttord([20, 50], [14, 60], 3, 40, True) #b, a = signal.butter(N, Wn, 'band', True) # Bandpass cfg b, a = signal.butter(N, Wn, 'stop', True) # Bandstop cfg w, h = signal.freqs(b, a, np.logspace(1, 2, 500)) plt.semilogx(w, 20 * np.log10(abs(h))) plt.title('Butterworth bandpass filter') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.grid(which='both', axis='both') plt.fill([1, 14, 14, 1], [-40, -40, 99, 99], '0.9', lw=0) # stop plt.fill([20, 20, 50, 50], [-99, -3, -3, -99], '0.9', lw=0) # pass plt.fill([60, 60, 1e9, 1e9], [99, -40, -40, 99], '0.9', lw=0) # stop plt.axis([10, 100, -60, 3]) plt.show()
import matplotlib.pyplot as plt import numpy as np N = 5 ftype_name = 'butter' db = False freq = np.array([[1 / 30, 1 / 20], [1 / 20, 1 / 10], [1 / 10, 1 / 5], [1 / 5, 1 / 2], [1 / 2, 1]]) fig = plt.figure() ax = fig.add_subplot(111) for f in freq: b, a = signal.iirfilter(N, (2 * np.pi) * f, btype='bandpass', analog=True, ftype=ftype_name) w, h = signal.freqs(b, a, 1000) w = (2 * np.pi) / w tips = str(1 / f[0]) + 's - ' + str(1 / f[1]) + 's' if db == True: ax.semilogx(w, 20 * np.log10(abs(h)), label=tips) elif db == False: ax.semilogx(w, abs(h), label=tips) ax.set_title(ftype_name + ' Order ' + str(N) + ' bandpass frequency response') ax.set_xlabel('Periods [s]') ax.set_ylabel('Amplitude') ax.axis((0.1, 100, 0, 1.5)) ax.grid(which='both', axis='both') ax.legend(shadow=True, fontsize=8, fancybox=True, framealpha=0.5) plt.show()
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))
K = 3.0 - 1 / Q # ganho por estagio R = 1 / (Wc * C) R4 = R3 * (K - 1) Av = K * Av # ganho total print(f'Estagio {N+1}') print(f'R = {R}') print(f'R3 = {R3}') print(f'R4 = {R4}') print(f'C2 = {C}') print(f'Wc = {Wc}') print(f'Q = {Q}') print(f'K = {K}') print(f'Funcao de trasferencia = {a}\n\n') RF = RB / Av # resistor para normalização do ganho print(f'RF = {RF}') print(f'Ganho total = {Av}') print(f'Equação geral = {k,transfer_func}') w, h = signal.freqs([k], transfer_func) plt.semilogx(w / (2 * np.pi), 20 * np.log10(abs(h)), label=f'Ordem = {ordem}') plt.title('Respsosta em frequencia do filtro Chebyshev') plt.xlabel('Frequencia [Hz]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(Fn, color='green') # cutoff frequency plt.legend(loc='upper right') plt.show()
def bessel_analog(f, fcut, order=2): b, a = bessel(order, 2 * np.pi * fcut, analog=True) return freqs(b, a, 2 * np.pi * f)[1]
def bode_plot(B, A, b, a, fs, N, fig=None): """Realize a bode plot containing magnitude, phase and zplane. input: B...numerator coefficients Laplace transfer function A...denominator coefficients Laplace transfer function b...numerator coefficients z-transfer function a...denominator coefficients z-transfer function fs...sampling frequency in Hz output: bode plot as new figure """ if fig is None: fig = plt.figure() p = np.roots(a) z = np.roots(b) W, Hd = signal.freqz(b, a, N) s, Ha = signal.freqs(B, A, fs * W) if Hd[0] == 0: Hd[0] = 1e-15 # avoid zero at DC for plotting dB if Ha[0] == 0: Ha[0] = 1e-15 f = fs * W / (2 * np.pi) gs = fig.add_gridspec(2, 2) # magnitude ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(f, 20 * np.log10(np.abs(Ha)), "C0", label=r'$|H(\omega)|$ continuous-time', linewidth=3) ax1.plot(f, 20 * np.log10(np.abs(Hd)), "C1", label=(r'$|H(\Omega)|$ discrete-time, fs=%5.f Hz' % fs), linewidth=2) ax1.set_xscale("log") ax1.set_yscale("linear") ax1.set_xlabel(r'$f$ / Hz', color="xkcd:navy blue") ax1.set_ylabel(r'$A$ / dB', color="xkcd:navy blue") ax1.set_title("Bode plot: magnitude", color="xkcd:navy blue") ax1.set_xlim(20, 20000) ax1.set_xticks((20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000)) ax1.set_xticklabels( ["20", "50", "100", "200", "500", "1k", "2k", "5k", "10k", "20k"], color="xkcd:navy blue") ax1.set_ylim(-15, 15) ax1.set_yticks(np.arange(-15, 15 + 3, 3)) ax1.set_yticklabels( ["-15", "-12", "-9", "-6", "-3", "0", "3", "6", "9", "12", "15"], color="xkcd:navy blue") ax1.legend(loc="best") ax1.grid(True, which="both", axis="both", linestyle="-", linewidth=0.5, color=(0.8, 0.8, 0.8)) # phase ax2 = fig.add_subplot(gs[1, 0]) ax2.plot(f, (np.angle(Ha) * 180 / np.pi), "C0", label=r'$\mathrm{angle}(H(' r'\omega))$ continuous-time', linewidth=3) ax2.plot(f, (np.angle(Hd) * 180 / np.pi), 'C1', label=(r'$\mathrm{angle}(H(\Omega))$ discrete-time, ' 'fs=%5.f Hz' % fs), linewidth=2) ax2.set_xscale("log") ax2.set_yscale("linear") ax2.set_xlabel(r'$f$ / Hz', color="xkcd:navy blue") ax2.set_ylabel(r'$\phi$ / deg', color="xkcd:navy blue") ax2.set_title("Bode plot: phase", color="xkcd:navy blue") ax2.set_xlim(20, 20000) ax2.set_xticks((20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000)) ax2.set_xticklabels( ["20", "50", "100", "200", "500", "1k", "2k", "5k", "10k", "20k"], color="xkcd:navy blue") ax2.set_ylim(-180, +180) ax2.set_yticks(np.arange(-180, 180 + 45, 45)) ax2.set_yticklabels( ["-180", "-135", "-90", "-45", "0", "45", "90", "135", "180"], color="xkcd:navy blue") ax2.legend(loc="best") ax2.grid(True, which="both", axis="both", linestyle="-", linewidth=0.5, color=(0.8, 0.8, 0.8)) # zplane ax3 = fig.add_subplot(gs[:, 1]) zplane_plot(ax3, z, p) print("B =", B) print("A =", A) print("b =", b) print("a =", a)
def filter(self, *filt, **kwargs): """Apply the given filter to this `Spectrum`. Recognised filter arguments are converted into the standard ``(numerator, denominator)`` representation before being applied to this `Spectrum`. .. note:: Unlike the related :meth:`TimeSeries.filter <gwpy.timeseries.TimeSeries.filter>` method, here all frequency information (e.g. frequencies of poles or zeros in a ZPK) is assumed to be in Hertz. Parameters ---------- *filt one of: - :class:`scipy.signal.lti` - ``(numerator, denominator)`` polynomials - ``(zeros, poles, gain)`` - ``(A, B, C, D)`` 'state-space' representation Returns ------- result : `Spectrum` the filtered version of the input `Spectrum` See also -------- Spectrum.zpk for information on filtering in zero-pole-gain format scipy.signal.zpk2tf for details on converting ``(zeros, poles, gain)`` into transfer function format scipy.signal.ss2tf for details on converting ``(A, B, C, D)`` to transfer function format scipy.signal.freqs for details on the filtering calculation Raises ------ ValueError If ``filt`` arguments cannot be interpreted properly """ # parse filter if len(filt) == 1 and isinstance(filt[0], signal.lti): filt = filt[0] a = filt.den b = filt.num elif len(filt) == 2: b, a = filt elif len(filt) == 3: b, a = signal.zpk2tf(*filt) elif len(filt) == 4: 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.") # parse keyword args inplace = kwargs.pop('inplace', False) if kwargs: raise TypeError("Spectrum.filter() got an unexpected keyword " "argument '%s'" % list(kwargs.keys())[0]) fresp = abs(signal.freqs(b, a, self.frequencies.value)[1]) if inplace: self.value *= fresp return self else: new = (self.value * fresp).view(type(self)) new.__dict__ = deepcopy(self.__dict__) return new
# -*- coding: utf-8 -*- from scipy import signal import pylab as pl from numpy import * fs = 8000.0 # 取样频率 fc = 1000.0 # 通带频率 # 频率为2kHz的3阶低通滤波器 b, a = signal.butter(3, 2 * pi * fc, analog=1) w, h = signal.freqs(b, a, worN=10000) p = 20 * log10(abs(h)) # 转换为取样频率为8kHz的数字滤波器 b2, a2 = signal.bilinear(b, a, fs=fs) # 计算数字滤波器的频率响应 w2, h2 = signal.freqz(b2, a2, worN=10000) # 计算增益特性 p2 = 20 * log10(abs(h2)) # 找到增益为-3dB[精确值为: 10*log10(0.5)]的下标 idx = argmin(abs(p2 - 10 * log10(0.5))) # 输出增益为-3dB时的频率 print((w2[idx] / 2 / pi * 8000)) # 输出公式 w = 2/T*arctan(wa*T/2) 计算的频率 print((2 * fs * arctan(2 * pi * fc / 2 / fs) / 2 / pi))
# shelving filter N = 4 f_cutoff = 1000 w_cutoff = 2 * np.pi * f_cutoff Gd = -12 z, p, k = higher_order_shelving_holters(Gd, N, wc=w_cutoff, normalize=True) b, a = zpk2tf(z, p, k) # frequency response fmin, fmax, num_f = 20, 22000, 2000 f = np.logspace(np.log10(fmin), np.log10(fmax), num=num_f, endpoint=True) w = 2 * np.pi * f _, H_zpk = freqs_zpk(z, p, k, worN=w) _, gd_zpk = zpk_group_delays(z, p, k, w=w) _, H_tf = freqs(b, a, worN=w) _, gd_tf = group_delays(b, a, w=w) gd_zorp = 0 # adding up group delays of individual zeros and poles for z_i in z: gd_zorp += zorp_group_delays(z_i, w=w)[1] for p_i in p: gd_zorp -= zorp_group_delays(p_i, w=w)[1] # plots kw_zpk = dict(color='lightgray', lw=5, ls='-', alpha=1, label='zpk') kw_tf = dict(color='C0', lw=2, ls='-', alpha=0.85, label='tf') kw_zorp = dict(color='k', lw=2, ls=':', alpha=0.85, label='zorp') flim = fmin, fmax fig, ax = plt.subplots(figsize=(12, 3), ncols=3, sharex=False, gridspec_kw=dict(wspace=0.4))