You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# this also works:# from numpy import fft as fftpack
fromscipyimportsignal
importscipy.io.wavfile
fromscipyimportio
Spectral analysis / Fourier Transforms
Fourier transform: F(v) of continuous signal f(t):
F(v) = sum{ f(t) * e^(-2piivt) dt }
complex-valued amplitude spectrum
Inverse
f(t) = sum{ F(v) * e^(2piivt) dv }
continuous signal, infinite duration
f(t) usually sampled from finite time duration, N uniformly spaced points.
used to build Discrete Fourier Transform (DFT) and inverse DFT.
# example simulated signal, pure sinusoid @ 1 Hz & 22 Hz, plus normal-distributed noisedefsignal_samples(t):
return (2*np.sin(1*2*np.pi*t) +3*np.sin(22*2*np.pi*t) +2*np.random.randn(*np.shape(t)))
# we are interested in finding frequency spectrum of signal up to 30Hz.# so we need to choose a sampling frequency of 60Hz# we also want frequency resolution of 0.01Hznp.random.seed(0)
B=30.0f_s=2*Bdelta_f=0.01
# N = number of reqd sample points; T = reqd time period (seconds)N=int(f_s/delta_f)
T=N/f_sN, T
(6000, 100.0)
# create array of sample times, uniformly spaced in timet=np.linspace(0, T, N)
# to see sinusoidal components in the signal:F=fftpack.fft(f_t)
# return frequencies corresponding to each freq bin (fftfreq = helper function)f=fftpack.fftfreq(N, 1/f_s)
# spectrum = symmetric at positive & negative frequencies, so# we are only interested in positive frequency data.mask=np.where(f>=0)
# example:# use window function before applying FFT to time-series signaldf=pd.read_csv(
'temperature_outdoor_2014.tsv',
delimiter="\t",
names=["time", "temperature"])
df.head()
# set index, resample to 1 hour increments, window between April & Junedf=df.set_index("time")
df=df.resample("H").ffill()
df=df[(df.index>="2014-04-01") * (df.index<"2014-06-01")].dropna()
# once dataframe processed, prepare underlying NumPy arrays # so time-series data can be process using fftpacktime=df.index.astype('int64')/1.0e9time[0:9]
# apply Blackman window function (leakage reducer)# need to pass length of sample array -- returns array of same lengthwindow=signal.blackman(len(temperature))
window.size
Filters in previous examples couldn't be done in real time - buffering problems.
Convolution filters
fourier transformation property: inverse FFT of product of two functions (ex: signal spectrum + filter shape) is convolution of the two functions' IFFTs.
To apply filter Hk to spectrum Xk of signal xn, we can find convolution ox xn with hm (the IFFT of Hk).
N,T
(22050, 100.0)
# use convolve function to perform inverse Fourier transform the frequency response function# use the result "h" as a kernel to convolve the original time-domain signal f_t.t=np.linspace(0,T,N); t
# use mode="same" to set output array size equal to the first input.# or use mode="valid" to only use elements not relying on zero padding.f_t_filtered_conv=signal.convolve(f_t, h, mode='same')
/home/bjpcjp/anaconda3/lib/python3.6/site-packages/scipy/fftpack/basic.py:160: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
z[index] = x
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-104-5d7859e1b3cd> in <module>()
14 ax = plt.subplot2grid((2,2), (1,0), colspan=2)
15 ax.plot(t, f_t, label='original', alpha=0.25)
---> 16 ax.plot(t, f_t_filtered.real, "r", lw=2, label='filtered in frequency domain')
17 ax.plot(t, f_t_filtered_conv.real, 'b--', lw=2, label='filtered with convolution')
18 ax.set_xlim(0, 10)
~/anaconda3/lib/python3.6/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
1808 "the Matplotlib list!)" % (label_namer, func.__name__),
1809 RuntimeWarning, stacklevel=2)
-> 1810 return func(ax, *args, **kwargs)
1811
1812 inner.__doc__ = _add_data_doc(inner.__doc__,
~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_axes.py in plot(self, scalex, scaley, *args, **kwargs)
1609 kwargs = cbook.normalize_kwargs(kwargs, mlines.Line2D._alias_map)
1610
-> 1611 for line in self._get_lines(*args, **kwargs):
1612 self.add_line(line)
1613 lines.append(line)
~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py in _grab_next_args(self, *args, **kwargs)
391 this += args[0],
392 args = args[1:]
--> 393 yield from self._plot_args(this, kwargs)
394
395
~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py in _plot_args(self, tup, kwargs)
368 x, y = index_of(tup[-1])
369
--> 370 x, y = self._xy_from_xy(x, y)
371
372 if self.command == 'plot':
~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py in _xy_from_xy(self, x, y)
229 if x.shape[0] != y.shape[0]:
230 raise ValueError("x and y must have same first dimension, but "
--> 231 "have shapes {} and {}".format(x.shape, y.shape))
232 if x.ndim > 2 or y.ndim > 2:
233 raise ValueError("x and y can be no greater than 2-D, but have "
ValueError: x and y must have same first dimension, but have shapes (22050,) and (6000,)
Finding a(k) & b(k) = filter design; can be found via SciPy.signal module functions like firwin().
FIR
# firwin args:# n = number of vals in ak (# of "taps)# cutoff = low-pass transition freq (units of Nyquist frequency)# nyq = Nyquist frequency scale# window = window function typen=101f_s=1.0/3600nyq=f_s/2b=signal.firwin(n, cutoff=nyq/12, nyq=nyq, window="hamming")
# sequence of coefficients b(k) that defines FIR filterplt.plot(b);
# use b(k) to find amplitude & phase of filter responsef, h=signal.freqz(b)
/home/bjpcjp/anaconda3/lib/python3.6/site-packages/scipy/signal/signaltools.py:1344: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
out = out_full[ind]
# apply filter to input signal (temp dataset)temperature_filtered_iir=signal.lfilter(b, a, temperature)
# alternative: filters both fwd & bkwdtemperature_filtered_filtfilt=signal.filtfilt(b, a, temperature)
/home/bjpcjp/anaconda3/lib/python3.6/site-packages/scipy/signal/_arraytools.py:45: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
b = a[a_slice]
/home/bjpcjp/anaconda3/lib/python3.6/site-packages/scipy/signal/signaltools.py:1344: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
out = out_full[ind]
# write to wav fileio.wavfile.write("guitar-echo.wav", sample_rate,
np.vstack([
data_filt, data_filt]).T.astype(np.int16))