def test_tf2minphase(self): htest = np.copy(self.h) h_min = adsp.tf2minphase(htest) # test group delay _, orig_delay = signal.group_delay((htest, 1)) _, min_delay = signal.group_delay((h_min, 1)) self.assertTrue(min_delay[0] <= orig_delay[0], 'Minimum phase IR does not have minimum group delay!')
def main(): if voucher_val == 'Slayerz': voucher_page() else: if add_selectbox == 'Lowpass': N = int( st.slider('Select butterfilter order', min_value=0, max_value=10)) system = dsp.butter(N, 25, fs=fs) lp_filtered = dsp.lfilter(*system, chrp) ww, gd = dsp.group_delay(system, fs=fs) fig, ax = plt.subplots(2, 1, figsize=[12, 9]) ax[0].plot(t, lp_filtered) ax[0].set_title('Lowpass filtered') ax[0].set_xlabel('Time') ax[0].set_ylabel('Amplitude') ax[1].plot(ww, gd) ax[1].set_title('Filter group delay') ax[1].set_xlabel('Frequency') ax[1].set_ylabel('Delay samples') plt.tight_layout() st.pyplot() if add_selectbox == 'Highpass': N = int( st.slider('Select butterfilter order', min_value=0, max_value=10)) system = dsp.butter(N, 25, btype='high', fs=fs) hp_filtered = dsp.lfilter(*system, chrp) ww, gd = dsp.group_delay(system, fs=fs) fig, ax = plt.subplots(2, 1, figsize=[12, 9]) ax[0].plot(t, hp_filtered) ax[0].set_title('Lowpass filtered') ax[0].set_xlabel('Time') ax[0].set_ylabel('Amplitude') ax[1].plot(ww, gd) ax[1].set_title('Filter group delay') ax[1].set_xlabel('Frequency') ax[1].set_ylabel('Delay samples') plt.tight_layout() st.pyplot() if add_selectbox == 'Original': plt.plot(t, chrp) plt.title('Chirp') plt.xlabel('Time') plt.ylabel('Amplitude') st.pyplot()
def char_plot(num, denom, sample_rate): w, h = freqz(num, denom) figure(1) subplot(2,1,1) hold(True) pow = plot((sample_rate*0.5/pi)*w, abs(h),'b-', label = 'Char. amplitudowa') title('Charakterystyki filtru') xlabel('Czestotliwosc [Hz]') ylabel('Amplituda') twinx(ax=None) angles = unwrap(angle(h)) aznie = plot((sample_rate*0.5/pi)*w, angles, 'g-', label = 'Char. fazowa') ylabel('Faza') grid() tekst = pow + aznie wybierz = [l.get_label() for l in tekst] legend(tekst, wybierz, loc='best') ######################################################################################################################## subplot(2,1,2) w2, gd = group_delay((num, denom)) plot((sample_rate*0.5/pi)*w2, gd) grid() xlabel('Czestotliwosc [Hz]') ylabel('Opoznienie grupowe [probki]') title('Opoznienie grupowe filtru') show()
def get_plot_data(fs_hz, number_coeffs, f_low_hz, f_high_hz, rp, rs, f_type, design): if f_type == 'lowpass': Wn = f_low_hz elif f_type == 'highpass': Wn = f_high_hz else: Wn = [f_low_hz, f_high_hz] if design not in ['cheby1', 'cheby2', 'ellip']: rp = None rs = None b, a = signal.iirfilter(number_coeffs, Wn, rp=rp, rs=rs, btype=f_type, ftype=design, output='ba', fs=fs_hz) worN = np.logspace(0, 4, num=1024) * (fs_hz / 2) / 1e4 frequency_hz, h = signal.freqz(b, a, worN=worN, fs=fs_hz, include_nyquist=False) _, gd_samples = signal.group_delay((b, a), w=worN, fs=fs_hz) amplitude_dB = 20 * np.log10(abs(h)) angle_deg = np.unwrap(np.angle(h)) * (180 / np.pi) return frequency_hz, amplitude_dB, angle_deg, gd_samples
def show_filters(filters, fs, ideal_delays=[]): fig, (linax, logax, grpax) = plt.subplots(3) for fil in filters: print_filter(fil) w, h = sps.freqz(fil.b, fil.a, fs=fs) linax.plot(w, np.abs(h)) logax.plot(w, 20 * np.log10(np.abs(h))) dw, d = sps.group_delay((fil.b, fil.a), w, fs=fs) grpax.plot(dw, d - d[0]) for ideal in ideal_delays: xs = np.linspace(ideal.fs[0], ideal.fs[-1], num=1000) vs_interp = sint.interp1d(ideal.fs, ideal.vs, kind='quadratic')(xs) grpax.plot(ideal.fs, ideal.vs, 'o') if ideal.tols is not None: tols_interp = sint.interp1d(ideal.fs, ideal.tols, kind='quadratic')(xs) grpax.fill_between(xs, vs_interp - tols_interp, vs_interp + tols_interp, alpha=0.2) for ax in (linax, logax, grpax): if ax is grpax: extras = [ideal.name for ideal in ideal_delays] else: extras = [] ax.legend(['%s <%d>' % (fil.name, len(fil.b)) for fil in filters] + extras) ax.set_xlabel('Frequency') ax.set_xlim(0, fs / 2) ax.grid(True) linax.set_ylabel('Magnitude response (linear)') logax.set_ylabel('Magnitude response (dB)') grpax.set_ylabel('Relative group delay (samples)') plt.show()
def filter_char(b, a, show=True): # Pole-zero characteristics zero, pole, __ = sp.tf2zpk(b, a) if (pole.shape < zero.shape): pole = np.concatenate( (pole, np.zeros(zero.shape[0] - pole.shape[0], dtype=complex))) zp = [zero, pole] # Magnitude and Phase Characteristics w1, H = sp.freqz(b, a, 1024, whole=True) # Time domain sequence (= Coefficients for given filter since it is FIR) h = ifft(H) ii = np.where(abs(h) > 1e-4) h = np.real( h[ii]) # remove noisy imaginary components- h is a real FIR filter # Group Delay of Filter w2, gd = sp.group_delay((b, a), whole=True) if show == True: plt.figure("Pole-Zero Plot") plt.polar(np.angle(zp[0]), np.abs(zp[0]), 'bo') plt.polar(np.angle(zp[1]), np.abs(zp[1]), 'gx') plt.polar(np.linspace(0, 2 * pi, 360), np.ones(360), 'k-') plt.title("Pole-Zero Plot") plt.figure("Mag-Phase Characteristics") plt.subplot(211) plt.plot(w1, abs(H)) plt.title("Mag-Phase Characteristics of FIR filter") plt.subplot(212) plt.plot(w1, np.unwrap(np.angle(H))) plt.figure("h[n]") plt.plot(h, "ro") plt.title("Time Domain: FIR Filter") plt.figure("Group Delay of Filter") plt.plot(w2, gd) plt.title("Group Delay of Filter") return zp, H, h, gd
def plot_group_delay(b, a): w, gd = signal.group_delay((b, a)) plt.plot(w, np.round(gd, 5)) plt.ylabel('Retardo de grupo [muestras]') plt.xlabel('Frecuencia [rad/muestra]') plt.title('Retardo de grupo') plt.show()
def plot_groupdelay_error(prefix, irs, delta_min, omega_max): omega_max *= numpy.pi pyplot.figure(figsize=(8, 4.8), dpi=100) pyplot.title(f"{prefix} Group Delay, N={len(irs[0])}") ax = pyplot.gca() ax.grid() cmap = pyplot.get_cmap("plasma") for index, ir in enumerate(irs): w, gd = signal.group_delay((ir, [1])) trim = numpy.searchsorted(w, omega_max) ax.plot( w[:trim + 1], gd[:trim + 1] - delta_min - index / (len(irs) - 1), label=str(delta_min + index / (len(irs) - 1)), color=cmap(index / len(irs)), lw=1, ) ax.axvline(omega_max, label="$\omega_{\max}$", color="black", alpha=0.25, ls="--") ax.set_ylabel("Error [samples]") ax.set_xlabel("Frequency [rad/sample]") ax.legend(ncol=2) pyplot.savefig(f"img/{prefix}_error.png", dpi=100)
def plotSos(sos, oversample, fs, worN=2048): fig, ax = plt.subplots(3, 1) fig.set_size_inches(6, 8) fig.set_tight_layout(True) ax[0].set_title("Amplitude Response") ax[0].set_ylabel("Amplitude [dB]") ax[1].set_title("Phase Response") ax[1].set_ylabel("Phase [rad]") ax[2].set_title("Group Delay") ax[2].set_ylabel("Group Delay [sample]") ax[2].set_xlabel("Frequency [rad/sample]") cmap = plt.get_cmap("plasma") freq, h0 = signal.sosfreqz(sos, worN=worN, fs=oversample * fs) b, a = signal.sos2tf(sos) _, gd = signal.group_delay((b, a), w=worN) ax[0].plot(freq, ampToDecibel(h0), alpha=0.75, color="black") ax[0].set_ylim((-140, 5)) ax[1].plot(freq, np.unwrap(np.angle(h0)), alpha=0.75, color="black") ax[2].plot(freq, gd, alpha=0.75, color="black") for axis in ax: # axis.set_xscale("log") axis.grid(which="both") plt.show()
def plot_filter_characteristics(self): w, h = freqz(self.freq_filter.num, self.freq_filter.denom) plt.figure(1) plt.subplot(2,1,1) plt.hold(True) powa = plt.plot((self.filter_parameters.sample_rate*0.5/pi)*w, abs(h),'b-', label = 'Char. amplitudowa') plt.title('Charakterystyki filtru') plt.xlabel('Czestotliwosc [Hz]') plt.ylabel('Amplituda') plt.twinx(ax=None) angles = unwrap(angle(h)) plt.znie = plot((self.filter_parameters.sample_rate*0.5/pi)*w,angles, 'g-', label = 'Char. fazowa') plt.ylabel('Faza') plt.grid() tekst = powa + znie wybierz = [l.get_label() for l in tekst] plt.legend(tekst, wybierz, loc='best') ######################################################################################################################## plt.subplot(2,1,2) w2, gd = group_delay((num, denom)) plt.plot((sample_rate*0.5/pi)*w2, gd) plt.grid() plt.xlabel('Czestotliwosc [Hz]') plt.ylabel('Opoznienie grupowe [probki]') plt.title('Opoznienie grupowe filtru') plt.show()
def plot(firTable, ylim): fig, ax = plt.subplots(3, 1) fig.set_size_inches(6, 8) fig.set_tight_layout(True) ax[0].set_title("Amplitude Response") ax[0].set_ylabel("Amplitude [dB]") ax[1].set_title("Phase Response") ax[1].set_ylabel("Phase [degree]") ax[2].set_title("Group Delay") ax[2].set_ylabel("Group Delay [sample]") ax[2].set_xlabel("Frequency [rad/sample]") ax[2].set_ylim(ylim) cmap = plt.get_cmap("plasma") for index, fir in enumerate(firTable): freq, mag, phase = signal.dbode((fir, 1, 1), n=1024) freq, gd = signal.group_delay((fir, 1), w=1024) cmapValue = index / len(firTable) ax[0].plot(freq, mag, alpha=0.75, color=cmap(cmapValue), label=f"{index}") ax[1].plot(freq, phase, alpha=0.75, color=cmap(cmapValue), label=f"{index}") ax[2].plot(freq, gd, alpha=0.75, color=cmap(cmapValue), label=f"{index}") for axis in ax: axis.grid() axis.legend() plt.show()
def test_grpdelay_1(self): # Test case for FIR filter fil = FIRDesign.fir1(self.order, self.cut) w, gd = signal.group_delay(fil, w=512, fs=2 * np.pi) gd = np.round(gd) ww, gdgd = FilterSpec.grpdelay(fil) self.assertTrue(np.all(w == ww) and np.all(gd == gdgd))
def group_delayz(b, a, w, plot=None, fs=2*np.pi): """ Compute the group delay of digital filter. Parameters ---------- b : array_like Numerator of a linear filter. a : array_like Denominator of a linear filter. w : array_like Frequencies in the same units as `fs`. plot : callable A callable that takes two arguments. If given, the return parameters `w` and `gd` are passed to plot. fs : float, optional The angular sampling frequency of the digital system. Returns ------- w : ndarray The frequencies at which `gd` was computed, in the same units as `fs`. gd : ndarray The group delay in seconds. """ b, a = map(np.atleast_1d, (b, a)) if len(a) == 1: # scipy.signal.group_delay returns gd in samples thus scaled by 1/fs gd = sig.group_delay((b, a), w=w, fs=fs)[1] else: sos = sig.tf2sos(b, a) gd = sos_group_delayz(sos, w, plot, fs)[1] if plot is not None: plot(w, gd) return w, gd
def plot_filter(b, a, dB=True, plot_gd=False): ''' Plots a filter's response ''' w, h = freqz(b, a) fig = plt.figure() ax1 = fig.add_subplot(1, 1, 1) ax1.set_title('frequency response') if dB: ax1.plot(w, 20 * np.log10(abs(h)), 'b', linewidth=2) ax1.set_ylabel('$20log_{10}|H|$', color='b') else: ax1.plot(w, abs(h), 'b') ax1.set_ylabel('$|H|$', color='b') ax1.set_xlabel('frequency [Rad/Sample]') ax1.grid() if plot_gd: ax2 = ax1.twinx() w, gd = group_delay((b, a), w) ax2.plot(w, gd, 'g', linewidth=2) ax2.set_ylabel('Group Delay [s]', color='g') fig.show() return
def filterplot(H): H = H[1] t1 = np.shape(H) f = np.linspace(-.5, .5, t1[2]) fig = plt.figure() ax1 = fig.add_subplot(311) ax1.plot(f, 20*np.log10(abs(npfft.fftshift(npfft.fft(H))))) ax1.set_xlabel('Uniform frequnency') ax1.set_ylabel('Power (dB)') ax1.set_title('Filter properties') ax1.grid(True) ax2 = fig.add_subplot(312) a = np.unwrap(np.angle(npfft.fftshift(npfft.fft(H)))) ax2.plot(f, a) ax2.set_xlabel('Uniform frequency') ax2.set_ylabel('Angle (rad)') ax2.axis([-.5, .5, min(a), 0]) ax2.grid(True) ax3 = fig.add_subplot(313) a = sps.group_delay((H, 1)) ax3.plot(np.linspace(-.5, .5, 512), npfft.fftshift(a) - t1(2)/2) ax3.set_xlabel('Uniform frequency') ax3.set_ylabel('Group delay') ax3.axis([-.5, .5, -500, 500]) ax3.grid(True)
def plotFilter(b, a, mag_type='abs', fs=2, ax1=None): w1, h = sig.freqz(b, a, fs=fs) w2, gd = sig.group_delay((b, a), fs=fs) if ax1 is None: fig, ax1 = plt.subplots() ax1.set_title('Digital filter frequency response') # ax1.plot(w1, 20 * np.log10(abs(h)), 'b') # ax1.plot(w1[:-1], (abs(h[:-1]) - abs(h[1:]))/(w1[1]-w1[0]), 'b') if mag_type == 'abs': mag = np.abs(h) mag_label = 'Magnitude' elif mag_type == 'dB': mag = 20 * np.log10(np.abs(h)) mag_label = 'Magnitude [dB]' elif mag_type == 'loss': mag = 20 * np.log10(1 / np.abs(h)) mag_label = 'Attenuation [dB]' ax1.plot(w1, mag, 'b') ax1.set_ylabel(mag_label, color='b') ax1.set_xlabel('Frequency [normalized]') ax2 = ax1.twinx() ax2.plot(w2, gd, 'g') ax2.set_ylabel('Group delay', color='g') ax2.grid() ax2.axis('tight') if mag_type == 'loss': ax2.set_ylim(-5, 5)
def lfilter0(b, a, x, axis=-1): """Filter data with an IIR or FIR filter with zero DC group delay. :func:`scipy.signal.lfilter` provides a way to filter a signal `x` using a FIR/IIR filter defined by `b` and `a`. The resulting output is delayed, as compared to the input by the group delay. This function corrects for the group delay, resulting in an output that is synchronized with the input signal. If the filter as an acausal impulse response, some precursor signal from the output will be lost. To avoid this, pad input signal `x` with sufficient zeros at the beginning to capture the precursor. Since both, :func:`scipy.signal.lfilter` and this function return a signal with the same length as the input, some signal tail is lost at the end. To avoid this, pad input signal `x` with sufficient zeros at the end. See documentation for :func:`scipy.signal.lfilter` for more details. >>> import arlpy >>> import numpy as np >>> fs = 250000 >>> b = arlpy.uwa.absorption_filter(fs, distance=500) >>> x = np.pad(arlpy.signal.sweep(20000, 40000, 0.5, fs), (127, 127), 'constant') >>> y = arlpy.signal.lfilter0(b, 1, x) """ w, g = _sig.group_delay((b, a)) ndx = _np.argmin(_np.abs(w)) d = int(round(g[ndx])) x = _np.apply_along_axis(lambda a: _np.pad(a, (0, d), 'constant'), axis, x) y = _sig.lfilter(b, a, x, axis)[d:] return y
def group_delay(w,phase,b,a): w, gd = sg.group_delay((b, a),w=w) plt.figure(6) plt.title('WMA filter group delay') plt.plot(w[1:990]/(2*np.pi),np.round(gd[1:990])) plt.ylabel('Group delay [samples]') plt.xlabel('Frequency [Hz]') plt.savefig(file_gd)
def freqz_plot(line, cell): # line, cellをparse N, FS = [float(v) for v in line.split()] ba = cell.split("\n") b = [float(v) for v in ba[0].split(",")] a = [float(v) for v in ba[1].split(",")] # 時間特性、周波数特性、位相特性、群遅延特性等を計算 w, h = sg.freqz(b, a, worN=int(N)) f = w * FS / (2.0 * np.pi) z, p, k = sg.tf2zpk(b, a) _, gd = sg.group_delay((b, a), w=w) # 上記パラメータをプロット fig = plt.figure(1, figsize=(8, 12)) ax = fig.add_subplot(321) ax.plot(b, "o-") ax.plot(a, "x-") ax.grid() ax.set_xlabel("time [pt]") ax.set_ylabel("amplitude") ax = fig.add_subplot(322) ax.semilogx(f, 20.0 * np.log10(np.abs(h))) ax.grid() ax.set_xlabel("frequency [Hz]") ax.set_ylabel("power [dB]") ax.set_xlim([10.0, FS/2.0]) ax.set_ylim([-40.0, 10.0]) ax = fig.add_subplot(323) ax.semilogx(f, np.angle(h)) ax.grid() ax.set_xlim([10.0, FS/2.0]) ax.set_ylim([-np.pi, np.pi]) ax.set_xlabel("frequency [Hz]") ax.set_ylabel("phase [rad]") ax = fig.add_subplot(324) ax.semilogx(f, gd) ax.grid() ax.set_xlabel("frequency [Hz]") ax.set_ylabel("group delay [pt]") ax.set_xlim([10.0, FS/2.0]) ax.set_ylim([-40.0, 40.0]) ax = fig.add_subplot(325) ax.add_patch(plt.Circle((0.0, 0.0), 1.0, fc="white")) ax.plot(np.real(z), np.imag(z), "o", mfc="white") ax.plot(np.real(p), np.imag(p), "x", mfc="white") ax.grid() ax.set_xlim([-1.5, 1.5]) ax.set_ylim([-1.5, 1.5]) plt.show()
def set_band_pass(self): self.num = [1, 0] self.den = [1, 1, 1] self.sys = signal.TransferFunction([1, 0], [1, 1, 1]) self.w, self.mag, self.phase = signal.bode(self.sys) self.stepT, self.stepMag = signal.step(self.sys) self.impT, self.impMag = signal.impulse(self.sys) self.pzg = signal.tf2zpk(self.sys.num, self.sys.den) self.GDfreq, self.gd = signal.group_delay((self.num, self.den)) self.plotMag()
def calc_error(irs, delta_min, omega_max): """ irs[fraction][tap] """ error = [] for index, ir in enumerate(irs): w, gd = signal.group_delay((ir, [1])) trim = numpy.searchsorted(w, omega_max * numpy.pi) error.append(gd[:trim + 1] - delta_min - index / (len(irs) - 1)) return numpy.sum(numpy.abs(numpy.array(error))) / omega_max / len(irs)
def plot_group_delay_to_axes(self, axes, limits): legend = 'Group Delay' n_points = 1000 w, gd = signal.group_delay((self.num, self.den)) axes.plot(w, gd, label=legend) axes.set_xlabel(r'Frequency [rad/sample]') axes.set_ylabel(r'Group Delay [samples]') first_w = w.item(0) last_w = w[-1] return first_w, last_w
def addFilter(b, a, sampling_freq, name=""): w, h = signal.freqz(b, a, fs=sampling_freq) t, y = signal.dstep((b, a, 1.0 / fs)) w_gd, gd = signal.group_delay((b, a)) frequencies.append(w) amplitudes.append(h) times.append(t) step_responses.append(y) group_delays.append(gd) names.append(name)
def fvtool(b, fs, a=1, worN=8192, fc1=None, fc2=None): ''' MATLAB関数fvtoolを参考 この関数を呼んだあと、必ずplt.show()を叩くこと param ----- b: array_like 伝達関数の分子の係数 a: array_like 伝達関数の分母の係数 デフォルト値は1 fs: float サンプリング周波数[Hz] worN: int 単位円の半円の分割数 周波数に変換するときは w/pi*fn をする fc1: float 周波数応答のグラフにカットオフ周波数などの印(縦線)を入れる fc2: float 周波数応答のグラフにカットオフ周波数などの印(縦線)を入れる ''' # ナイキスト周波数計算 fn = fs / 2 # 周波数応答計算 w, h = signal.freqz(b, a, worN) x_freq_rspns = w / np.pi * fn y_freq_rspns = db(abs(h)) # 複素数→デシベル変換 # 群遅延計算 w, gd = signal.group_delay([b, a], worN) x_gd = w / np.pi * fn y_gd = gd # グラフ表示 plt.figure(figsize=(8, 6)) # 周波数応答プロット plt.subplot(2, 1, 1) plt.plot(x_freq_rspns, y_freq_rspns) if fc1 is not None: plt.plot([fc1, fc1], [y_freq_rspns.min(), y_freq_rspns.max()]) if fc2 is not None: plt.plot([fc2, fc2], [y_freq_rspns.min(), y_freq_rspns.max()]) #plt.ylim(-70, 2) # MATLAB fvtool仕様 plt.ylabel('Amplitude [dB]') plt.grid() # 群遅延プロット plt.subplot(2, 1, 2) plt.plot(x_gd, y_gd) plt.ylim(0, len(b)) # MATALB fvtool仕様 plt.xlabel('Frequency [Hz]') plt.ylabel('Group delay [samples]') plt.grid()
def calc_tau_g(self): """ (Re-)Calculate the complex frequency response H(f) """ bb = fb.fil[0]['ba'][0] aa = fb.fil[0]['ba'][1] # calculate H_cmplx(W) (complex) for W = 0 ... 2 pi: self.W, self.tau_g = group_delay((bb, aa), w=params['N_FFT'], whole = True) #verbose = self.verbose) # self.chkWarnings.isChecked()) # Zero phase filters have no group delay (Causal+AntiCausal) if 'baA' in fb.fil[0]: self.tau_g = np.zeros(self.tau_g.size)
def rdgPlot(self, axes, canvas): for i in range(0, len(self.stages_list)): if self.stages_list[i]: temp_list = [] temp_list.append(self.sos[i]) b, a = ss.sos2tf(temp_list) w, gd = ss.group_delay((b, a)) axes.plot(w / (2 * np.pi), gd, label=str(i)) axes.set_xscale('log') axes.set_ylabel('Group delay [samples]') axes.set_xlabel('Frequency [Hz]') axes.minorticks_on() axes.legend(loc='best') canvas.draw()
def grpdelay(system, worN:int=512, fs=2*np.pi)->Tuple: """ Group delay of a digital filter. Parameters ---------- system : a tuple of array_like describing the system. The following gives the number of elements in the tuple and the interpretation: * (num, den) worN : {None, int, array_like}, optional If a single integer, then compute at that many frequencies (default is N=512). This is a convenient alternative to: np.linspace(0, fs if whole else fs/2, N, endpoint=False) Using a number that is fast for FFT computations can result in faster computations (see Notes). If an array_like, compute the response at the frequencies given. These are in the same units as fs. fs : float, optional The sampling frequency of the digital system. Defaults to 2*pi radians/sample (so w is from 0 to pi). Returns ------- w : ndarray The frequencies at which h was computed, in the same units as fs. By default, w is normalized to the range [0, pi) (radians/sample). gd : ndarray The group delay. """ #デジタルフィルタの群遅延を計算 w, gd = signal.group_delay(system, w = worN, fs = fs) #計算誤差を整数に丸める if system[1] == 1: # If filter is FIR, round the group_delay gd = np.round(gd) #周波数と対応する群遅延を返す return w, gd
def plot_filter(self, xlim=None, ylim=None, label=False, xlabel=False, ylabel=False, plot_group_delay=None): """ Visualize the prototype filter. """ xlabel = True if label else xlabel ylabel = True if label else ylabel _w, _filts = self._create_prototype_filter(shift=True, output='freq') _fig, _ax = plt.subplots(2, 1, figsize=(8, 6), sharex=True) _ax[0].plot(_w, np.abs(_filts)) _ax[1].plot(_w, np.angle(_filts)) if xlim is not None: _ax[0].set_xlim(xlim) _ax[1].set_xlim(xlim) if xlabel: _ax[1].set_xlabel('Frequencies [Hz]') if ylabel: _ax[0].set_ylabel('Magnitude') _ax[1].set_ylabel('Phases [rad]') if plot_group_delay is not None: _filt = self._create_prototype_filter(output='time')[1] _w, _gd = group_delay([_filt, 1]) _w *= (self.sample_rate / (2 * np.pi)) _fig1, _ax1 = plt.subplots(1, 1, figsize=(8, 3)) _ax1.plot(_w, _gd) if xlim is not None: _ax1.set_xlim([0, xlim[-1]]) _ax1.set_ylim([0, _gd.max() * 1.25]) if xlabel: _ax1.set_xlabel('Frequencies [Hz]') if ylabel: _ax1.set_ylabel('Number of Samples') return [_fig, _fig1] else: return _fig
def rdgPlot(self, axes, canvas): for f in self.filter_list: if f.chk: w, gd = ss.group_delay((f.Filtro.b, f.Filtro.a), w=1024) if f.plotColor is not None: axes.plot(w / (2 * np.pi), gd, label=f.name, color=self.formatColor(f.plotColor)) else: axes.plot(w / (2 * np.pi), gd, label=f.name) axes.set_xscale('log') axes.set_ylabel('Group delay [samples]') axes.set_xlabel('Frequency [Hz]') axes.minorticks_on() axes.legend(loc='best') canvas.draw()
def median_group_delay(ba, fs) -> float: """ :return: Median group delay of filter in `band`, in milliseconds. `nan` if filter poles lie so close to the unit circle that group delay cannot be reliably calculated. """ f_nyq = fs / 2 freqs = linspace(*band, num=1000) / f_nyq with ignore(BadCoefficients): _, p, _ = tf2zpk(*ba) if any(abs(p) > 0.97): return nan else: _, gd_samples = group_delay(ba, freqs) mgd_samples = median(gd_samples) mgd_seconds = mgd_samples / fs return mgd_seconds * 1000
def plot_filter(h, sfreq, freq=None, gain=None, title=None, color='#1f77b4', flim=None, fscale='log', alim=_DEFAULT_ALIM, show=True, compensate=False): """Plot properties of a filter. Parameters ---------- h : dict or ndarray An IIR dict or 1D ndarray of coefficients (for FIR filter). sfreq : float Sample rate of the data (Hz). freq : array-like or None The ideal response frequencies to plot (must be in ascending order). If None (default), do not plot the ideal response. gain : array-like or None The ideal response gains to plot. If None (default), do not plot the ideal response. title : str | None The title to use. If None (default), deteremine the title based on the type of the system. color : color object The color to use (default '#1f77b4'). flim : tuple or None If not None, the x-axis frequency limits (Hz) to use. If None, freq will be used. If None (default) and freq is None, ``(0.1, sfreq / 2.)`` will be used. fscale : str Frequency scaling to use, can be "log" (default) or "linear". alim : tuple The y-axis amplitude limits (dB) to use (default: (-60, 10)). show : bool Show figure if True (default). compensate : bool If True, compensate for the filter delay (phase will not be shown). - For linear-phase FIR filters, this visualizes the filter coefficients assuming that the output will be shifted by ``N // 2``. - For IIR filters, this changes the filter coefficient display by filtering backward and forward, and the frequency response by squaring it. .. versionadded:: 0.18 Returns ------- fig : matplotlib.figure.Figure The figure containing the plots. See Also -------- mne.filter.create_filter plot_ideal_filter Notes ----- .. versionadded:: 0.14 """ from scipy.signal import freqz, group_delay, lfilter, filtfilt, sosfilt import matplotlib.pyplot as plt from matplotlib.ticker import FormatStrFormatter, NullFormatter sosfiltfilt = get_sosfiltfilt() sfreq = float(sfreq) _check_option('fscale', fscale, ['log', 'linear']) flim = _get_flim(flim, fscale, freq, sfreq) if fscale == 'log': omega = np.logspace(np.log10(flim[0]), np.log10(flim[1]), 1000) else: omega = np.linspace(flim[0], flim[1], 1000) omega /= sfreq / (2 * np.pi) if isinstance(h, dict): # IIR h.ndim == 2: # second-order sections if 'sos' in h: H = np.ones(len(omega), np.complex128) gd = np.zeros(len(omega)) for section in h['sos']: this_H = freqz(section[:3], section[3:], omega)[1] H *= this_H if compensate: H *= this_H.conj() # time reversal is freq conj else: # Assume the forward-backward delay zeros out, which it # mostly should with warnings.catch_warnings(record=True): # singular GD warnings.simplefilter('ignore') gd += group_delay((section[:3], section[3:]), omega)[1] n = estimate_ringing_samples(h['sos']) delta = np.zeros(n) delta[0] = 1 if compensate: delta = np.pad(delta, [(n - 1, 0)], 'constant') func = sosfiltfilt gd += (len(delta) - 1) // 2 else: func = sosfilt h = func(h['sos'], delta) else: H = freqz(h['b'], h['a'], omega)[1] if compensate: H *= H.conj() with warnings.catch_warnings(record=True): # singular GD warnings.simplefilter('ignore') gd = group_delay((h['b'], h['a']), omega)[1] if compensate: gd += group_delay(h['b'].conj(), h['a'].conj(), omega)[1] n = estimate_ringing_samples((h['b'], h['a'])) delta = np.zeros(n) delta[0] = 1 if compensate: delta = np.pad(delta, [(n - 1, 0)], 'constant') func = filtfilt else: func = lfilter h = func(h['b'], h['a'], delta) if title is None: title = 'SOS (IIR) filter' if compensate: title += ' (forward-backward)' else: H = freqz(h, worN=omega)[1] with warnings.catch_warnings(record=True): # singular GD warnings.simplefilter('ignore') gd = group_delay((h, [1.]), omega)[1] title = 'FIR filter' if title is None else title if compensate: title += ' (delay-compensated)' # eventually axes could be a parameter fig, (ax_time, ax_freq, ax_delay) = plt.subplots(3) t = np.arange(len(h)) if compensate: n_shift = (len(h) - 1) // 2 t -= n_shift assert t[0] == -t[-1] gd -= n_shift t = t / sfreq gd = gd / sfreq f = omega * sfreq / (2 * np.pi) ax_time.plot(t, h, color=color) ax_time.set(xlim=t[[0, -1]], xlabel='Time (s)', ylabel='Amplitude', title=title) mag = 10 * np.log10(np.maximum((H * H.conj()).real, 1e-20)) sl = slice(0 if fscale == 'linear' else 1, None, None) # Magnitude ax_freq.plot(f[sl], mag[sl], color=color, linewidth=2, zorder=4) if freq is not None and gain is not None: plot_ideal_filter(freq, gain, ax_freq, fscale=fscale, show=False) ax_freq.set(ylabel='Magnitude (dB)', xlabel='', xscale=fscale) # Delay ax_delay.plot(f[sl], gd[sl], color=color, linewidth=2, zorder=4) # shade nulled regions for start, stop in zip(*_mask_to_onsets_offsets(mag <= -39.9)): ax_delay.axvspan(f[start], f[stop - 1], facecolor='k', alpha=0.05, zorder=5) ax_delay.set(xlim=flim, ylabel='Group delay (s)', xlabel='Frequency (Hz)', xscale=fscale) xticks, xticklabels = _filter_ticks(flim, fscale) dlim = np.abs(t).max() / 2. dlim = [-dlim, dlim] for ax, ylim, ylabel in ((ax_freq, alim, 'Amplitude (dB)'), (ax_delay, dlim, 'Delay (s)')): if xticks is not None: ax.set(xticks=xticks) ax.set(xticklabels=xticklabels) ax.xaxis.set_major_formatter(FormatStrFormatter('%0.1f')) ax.xaxis.set_minor_formatter(NullFormatter()) ax.set(xlim=flim, ylim=ylim, xlabel='Frequency (Hz)', ylabel=ylabel) adjust_axes([ax_time, ax_freq, ax_delay]) tight_layout() plt_show(show) return fig
def plot_filter(h, sfreq, freq=None, gain=None, title=None, color='#1f77b4', flim=None, fscale='log', alim=(-60, 10), show=True): """Plot properties of a filter. Parameters ---------- h : dict or ndarray An IIR dict or 1D ndarray of coefficients (for FIR filter). sfreq : float Sample rate of the data (Hz). freq : array-like or None The ideal response frequencies to plot (must be in ascending order). If None (default), do not plot the ideal response. gain : array-like or None The ideal response gains to plot. If None (default), do not plot the ideal response. title : str | None The title to use. If None (default), deteremine the title based on the type of the system. color : color object The color to use (default '#1f77b4'). flim : tuple or None If not None, the x-axis frequency limits (Hz) to use. If None, freq will be used. If None (default) and freq is None, ``(0.1, sfreq / 2.)`` will be used. fscale : str Frequency scaling to use, can be "log" (default) or "linear". alim : tuple The y-axis amplitude limits (dB) to use (default: (-60, 10)). show : bool Show figure if True (default). Returns ------- fig : matplotlib.figure.Figure The figure containing the plots. See Also -------- mne.filter.create_filter plot_ideal_filter Notes ----- .. versionadded:: 0.14 """ from scipy.signal import freqz, group_delay import matplotlib.pyplot as plt sfreq = float(sfreq) _check_fscale(fscale) flim = _get_flim(flim, fscale, freq, sfreq) if fscale == 'log': omega = np.logspace(np.log10(flim[0]), np.log10(flim[1]), 1000) else: omega = np.linspace(flim[0], flim[1], 1000) omega /= sfreq / (2 * np.pi) if isinstance(h, dict): # IIR h.ndim == 2: # second-order sections if 'sos' in h: from scipy.signal import sosfilt h = h['sos'] H = np.ones(len(omega), np.complex128) gd = np.zeros(len(omega)) for section in h: this_H = freqz(section[:3], section[3:], omega)[1] H *= this_H with warnings.catch_warnings(record=True): # singular GD gd += group_delay((section[:3], section[3:]), omega)[1] n = estimate_ringing_samples(h) delta = np.zeros(n) delta[0] = 1 h = sosfilt(h, delta) else: from scipy.signal import lfilter n = estimate_ringing_samples((h['b'], h['a'])) delta = np.zeros(n) delta[0] = 1 H = freqz(h['b'], h['a'], omega)[1] with warnings.catch_warnings(record=True): # singular GD gd = group_delay((h['b'], h['a']), omega)[1] h = lfilter(h['b'], h['a'], delta) title = 'SOS (IIR) filter' if title is None else title else: H = freqz(h, worN=omega)[1] with warnings.catch_warnings(record=True): # singular GD gd = group_delay((h, [1.]), omega)[1] title = 'FIR filter' if title is None else title gd /= sfreq fig, axes = plt.subplots(3) # eventually axes could be a parameter t = np.arange(len(h)) / sfreq f = omega * sfreq / (2 * np.pi) axes[0].plot(t, h, color=color) axes[0].set(xlim=t[[0, -1]], xlabel='Time (sec)', ylabel='Amplitude h(n)', title=title) mag = 10 * np.log10(np.maximum((H * H.conj()).real, 1e-20)) axes[1].plot(f, mag, color=color, linewidth=2, zorder=4) if freq is not None and gain is not None: plot_ideal_filter(freq, gain, axes[1], fscale=fscale, title=None, show=False) axes[1].set(ylabel='Magnitude (dB)', xlabel='', xscale=fscale) sl = slice(0 if fscale == 'linear' else 1, None, None) axes[2].plot(f[sl], gd[sl], color=color, linewidth=2, zorder=4) axes[2].set(xlim=flim, ylabel='Group delay (sec)', xlabel='Frequency (Hz)', xscale=fscale) xticks, xticklabels = _filter_ticks(flim, fscale) dlim = [0, 1.05 * gd[1:].max()] for ax, ylim, ylabel in zip(axes[1:], (alim, dlim), ('Amplitude (dB)', 'Delay (sec)')): if xticks is not None: ax.set(xticks=xticks) ax.set(xticklabels=xticklabels) ax.set(xlim=flim, ylim=ylim, xlabel='Frequency (Hz)', ylabel=ylabel) adjust_axes(axes) tight_layout() plt_show(show) return fig