def build_filter(): die_window = 3 live_window = 4 live_gain = 2 ** 0.5 freq_full = [0, 3, 5, 50-live_window, 50-die_window, 50+die_window, 50+live_window, 100-live_window, 100-die_window, 100+die_window, 100+live_window, nyq] gain_full = [0, 0, 2 ** 0.5, live_gain, 0, 0, live_gain, live_gain, 0, 0, live_gain, 1] freq_low = [0, 3, 5, 40, 45, nyq] gain_low = [0, 0, live_gain, live_gain, 0, 0] b = signal.firwin2(sfreq, freq_low, gain_low, nyq=nyq, antisymmetric=False) return b
def lab6_ex2(): # set parameters of system fn = 1.0 nt = 50 #number of taps freq = array([0,0.1,0.2,0.5,1.0]) #frequency sampling points gain = array([1.0,1.0,0.01,0.001,0]) b = firwin2(nt,freq,gain,nyq=fn) #calc FIR coefficients with given frequency response a = array([1.0,0]) #(no feedback (FIR), poles at origin reduced to 1 for simplification) # calc frequency response of filter and plot w,h = freqz(b,a) plot(w/pi, 20*log10(abs(h)),'b-') title('FIR of given frequency response') xlabel('normalized frequency (1 = fn)') ylabel('magnitude (dB scale)') grid() show() print('\nResponses in dB scale (all frequencies are relative to fn):\nf = 0, gain = 0 dB\nf = 0.1, gain = -1.05 dB\nf = 0.2, gain = -18.25 dB\nf = 0.5, gain = -56.4 dB\nf = 1.0, gain =~ -92 dB (filter tries to approach -inf and goes off the scale around f = 0.999)') print('\nThe filter has 49 zeros (the same as number of taps - 1)') print('The filter should also have 49 poles (all at the origin) so that it is causal. However, in this implementation (firwin2) there are no poles (except those added by the user)') # calc and show zeros and poles on zplane z,p,k = tf2zpk(b,a) zplane(z,p) title('zplane of FIR of given frequency response (50 taps)') show() print('\nFrom the zplane diagram, we can see pairs of conjugate pairs of zeros that follow along the unit circle. For each pair of conjugate pairs, one conjugate pair is inside of the unit circle and one is on the outside. As the frequency increases to fn, each pair of zeros generally gets closer and closer to the unit circle, thus attenuating the signal even further, up to a gain of 0 @ f = fn)')
def fir2FiltAlt(f1, f2, f3, f4, filterType, snd, fs, filterOrder): fs = float(fs) f1 = (f1 * 2) / fs f2 = (f2 * 2) / fs f3 = (f3 * 2) / fs f4 = (f4 * 2) / fs n = filterOrder if filterType == 'lowpass': f = [0, f3, f4, 1] m = [1, 1, 0.00003, 0] elif filterType == 'highpass': f = [0, f1, f2, 0.999999, 1] #high pass m = [0, 0.00003, 1, 1, 0] elif filterType == 'bandpass': f = [0, f1, f2, ((f2+f3)/2), f3, f4, 1] m = [0, 0.00003, 1, 1, 1, 0.00003, 0] elif filterType == 'bandstop': f = [0, f1, f2, ((f2+f3)/2), f3, f4, 0.999999, 1] #band stop m = [1, 1, 0.00003, 0, 0.00003, 1, 1, 0] b = firwin2 (n,f,m); x = copy.copy(snd) x = convolve(snd, b, 1) #x[:, 1] = convolve(snd[:,1], b, 1) return x
def filter_VE(data): f=np.linspace(0,1,50000) a = np.ones(50000) #Switching power supply frequency (~290 KHz) a[2850:2950] =0 #1.49 MHz a[14850:14950]=0 #AM 1.37 MHz a[13650:13750] = 0 #80 m Ham band (3.97 MHz) a[39650:39750] = 0 #80 m Ham band (4 MHz) a[39950:40050]= 0 a[-1]=0 b=sigs.firwin2(3000,f,a) [h, fpoints] = sigs.freqz(b, 1, 50000,10E6) #Run the FIR filter vec = sigs.lfilter(b,1,data) return vec
def get_channelizer_taps(M, n_taps=100): taps = signal.firwin2(100, [0, 1.0/M, 1.0/M+0.05, 1], [1, 1, 0, 0]) # Divide by integral of absolute values to prevent the possibility # of overflow. chantaps = [taps[i::M] for i in range(M)] scaledtaps, tapscalefactor = scale_taps(chantaps) return scaledtaps, tapscalefactor
def test03(self): width = 0.02 ntaps, beta = kaiserord(120, width) # ntaps must be odd for positive gain at Nyquist. ntaps = int(ntaps) | 1 freq = [0.0, 0.4, 0.4, 0.5, 0.5, 1.0] gain = [1.0, 1.0, 0.0, 0.0, 1.0, 1.0] taps = firwin2(ntaps, freq, gain, window=("kaiser", beta)) freq_samples = np.array([0.0, 0.4 - width, 0.4 + width, 0.45, 0.5 - width, 0.5 + width, 0.75, 1.0]) freqs, response = freqz(taps, worN=np.pi * freq_samples) assert_array_almost_equal(np.abs(response), [1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0], decimal=5)
def test04(self): """Test firwin2 when window=None.""" ntaps = 5 # Ideal lowpass: gain is 1 on [0,0.5], and 0 on [0.5, 1.0] freq = [0.0, 0.5, 0.5, 1.0] gain = [1.0, 1.0, 0.0, 0.0] taps = firwin2(ntaps, freq, gain, window=None, nfreqs=8193) alpha = 0.5 * (ntaps - 1) m = np.arange(0, ntaps) - alpha h = 0.5 * sinc(0.5 * m) assert_array_almost_equal(h, taps)
def firf(x, f_range, fs = 1000, w = 7, tw = .15): """ Filter signal with an FIR filter x : array-like, 1d Time series to filter f_range : (low, high), Hz Cutoff frequencies of bandpass filter fs : float, Hz Sampling rate w : float Length of the filter in terms of the number of cycles of the oscillation whose frequency is the center of the bandpass filter tw : float Transition width of the filter in normalized frequency space Returns ------- x_filt : array-like, 1d Filtered time series """ if w <= 0: raise ValueError('Number of cycles in a filter must be a positive number.') if np.logical_or(tw < 0, tw > 1): raise ValueError('Transition width must be between 0 and 1.') nyq = fs/2 if np.any(np.array(f_range) > nyq): raise ValueError('Filter frequencies must be below nyquist rate.') if np.any(np.array(f_range) < 0): raise ValueError('Filter frequencies must be positive.') cf = np.mean(f_range) Ntaps = np.floor(w * fs / cf) if len(x) < Ntaps: raise RuntimeError('Length of filter is loger than data. Provide more data or a shorter filter.') # Characterize desired filter f = [0, (1-tw)*f_range[0]/nyq, f_range[0]/nyq, f_range[1]/nyq, (1+tw)*f_range[1]/nyq, 1] m = [0,0,1,1,0,0] if any(np.diff(f)<0): raise RuntimeError('Invalid FIR filter parameters. Please decrease the transition width parameter.') # Perform filtering taps = firwin2(Ntaps, f, m) x_filt = filtfilt(taps,[1],x) if any(np.isnan(x_filt)): raise RuntimeError('Filtered signal contains nans. Adjust filter parameters.') return x_filt
def test05(self): """Test firwin2 for calculating Type IV filters""" ntaps = 1500 freq = [0.0, 1.0] gain = [0.0, 1.0] taps = firwin2(ntaps, freq, gain, window=None, antisymmetric=True) assert_array_almost_equal(taps[: ntaps // 2], -taps[ntaps // 2:][::-1]) freqs, response = freqz(taps, worN=2048) assert_array_almost_equal(abs(response), freqs / np.pi, decimal=4)
def test02(self): width = 0.04 beta = 12.0 # ntaps must be odd for positive gain at Nyquist. ntaps = 401 # An ideal highpass filter. freq = [0.0, 0.5, 0.5, 1.0] gain = [0.0, 0.0, 1.0, 1.0] taps = firwin2(ntaps, freq, gain, window=("kaiser", beta)) freq_samples = np.array([0.0, 0.25, 0.5 - width, 0.5 + width, 0.75, 1.0]) freqs, response = freqz(taps, worN=np.pi * freq_samples) assert_array_almost_equal(np.abs(response), [0.0, 0.0, 0.0, 1.0, 1.0, 1.0], decimal=5)
def test01(self): width = 0.04 beta = 12.0 ntaps = 400 # Filter is 1 from w=0 to w=0.5, then decreases linearly from 1 to 0 as w # increases from w=0.5 to w=1 (w=1 is the Nyquist frequency). freq = [0.0, 0.5, 1.0] gain = [1.0, 1.0, 0.0] taps = firwin2(ntaps, freq, gain, window=("kaiser", beta)) freq_samples = np.array([0.0, 0.25, 0.5 - width / 2, 0.5 + width / 2, 0.75, 1.0 - width / 2]) freqs, response = freqz(taps, worN=np.pi * freq_samples) assert_array_almost_equal(np.abs(response), [1.0, 1.0, 1.0, 1.0 - width, 0.5, width], decimal=5)
def test06(self): """Test firwin2 for calculating Type III filters""" ntaps = 1501 freq = [0.0, 0.5, 0.55, 1.0] gain = [0.0, 0.5, 0.0, 0.0] taps = firwin2(ntaps, freq, gain, window=None, antisymmetric=True) assert_equal(taps[ntaps // 2], 0.0) assert_array_almost_equal(taps[: ntaps // 2], -taps[ntaps // 2 + 1:][::-1]) freqs, response1 = freqz(taps, worN=2048) response2 = np.interp(freqs / np.pi, freq, gain) assert_array_almost_equal(abs(response1), response2, decimal=3)
def design_filter(filter_type, f_p, f_w, filter_dur, window): if filter_type == 'highpass': f_s = f_p - f_w freq = [0., f_s, f_p, sfreq / 2.] gain = [0., 0., 1., 1.] else: f_s = f_p + f_w freq = [0., f_p, f_s, sfreq / 2.] gain = [1., 1., 0., 0.] n = int(sfreq * filter_dur) n += ~(n % 2) # Type II filter can't have 0 attenuation at nyq h = signal.firwin2(n, freq, gain, nyq=sfreq / 2., window=window) return h
def lock2(f0, fp, fc, fs, coeff_ratio=8.0, coeffs=None, window='blackman', print_response=True): """Create a gentle fir filter. Pass frequencies below fp, cutoff frequencies above fc, and gradually taper to 0 in between.""" # Convert to digital frequencies, normalizing f_nyq to 1, # as requested by scipy.signal.firwin2 nyq = fs / 2 fp = fp / nyq fc = fc / nyq if coeffs is None: coeffs = int(round(coeff_ratio / fc, 0)) # Force number of tukey coefficients odd alpha = (1-fp*1.0/fc) n = int(round(1000. / alpha) // 2) N = n * 2 + 1 f = np.linspace(0, fc, n+1) fm = np.zeros(n + 2) mm = np.zeros(n + 2) fm[:-1] = f # Append fm = nyquist frequency by hand; needed by firwin2 fm[-1] = 1. m = signal.tukey(N, alpha=alpha) # Only take the falling part of the tukey window, # not the part equal to zero mm[:-1] = m[n:] # Use approx. 8x more frequencies than total coefficients we need nfreqs = 2**(int(round(np.log2(coeffs)))+3)+1 b = signal.firwin2(coeffs, fm, mm, nfreqs=nfreqs, window=window) # Force filter gain to 1 at DC; corrects for small rounding errors b = b / np.sum(b) w, rep = signal.freqz(b, worN=np.pi*np.array([0., fp/2, fp, fc, 2*fc, 0.5*f0/nyq, f0/nyq, 1.])) if print_response: print("Response:") _print_magnitude_data(w, rep, fs) return b
def get_filter(sfreq=125., band='alpha'): f_low_lb = band_bounds[band][0] - 1 f_low_ub = band_bounds[band][0] f_high_lb = band_bounds[band][1] f_high_ub = band_bounds[band][1] + 1 nyq = sfreq / 2. # the Nyquist frequency is half our sample rate freq = [0., f_low_lb, f_low_ub, f_high_lb, f_high_ub, nyq] gain = [0, 0, 1, 1, 0, 0] n = int(round(1 * sfreq)) + 1 filt = signal.firwin2(n, freq, gain, nyq=nyq) return filt
def test01(self): width = 0.04 beta = 12.0 ntaps = 400 # Filter is 1 from w=0 to w=0.5, then decreases linearly from 1 to 0 as w # increases from w=0.5 to w=1 (w=1 is the Nyquist frequency). freq = [0.0, 0.5, 1.0] gain = [1.0, 1.0, 0.0] taps = firwin2(ntaps, freq, gain, window=('kaiser', beta)) freq_samples = np.array([ 0.0, 0.25, 0.5 - width / 2, 0.5 + width / 2, 0.75, 1.0 - width / 2 ]) freqs, response = freqz(taps, worN=np.pi * freq_samples) assert_array_almost_equal(np.abs(response), [1.0, 1.0, 1.0, 1.0 - width, 0.5, width], decimal=5)
def test03(self): width = 0.02 ntaps, beta = kaiserord(120, width) # ntaps must be odd for positive gain at Nyquist. ntaps = int(ntaps) | 1 freq = [0.0, 0.4, 0.4, 0.5, 0.5, 1.0] gain = [1.0, 1.0, 0.0, 0.0, 1.0, 1.0] taps = firwin2(ntaps, freq, gain, window=('kaiser', beta)) freq_samples = np.array([ 0.0, 0.4 - width, 0.4 + width, 0.45, 0.5 - width, 0.5 + width, 0.75, 1.0 ]) freqs, response = freqz(taps, worN=np.pi * freq_samples) assert_array_almost_equal(np.abs(response), [1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0], decimal=5)
def preprocess(abd, chest, orig_freq=200): ''' sigs[0] should be ABD sigs[1] should be Chest ''' # Resample to 64Hz abd_64, chest_64 = resample_signals([abd, chest], orig_freq) bands = (0, 0.05, 0.1, 5, 10, 32) desired = (0, 0, 1, 1, 0, 0) b_firwin = signal.firwin2(73, bands, desired, fs=64) #b_firls = signal.firls(73, bands, desired, fs=64) abd_64_filt = signal.filtfilt(b_firwin, 1, abd_64) chest_64_filt = signal.filtfilt(b_firwin, 1, chest_64) return abd_64_filt, chest_64_filt
def callback(in_data, frame_count, time_info, status): data = wf.readframes(frame_count) if len(data) == 0: return data, pyaudio.paComplete signal = bytes_to_float(data) # converting data gains = 10**((np.array([ int(self.slider_00032.value()), int(self.slider_00064.value()), int(self.slider_00128.value()), int(self.slider_00256.value()), int(self.slider_00512.value()), int(self.slider_01024.value()), int(self.slider_02048.value()), int(self.slider_04096.value()), int(self.slider_08192.value()), int(self.slider_16384.value()) ], dtype=np.float64)) / 20) self.label_00032.setText(str(self.slider_00032.value())) self.label_00064.setText(str(self.slider_00064.value())) self.label_00128.setText(str(self.slider_00128.value())) self.label_00256.setText(str(self.slider_00256.value())) self.label_00512.setText(str(self.slider_00512.value())) self.label_01024.setText(str(self.slider_01024.value())) self.label_02048.setText(str(self.slider_02048.value())) self.label_04096.setText(str(self.slider_04096.value())) self.label_08192.setText(str(self.slider_08192.value())) self.label_16384.setText(str(self.slider_16384.value())) a = [1.] b = firwin2(self.n_taps, self.eq_frequencies, np.concatenate(([0], gains, [0]), axis=0), nyq=f_rate / 2, window=None, antisymmetric=True) # need to give an initial condition for self.z other than 0 filtered, self.z = lfilter(b, a, signal, zi=self.z) # when using data self.update_freq_plot(filtered) self.update_filter_plot((a, b)) output = float_to_bytes(filtered) return output, pyaudio.paContinue
def _apply_notches(X, notches, rate, fft=True): """Low-level code which applies notch filters. Parameters ---------- X : ndarray, (n_time, n_channels) Input data. notches : ndarray Frequencies to notch filter. rate : float Number of samples per second for X. fft : bool Whether to filter in the time or frequency domain. Returns ------- Xp : ndarray, (n_time, n_channels) Notch filtered data. """ delta = 1. if fft: fs = rfftfreq(X.shape[0], 1. / rate) fd = rfft(X, axis=0) else: nyquist = rate / 2. n_taps = 1001 gain = [1, 1, 0, 0, 1, 1] for notch in notches: if fft: window_mask = np.logical_and(fs > notch - delta, fs < notch + delta) window_size = window_mask.sum() window = np.hamming(window_size) fd[window_mask] = fd[window_mask] * (1. - window)[:, np.newaxis] else: freq = np.array([ 0, notch - delta, notch - delta / 2., notch + delta / 2., notch + delta, nyquist ]) / nyquist filt = firwin2(n_taps, freq, gain) Xp = filtfilt(filt, np.array([1]), X, axis=0) if fft: Xp = irfft(fd, n=X.shape[0], axis=0) return Xp
def _built_in_filter_design(self, f_ch): """ Design basic shape-matching 127th order FIR filter. The filter will attempt to match the following gain envelope: w = [0, s1, p1, p2, s1, 1] h = [0, 0, 1, 1, 0, 0] where s1 = f_ch - DIGITAL_CHANNEL_WIDTH*0.6 p1 = f_ch - DIGITAL_CHANNEL_WIDTH*0.4 p2 = f_ch + DIGITAL_CHANNEL_WIDTH*0.4 s2 = f_ch + DIGITAL_CHANNEL_WIDTH*0.6, h is normalized to a maximum of 1, and w is the angular frequency normalized to pi. Parameters ---------- f_ch : float Center frequency of bandpass filter. Returns ------- B : ndarray FIR filter coefficients. """ # filter channel should be at least more than digital bandwidth from sampled boundaries f_lower = self.DIGITAL_CHANNEL_WIDTH f_upper = self.ADC_SAMPLE_RATE / 2 - self.DIGITAL_CHANNEL_WIDTH if f_ch <= f_lower or f_ch >= f_upper: raise RuntimeError( "Digital channel center frequency is {0:7.3f}MHz, but should be within ({1:7.3f},{2:7.3f}) MHz" .format(f_ch / 1e6, f_lower / 1e6, f_upper / 1e6)) # construct envelope f_pass = f_ch + array([-1, 1]) * self.DIGITAL_CHANNEL_WIDTH * 0.4 f_stop = f_ch + array([-1, 1]) * self.DIGITAL_CHANNEL_WIDTH * 0.6 w_pass = f_pass / (self.ADC_SAMPLE_RATE / 2) w_stop = f_stop / (self.ADC_SAMPLE_RATE / 2) filt_gain = array([0, 0, 1, 1, 0, 0]) filt_freq = concatenate(([0], [w_stop[0]], w_pass, [w_pass[1]], [1.0])) B = firwin2(128, filt_freq, filt_gain, window='boxcar') # normalize to absolute maximum of 0.5 B = 0.5 * B / (abs(B).max()) return B
def computefir(fc, L: int, ofn, fs: int, method: str): """ bandpass FIR design https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.firwin.html http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.remez.html L: number of taps output: b: FIR filter coefficients """ assert len(fc) == 2, 'specify lower and upper bandpass filter corner frequencies in Hz.' if method == 'remez': b = signal.remez(numtaps=L, bands=[0, 0.9*fc[0], fc[0], fc[1], 1.1*fc[1], 0.5*fs], desired=[0, 1, 0], Hz=fs) elif method == 'firwin': b = signal.firwin(L, [fc[0], fc[1]], window='blackman', pass_zero=False, nyq=fs//2) elif method == 'firwin2': b = signal.firwin2(L, [0, fc[0], fc[1], fs//2], [0, 1, 1, 0], window='blackman', nyq=fs//2, # antisymmetric=True, ) else: raise ValueError(f'unknown filter design method {method}') if ofn: ofn = Path(ofn).expanduser() print(f'writing {ofn}') # FIXME make binary with ofn.open('w') as h: h.write(f'{b.size}\n') # first line is number of coefficients b.tofile(h, sep=" ") # second line is space-delimited coefficents return b
def fir_filter_bank(scale, taps, samplerate, window): basis = np.zeros((len(scale), taps)) basis = ArrayWithUnits( basis, [FrequencyDimension(scale), TimeDimension(*samplerate)]) nyq = samplerate.nyquist if window.ndim == 1: window = repeat(window, len(scale)) for i, band, win in zip(range(len(scale)), scale, window): start_hz = max(0, band.start_hz) stop_hz = min(nyq, band.stop_hz) freqs = np.linspace(start_hz / nyq, stop_hz / nyq, len(win)) freqs = [0] + list(freqs) + [1] gains = [0] + list(win) + [0] basis[i] = firwin2(taps, freqs, gains) return basis
def get_taps(N, R, M, ntaps=128, cutoff=0.45): """ Find the coefficients of the half-band FIR filter that compensate the CIC filter from 0 to cutoff N : number of CIC stages R : decimation rate M : differential delay in the comb section stages of the filter """ f = np.arange(2048) / 2047. cic_response = lambda f : abs( M/R * (np.sin((f*R)/2)) / (np.sin((f*M)/2.)) )**N if f !=0 else 1 H = np.array(map(cic_response, f*np.pi)) # Define frequency reponse of ideal compensation filter H = np.array(map(cic_response, f*np.pi / R)) Hc = 1/H * (f < cutoff) beta = 8 taps = signal.firwin2(ntaps, f, Hc, nfreqs = 1025, window=('kaiser', beta)) taps /= np.sum(taps) return taps, cic_response
def get_taps(N, R, M, ntaps=256, cutoff=0.45): """ Find the coefficients of the half-band FIR filter that compensate the CIC filter from 0 to cutoff N : number of CIC stages R : decimation rate M : differential delay in the comb section stages of the filter """ f = np.arange(2048) / 2047. cic_response = lambda f : abs( M/R * (np.sin((f*R)/2)) / (np.sin((f*M)/2.)) )**N if f !=0 else 1 H = np.fromiter(map(cic_response, f*np.pi), dtype=np.float64) # Define frequency reponse of ideal compensation filter H = np.fromiter(map(cic_response, f*np.pi / R), dtype=np.float64) Hc = 1/H * (f < cutoff) beta = 8 taps = signal.firwin2(ntaps, f, Hc, nfreqs = 1025, window=('kaiser', beta)) taps /= np.sum(taps) return taps, cic_response
def _matched_filters(ks, x_m, N_pts, dec=16, window='hann', n_pts_eval_fir=48000): ks = ks / dec N = N_pts // dec k = np.linspace(0, ks/2, n_pts_eval_fir) resp_ac = _j1filt(k * 2 * np.pi * x_m) fir_ac_dec = signal.firwin2(N, k, resp_ac, nyq=k[-1], window=window) fir_dc_dec = signal.firwin(N, jn_zeros(0, 1)[0] / (2*np.pi*x_m), nyq=k[-1], window=window) # Manually force gain to 1 at DC; firwin2 rounding errors probable cause of # minor losses (< 1 percent) fir_ac_dec = fir_ac_dec / np.sum(fir_ac_dec) fir_dc_dec = fir_dc_dec / np.sum(fir_dc_dec) fir_ac = np.fft.irfft(np.fft.rfft(fir_ac_dec), fir_ac_dec.size * dec) fir_dc = np.fft.irfft(np.fft.rfft(fir_dc_dec), fir_dc_dec.size * dec) return fir_ac, fir_dc
def _built_in_filter_design(self,f_ch): """ Design basic shape-matching 127th order FIR filter. The filter will attempt to match the following gain envelope: w = [0, s1, p1, p2, s1, 1] h = [0, 0, 1, 1, 0, 0] where s1 = f_ch - DIGITAL_CHANNEL_WIDTH*0.6 p1 = f_ch - DIGITAL_CHANNEL_WIDTH*0.4 p2 = f_ch + DIGITAL_CHANNEL_WIDTH*0.4 s2 = f_ch + DIGITAL_CHANNEL_WIDTH*0.6, h is normalized to a maximum of 1, and w is the angular frequency normalized to pi. Parameters ---------- f_ch : float Center frequency of bandpass filter. Returns ------- B : ndarray FIR filter coefficients. """ # filter channel should be at least more than digital bandwidth from sampled boundaries f_lower = self.DIGITAL_CHANNEL_WIDTH f_upper = self.ADC_SAMPLE_RATE/2-self.DIGITAL_CHANNEL_WIDTH if f_ch <= f_lower or f_ch >= f_upper: raise RuntimeError("Digital channel center frequency is {0:7.3f}MHz, but should be within ({1:7.3f},{2:7.3f}) MHz".format(f_ch/1e6,f_lower/1e6,f_upper/1e6)) # construct envelope f_pass = f_ch + array([-1,1])*self.DIGITAL_CHANNEL_WIDTH*0.4 f_stop = f_ch + array([-1,1])*self.DIGITAL_CHANNEL_WIDTH*0.6 w_pass = f_pass/(self.ADC_SAMPLE_RATE/2) w_stop = f_stop/(self.ADC_SAMPLE_RATE/2) filt_gain = array([0,0,1,1,0,0]) filt_freq = concatenate(([0],[w_stop[0]], w_pass, [w_pass[1]], [1.0])) B = firwin2(128,filt_freq,filt_gain,window='boxcar') # normalize to absolute maximum of 0.5 B = 0.5*B/(abs(B).max()) return B
def outmidear(n,fs): # This funtion creates an N-coefficients FIR filter that simulates the # outer-middle ear. FS is the sampling frequency of the signal to be # filtered. # The specification of the filter is taken from a figure in: # B.R. Glasberg and B.C.J. Moore, A model of loudness applicable to # time-varying sounds, J. Audio Eng. Soc. 50: 331-342 (2002) f = array([ 0, .02, .05, .1, .2, .5, .6, .7, 1, 2, 3, 4, 5, 8, 9, 10, 12, 13, 14, 15]) * 1000 g = array([ float('-inf'), -39, -19, -12.5, -8, -2, -1, 0, 0, 4, 8, 8, 5, -9, -11, -11, -9, -13, -19, -15]) # gain m = 10 ** (g/20) if fs/2 > f[-1]: f = concatenate( (f, [fs/2]) ) m = concatenate( (m, [0]) ) else: mend = interp( fs/2, f, m ) i = f < fs/2 f = concatenate( ( f[i], [fs/2] ) ) m = concatenate( ( m[i], [mend] ) ) oddsize = 2*ceil(n/2) + 1 b = firwin2( oddsize, f/(fs/2), m ) return b
def build_filter(): die_window = 3 live_window = 4 live_gain = 2**0.5 freq_full = [ 0, 3, 5, 50 - live_window, 50 - die_window, 50 + die_window, 50 + live_window, 100 - live_window, 100 - die_window, 100 + die_window, 100 + live_window, nyq ] gain_full = [ 0, 0, 2**0.5, live_gain, 0, 0, live_gain, live_gain, 0, 0, live_gain, 1 ] freq_low = [0, 3, 5, 40, 45, nyq] gain_low = [0, 0, live_gain, live_gain, 0, 0] b = signal.firwin2(sfreq, freq_low, gain_low, nyq=nyq, antisymmetric=False) return b
def __init__(self, band, fs, delay, n_taps, n_taps_edge, ar_order, max_chunk_size=1, butter_order=2, **kwargs): self.n_taps = n_taps self.buffer = SlidingWindowBuffer(self.n_taps) self.ba_bandpass = sg.firwin2( 64 * butter_order, [0, band[0], band[0], band[1], band[1], fs / 2], [0, 0, 1, 1, 0, 0], fs=fs), [1., 0] self.n_taps_edge = n_taps_edge self.ar_order = ar_order self.band = band self.fs = fs self.max_chunk_size = max_chunk_size
def equalize_with_absolute_frequencies(sound: np.ndarray, event: 'sinethesizer.synth.core.Event', breakpoint_frequencies: List[float], gains: List[float], **kwargs) -> np.ndarray: """ Change power and amplitude distribution across frequencies. :param sound: sound to be modified :param event: parameters of sound event for which this function is called :param breakpoint_frequencies: frequencies (in Hz) that correspond to breaks in frequency response of equalizer :param gains: relative gains at corresponding breakpoint frequencies; a gain at an intermediate frequency is linearly interpolated :return: sound with altered frequency balance """ nyquist_frequency = 0.5 * event.frame_rate breakpoint_frequencies = [ min(x / nyquist_frequency, 1) for x in breakpoint_frequencies ] gains = [x for x in gains] # Copy it to prevent modifying original list. if breakpoint_frequencies[0] != 0: breakpoint_frequencies.insert(0, 0) gains.insert(0, gains[0]) if breakpoint_frequencies[-1] != 1: breakpoint_frequencies.append(1) gains.append(gains[-1]) # `fir_size` is odd, because else there are constraints on `gains`. fir_size = 2 * int(round(event.frame_rate / 100)) + 1 fir = firwin2(fir_size, breakpoint_frequencies, gains, **kwargs) sound = np.vstack(( convolve(sound[0, :], fir, mode='same'), convolve(sound[1, :], fir, mode='same'), )) return sound
def _design_window(self): self._nyquist = self.sample_rate / 2 # firwin2 requires that the freqs vector begin at 0 and end at nyquist. # therefore we will add those manually if they're not there. if len(self.freqs) != len(self.gains): raise ValueError("Lengths of freqs and gains should be the same.") self.freqs = [float(freq) for freq in self.freqs] self.gains = [float(gain) for gain in self.gains] if self.freqs[0] != 0: self.freqs.insert(0,0) if self.freqs[-1] != self._nyquist: self.freqs.append(self._nyquist) # Pad the filter appropriately. my_type = self.get_filter_type() print("Type of filter is ", my_type) if my_type == 2 or my_type == 3: if self.gains[-1] != 0: self.gains.append(0) if my_type == 3 or my_type == 4: if self.gains[0] != 0: self.gains.insert(0,0) while len(self.freqs) > len(self.gains): print("Had to pad so that len freqs = len gains...") self.gains.append(0) print("freqs vector became ", self.freqs) print("gains vector became ", self.gains) self.B = signal.firwin2(self.taps, self.freqs, self.gains, window=self.window, nyq=self._nyquist, antisymmetric=self.antisymmetric)
def get_filter(bounds = [8,13], sfreq=125.): """ Args: bounds: np.array, (2,) sfreq: float Returns: filt: np.array, (int(round(1 * sfreq)) + 1,) """ f_low_lb = bounds[0] - 1 f_low_ub = bounds[0] f_high_lb = bounds[1] f_high_ub = bounds[1] + 1 nyq = sfreq / 2. # the Nyquist frequency is half our sample rate freq = [0., f_low_lb, f_low_ub, f_high_lb, f_high_ub, nyq] gain = [0, 0, 1, 1, 0, 0] n = int(round(1 * sfreq)) + 1 filt = signal.firwin2(n, freq, gain, nyq=nyq) return filt
def create_lowpass_filter(band_center=0.5, kernelLength=256, transitionBandwidth=0.03): """ Calculate the highest frequency we need to preserve and the lowest frequency we allow to pass through. Note that frequency is on a scale from 0 to 1 where 0 is 0 and 1 is Nyquist frequency of the signal BEFORE downsampling. """ # transitionBandwidth = 0.03 passbandMax = band_center / (1 + transitionBandwidth) stopbandMin = band_center * (1 + transitionBandwidth) # Unlike the filter tool we used online yesterday, this tool does # not allow us to specify how closely the filter matches our # specifications. Instead, we specify the length of the kernel. # The longer the kernel is, the more precisely it will match. # kernelLength = 256 # We specify a list of key frequencies for which we will require # that the filter match a specific output gain. # From [0.0 to passbandMax] is the frequency range we want to keep # untouched and [stopbandMin, 1.0] is the range we want to remove keyFrequencies = [0.0, passbandMax, stopbandMin, 1.0] # We specify a list of output gains to correspond to the key # frequencies listed above. # The first two gains are 1.0 because they correspond to the first # two key frequencies. the second two are 0.0 because they # correspond to the stopband frequencies gainAtKeyFrequencies = [1.0, 1.0, 0.0, 0.0] # This command produces the filter kernel coefficients filterKernel = signal.firwin2(kernelLength, keyFrequencies, gainAtKeyFrequencies) return filterKernel.astype(np.float32)
def absorption_filter(fs, ntaps=31, nfreqs=64, distance=1000, temperature=27, salinity=35, depth=10): """Design a FIR filter with response based on acoustic absorption in water. :param fs: sampling frequency in Hz :param ntaps: number of FIR taps :param nfreqs: number of frequencies to use for modeling frequency response :param distance: distance in m :param temperature: temperature in deg C :param salinity: salinity in ppt :param depth: depth in m :returns: tap weights for a FIR filter that represents absorption at the given distance >>> import arlpy >>> import numpy as np >>> fs = 250000 >>> b = arlpy.uwa.absorption_filter(fs, distance=500) >>> x = arlpy.signal.sweep(20000, 40000, 0.5, fs) >>> y = arlpy.signal.lfilter0(b, 1, x) >>> y /= 500**2 # apply spreading loss for 500m """ nyquist = fs/2.0 f = _np.linspace(0, nyquist, num=nfreqs) g = absorption(f, distance, temperature, salinity, depth) return _sp.firwin2(ntaps, f, g, nyq=nyquist)
# elimina banda frecs = [0.0, 0.3, 0.4, 0.6, 0.7, 1.0] gains = [0.0, -ripple, -atenuacion, -atenuacion, -ripple, 0.0] gains = 10**(np.array(gains) / 20) fs = 2.0 # algunas ventanas para evaluar #win_name = 'boxcar' win_name = 'hamming' #win_name = 'blackmanharris' #win_name = 'flattop' # FIR design num_win = sig.firwin2(cant_coef, frecs, gains, window=win_name) num_firls = sig.firls(cant_coef, frecs, gains, fs=fs) num_remez = sig.remez(cant_coef, frecs, gains[::2], fs=fs) # coeficientes a_0 = 1; a_i = 0, i=1:cant_coef para los filtros FIR den = 1 ww, hh_win = sig.freqz(num_win, den) _, hh_firls = sig.freqz(num_firls, den) _, hh_remez = sig.freqz(num_remez, den) ww = ww / np.pi plt.figure() plt.plot(ww, 20 * np.log10(abs(hh_win)), label='win') plt.plot(ww, 20 * np.log10(abs(hh_firls)), label='ls')
filt_gains_linear = 10**(diff_resp/20) st_freq = 1 en_freq = RATE // 2 plot_log = True freq_filt_str = 'none' filt_gains_clean, filt_gains_freq = utils.cleanup_desired_filter_gain(filt_gains_linear.copy(), freqs.copy(), freq_range=freq_filt_str, fs=RATE) # plot_resp(filt_gains_linear, freqs, '-', 'Filter gain', meas_type='filter gains', plot_in_db=True, xlim=[st_freq, en_freq], log_x=plot_log) # plot_resp(filt_gains_clean, filt_gains_freq, '-', 'Cleaned filter gain', meas_type='diff', plot_in_db=True, xlim=[st_freq, en_freq], log_x=plot_log) numtaps_fir = 769 taps = firwin2(numtaps_fir, filt_gains_freq, filt_gains_clean, fs=RATE) for tap in taps: print('{:10.12f}'.format(tap)) w, h = freqz(taps, 1.0, worN=32768) w_hz = w / max(w) * RATE / 2 with open('filt_taps_fir.txt', 'w') as out_file: for tap in taps: out_file.write('{:10.12f}'.format(tap)) out_file.write('\n') in_data = [0] * RATE in_data[0] = len(in_data) / 2
# der DurchlassbÀnder. F=[0.35 0.55] und pass_zero = 1 erzeugt Bandpass bb = sig.firwin( L, F_DB*2.0, window=FILT_FIR_WINDOW ) elif FILT_FIR_METHOD == 'WIN2': #======================================================================= ## FIRWIN2: Frequency Sampling FIR-Filterentwurf: Es wird ein linearphas. # Filter erzeugt, das bei den Frequenzen 'freq' die VerstÀrkung # 'gain' hat (entsprechend fir2 bei Matlab / Octave) # scipy.signal.firwin2(numtaps, freq, gain, nfreqs=None, window='hamming', # nyq=1.0, antisymmetric=False) # # Mit antisymmetric = True werden Filter mit ungerader Symmetrie gewÀhlt # (Typ III oder IV), je nachdem ob numtaps gerade oder ungerade ist, wird # der Typ weiter eingeschrÀnkt. bb = sig.firwin2( L, [0, F_DB, F_SB, 1], [1, 1, 0, 0], window=FILT_FIR_WINDOW ) # Example for Multi-band Hilbert Filter taken from Matlab firls reference # F = [0, 0.3, 0.4, 0.6, 0.7, 0.9, 1]; A = [0, 1, 0, 0, 0.5, 0.5, 0] # bb = sig.firwin2( 25, F,A, window='boxcar', antisymmetric=True ) # elif FILT_FIR_METHOD == 'REMEZ': #======================================================================= # Filterentwurf mit Parks-McClellan / Remez / Equiripple ... Algorithmus # # Angabe von Frequenz/Amplituden Punkten im Durchlassband und Sperrband, # optional mit Gewichtung (hier: 1 im Durchlassband, 4 im Sperrband) # print dsp.remlplen_kaiser(F_DB,F_SB,del_DB,del_SB) print (dsp.remlplen_herrmann(F_DB,F_SB,del_DB,del_SB)) print (dsp.remlplen_ichige(F_DB,F_SB,del_DB,del_SB)) L = dsp.remlplen_ichige(F_DB,F_SB,del_DB,del_SB) + 1
def filter_DBY(data): f=np.linspace(0,1,50000) a = np.ones(50000) #Switching power supply frequency (~290 KHz) a[2850:2950]=0 #AM 540 KHz a[5350:5450] = 0 #AM 580 KHz a[5750:5850] =0 #AM 740 KHz a[7350:7450] = 0 #AM 810 KHz a[8050:8150] =0 #AM 840 KHz a[8350:8450] =0 #AM 920 KHz a[9150:9250] =0 #AM 990 KHz a[9850:9950] =0 #AM 1030 KHz a[10250:10350] = 0 #AM 1060 KHz a[10550:10650] = 0 #AM 1180 KHz a[11750:11850] = 0 #AM 1240 KHz a[12350:12450] =0 #AM 1300 KHz a[12950:13050] = 0 #AM 1350 KHz a[13450:13550] = 0 #AM 1510 KHz a[15050:15150] = 0 #80 m Ham band (3.97 MHz) a[39650:39750] = 0 #80 m Ham band (4 MHz) a[39950:40050]= 0 a[-1]=0 b=sigs.firwin2(3000,f,a) [h, fpoints] = sigs.freqz(b, 1, 50000,10E6) #Run the FIR filter vec = sigs.lfilter(b,1,data) return vec
def test_input_modyfication(self): freq1 = np.array([0.0, 0.5, 0.5, 1.0]) freq2 = np.array(freq1) firwin2(80, freq1, [1.0, 1.0, 0.0, 0.0]) assert_equal(freq1, freq2)
def CicComp(fc : float, fstop : float, fs_cicout : float, cic_order : int, cic_ratio : int, fir_order : int, fir_ratio : int, cic_diffDel: int = 1, window: str = None, suppressionDb: float = 80.0, minPhase: bool = False) -> np.ndarray: """ Design CIC compensation filter. The compensatio filter does additional decimation since this is the most common approach to build compound filters. :param fc: Cutoff frequency in Hz :param fstop: Start frequency of the stop-band in Hz :param fs_cicout: Sampling frequency at the CIC output in Hz :param cic_order: Order of the CIC filter :param cic_ratio: CIC filter decimation ratio :param fir_order: Order of the FIR filter :param fir_ratio: Decimation ratio of the FIR filter :param cic_diffDel: Differential delay of CIC filter (optional, default = 1) :param window: Window type as string (e.g. "flattop", "hamming", "blackman") :param suppressionDb: Stopband suppression in dB :param minPhase: True = Design a minimum phase FIR, False = design a linear phase FIR :return: FIR coefficients """ #Derived parameters fsFirOut = fs_cicout/fir_ratio fsCicIn = fs_cicout*cic_ratio if window is None: window = "flattop" POINTS = 16384 gainStop = 1/dB2Lin(suppressionDb) #Check parameters if fc >= fstop: raise ValueError("fc must be < fstop") if fstop >= fsFirOut/2: raise ValueError("fstop must be < FIR output sample rate / 2") #Calculate Parameters fCicCorr = np.linspace(0, fs_cicout/2, POINTS) cicResp = CicFreqResp(fCicCorr, fsCicIn, cic_ratio, cic_order, normalize=True, diffDelay=cic_diffDel) hCicCorr = 1/cicResp fFir = [] hFir = [] addedFstop = False for f, h in zip(fCicCorr, hCicCorr): if f < fc: fFir.append(f) hFir.append(h) elif (f > fstop) and (f < fs_cicout/2): fFir.append(f) hFir.append(gainStop) elif not addedFstop: fFir.append(fstop) hFir.append(gainStop) addedFstop = True #Filter must have a zero at fs/2 fFir.append(fs_cicout/2) hFir.append(0) fFirNorm = np.array(fFir) / (fs_cicout/2) firCoefs = sps.firwin2(fir_order+1, fFirNorm, hFir, window=window) #Correct DC gain has priority firCoefs = firCoefs / np.sum(firCoefs) #Convert to minimum phase if required if minPhase: return MinPhaseFromLinPhase(firCoefs) return firCoefs
F_SB = f_SB/(f_S/2) # auf HALBE Abtastfreq. # A_DB = 0.1 # max. Ripple im DB in dB A_DB_lin = (10**(A_DB/20.0)-1) / \ (10**(A_DB/20.0)+1)*2 # und linear A_SB = 60 # min. Dämpfung im SB in dB A_SB_lin = 10**(-A_SB/20.0) # und linear # L = 44 # Manuelle Vorgabe Filterordnung ############## FIR-Filterentwurf ########## a = [1] # Nennerpolynom = 1 bei FIR-Filtern #=== Windowed FIR / Least Square ========= F_c = f_DB / (f_S/2) # -6dB - Frequenz b = sig.firwin(L, F_c) # Hamming-Window #=== Frequency Sampling ================== b = sig.firwin2(L, [0, F_DB, F_SB, 1], [1, 1, 0, 0]) #=== REMEZ / Parks-McClellan / Equiripple W_DB = 1; W_SB = 1 # manuelle Ordnung: b = sig.remez(L, [0, F_DB, F_SB, 1], [0, 1], [W_DB, W_SB], Hz = 2) # minimale Ordnung: (L_min,F,A,W) = dsp.remezord([F_DB, F_SB], [1, 0], [A_DB_lin, A_SB_lin], Hz = 2) b = sig.remez(L_min, F, A, W ) ############## IIR-Filterentwurf ######## #=== Butterworth Filter=================== [Lb,F_b] = sig.buttord(F_DB,F_SB,A_DB,A_SB) #[b, a] = sig.butter(Lb, F_b) #=== IIR-Wrapper (nur Python) ===== #[b, a] = sig.iirdesign(F_DB, F_SB, # A_DB, A_SB, ftype='ellip')
def test_firwin2(): """Test firwin2 backport """ taps1 = mne_firwin2(150, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0]) taps2 = signal.firwin2(150, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0]) assert_array_equal(taps1, taps2)
def cic_calc(): """ Main function: calculate fir filter compensator """ # Cutoff frequency after decimation by R: fr = Fo / R flin = np.linspace(0, 1, NFFT // 2) fhlf = np.linspace(0, 0.5, NFFT // 2) hcic = np.zeros(NFFT) hfir = np.zeros(NFFT // 2) # Calculate CIC responce: for i in range(NFFT): if i == 0: hcic[i] = 1 else: hcic[i] = R**(-N) * M**N * np.abs( np.sin(np.pi * M * R * i / NFFT) / np.sin(np.pi * i / NFFT))**N hcic_db = 20 * np.log10(hcic) # Calculate Ideal FIF filter responce: # NB! You can change FIR corrector freq bandwidth. Just multiply sine # arguments for the next equation by 2. for i in range(NFFT // 2): if i < int(Fo * NFFT): if i == 0: hfir[i] = 1 else: hfir[i] = np.abs(M * R * np.sin(np.pi * i / R / NFFT) / np.sin(np.pi * M * i / NFFT))**N else: hfir[i] = 0 # Calculate FIR by using firwin2() function: fir_win = signal.firwin2(numtaps=NFIR, freq=flin, gain=hfir, window=("kaiser", BETA)) fir_win /= np.max(fir_win) # Calculate freq responce for FIR filter fir_fft = np.abs(fft(fir_win, int(np.ceil(NFFT / R)))) fir_fft[fir_fft == 0] = 1e-10 # For log(x) function fir_db2 = 20 * np.log10(fir_fft) fir_db2 -= np.max(fir_db2) fir_rep = np.tile(fir_db2, R) fir_dif = hcic_db + fir_rep fir_dif -= np.max(fir_dif) if IS_COE: fix_coe = np.round(fir_win * ((2**NWDT - 1) - 1)) with open("fir_taps.coe", "w") as fl: fl.write("; XILINX FIR filter coefficient (.COE) File\n") fl.write("; Generated by Python " + version[0:5] + "\n") fl.write("; Generated on " + dt.datetime.now().strftime("%Y-%m-%d %H:%M") + "\n") fl.write("Radix = 10;\nCoefficient_Width = %d;\n" % NWDT) fl.write("CoefData = \n") for i in range(NFIR): fl.write("%s" % int(fix_coe[i])) if i == (NFIR - 1): fl.write(";\n") else: fl.write(",\n") fl.close() if IS_HDR: with open("fir_taps.h", "w") as fl: fl.write("/*\n * Filter Coefficients (C Source) file header\n" " * Generated by Python " + version[0:5] + "\n") fl.write(" * Generated on " + dt.datetime.now().strftime("%Y-%m-%d %H:%M") + "\n */\n\n") fl.write("const int BL = %d;\n" % NWDT) fl.write("const float B[%d] = {\n" % NWDT) for i in range(NFIR): fl.write("\t%f" % fir_win[i]) if i == (NFIR - 1): fl.write("\n};") else: fl.write(",\t") if (i + 1) % 4 == 0: fl.write("\n") fl.close() # Passband irregularity: calculate mean value and freq error p_band = int(np.ceil(0.9 * fr * fir_dif.size)) i_band = fir_dif[2:p_band] i_mean = np.mean(i_band) * np.ones(int(NFFT / 2 / R)) i_stdx = 0.5 * (np.max(i_band) - np.min(i_band)) # Plot results plt.figure("FIR Filter Compensator ideal response") plt.subplot(3, 2, 1) plt.plot(np.linspace(0, 0.5, NFFT // 2), hfir, linewidth=0.75, label="Fo = %0.2f" % Fo) plt.title("Ideal freq response") plt.grid() plt.xlim([0, 0.5]) plt.legend(loc=4) plt.subplot(3, 2, 2) plt.plot(np.linspace(-NFIR / 2, NFIR / 2, NFIR), fir_win, linewidth=0.75, label="N = %d" % NFIR) plt.title("FIR impulse response") plt.grid() plt.xlim([-NFIR / 2, NFIR / 2]) plt.legend(loc=1) plt.subplot(3, 2, 3) plt.plot(np.linspace(0, 1, NFFT), hcic_db, "-", linewidth=0.90, label="R = %d\nN = %d" % (R, N)) plt.title("CIC freq responce") plt.grid() plt.xlim([0, 1]) plt.ylim([-140, 5]) plt.legend(loc=1) plt.subplot(3, 2, 4) plt.plot(fhlf, hcic_db[0:NFFT // 2], "-.", linewidth=0.95) plt.plot(fhlf, fir_rep[0:NFFT // 2], "--", linewidth=0.95) plt.plot(fhlf, fir_dif[0:NFFT // 2], "-", linewidth=1.20) plt.title("CIC, FIR, SUM") plt.grid() plt.xlim([0, 0.5]) plt.ylim([-120, 5]) plt.subplot(3, 2, 5) plt.plot(fhlf, hcic_db[0:NFFT // 2], "-.", linewidth=0.90) plt.plot(fhlf, fir_rep[0:NFFT // 2], "--", linewidth=0.90) plt.plot(fhlf, fir_dif[0:NFFT // 2], "-", linewidth=1.20) plt.title("Zoom result") plt.grid() plt.xlim([0, 0.5 / R]) plt.ylim([-120, 5]) plt.subplot(3, 2, 6) plt.plot(fhlf, fir_dif[0:NFFT // 2], "--", linewidth=0.75) plt.plot(i_mean, "-", linewidth=1.00, label="Error = %0.4f" % i_stdx) # label="Mean = %0.4f \nError = %0.4f" % (i_mean[0], i_stdx)) plt.title("Passband irregularity") plt.grid() plt.xlim([0, fr]) plt.ylim([i_mean[0] - 3 * i_stdx, i_mean[0] + 3 * i_stdx]) plt.legend(loc=4) plt.tight_layout() plt.show()
trans_bandwidth = 10 # 10 Hz transition band f_s = f_p + trans_bandwidth # = 50 Hz freq = [0., f_p, f_s, nyq] gain = [1., 1., 0., 0.] ax = plt.subplots(1, figsize=third_height)[1] title = '%s Hz lowpass with a %s Hz transition' % (f_p, trans_bandwidth) plot_ideal_filter(freq, gain, ax, title=title, flim=flim) ############################################################################### # Accepting a shallower roll-off of the filter in the frequency domain makes # our time-domain response potentially much better. We end up with a # smoother slope through the transition region, but a *much* cleaner time # domain signal. Here again for the 1 sec filter: h = signal.firwin2(n, freq, gain, nyq=nyq) plot_filter(h, sfreq, freq, gain, 'Windowed 10-Hz transition (1.0 sec)', flim=flim) ############################################################################### # Since our lowpass is around 40 Hz with a 10 Hz transition, we can actually # use a shorter filter (5 cycles at 10 Hz = 0.5 sec) and still get okay # stop-band attenuation: n = int(round(sfreq * 0.5)) + 1 h = signal.firwin2(n, freq, gain, nyq=nyq) plot_filter(h, sfreq, freq, gain, 'Windowed 10-Hz transition (0.5 sec)', flim=flim) ############################################################################### # But then if we shorten the filter too much (2 cycles of 10 Hz = 0.2 sec),
def test_firwin2(): """Test firwin2 backport """ taps1 = mne_firwin2(150, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0]) taps2 = signal.firwin2(150, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0]) assert_equal(taps1, taps2)
def roomcomp(impresp, filter, target, ntaps, mixed_phase, opformat, trim, nsthresh, noplot): print "Loading impulse response" # Read impulse response Fs, data = wavfile.read(impresp) data = norm(np.hstack(data)) if trim: print "Removing leading silence" for spos,sval in enumerate(data): if abs(sval)>nsthresh: lzs=max(spos-1,0) ld =len(data) print 'Impulse starts at position ', spos, '/', len(data) print 'Trimming ', float(lzs)/float(Fs), ' seconds of silence' data=data[lzs:len(data)] #remove everything before sample at spos break print "\nSample rate = ", Fs print "\nGenerating correction filter" ### ## Logarithmic pole positioning ### fplog = np.hstack((sp.logspace(sp.log10(20.), sp.log10(200.), 14.), sp.logspace(sp.log10(250.), sp.log10(20000.), 13.))) plog = freqpoles(fplog, Fs) ### ## Preparing data ### # making the measured response minumum-phase cp, minresp = rceps(data) # Impulse response imp = np.zeros(len(data), dtype=np.float64) imp[0]=1.0 # Target outf = [] db = [] if target is 'flat': # Make the target output a bandpass filter Bf, Af = sig.butter(4, 30/(Fs/2), 'high') outf = sig.lfilter(Bf, Af, imp) else: # load target file t = np.loadtxt(target) frq = t[:,0]; pwr = t[:,1] # calculate the FIR filter via windowing method fir = sig.firwin2(501, frq, np.power(10, pwr/20.0), nyq = frq[-1]) # Minimum phase, zero padding cp, outf = rceps(np.append(fir, np.zeros(len(minresp) - len(fir)))) ### ## Filter design ### #Parallel filter design (Bm, Am, FIR) = parfiltid(minresp, outf, plog) # equalized loudspeaker response - filtering the # measured transfer function by the parallel filter equalizedresp = parfilt(Bm, Am, FIR, data) # Equalizer impulse response - filtering a unit pulse equalizer = norm(parfilt(Bm, Am, FIR, imp)) # Windowing with a half hanning window in time domain han = np.hanning(ntaps*2)[-ntaps:] equalizer = han * equalizer[:ntaps] ### ## Mixed-phase compensation ## Based on the paper "Mixed Time-Frequency approach for Multipoint ## Room Rosponse Equalization," by A. Carini et al. ## To use this feature, your Room Impulse Response should have all ## the leading zeros removed. ### if mixed_phase is True: # prototype function hp = norm(np.real(equalizedresp)) # time integration of the human ear is ~24ms # See "Measuring the mixing time in auditoria," by Defrance & Polack hop_size = 0.024 samples = hop_size * Fs bins = np.int(np.ceil(len(hp) / samples)) tmix = 0 # Kurtosis method for b in range(bins): start = np.int(b * samples) end = np.int((b+1) * samples) k = kurtosis(hp[start:end]) if k <= 0: tmix = b * hop_size break # truncate the prototype function taps = np.int(tmix*Fs) print "\nmixing time(secs) = ", tmix, "; taps = ", taps if taps > 0: # Time reverse the array h = hp[:taps][::-1] # create all pass filter phase = np.unwrap(np.angle(h)) H = np.exp(1j*phase) # convert from db to linear mixed = np.power(10, np.real(H)/20.0) # create filter's impulse response mixed = np.real(ifft(mixed)) # convolve and window to desired length equalizer = conv(equalizer, mixed) equalizer = han * equalizer[:ntaps] #data = han * data[:ntaps] #eqresp = np.real(conv(equalizer, data)) else: print "zero taps; skipping mixed-phase computation" if opformat in ('wav', 'wav24'): # Write data wavwrite_24(filter, Fs, norm(np.real(equalizer))) print '\nOutput format is wav24' print 'Output filter length =', len(equalizer), 'taps' print 'Output filter written to ' + filter print "\nUse sox to convert output .wav to raw 32 bit IEEE floating point if necessary," print "or to merge left and right channels into a stereo .wav" print "\nExample: sox leq48.wav -t f32 leq48.bin" print " sox -M le148.wav req48.wav output.wav\n" elif opformat == 'wav32': wavwrite_32(filter, Fs, norm(np.real(equalizer))) print '\nOutput format is wav32' print 'Output filter length =', len(equalizer), 'taps' print 'Output filter written to ' + filter print "\nUse sox to convert output .wav to raw 32 bit IEEE floating point if necessary," print "or to merge left and right channels into a stereo .wav" print "\nExample: sox leq48.wav -t f32 leq48.bin" print " sox -M le148.wav req48.wav output.wav\n" elif opformat == 'bin': # direct output to bin avoids float64->pcm16->float32 conversion by going direct #float64->float32 f = open(filter, 'wb') norm(np.real(equalizer)).astype('float32').tofile(f) f.close() print '\nOutput filter length =', len(equalizer), 'taps' print 'Output filter written to ' + filter else: print 'Output format not recognized, no file generated.' ### ## Plots ### if not noplot: data *= 500 # original loudspeaker-room response tfplot(data, Fs, avg = 'abs') # 1/3 Octave smoothed tfplots(data, Fs, 'r') #tfplot(mixed, Fs, 'r') # equalizer transfer function tfplot(0.75*equalizer, Fs, 'g') # indicating pole frequencies plt.vlines(fplog, -2, 2, color='k', linestyles='solid') # equalized loudspeaker-room response tfplot(equalizedresp*0.01, Fs, avg = 'abs') # 1/3 Octave smoothed tfplots(equalizedresp*0.01, Fs, 'r') # Add labels # May need to reposition these based on input data plt.text(325,30,'Unequalized loudspeaker-room response') plt.text(100,-15,'Equalizer transfer function') plt.text(100,-21,'(Black lines: pole locations)') plt.text(130,-70,'Equalized loudspeaker-room response') a = plt.gca() a.set_xlim([20, 20000]) a.set_ylim([-80, 80]) plt.ylabel('Amplitude (dB)', color='b') plt.xlabel('Frequency (Hz)') plt.grid() plt.legend() plt.show()
def artifact_rejection_with_lcf(eeg_data, fs, freq=(0.5, None), ref_ch=None, eeg_ch=None): """ Example function covering the steps defined in :ref:`step_by_step`. 1. **Filter the data**: FIR filters are applied within the specified range (*freq*). 2. **Check reference channel**: Re-reference the data to the specified channel (*ref_ch*). 3. **Remove the baseline**: Baseline is computed using function :func:`eeglcf.mixnp.zscore_outliers`, which ignores outliers. 4. **Reject noisy EEG channels**: Channel rejected using sample function :func:`eeglcf.lazy.noisy_ch`. 5. **Reject noisy EEG trials**: Trial rejected using sample function :func:`eeglcf.lazy.noisy_ev`. 6. **Apply the BSS algorithm**: `FastICA`_ algorithm is applied as the BSS technique, via the sample function :func:`eeglcf.lazy.fastica`. 7. **Identify artifactual components**: In this case, we do not apply this step. Hence, the architecture corresponds to the application of the LCF method by itself. 8. **Process artifactual components**: All 0s components are used as alternative components. 9. **Apply LCF**: This is: .. code-block:: python c_data = eeglcf.lcf(b_data, a_data) where *b_data* is a numpy.ndarray containing the result of applying a BSS method to EEG data, and *a_data* is an alternative "cleaner" version of the previous. Both variable have dimensions CxTxE, where C, T and E are the number of channels, time samples and events respectively. 10. **Apply the BSS^{-1} algorithm**: Back-project `FastICA`_ via the sample function :func:`eeglcf.lazy.inv_fastica`. 11. **Remove baseline**. Baseline is computed using function :func:`eeglcf.mixnp.zscore_outliers`, which ignores outliers. 12. **Reject channels inside events**: Not coded. 13. **Interpolate channels**: Not coded. Parameters ---------- eeg_data : array EEG data. fs : float EEG sampling frequency. freq : tuple Tuple with the lower and higher cut-off frequencies respectively. If freq[0] is None, no high-pass filter is applied. If freq[1] is None, no low-pass filter is applied. ref_ch : int, None Index of the EEG reference channel. If None, the EEG will be re-referenced to channel 0. eeg_ch : list, None List of the channel indices corresponding to EEG signals (i.e. excluding EOG, EMG, ...). If None, all channels will be considered EEG channels. Returns ------- res : array Clean EEG data """ # Set the dimensions of eeg_data ch_dim = 0 t_dim = 1 # ------------------------------------------------------------------------- # 1. Filter the data to remove uninteresting frequencies, which can # potentially carry noise. if freq[0] is not None: # High-pass filter the data # Design the filter. We will use a FIR filter of order 100 and a # Hamming window if freq[0] > 2: # Set a transition band of 2 Hz. x_freq = [0, freq[0]/fs, (freq[0]-2)/fs, 1] gain = [0, 0, 1, 1] else: # freq[0] <= 2 # No transition band x_freq = [0, freq[0]/fs, 1] gain = [0, 1, 1] filt_ba = [sp_signal.firwin2(numtaps=100, freq=x_freq, gain=gain, window='hamming', antisymmetric=True), np.array([1])] # High-pass filtered data hpf_data = sp_signal.filtfilt(b=filt_ba[0], a=filt_ba[1], x=eeg_data, axis=t_dim, padtype='odd', padlen=len(filt_ba[0])) else: # Do not filter hpf_data = eeg_data if freq[1] is not None: # Low-pass filter the data # Design the filter. We will use a FIR filter of order 101 and a # Hamming window if freq[1]+2 < fs: # Use a transition band of 2 Hz x_freq = [0, freq[1]/fs, (freq[1]+2)/fs, 1] gain = [1, 1, 0, 0] else: # freq[1]+2 >= fs # No transition band x_freq = [0, freq[1]/eeg_data.fs, 1] gain = [1, 1, 0] filt_ba = [sp_signal.firwin2(numtaps=101, freq=x_freq, gain=gain, window='hamming', antisymmetric=False), np.array([1])] # Low-pass filtered data f_data = sp_signal.filtfilt(b=filt_ba[0], a=filt_ba[1], x=hpf_data, axis=t_dim, padtype='odd', padlen=len(filt_ba[0])) else: # Do not filter f_data = hpf_data # ------------------------------------------------------------------------- # 2. Make sure that the data has a reference channel. # # Avoid common average reference before cleaning the signal, as it will # spread the noise throughout all channels. # Some systems, such as BIOSEMI, provide signal without reference. if ref_ch is None: # Re-reference the data to channel 0 ref_ch = 0 ref_data = f_data - f_data.take([ref_ch], axis=ch_dim) else: ref_data = f_data # ------------------------------------------------------------------------- # 3. Remove the baseline # We compute the average rejecting outliers rb_data = ref_data - mixnp.zscore_outliers(ref_data, axis=t_dim, keep_dims=True)[1] # ------------------------------------------------------------------------- # 4. Reject noisy EEG channels # Apply your preferred method for channel rejection. In this case, we will # use *noisy_ch* function as an example. if eeg_ch is None: # All channels are EEG channels eeg_ch = range(rb_data.shape[ch_dim]) sel_chs = np.array([ch_n for ch_n in range(rb_data.shape[ch_dim]) if (ch_n != ref_ch) and (ch_n in eeg_ch)]) rej_ch = noisy_ch(rb_data.take(sel_chs, axis=ch_dim)) # Adapt the list of rejected channels to consider all channels rej_ch = sel_chs[rej_ch] # Remove channels kept_ch = [ch_n for ch_n in range(rb_data.shape[ch_dim]) if ch_n not in rej_ch] ch_data = rb_data.take(kept_ch, axis=ch_dim) # You should keep the list of rejected channels if you wish to interpolate # them back into the data later on. # ------------------------------------------------------------------------- # 5. Reject noisy EEG events/trials # Apply your preferred method for event rejection. We will use the support # function *noisy_ev*. rej_ev = noisy_ev(ch_data) kept_ev = [ev_n for ev_n in range(rb_data.shape[ev_dim]) if ev_n not in rej_ev] ev_data = ch_data.take(kept_ev, axis=ev_dim) # ------------------------------------------------------------------------- # 6. Apply the BSS algorithm ica, comp = fastica(ev_data) # ------------------------------------------------------------------------- # 7. Apply the artifactual component detection and processing algorithm # In this example, we do not apply any artifactual component detection or # processing algorithm. We evaluate all components with LCF using all 0s # alternative signals. pp_comp = None rej_comps = None # ------------------------------------------------------------------------- # 8. Apply LCF if rej_comps is None: # All components considered lcf_comp = lcf(comp, pp_comp) else: # Apply LCF only to the rejected components rej_slice = [None]*3 rej_slice[ch_dim] = rej_comps lcf_comp = copy.copy(comp) lcf_comp[rej_slice] = lcf(comp[rej_slice], pp_comp[rej_slice]) # ------------------------------------------------------------------------- # 9. Back-project to the original space rc_data = inv_fastica(ica, lcf_comp) # ------------------------------------------------------------------------- # 10. Remove baseline # The baseline can be offset by the BSS processing. It is recommended to # re-remove the baseline rb_data = rc_data - mixnp.zscore_outliers(rc_data, axis=t_dim, keep_dims=True)[1] # ------------------------------------------------------------------------- # 11. Reject channels inside events # # Analyze channels within each event to reject and interpolate those that # are still too noisy. Note that the interpolation is also done within # individual events. pass # ------------------------------------------------------------------------- # 12. Interpolate channels rejected in step 4 pass return rb_data
def test_nyq(self): taps1 = firwin2(80, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0]) taps2 = firwin2(80, [0.0, 30.0, 60.0], [1.0, 1.0, 0.0], nyq=60.0) assert_array_almost_equal(taps1, taps2)
import numpy as np import scipy.signal as signal import matplotlib.pyplot as plt b = signal.firwin2(150, [0.0, 0.3, 0.6, 1.0], [1.0, 2.0, 0.5, 0.0]) w, h = signal.freqz(b) plt.title('Digital filter frequency response') plt.plot(w, np.abs(h)) plt.title('Digital filter frequency response') plt.ylabel('Amplitude Response') plt.xlabel('Frequency (rad/sample)') plt.grid() plt.show()
freq_pal4fsc = 4 * 4.43361875 Npilot = 16 #pilot_filter = sps.firwin(Npilot + 1, [3.7 / (freq_pal4fsc / 2), 3.8 / (freq_pal4fsc / 2)], window='hamming', pass_zero=False) pilot_filter = sps.firwin(Npilot + 1, [3.74 / 7.5, 3.76 / 7.5], window='hamming', pass_zero=False) WriteFilter("pilot", pilot_filter) # fm deemphasis (75us) table = [[.000, 0], [.1, -.01], [.5, -.23], [1, -.87], [2, -2.76], [3, -4.77], [4, -6.58], [5, -8.16], [6, -9.54], [7, -10.75], [8, -11.82], [9, -12.78], [10, -13.66], [11, -14.45], [12, -15.18], [13, -15.86], [14, -16.49], [15, -17.07], [16, -17.62], [17, -18.14], [18, -18.63], [19, -19.09], [20, -19.53], [24, -20]] Fr = np.empty([len(table)]) Am = np.empty([len(table)]) for i in range(0, len(table)): Fr[i] = (table[i][0] / 24.0) Am[i] = (np.exp(table[i][1] / 9.0)) Bfmdeemp = sps.firwin2(33, Fr, Am) WriteFilter("fmdeemp", Bfmdeemp) # bandpass filter for smoothing out EFM audio, fsc=8 efm_filter_bf = sps.firwin(49, [.05/freq, 1.10/freq], pass_zero=False) efm_filter_af = [1.0] WriteFilter("efm8", efm_filter_bf, efm_filter_af) # Used to determine sync status - feed it a 1 when level < 12000 (fsc8) or IRE -10 or so (fsc4) f_syncid_b, f_syncid_a = sps.butter(3, 0.002) WriteFilter("syncid8", f_syncid_b, f_syncid_a) f_syncid_b, f_syncid_a = sps.butter(3, 0.004) WriteFilter("syncid4", f_syncid_b, f_syncid_a) f_syncid_b, f_syncid_a = sps.butter(3, 0.0018)
def test_tuple(self): taps1 = firwin2(150, (0.0, 0.5, 0.5, 1.0), (1.0, 1.0, 0.0, 0.0)) taps2 = firwin2(150, [0.0, 0.5, 0.5, 1.0], [1.0, 1.0, 0.0, 0.0]) assert_array_almost_equal(taps1, taps2)
for j in range(0, 511): k = -i + 512 - 256 l = -j + 512 - 256 L_MATRIX[j, i] = np.sqrt(k**2 + (D - l)**2) L_MATRIX = L_MATRIX**(-2) / np.max(np.max(L_MATRIX**(-2))) DATA = 0 plt.figure(2) #Design of the weighted ramp filter deltaterm = np.divide((delta**2), (np.sin(delta)**2)) deltaterm[278] = 1 deltaterm[279] = 1 deltaterm[280] = 1 m = np.concatenate((np.array(np.linspace(0.1, 1 - 1 / 558, 557)), [0]), axis=0) MODIMPULSERESPONSE = (1 / 2) * signal.firwin2( 558, np.linspace(0, 1, 558), m, window='hamming') MODIMPULSERESPONSE = np.multiply(MODIMPULSERESPONSE, deltaterm) # tansformation of the weighted ramp filter after zero padding. MODFILTER = fft(MODIMPULSERESPONSE, 1117, norm="ortho") fanbeamprojection_modified1 = np.zeros((360, 558)) fanbeamprojection_modified2 = np.zeros((360, 1117), dtype=complex) fanbeamprojection_modified3 = np.zeros((360, 1117)) #%% plt.figure(5) DATA = np.zeros((511, 511)) for k in range(0, 359): RECONSTRUCTEDMATRIX = np.zeros((511, 511)) #Compuation of the Modified fanbeam projection fanbeamprojection_modified1[k] = np.multiply((D * np.cos(delta)),
def test_fs_nyq(self): taps1 = firwin2(80, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0]) taps2 = firwin2(80, [0.0, 30.0, 60.0], [1.0, 1.0, 0.0], fs=120.0) assert_array_almost_equal(taps1, taps2) taps2 = firwin2(80, [0.0, 30.0, 60.0], [1.0, 1.0, 0.0], nyq=60.0) assert_array_almost_equal(taps1, taps2)
gstop=atenuacion, analog=False, ftype='ellip', output='sos') bp_sos_cheby2 = sig.iirdesign(wp=np.array([wp1, wp2]) / nyq_frec, ws=np.array([ws1, ws2]) / nyq_frec, gpass=ripple, gstop=atenuacion, analog=False, ftype='cheby2', output='sos') #bp_sos_bessel = sig.iirdesign(wp=np.array([wp1, wp2]) / nyq_frec, ws=np.array([ws1, ws2]) / nyq_frec, gpass=ripple, gstop=atenuacion, analog=False, ftype='bessel', output='sos') cant_coef = 501 den = 1.0 num_win = sig.firwin2(cant_coef, frecs, gains, window='blackmanharris') # el _ es porque todo devuelve lo mismo,no? # Devuelve un vector de frecuencias y un vector con sus respuestas w, h_butter = sig.sosfreqz(bp_sos_butter) _, h_cheby = sig.sosfreqz(bp_sos_cheby) _, h_cauer = sig.sosfreqz(bp_sos_cauer) _, h_cheby2 = sig.sosfreqz(bp_sos_cheby2) #_, h_bessel = sig.sosfreqz(bp_sos_bessel) _, hh_win = sig.freqz(num_win, den) w = w / np.pi * nyq_frec plt.figure(1) plt.plot(w, 20 * np.log10(np.abs(h_butter)), label='IIR-Butter') plt.plot(w, 20 * np.log10(np.abs(h_cheby)), label='IIR-Cheby')
def design_FIR(taps, sample_rate): nyquist = sample_rate/2 return signal.firwin2(taps, [0, nyquist/2, nyquist], [1, 1, 0], nyq=nyquist)