Source code for toto.filters.bandpass_filter
"""Creates Fourier low, high, or bandpass filter.
Parameters
~~~~~~~~~~
input_array : (Panda Obj)
The Panda dataframe.
lower cut-off (s) : float
The minimum period filter cutoff
upper cut-off (s) : float
The maximum period filter cutoff
Notes
~~~~~
* lower cut-off set < (2*delt) for no cutoff at high freq end
* upper cut-off set > (length(data)*delt) for no cutoff at low freq end
Examples:
~~~~~~~~~
>>> df['bandpass']=bandpass_filter.bandpass_filter(df['signal'].copy(),\
args={'lower cut-off (s)':3600*30,'upper cut-off (s)':24*3600*30})
>>>
"""
import numpy as np
from scipy.fftpack import fft,ifft,rfft, irfft, fftfreq
from toto.core.toolbox import dyadlength
[docs]def bandpass_filter(input_array,args={'lower cut-off (s)':float(),'upper cut-off (s)':float()}):
output_array=input_array.copy()
delt=(input_array.index[1]-input_array.index[0]).total_seconds()/3600 # in hours
tmin=args['lower cut-off (s)']
tmax=args['upper cut-off (s)']
if tmin == None or tmin ==0:
tmin=delt*2.
else:
tmin=tmin/3600.
if tmax == None or tmax ==0:
tmax=len(output_array.values)*delt
else:
tmax=tmax/3600.
nan_ind=np.isnan(input_array)
input_array.interpolate(inplace=True) #linear interp between gaps
trend=np.nanmean(input_array)
input_array=input_array-trend #% remove trend
input_array[np.isnan(input_array)]=0 #remove NaN which are on edges of time series and not filled by interp1
npts_orig,J=dyadlength(input_array.values)
npts=2**J #;%least power of two greater than npts_orig
if npts-npts_orig<npts/16:
npts=2**(J+1) #;%2nd least power of two greater than npts_orig if not enough zeros
nby2=(npts/2)
data_padded=np.zeros((int(npts),))
data=input_array.values
#adjust the padding with first and last value of the time series
data_padded[:int(np.round(npts/2))]=data[(~np.isnan(data)).nonzero()[0][0]]
data_padded[int(np.round(npts/2)):]=data[(~np.isnan(data)).nonzero()[0][-1]]
data_padded[int(nby2-np.round(npts_orig/2)):int(nby2-np.round(npts_orig/2)+npts_orig)]=data
data=data_padded #clear data_padded
#readjust to have zero mean
data=data-np.nanmean(data)
tfund=npts*delt
ffund=1.0/tfund
# fourier transform data:
coeffs = fft(data)
# filter coefficients:
f=np.cumsum(ffund*np.ones((int(nby2),)))
t=np.concatenate(([np.NaN],1.0/f))
idx=np.logical_or(t > tmax , t < tmin)
coeffs[idx.nonzero()[0]]=0.0
# calculate the remaining coefficients:
coeffs[int(npts+1-nby2):int(npts)]=np.conj(coeffs[int(nby2-1):0:-1])
# backtransform data and take real part:
backcoeffs=ifft(coeffs)
filtdat=np.real(backcoeffs)
filtdat=filtdat[int(nby2-round(npts_orig/2)):int(nby2-round(npts_orig/2)+npts_orig)] #;%remove padded zeros
filtdat=filtdat+trend #;% add back the trend
filtdat[nan_ind]=np.NaN;
output_array.values[:]=filtdat
return output_array