def test_kaiser_beta(): b = kaiser_beta(58.7) assert_almost_equal(b, 0.1102 * 50.0) b = kaiser_beta(22.0) assert_almost_equal(b, 0.5842 + 0.07886) b = kaiser_beta(21.0) assert_equal(b, 0.0) b = kaiser_beta(10.0) assert_equal(b, 0.0)
def firwin_kaiser_lpf(f_pass, f_stop, d_stop, fs = 1.0, N_bump=0): """ Design an FIR lowpass filter using the sinc() kernel and a Kaiser window. The filter order is determined based on f_pass Hz, f_stop Hz, and the desired stopband attenuation d_stop in dB, all relative to a sampling rate of fs Hz. Note: the passband ripple cannot be set independent of the stopband attenuation. Mark Wickert October 2016 """ wc = 2*np.pi*(f_pass + f_stop)/2/fs delta_w = 2*np.pi*(f_stop - f_pass)/fs # Find the filter order M = np.ceil((d_stop - 8)/(2.285*delta_w)) # Adjust filter order up or down as needed M += N_bump N_taps = M + 1 # Obtain the Kaiser window beta = signal.kaiser_beta(d_stop) w_k = signal.kaiser(N_taps,beta) n = np.arange(N_taps) b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k b_k /= np.sum(b_k) print('Kaiser Win filter taps = %d.' % N_taps) return b_k
def firwin_kaiser_hpf(f_stop, f_pass, d_stop, fs = 1.0, N_bump=0, status = True): """ Design an FIR highpass filter using the sinc() kernel and a Kaiser window. The filter order is determined based on f_pass Hz, f_stop Hz, and the desired stopband attenuation d_stop in dB, all relative to a sampling rate of fs Hz. Note: the passband ripple cannot be set independent of the stopband attenuation. Mark Wickert October 2016 """ # Transform HPF critical frequencies to lowpass equivalent f_pass_eq = fs/2. - f_pass f_stop_eq = fs/2. - f_stop # Design LPF equivalent wc = 2*np.pi*(f_pass_eq + f_stop_eq)/2/fs delta_w = 2*np.pi*(f_stop_eq - f_pass_eq)/fs # Find the filter order M = np.ceil((d_stop - 8)/(2.285*delta_w)) # Adjust filter order up or down as needed M += N_bump N_taps = M + 1 # Obtain the Kaiser window beta = signal.kaiser_beta(d_stop) w_k = signal.kaiser(N_taps,beta) n = np.arange(N_taps) b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k b_k /= np.sum(b_k) # Transform LPF equivalent to HPF n = np.arange(len(b_k)) b_k *= (-1)**n if status: log.info('Kaiser Win filter taps = %d.' % N_taps) return b_k
def bandpass_kaiser(ntaps, lowcut, highcut, fs, width): nyq = 0.5 * fs atten = kaiser_atten(ntaps, width / nyq) beta = kaiser_beta(atten) taps = firwin(ntaps, [lowcut, highcut], nyq=nyq, pass_zero=False, window=('kaiser', beta), scale=False) return taps
def firwin_kaiser_lpf(f_pass, f_stop, d_stop, fs = 1.0, N_bump=0, status = True): """ Design an FIR lowpass filter using the sinc() kernel and a Kaiser window. The filter order is determined based on f_pass Hz, f_stop Hz, and the desired stopband attenuation d_stop in dB, all relative to a sampling rate of fs Hz. Note: the passband ripple cannot be set independent of the stopband attenuation. Mark Wickert October 2016 """ wc = 2*np.pi*(f_pass + f_stop)/2/fs delta_w = 2*np.pi*(f_stop - f_pass)/fs # Find the filter order M = np.ceil((d_stop - 8)/(2.285*delta_w)) # Adjust filter order up or down as needed M += N_bump N_taps = M + 1 # Obtain the Kaiser window beta = signal.kaiser_beta(d_stop) w_k = signal.kaiser(N_taps,beta) n = np.arange(N_taps) b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k b_k /= np.sum(b_k) if status: log.info('Kaiser Win filter taps = %d.' % N_taps) return b_k
def resample(s, p, q, h=None): """Change sampling rate by rational factor. This implementation is based on the Octave implementation of the resample function. It designs the anti-aliasing filter using the window approach applying a Kaiser window with the beta term calculated as specified by [2]. Ref [1] J. G. Proakis and D. G. Manolakis, Digital Signal Processing: Principles, Algorithms, and Applications, 4th ed., Prentice Hall, 2007. Chap. 6 Ref [2] A. V. Oppenheim, R. W. Schafer and J. R. Buck, Discrete-time signal processing, Signal processing series, Prentice-Hall, 1999 """ gcd = fractions.gcd(p,q) if gcd>1: p=p/gcd q=q/gcd if h is None: #design filter #properties of the antialiasing filter log10_rejection = -3.0 stopband_cutoff_f = 1.0/(2.0 * max(p,q)) roll_off_width = stopband_cutoff_f / 10.0 #determine filter length #use empirical formula from [2] Chap 7, Eq. (7.63) p 476 rejection_db = -20.0*log10_rejection; l = numpy.ceil((rejection_db-8.0) / (28.714 * roll_off_width)) #ideal sinc filter t = numpy.arange(-l, l + 1) ideal_filter=2*p*stopband_cutoff_f*numpy.sinc(2*stopband_cutoff_f*t) #determine parameter of Kaiser window #use empirical formula from [2] Chap 7, Eq. (7.62) p 474 beta = signal.kaiser_beta(rejection_db) #apodize ideal filter response h = numpy.kaiser(2*l+1, beta)*ideal_filter ls = len(s) lh = len(h) l = (lh - 1)/2.0 ly = numpy.ceil(ls*p/float(q)) #pre and postpad filter response nz_pre = numpy.floor(q - numpy.mod(l,q)) hpad = h[-lh+nz_pre:] offset = numpy.floor((l+nz_pre)/q) nz_post = 0; while numpy.ceil(((ls-1)*p + nz_pre + lh + nz_post )/q ) - offset < ly: nz_post += 1 hpad = hpad[:lh + nz_pre + nz_post] #filtering xfilt = upfirdn(s, hpad, p, q) return xfilt[offset-1:offset-1+ly]
def firwin_kaiser_hpf(f_stop, f_pass, d_stop, fs = 1.0, N_bump=0): """ Design an FIR highpass filter using the sinc() kernel and a Kaiser window. The filter order is determined based on f_pass Hz, f_stop Hz, and the desired stopband attenuation d_stop in dB, all relative to a sampling rate of fs Hz. Note: the passband ripple cannot be set independent of the stopband attenuation. Mark Wickert October 2016 """ # Transform HPF critical frequencies to lowpass equivalent f_pass_eq = fs/2. - f_pass f_stop_eq = fs/2. - f_stop # Design LPF equivalent wc = 2*np.pi*(f_pass_eq + f_stop_eq)/2/fs delta_w = 2*np.pi*(f_stop_eq - f_pass_eq)/fs # Find the filter order M = np.ceil((d_stop - 8)/(2.285*delta_w)) # Adjust filter order up or down as needed M += N_bump N_taps = M + 1 # Obtain the Kaiser window beta = signal.kaiser_beta(d_stop) w_k = signal.kaiser(N_taps,beta) n = np.arange(N_taps) b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k b_k /= np.sum(b_k) # Transform LPF equivalent to HPF n = np.arange(len(b_k)) b_k *= (-1)**n print('Kaiser Win filter taps = %d.' % N_taps) return b_k
def lpf(sample_rate, x, cutoff_hz=500.0, attenuation=25): nyq_rate = sample_rate / 2.0 attenuation = attenuation N = 100 beta = kaiser_beta(attenuation) cutoff_hz = cutoff_hz taps = firwin(N, cutoff_hz / nyq_rate, window=('kaiser', beta)) filtered_x = lfilter(taps, [1.0, 0], x) return filtered_x
def bandpass_kaiser(self, channel,freqs=(1, 15)): ntaps = 16 nyq = 0.5 * self.rate width = 1.6 atten = signal.kaiser_atten(ntaps, width / nyq) beta = signal.kaiser_beta(atten) taps = signal.firwin(ntaps, [freqs[0], freqs[1]], nyq=nyq, pass_zero=False, window=('kaiser', beta), scale=False) newsig = signal.filtfilt(taps_kaiser16, 1.0, self.single_sweep_data[channel], padlen=500) return newsig
def firwin_kaiser_bsf(f_stop1, f_pass1, f_pass2, f_stop2, d_stop, fs=1.0, n_bump=0, status=True): """ Design an FIR bandstop filter using the sinc() kernel and a Kaiser window. The filter order is determined based on f_stop1 Hz, f_pass1 Hz, f_pass2 Hz, f_stop2 Hz, and the desired stopband attenuation d_stop in dB for both stopbands, all relative to a sampling rate of fs Hz. Note: The passband ripple cannot be set independent of the stopband attenuation. Note: The filter order is forced to be even (odd number of taps) so there is a center tap that can be used to form 1 - H_BPF. Mark Wickert October 2016 """ # First design a BPF starting from simple LPF equivalent # The upper and lower stopbands are assumed to have # the same attenuation level. The LPF equivalent critical # frequencies: f_pass = (f_pass2 - f_pass1) / 2 f_stop = (f_stop2 - f_stop1) / 2 # Continue to design equivalent LPF wc = 2 * np.pi * (f_pass + f_stop) / 2 / fs delta_w = 2 * np.pi * (f_stop - f_pass) / fs # Find the filter order M = np.ceil((d_stop - 8) / (2.285 * delta_w)) # Adjust filter order up or down as needed M += n_bump # Make filter order even (odd number of taps) if ((M + 1) / 2.0 - int((M + 1) / 2.0)) == 0: M += 1 N_taps = M + 1 # Obtain the Kaiser window beta = signal.kaiser_beta(d_stop) w_k = signal.kaiser(N_taps, beta) n = np.arange(N_taps) b_k = wc / np.pi * np.sinc(wc / np.pi * (n - M / 2)) * w_k b_k /= np.sum(b_k) # Transform LPF to BPF f0 = (f_pass2 + f_pass1) / 2 w0 = 2 * np.pi * f0 / fs n = np.arange(len(b_k)) b_k_bs = 2 * b_k * np.cos(w0 * (n - M / 2)) # Transform BPF to BSF via 1 - BPF for odd N_taps b_k_bs = -b_k_bs b_k_bs[int(M / 2)] += 1 if status: log.info('Kaiser Win filter taps = %d.' % N_taps) return b_k_bs
def bandpass_kaiser(ntaps, lowcut, highcut, fs, width): nyq = 0.5 * fs atten = kaiser_atten(ntaps, width / nyq) beta = kaiser_beta(atten) taps = firwin( ntaps, [lowcut, highcut], nyq=nyq, pass_zero="bandpass", window=("kaiser", beta), scale=True, ) return taps
def resample(s, p, q, h=None): gcd = fractions.gcd(p, q) if gcd > 1: p = p / gcd q = q / gcd if h is None: #design filter #properties of the antialiasing filter log10_rejection = -3.0 stopband_cutoff_f = 1.0 / (2.0 * max(p, q)) roll_off_width = stopband_cutoff_f / 10.0 #determine filter length #use empirical formula from [2] Chap 7, Eq. (7.63) p 476 rejection_db = -20.0 * log10_rejection l = numpy.ceil((rejection_db - 8.0) / (28.714 * roll_off_width)) #ideal sinc filter t = numpy.arange(-l, l + 1) ideal_filter = 2 * p * stopband_cutoff_f * numpy.sinc( 2 * stopband_cutoff_f * t) #determine parameter of Kaiser window #use empirical formula from [2] Chap 7, Eq. (7.62) p 474 beta = signal.kaiser_beta(rejection_db) #apodize ideal filter response h = numpy.kaiser(2 * l + 1, beta) * ideal_filter ls = len(s) lh = len(h) l = (lh - 1) / 2.0 ly = numpy.ceil(ls * p / float(q)) #pre and postpad filter response nz_pre = numpy.floor(q - numpy.mod(l, q)) hpad = h[int(-lh + nz_pre):] offset = numpy.floor((l + nz_pre) / q) nz_post = 0 while numpy.ceil(((ls - 1) * p + nz_pre + lh + nz_post) / q) - offset < ly: nz_post += 1 hpad = hpad[:int(lh + nz_pre + nz_post)] #filtering xfilt = upfirdn(s, hpad, p, q) return xfilt[int(offset - 1):int(offset - 1 + ly)]
def firwin_kaiser_bsf(f_stop1, f_pass1, f_pass2, f_stop2, d_stop, fs = 1.0, N_bump=0): """ Design an FIR bandstop filter using the sinc() kernel and a Kaiser window. The filter order is determined based on f_stop1 Hz, f_pass1 Hz, f_pass2 Hz, f_stop2 Hz, and the desired stopband attenuation d_stop in dB for both stopbands, all relative to a sampling rate of fs Hz. Note: The passband ripple cannot be set independent of the stopband attenuation. Note: The filter order is forced to be even (odd number of taps) so there is a center tap that can be used to form 1 - H_BPF. Mark Wickert October 2016 """ # First design a BPF starting from simple LPF equivalent # The upper and lower stopbands are assumed to have # the same attenuation level. The LPF equivalent critical # frequencies: f_pass = (f_pass2 - f_pass1)/2 f_stop = (f_stop2 - f_stop1)/2 # Continue to design equivalent LPF wc = 2*np.pi*(f_pass + f_stop)/2/fs delta_w = 2*np.pi*(f_stop - f_pass)/fs # Find the filter order M = np.ceil((d_stop - 8)/(2.285*delta_w)) # Adjust filter order up or down as needed M += N_bump # Make filter order even (odd number of taps) if ((M+1)/2.0-int((M+1)/2.0)) == 0: M += 1 N_taps = M + 1 # Obtain the Kaiser window beta = signal.kaiser_beta(d_stop) w_k = signal.kaiser(N_taps,beta) n = np.arange(N_taps) b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/2)) * w_k b_k /= np.sum(b_k) # Transform LPF to BPF f0 = (f_pass2 + f_pass1)/2 w0 = 2*np.pi*f0/fs n = np.arange(len(b_k)) b_k_bs = 2*b_k*np.cos(w0*(n-M/2)) # Transform BPF to BSF via 1 - BPF for odd N_taps b_k_bs = -b_k_bs b_k_bs[int(M/2)] += 1 print('Kaiser Win filter taps = %d.' % N_taps) return b_k_bs
def bandpass_kaiser(self, channel, freqs=(1, 15)): ntaps = 16 nyq = 0.5 * self.rate width = 1.6 atten = signal.kaiser_atten(ntaps, width / nyq) beta = signal.kaiser_beta(atten) taps = signal.firwin(ntaps, [freqs[0], freqs[1]], nyq=nyq, pass_zero=False, window=('kaiser', beta), scale=False) newsig = signal.filtfilt(taps_kaiser16, 1.0, self.single_sweep_data[channel], padlen=500) return newsig
def firwin_kaiser_bpf(f_stop1, f_pass1, f_pass2, f_stop2, d_stop, fs=1.0, N_bump=0): """ Design an FIR bandpass filter using the sinc() kernel and a Kaiser window. The filter order is determined based on f_stop1 Hz, f_pass1 Hz, f_pass2 Hz, f_stop2 Hz, and the desired stopband attenuation d_stop in dB for both stopbands, all relative to a sampling rate of fs Hz. Note: the passband ripple cannot be set independent of the stopband attenuation. Mark Wickert October 2016 """ # Design BPF starting from simple LPF equivalent # The upper and lower stopbands are assumed to have # the same attenuation level. The LPF equivalent critical # frequencies: f_pass = (f_pass2 - f_pass1) / 2 f_stop = (f_stop2 - f_stop1) / 2 # Continue to design equivalent LPF wc = 2 * np.pi * (f_pass + f_stop) / 2 / fs delta_w = 2 * np.pi * (f_stop - f_pass) / fs # Find the filter order M = np.ceil((d_stop - 8) / (2.285 * delta_w)) # Adjust filter order up or down as needed M += N_bump N_taps = M + 1 # Obtain the Kaiser window beta = signal.kaiser_beta(d_stop) w_k = signal.kaiser(N_taps, beta) n = np.arange(N_taps) b_k = wc / np.pi * np.sinc(wc / np.pi * (n - M / 2)) * w_k b_k /= np.sum(b_k) # Transform LPF to BPF f0 = (f_pass2 + f_pass1) / 2 w0 = 2 * np.pi * f0 / fs n = np.arange(len(b_k)) b_k_bp = 2 * b_k * np.cos(w0 * (n - M / 2)) print('Kaiser Win filter taps = %d.' % N_taps) return b_k_bp
def resample(s, p, q, h=None): """Change sampling rate by rational factor. This implementation is based on the Octave implementation of the resample function. It designs the anti-aliasing filter using the window approach applying a Kaiser window with the beta term calculated as specified by [2]. Ref [1] J. G. Proakis and D. G. Manolakis, Digital Signal Processing: Principles, Algorithms, and Applications, 4th ed., Prentice Hall, 2007. Chap. 6 Ref [2] A. V. Oppenheim, R. W. Schafer and J. R. Buck, Discrete-time signal processing, Signal processing series, Prentice-Hall, 1999 """ gcd = fractions.gcd(p, q) if gcd > 1: p = p / gcd q = q / gcd if h is None: #design filter #properties of the antialiasing filter log10_rejection = -3.0 stopband_cutoff_f = 1.0 / (2.0 * max(p, q)) roll_off_width = stopband_cutoff_f / 10.0 #determine filter length #use empirical formula from [2] Chap 7, Eq. (7.63) p 476 rejection_db = -20.0 * log10_rejection l = numpy.ceil((rejection_db - 8.0) / (28.714 * roll_off_width)) #ideal sinc filter t = numpy.arange(-l, l + 1) ideal_filter = 2 * p * stopband_cutoff_f * numpy.sinc( 2 * stopband_cutoff_f * t) #determine parameter of Kaiser window #use empirical formula from [2] Chap 7, Eq. (7.62) p 474 beta = signal.kaiser_beta(rejection_db) #apodize ideal filter response h = numpy.kaiser(2 * l + 1, beta) * ideal_filter ls = len(s) lh = len(h) l = (lh - 1) / 2.0 ly = numpy.ceil(ls * p / float(q)) #pre and postpad filter response nz_pre = numpy.floor(q - numpy.mod(l, q)) hpad = h[-lh + nz_pre:] offset = numpy.floor((l + nz_pre) / q) nz_post = 0 while numpy.ceil(((ls - 1) * p + nz_pre + lh + nz_post) / q) - offset < ly: nz_post += 1 hpad = hpad[:lh + nz_pre + nz_post] #filtering xfilt = upfirdn(s, hpad, p, q) return xfilt[offset - 1:offset - 1 + ly]
tol_db = -20.0 * np.log10(tolerance) window_size = size(tol_db, transition_width) window_beta = beta(tol_db) return window_size, window_beta tol_list = np.arange(1e-6, 0.2, 1e-4) tol_db_list = -20.0 * np.log10(tol_list) beta_list = np.empty_like(tol_db_list) for i, tol in enumerate(np.nditer(tol_db_list)): beta_list[i] = beta(tol) beta_list_ref = np.empty_like(tol_db_list) for i, tol in enumerate(np.nditer(tol_db_list)): beta_list_ref[i] = kaiser_beta(tol) print('max abs beta error:', np.abs(beta_list - beta_list_ref).max()) hdf5util.write_ndarray(data=tol_db_list, file_path='kaiser_tol_db.h5', dataset_name='v') hdf5util.write_ndarray(data=beta_list_ref, file_path='kaiser_beta.h5', dataset_name='v') plt.figure() plt.plot(tol_db_list, beta_list, label='local') plt.plot(tol_db_list, beta_list_ref, label='scipy') plt.title('Beta list') plt.legend(loc='upper right', labelspacing=0.2) trans_width_list = np.array([0.05, 0.1, 0.5]) size_matrix = np.zeros((len(trans_width_list), len(tol_list)), dtype=int)
def construct_fir_filter(rate, frequencies, gains, order, phase, window, design): """ Construct coeffs of FIR filter. Args: rate (float): Nominal sampling rate of the input data. order (int): Filter order frequencies (list): Transition frequencies in Hz. design (str|'firwin2'): Design of the transfert function of the filter. phase (str|`linear`): Phase response ("zero", "zero-double" or "minimum"). window (float|`hamming`): The window to use in FIR design, ("hamming", "hann", or "blackman"). Returns: array h. FIR coeffs. Notes: Adapted from mne.filters, see the documentation of: * `mne.filters <https://martinos.org/mne/stable/generated/mne.filter.construct_fir_filter.html>`_ * `scipy.signal.firwin2 <https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.signal.firwin2.html>`_ """ nyq = rate / 2. if design == 'firwin2': from scipy.signal import firwin2 as design else: # not implemented yet raise ValueError( 'firwin, remez and firls have not been implemented yet ') # issue a warning if attenuation is less than this min_att_db = 12 if phase == 'minimum' else 20 if frequencies[0] != 0 or frequencies[-1] != nyq: raise ValueError( 'freq must start at 0 and end an Nyquist (%s), got %s' % (nyq, frequencies)) gains = np.array(gains) if window == "kaiser": diffs = np.diff(frequencies) width = min(diffs[diffs > 0]) beta = signal.kaiser_beta(signal.kaiser_atten(order, width / nyq)) window = ("kaiser", beta) # check zero phase length N = int(order) if N % 2 == 0: if phase == 'zero': LOGGER.info('filter_length must be odd if phase="zero", ' 'got %s' % N) N += 1 elif phase == 'zero-double' and gains[-1] == 1: N += 1 # construct symmetric (linear phase) filter if phase == 'minimum': h = design(N * 2 - 1, frequencies, gains, fs=rate, window=window) h = signal.minimum_phase(h) else: h = design(N, frequencies, gains, fs=rate, window=window) assert h.size == N att_db, att_freq = _filter_attenuation(h, frequencies, gains) if phase == 'zero-double': att_db += 6 if att_db < min_att_db: att_freq *= rate / 2. LOGGER.info('Attenuation at stop frequency %0.1fHz is only %0.1fdB. ' 'Increase filter_length for higher attenuation.' % (att_freq, att_db)) return h
def getFilterCoefficients(self): 'Get coefficients via `:py:function:`firwin <scipy.signal.firwin>`.' return signal.firwin(self.getNumTaps(), cutoff=self.cutoff, window=('kaiser', kaiser_beta(self.ripple_dB)), pass_zero=self.pass_zero, nyq=(0.5 * self.Fs))
def cpu_version(self, a): return signal.kaiser_beta(a)
def kaiserord(f: np.ndarray, a: np.ndarray, dev: np.ndarray, fs: float = 2) -> Tuple: """Kaiser window FIR filter design estimation parameters Parameters ---------- f : ndarray Band edges. The length of `f` is the length of `2*len(a)-2`. a : ndarray Band amplitude. The amplitude is specified on the bands defined by `f`. Together, `f` and `a` define a piecewise-constant response function. dev : ndarray Maximum allowable deviation. `dev` is a vector the same size as `a` that specifies the maximum allowable deviation between the frequency response of the output filter and its band amplitude, for each band. The entries in dev specify the passband ripple and the stopband attenuation. Specify each entry in `dev` as a positive number, representing absolute filter gain (unit-less). fs : float, optional Sample rate in Hz. Use this syntax to specify band edges scaled to a particular application's sample rate. The frequency band edges in f must be from 0 to fs/2. Default is 2. Raises ------ ValueError If the length of `f` is not same as `2*len(a)-2`. If the length `a` and `dev` is not the same. If `dev` includes minus value. Returns ------- n : int Filter order. Wn : ndarray Normalized frequency band edges. beta : float The `beta` parameter to be used in the formula for a Kaiser window. ftype : string Filter type of filter('low', 'high', 'bandpass', 'stop', 'DC-0' or 'DC-1'). Specified as one of the following. 1. 'low' specifies a lowpass filter with cutoff frequency Wn. 'low' is the default for scalar Wn. 2. 'high' specifies a highpass filter with cutoff frequency Wn. 3. 'bandpass' specifies a bandpass filter if Wn is a two-element vector. 'bandpass' is the default when Wn has two elements. 4. 'stop' specifies a bandstop filter if Wn is a two-element vector. 5. 'DC-0' specifies that the first band of a multiband filter is a stopband. 'DC-0' is the default when Wn has more than two elements. 6. 'DC-1' specifies that the first band of a multiband filter is a passband. """ if type(f) != np.ndarray: if type(f) == list: f = np.array(f) else: f = np.array([f]) if type(a) != np.ndarray: if type(a) == list: a = np.array(a) else: a = np.array([a]) if type(dev) != np.ndarray: if type(dev) == list: dev = np.array(dev) else: dev = np.array([dev]) # Parameter check if len(f) != 2 * len(a) - 2: raise ValueError("The length of 'f' must be the length of 2*len(a)-2.") if np.any(a[0:len(a) - 2] != a[2:len(a)]): raise ValueError( "Pass and stop bands in a must be strictly alternating.") if (len(dev) != len(a)) and (len(dev) != 1): raise ValueError("'dev' and 'a' must be the same size.") dev = np.min(dev) if dev <= 0: raise ValueError("'dev' must be larger than 0.") # Calcurate normalized frequency band edges. Wn = (f[0:len(f):2] + f[1:len(f):2]) / fs # Determine ftype if len(Wn) == 1: if a[0] > a[1]: ftype = 'low' else: ftype = 'high' elif len(Wn) == 2: if a[0] > a[1]: ftype = 'stop' else: ftype = 'bandpass' else: if a[0] > a[1]: ftype = 'DC-1' else: ftype = 'DC-0' # Calcurate beta A = -20 * np.log10(dev) beta = signal.kaiser_beta(A) # Calcurate n from beta and dev width = 2 * np.pi * np.min(f[1:len(f):2] - f[0:len(f):2]) / fs n = np.max((1, int(np.ceil((A - 8) / (2.285 * width))))) # If last band is high, make sure the order of the filter is even if ((a[0] > a[1]) == (len(Wn) % 2 == 0)) and (n % 2 == 1): n += 1 if len(Wn) == 1: Wn = Wn[0] return int(n), Wn, beta, ftype