def test_hilbert(self): # compare to MATLAB output of reference implementation # f=[0 0.3 0.5 1]; # a=[1 1 0 0]; # h=remez(11,f,a); h = remez(12, [0, 0.3, 0.5, 1], [1, 0], fs=2.) k = [ 0.349585548646686, 0.373552164395447, 0.326082685363438, 0.077152207480935, -0.129943946349364, -0.059355880509749 ] m = minimum_phase(h, 'hilbert') assert_allclose(m, k, rtol=5e-3) # f=[0 0.8 0.9 1]; # a=[0 0 1 1]; # h=remez(20,f,a); h = remez(21, [0, 0.8, 0.9, 1], [0, 1], fs=2.) k = [ 0.232486803906329, -0.133551833687071, 0.151871456867244, -0.157957283165866, 0.151739294892963, -0.129293146705090, 0.100787844523204, -0.065832656741252, 0.035361328741024, -0.014977068692269, -0.158416139047557 ] m = minimum_phase(h, 'hilbert', n_fft=2**19) assert_allclose(m, k, rtol=2e-3)
def test_homomorphic(self): # check that it can recover frequency responses of arbitrary # linear-phase filters # for some cases we can get the actual filter back h = [1, -1] h_new = minimum_phase(np.convolve(h, h[::-1])) assert_allclose(h_new, h, rtol=0.05) # but in general we only guarantee we get the magnitude back rng = np.random.RandomState(0) for n in (2, 3, 10, 11, 15, 16, 17, 20, 21, 100, 101): h = rng.randn(n) h_new = minimum_phase(np.convolve(h, h[::-1])) assert_allclose(np.abs(fft(h_new)), np.abs(fft(h)), rtol=1e-4)
def test_homomorphic(self): # check that it can recover frequency responses of arbitrary # linear-phase filters # for some cases we can get the actual filter back h = [1, -1] h_new = minimum_phase(np.convolve(h, h[::-1])) assert_allclose(h_new, h, rtol=0.05) # but in general we only guarantee we get the magnitude back rng = np.random.RandomState(0) for n in (2, 3, 10, 11, 15, 16, 17, 20, 21, 100, 101): h = rng.randn(n) h_new = minimum_phase(np.convolve(h, h[::-1])) assert_allclose(np.abs(np.fft.fft(h_new)), np.abs(np.fft.fft(h)), rtol=1e-4)
def minimum_phase(h): """Convert a linear-phase FIR filter to minimum phase. Parameters ---------- h : array Linear-phase FIR filter coefficients. Returns ------- h_minimum : array The minimum-phase version of the filter, with length ``(length(h) + 1) // 2``. """ try: from scipy.signal import minimum_phase except Exception: pass else: return minimum_phase(h) from scipy.fftpack import fft, ifft h = np.asarray(h) if np.iscomplexobj(h): raise ValueError('Complex filters not supported') if h.ndim != 1 or h.size <= 2: raise ValueError('h must be 1D and at least 2 samples long') n_half = len(h) // 2 if not np.allclose(h[-n_half:][::-1], h[:n_half]): warnings.warn( 'h does not appear to by symmetric, conversion may ' 'fail', RuntimeWarning) n_fft = 2**int(np.ceil(np.log2(2 * (len(h) - 1) / 0.01))) # zero-pad; calculate the DFT h_temp = np.abs(fft(h, n_fft)) # take 0.25*log(|H|**2) = 0.5*log(|H|) h_temp += 1e-7 * h_temp[h_temp > 0].min() # don't let log blow up np.log(h_temp, out=h_temp) h_temp *= 0.5 # IDFT h_temp = ifft(h_temp).real # multiply pointwise by the homomorphic filter # lmin[n] = 2u[n] - d[n] win = np.zeros(n_fft) win[0] = 1 stop = (len(h) + 1) // 2 win[1:stop] = 2 if len(h) % 2: win[stop] = 1 h_temp *= win h_temp = ifft(np.exp(fft(h_temp))) h_minimum = h_temp.real n_out = n_half + len(h) % 2 return h_minimum[:n_out]
def minimum_phase(h): """Convert a linear-phase FIR filter to minimum phase. Parameters ---------- h : array Linear-phase FIR filter coefficients. Returns ------- h_minimum : array The minimum-phase version of the filter, with length ``(length(h) + 1) // 2``. """ try: from scipy.signal import minimum_phase except Exception: pass else: return minimum_phase(h) from scipy.fftpack import fft, ifft h = np.asarray(h) if np.iscomplexobj(h): raise ValueError('Complex filters not supported') if h.ndim != 1 or h.size <= 2: raise ValueError('h must be 1D and at least 2 samples long') n_half = len(h) // 2 if not np.allclose(h[-n_half:][::-1], h[:n_half]): warnings.warn('h does not appear to by symmetric, conversion may ' 'fail', RuntimeWarning) n_fft = 2 ** int(np.ceil(np.log2(2 * (len(h) - 1) / 0.01))) # zero-pad; calculate the DFT h_temp = np.abs(fft(h, n_fft)) # take 0.25*log(|H|**2) = 0.5*log(|H|) h_temp += 1e-7 * h_temp[h_temp > 0].min() # don't let log blow up np.log(h_temp, out=h_temp) h_temp *= 0.5 # IDFT h_temp = ifft(h_temp).real # multiply pointwise by the homomorphic filter # lmin[n] = 2u[n] - d[n] win = np.zeros(n_fft) win[0] = 1 stop = (len(h) + 1) // 2 win[1:stop] = 2 if len(h) % 2: win[stop] = 1 h_temp *= win h_temp = ifft(np.exp(fft(h_temp))) h_minimum = h_temp.real n_out = n_half + len(h) % 2 return h_minimum[:n_out]
def test_hilbert(self): # compare to MATLAB output of reference implementation # f=[0 0.3 0.5 1]; # a=[1 1 0 0]; # h=remez(11,f,a); h = remez(12, [0, 0.3, 0.5, 1], [1, 0], fs=2.) k = [0.349585548646686, 0.373552164395447, 0.326082685363438, 0.077152207480935, -0.129943946349364, -0.059355880509749] m = minimum_phase(h, 'hilbert') assert_allclose(m, k, rtol=1e-3) # f=[0 0.8 0.9 1]; # a=[0 0 1 1]; # h=remez(20,f,a); h = remez(21, [0, 0.8, 0.9, 1], [0, 1], fs=2.) k = [0.232486803906329, -0.133551833687071, 0.151871456867244, -0.157957283165866, 0.151739294892963, -0.129293146705090, 0.100787844523204, -0.065832656741252, 0.035361328741024, -0.014977068692269, -0.158416139047557] m = minimum_phase(h, 'hilbert', n_fft=2**19) assert_allclose(m, k, rtol=1e-3)
def construct_fir_filter(rate, frequencies, gains, order, phase, window, design): """ Construct coeffs of FIR filter. Args: rate (float): Nominal sampling rate of the input data. order (int): Filter order frequencies (list): Transition frequencies in Hz. design (str|'firwin2'): Design of the transfert function of the filter. phase (str|`linear`): Phase response ("zero", "zero-double" or "minimum"). window (float|`hamming`): The window to use in FIR design, ("hamming", "hann", or "blackman"). Returns: array h. FIR coeffs. Notes: Adapted from mne.filters, see the documentation of: * `mne.filters <https://martinos.org/mne/stable/generated/mne.filter.construct_fir_filter.html>`_ * `scipy.signal.firwin2 <https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.signal.firwin2.html>`_ """ nyq = rate / 2. if design == 'firwin2': from scipy.signal import firwin2 as design else: # not implemented yet raise ValueError( 'firwin, remez and firls have not been implemented yet ') # issue a warning if attenuation is less than this min_att_db = 12 if phase == 'minimum' else 20 if frequencies[0] != 0 or frequencies[-1] != nyq: raise ValueError( 'freq must start at 0 and end an Nyquist (%s), got %s' % (nyq, frequencies)) gains = np.array(gains) if window == "kaiser": diffs = np.diff(frequencies) width = min(diffs[diffs > 0]) beta = signal.kaiser_beta(signal.kaiser_atten(order, width / nyq)) window = ("kaiser", beta) # check zero phase length N = int(order) if N % 2 == 0: if phase == 'zero': LOGGER.info('filter_length must be odd if phase="zero", ' 'got %s' % N) N += 1 elif phase == 'zero-double' and gains[-1] == 1: N += 1 # construct symmetric (linear phase) filter if phase == 'minimum': h = design(N * 2 - 1, frequencies, gains, fs=rate, window=window) h = signal.minimum_phase(h) else: h = design(N, frequencies, gains, fs=rate, window=window) assert h.size == N att_db, att_freq = _filter_attenuation(h, frequencies, gains) if phase == 'zero-double': att_db += 6 if att_db < min_att_db: att_freq *= rate / 2. LOGGER.info('Attenuation at stop frequency %0.1fHz is only %0.1fdB. ' 'Increase filter_length for higher attenuation.' % (att_freq, att_db)) return h
def minphase(r): return signal.minimum_phase(r, method='hilbert', n_fft=8192)
# whereby each sample :math:`t` is filtered only using time points that came # after it. # # Note that the delay is variable (whereas for linear/zero-phase filters it # is constant) but small in the pass-band. Unlike zero-phase filters, which # require time-shifting backward the output of a linear-phase filtering stage # (and thus becoming non-causal), minimum-phase filters do not require any # compensation to achieve small delays in the pass-band. Note that as an # artifact of the minimum phase filter construction step, the filter does # not end up being as steep as the linear/zero-phase version. # # We can construct a minimum-phase filter from our existing linear-phase # filter with the :func:`scipy.signal.minimum_phase` function, and note # that the falloff is not as steep: h_min = signal.minimum_phase(h) plot_filter(h_min, sfreq, freq, gain, 'Minimum-phase', flim=flim) # %% # .. _tut-effect-on-signals: # # Applying FIR filters # -------------------- # # Now lets look at some practical effects of these filters by applying # them to some data. # # Let's construct a Gaussian-windowed sinusoid (i.e., Morlet imaginary part) # plus noise (random and line). Note that the original clean signal contains # frequency content in both the pass band and transition bands of our # low-pass filter.
rec_cfir_t = np.abs(lfilter(b_cfir_t, [1], x_test))[d:] corrs_fir[k, j] = np.corrcoef(rec_fir, tar)[0, 1] saf = SWAnalyticFilter2(fs, band, d * 2, n_fft) chunked = np.zeros((len(x_test), d * 2)) for l in range(d * 2, len(x_test)): chunked[l, :] = x_test[l - 2 * d:l] rec_hilbert = np.abs(saf.apply(x_test)) #rec = np.abs(saf.apply(x_test))[d:] corrs_hilbert[k, j] = np.corrcoef(rec_hilbert[d:], tar)[0, 1] if d > 0: tar1 = np.abs(y_test) b_fir_band = minimum_phase( firwin(d, band / fs * 2, pass_zero=False)) b_fir_smooth = minimum_phase(firwin(d, 2 / fs * 2)) rec_fir = lfilter(b_fir_smooth, [1], np.abs(lfilter(b_fir_band, [1], x_test))) corr_delays = np.arange(1, 300) cross_corr = np.array([ np.corrcoef(tar1[:-d1], rec_fir[d1:])[0][1] for d1 in corr_delays ]) opt_delay = corr_delays[np.argmax(cross_corr)] min_phase_delays[k, j] = opt_delay corrs_min_phase[k, j] = np.max(cross_corr) else: tar = np.abs(y_test)[-d:] rec_cfir_f = np.abs(lfilter(b_cfir_f, [1], x_test))[:d]
# Create an optimal linear-phase filter, then convert it to minimum phase: from scipy.signal import remez, minimum_phase, freqz, group_delay import matplotlib.pyplot as plt freq = [0, 0.2, 0.3, 1.0] desired = [1, 0] h_linear = remez(151, freq, desired, Hz=2.) # Convert it to minimum phase: h_min_hom = minimum_phase(h_linear, method='homomorphic') h_min_hil = minimum_phase(h_linear, method='hilbert') # Compare the three filters: fig, axs = plt.subplots(4, figsize=(4, 8)) for h, style, color in zip((h_linear, h_min_hom, h_min_hil), ('-', '-', '--'), ('k', 'r', 'c')): w, H = freqz(h) w, gd = group_delay((h, 1)) w /= np.pi axs[0].plot(h, color=color, linestyle=style) axs[1].plot(w, np.abs(H), color=color, linestyle=style) axs[2].plot(w, 20 * np.log10(np.abs(H)), color=color, linestyle=style) axs[3].plot(w, gd, color=color, linestyle=style) for ax in axs: ax.grid(True, color='0.5') ax.fill_between(freq[1:3], *ax.get_ylim(), color='#ffeeaa', zorder=1) axs[0].set(xlim=[0, len(h_linear) - 1], ylabel='Amplitude', xlabel='Samples') axs[1].legend(['Linear', 'Min-Hom', 'Min-Hil'], title='Phase') for ax, ylim in zip(axs[1:], ([0, 1.1], [-150, 10], [-60, 60])):
fs = 500 t = np.arange(fs * 2) / fs signal = ((np.sin(2 * np.pi * 10 * t) + 0.2) - 0.2 * (np.cos(2 * np.pi * 20 * t) + 0.25)) * np.sin(2 * np.pi * t * 3 / 4) signal[(t < 1 / 3 * 2) | (t > 2 / 3 * 2)] = 0 noise_spec = np.fft.rfft( np.random.normal(size=2 * fs)) * 1 / (1 + np.arange(fs + 1)**1) noise_spec[:10] = 0 noise = np.fft.irfft(noise_spec) * 12 x = signal + noise n_taps = fs // 2 band = [8, 12] freq = [0, band[0], band[0], band[1], band[1], fs / 2] gain = [0, 0, 1, 1, 0, 0] b1 = sg.minimum_phase(sg.firwin2(n_taps * 2, freq, gain, fs=fs)) b = sg.firwin2(n_taps, freq, gain, fs=fs) y = sg.lfilter(b, 1, x) y1 = sg.lfilter(b1, 1, x) # plt.semilogy(*sg.welch(y)) def setup_gca(ax, bottom=False): ax.spines['right'].set_visible(False) ax.spines['left'].set_visible(False) ax.spines['top'].set_visible(False) if bottom: ax.spines['bottom'].set_visible(False) ax.get_yaxis().set_visible(False) ax.set_ylim(-1.4, 1.4) #ax.get_xaxis().set_visible(False)
"""plt.plot(time, audio_normalised) plt.show()""" def butter_highpass(cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = signal.butter(order, normal_cutoff, btype='high', analog=False) return b, a def butter_highpass_filter(data, cutoff, fs, order=5): b, a = butter_highpass(cutoff, fs, order=order) y = signal.filtfilt(b, a, data) return y #Plot autocorrelation def autocorr(x): x = butter_highpass_filter(x, 10, 1000) result = sg.correlate(x, x, mode='full', method="fft") return result a = autocorr(audio_normalised) """plt.plot(range(0, len(a)//2+1), a[len(a)//2:]/a[len(a)//2]) plt.show()""" ceps = minimum_phase(audio_normalised) plt.plot(range(len(ceps)), ceps) plt.show()
def minphase(r): return signal.minimum_phase(r, method = 'hilbert', n_fft= 8192)