def test_plot_frequency_response(): coefs = design_fir_filter(FS, 'bandpass', (8, 12), 3) f_db, db = compute_frequency_response(coefs, a_vals=1, fs=FS) plot_frequency_response(f_db, db, save_fig=True, file_path=TEST_PLOTS_PATH, file_name='test_plot_frequency_response.png')
def test_plot_frequency_response(): coefs = design_fir_filter(2000, 1000, 'bandpass', (8, 12), 3) f_db, db = compute_frequency_response(coefs, a_vals=1, fs=1000) plot_frequency_response(f_db, db) assert True
def test_plot_filter_properties(): fs = 1000 coefs = design_fir_filter(2000, fs, 'bandpass', (8, 12), 3) f_db, db = compute_frequency_response(coefs, a_vals=1, fs=1000) plot_filter_properties(f_db, db, fs, coefs) assert True
def filter_signal_iir(sig, fs, pass_type, f_range, butterworth_order, print_transitions=False, plot_properties=False, return_filter=False): """Apply an IIR filter to a signal. Parameters ---------- sig : array Time series to be filtered. fs : float Sampling rate, in Hz. pass_type : {'bandpass', 'bandstop', 'lowpass', 'highpass'} Which kind of filter to apply: * 'bandpass': apply a bandpass filter * 'bandstop': apply a bandstop (notch) filter * 'lowpass': apply a lowpass filter * 'highpass' : apply a highpass filter f_range : tuple of (float, float) or float Cutoff frequency(ies) used for filter, specified as f_lo & f_hi. For 'bandpass' & 'bandstop', must be a tuple. For 'lowpass' or 'highpass', can be a float that specifies pass frequency, or can be a tuple and is assumed to be (None, f_hi) for 'lowpass', and (f_lo, None) for 'highpass'. butterworth_order : int Order of the butterworth filter, if using an IIR filter. See input 'N' in scipy.signal.butter. print_transitions : bool, optional, default: False If True, print out the transition and pass bandwidths. plot_properties : bool, optional, default: False If True, plot the properties of the filter, including frequency response and/or kernel. return_filter : bool, optional, default: False If True, return the filter coefficients of the IIR filter. Returns ------- sig_filt : 1d array Filtered time series. filter_coefs : tuple of (1d array, 1d array) Filter coefficients of the IIR filter, as (b_vals, a_vals). Only returned if `return_filter` is True. """ # Design filter b_vals, a_vals = design_iir_filter(fs, pass_type, f_range, butterworth_order) # Check filter properties: compute transition bandwidth & run checks check_filter_properties(b_vals, a_vals, fs, pass_type, f_range, verbose=print_transitions) # Remove any NaN on the edges of 'sig' sig, sig_nans = remove_nans(sig) # Apply filter sig_filt = apply_iir_filter(sig, b_vals, a_vals) # Add NaN back on the edges of 'sig', if there were any at the beginning sig_filt = restore_nans(sig_filt, sig_nans) # Plot frequency response, if desired if plot_properties: f_db, db = compute_frequency_response(b_vals, a_vals, fs) plot_frequency_response(f_db, db) if return_filter: return sig_filt, (b_vals, a_vals) else: return sig_filt
def check_filter_properties(b_vals, a_vals, fs, pass_type, f_range, transitions=(-20, -3), verbose=True): """Check a filters properties, including pass band and transition band. Parameters ---------- b_vals : 1d array B value filter coefficients for a filter. a_vals : 1d array A value filter coefficients for a filter. fs : float Sampling rate, in Hz. pass_type : {'bandpass', 'bandstop', 'lowpass', 'highpass'} Which kind of filter to apply: * 'bandpass': apply a bandpass filter * 'bandstop': apply a bandstop (notch) filter * 'lowpass': apply a lowpass filter * 'highpass' : apply a highpass filter f_range : tuple of (float, float) or float Cutoff frequency(ies) used for filter, specified as f_lo & f_hi. For 'bandpass' & 'bandstop', must be a tuple. For 'lowpass' or 'highpass', can be a float that specifies pass frequency, or can be a tuple and is assumed to be (None, f_hi) for 'lowpass', and (f_lo, None) for 'highpass'. transitions : tuple of (float, float), optional, default: (-20, -3) Cutoffs, in dB, that define the transition band. verbose : bool, optional, default: True Whether to print out transition and pass bands. Returns ------- passes : bool Whether all the checks pass. False if one or more checks fail. """ # Import utility functions inside function to avoid circular imports from neurodsp.filt.utils import (compute_frequency_response, compute_pass_band, compute_transition_band) # Initialize variable to keep track if all checks pass passes = True # Compute the frequency response f_db, db = compute_frequency_response(b_vals, a_vals, fs) # Check that frequency response goes below transition level (has significant attenuation) if np.min(db) >= transitions[0]: passes = False warn('The filter attenuation never goes below {} dB.'\ 'Increase filter length.'.format(transitions[0])) # If there is no attenuation, cannot calculate bands, so return here return passes # Check that both sides of a bandpass have significant attenuation if pass_type == 'bandpass': if db[0] >= transitions[0] or db[-1] >= transitions[0]: passes = False warn('The low or high frequency stopband never gets attenuated by'\ 'more than {} dB. Increase filter length.'.format(abs(transitions[0]))) # Compute pass & transition bandwidth pass_bw = compute_pass_band(fs, pass_type, f_range) transition_bw = compute_transition_band(f_db, db, transitions[0], transitions[1]) # Raise warning if transition bandwidth is too high if transition_bw > pass_bw: passes = False warn('Transition bandwidth is {:.1f} Hz. This is greater than the desired'\ 'pass/stop bandwidth of {:.1f} Hz'.format(transition_bw, pass_bw)) # Print out transition bandwidth and pass bandwidth to the user if verbose: print('Transition bandwidth is {:.1f} Hz.'.format(transition_bw)) print('Pass/stop bandwidth is {:.1f} Hz.'.format(pass_bw)) return passes
def test_plot_frequency_response(): coefs = design_fir_filter(FS, 'bandpass', (8, 12), 3) f_db, db = compute_frequency_response(coefs, a_vals=1, fs=FS) plot_frequency_response(f_db, db)
def filter_signal_fir(sig, fs, pass_type, f_range, n_cycles=3, n_seconds=None, remove_edges=True, print_transitions=False, plot_properties=False, return_filter=False): """Apply an FIR filter to a signal. Parameters ---------- sig : array Time series to be filtered. fs : float Sampling rate, in Hz. pass_type : {'bandpass', 'bandstop', 'lowpass', 'highpass'} Which kind of filter to apply: * 'bandpass': apply a bandpass filter * 'bandstop': apply a bandstop (notch) filter * 'lowpass': apply a lowpass filter * 'highpass' : apply a highpass filter f_range : tuple of (float, float) or float Cutoff frequency(ies) used for filter, specified as f_lo & f_hi. For 'bandpass' & 'bandstop', must be a tuple. For 'lowpass' or 'highpass', can be a float that specifies pass frequency, or can be a tuple and is assumed to be (None, f_hi) for 'lowpass', and (f_lo, None) for 'highpass'. n_cycles : float, optional, default: 3 Length of filter, in number of cycles, defined at the 'f_lo' frequency. This parameter is overwritten by `n_seconds`, if provided. n_seconds : float, optional Length of filter, in seconds. This parameter overwrites `n_cycles`. remove_edges : bool, optional If True, replace samples within half the kernel length to be np.nan. print_transitions : bool, optional, default: False If True, print out the transition and pass bandwidths. plot_properties : bool, optional, default: False If True, plot the properties of the filter, including frequency response and/or kernel. return_filter : bool, optional, default: False If True, return the filter coefficients of the FIR filter. Returns ------- sig_filt : array Filtered time series. filter_coefs : 1d array Filter coefficients of the FIR filter. Only returned if `return_filter` is True. Examples -------- Apply a band pass FIR filter to a simulated signal: >>> from neurodsp.sim import sim_combined >>> sig = sim_combined(n_seconds=10, fs=500, ... components={'sim_powerlaw': {}, 'sim_oscillation' : {'freq': 10}}) >>> filt_sig = filter_signal_fir(sig, fs=500, pass_type='bandpass', f_range=(1, 25)) Apply a high pass FIR filter to a signal, with a specified number of cycles: >>> sig = sim_combined(n_seconds=10, fs=500, ... components={'sim_powerlaw': {}, 'sim_oscillation' : {'freq': 10}}) >>> filt_sig = filter_signal_fir(sig, fs=500, pass_type='highpass', f_range=(2, None), n_cycles=5) """ # Design filter & check that the length is okay with signal filter_coefs = design_fir_filter(fs, pass_type, f_range, n_cycles, n_seconds) check_filter_length(sig.shape[-1], len(filter_coefs)) # Check filter properties: compute transition bandwidth & run checks check_filter_properties(filter_coefs, 1, fs, pass_type, f_range, verbose=print_transitions) # Remove any NaN on the edges of 'sig' sig, sig_nans = remove_nans(sig) # Apply filter sig_filt = apply_fir_filter(sig, filter_coefs) # Remove edge artifacts if remove_edges: sig_filt = remove_filter_edges(sig_filt, len(filter_coefs)) # Add NaN back on the edges of 'sig', if there were any at the beginning sig_filt = restore_nans(sig_filt, sig_nans) # Plot filter properties, if specified if plot_properties: f_db, db = compute_frequency_response(filter_coefs, 1, fs) plot_filter_properties(f_db, db, fs, filter_coefs) if return_filter: return sig_filt, filter_coefs else: return sig_filt
def filter_signal_iir(sig, fs, pass_type, f_range, butterworth_order, print_transitions=False, plot_properties=False, return_filter=False): """Apply an IIR filter to a signal. Parameters ---------- sig : array Time series to be filtered. fs : float Sampling rate, in Hz. pass_type : {'bandpass', 'bandstop', 'lowpass', 'highpass'} Which kind of filter to apply: * 'bandpass': apply a bandpass filter * 'bandstop': apply a bandstop (notch) filter * 'lowpass': apply a lowpass filter * 'highpass' : apply a highpass filter f_range : tuple of (float, float) or float Cutoff frequency(ies) used for filter, specified as f_lo & f_hi. For 'bandpass' & 'bandstop', must be a tuple. For 'lowpass' or 'highpass', can be a float that specifies pass frequency, or can be a tuple and is assumed to be (None, f_hi) for 'lowpass', and (f_lo, None) for 'highpass'. butterworth_order : int Order of the butterworth filter, if using an IIR filter. See input 'N' in scipy.signal.butter. print_transitions : bool, optional, default: False If True, print out the transition and pass bandwidths. plot_properties : bool, optional, default: False If True, plot the properties of the filter, including frequency response and/or kernel. return_filter : bool, optional, default: False If True, return the second order series coefficients of the IIR filter. Returns ------- sig_filt : 1d array Filtered time series. sos : 2d array Second order series coefficients of the IIR filter. Has shape of (n_sections, 6). Only returned if `return_filter` is True. Examples -------- Apply a bandstop IIR filter to a simulated signal: >>> from neurodsp.sim import sim_combined >>> sig = sim_combined(n_seconds=10, fs=500, ... components={'sim_powerlaw': {}, 'sim_oscillation' : {'freq': 10}}) >>> filt_sig = filter_signal_iir(sig, fs=500, pass_type='bandstop', ... f_range=(55, 65), butterworth_order=7) """ # Design filter sos = design_iir_filter(fs, pass_type, f_range, butterworth_order) # Check filter properties: compute transition bandwidth & run checks check_filter_properties(sos, None, fs, pass_type, f_range, verbose=print_transitions) # Remove any NaN on the edges of 'sig' sig, sig_nans = remove_nans(sig) # Apply filter sig_filt = apply_iir_filter(sig, sos) # Add NaN back on the edges of 'sig', if there were any at the beginning sig_filt = restore_nans(sig_filt, sig_nans) # Plot frequency response, if desired if plot_properties: f_db, db = compute_frequency_response(sos, None, fs) plot_frequency_response(f_db, db) if return_filter: return sig_filt, sos else: return sig_filt
butterworth_order = 12 # Design the filter, getting the second-order series (sos) values for the filter sos = design_iir_filter(fs, pass_type, f_range, butterworth_order) ################################################################################################### # # Now that we have our filter definition, we can evaluate our filter. # # Next, we can calculate the frequency response, :math:`b_k`, for our IIR filter. # ################################################################################################### # Compute the frequency response for the IIR filter f_db, db = compute_frequency_response(sos, None, fs) # Plot the frequency response plot_frequency_response(f_db, db) ################################################################################################### # # Above, we can see our frequency response of our filter, which shows us how different # frequencies are affected by our filter. Ideally, we want zero attenuation in our passband, # and a lot of attenuation in the stopband(s). # # Another way to quantify these properties is the transition band, which is bandwidth (in Hz) # that it takes for the filter to change from high to low attenuation. This quantifies how # sharp the transition is between stopband and passband. By default, transition bands are computed # as the range between -20 dB and -3 dB attenuation, but you can also customize these values. #
n_cycles = 3 # Design the filter coefficients for a specified filter filter_coefs = design_fir_filter(fs, pass_type, f_range, n_cycles=n_cycles) ################################################################################################### # # Now that we have our filter coefficients, we can evaluate our filter. # # Next, we can calculate the frequency response, :math:`b_k`, for our alpha bandpass filter. # ################################################################################################### # Compute the frequency response of the filter f_db, db = compute_frequency_response(filter_coefs, 1, fs) # Plot the filter properties plot_filter_properties(f_db, db, fs, filter_coefs) ################################################################################################### # # On the right is the impulse response, or the filter kernel. This is a visualization of our # filter coefficients, which also demonstrates the activity of our filter for a single point # (the impulse response). # # On the left, we can see the frequency response of our filter, which shows us how different # frequencies are affected by our filter. Ideally, we want zero attenuation in our passband, # and a lot of attenuation in the stopband(s). # # Another way to quantify these properties is the transition band, which is bandwidth (in Hz)