s ( t ) = sl O w( t ) + sh i g h( T )
sl O w( t ) = cos( 2 πf0 0t ) + cos( 2 πf1 1t + π3)
sh i g h( t ) = 12⋅ cos( 2 πf2t + 0,2 )
f0 0, f1 1fc u tf0 0< f1 1< fc u tf2> fc u t
Nfs> 2 ⋅ f2fs» 2 ⋅ f2
Combinei um pequeno programa Python para ilustrar alguns dos conceitos - o código é horrível, mas peguei um código antigo que eu tinha para problemas semelhantes. Embora quase não haja comentários, deve ser bastante fácil de seguir devido aos pequenos módulos. O são dois dft / IDFT funções; duas funções fshiftn / fshiftp para mudar a frequência do domínio domínio DFT para filtragem; uma função dftlpass para realizar a filtragem no domínio DFT; uma função zpblpass para fazer a filtragem usando um filtro Butterworth; uma função bbdftsig para formar o sinal de teste e realizar a filtragem; e, finalmente, uma pequena função plotsigstraçar os sinais. No final do script, os diferentes parâmetros são definidos e as diferentes figuras são feitas.
"""
Test of DFT versus scipy.signal.butter filtering with respect to
signal reconstruction.
"""
# import ############################################################ import #
import matplotlib as mpl; mpl.rcParams['backend'] = 'Agg'
import matplotlib.pyplot as mplpp
import matplotlib.mlab as mplml
import numpy as np
import scipy.signal as sps
# initialize #################################################### initialize #
try:
mpl.rc('text', usetex=False)
mpl.rc('font', family='serif')
mpl.rc('font', serif='STIXGeneral')
mpl.rc('font', size=8)
except AttributeError:
None
# dft ################################################################## dft #
def dft(xt, fs, t0):
N, d = len(xt), -2j*np.pi/len(xt)
w = np.arange(N, dtype=np.float).reshape((N,1))
c = np.exp(d*t0*fs*w)
W = np.exp(d*np.dot(w,np.transpose(w)))
xf = np.multiply(c,np.dot(W,xt)) / float(N)
f = w*fs/float(N)
return xf, f
# idft ################################################################ idft #
def idft( X, FS, T0 ):
N, d = len(X), 2j*np.pi/len(X)
w = np.arange(N, dtype=float).reshape((N,1))
cc = np.exp(d*T0*FS*w)
Wc = np.exp(d*np.dot(w, np.transpose(w)))
Y = np.dot(Wc, np.multiply(cc, X))
return Y
# fshiftn ########################################################## fshiftn #
def fshiftn( xf, f ):
assert type(f) == np.ndarray, "f must be a np.ndarray"
assert f.shape[1] == 1, "f must be a column array"
assert xf.shape[1] == 1, "xf must be a column array"
assert sum(f<0) == 0, "All frequency components must be 0 or positive"
# Determine sampling rate, tolerance, and allocate output array
fs, tol = len(f)*(np.abs(f[1,0]-f[0,0])), 1.E-2
fshift = np.zeros((len(f),1), dtype=float)
xfshift = np.zeros((len(f),1), dtype=complex)
# Determine index where f > fs/2
Nm = np.floor(len(f)/2.0)
Np = np.floor((len(f)-1.0)/2.0)
# Compute output frequency array such that -fs/2 <= f < fs/2 and the
# corresponding Fourier coefficients
fshift[:Nm,0] = f[Np+1:,0] - fs
fshift[Nm,0] = f[0,0]
fshift[Nm+1:,0] = f[1:Np+1,0]
xfshift[:Nm,0] = xf[Np+1:,0]
xfshift[Nm,0] = xf[0,0]
xfshift[Nm+1:,0] = xf[1:Np+1,0]
return xfshift, fshift
# fshiftp ########################################################## fshiftp #
def fshiftp(xf, f):
assert type(f) == np.ndarray, "f must be a np.ndarray"
assert f.shape[1] == 1, "f must be a column array"
assert xf.shape[1] == 1, "xf must be a column array"
assert sum(f<0) > 0, "Some input frequencies must be negative"
# Determine sampling rate, tolerance, and allocate output array
fs, tol = len(f)*(np.abs(f[1,0]-f[0,0])), 1.E-2
fshift = np.zeros((len(f),1), dtype=float)
xfshift = np.zeros((len(f),1), dtype=complex)
# Determine index where f > fs/2
#Nx = np.floor((len(f)+1+tol)/2)
Nm = np.floor(len(f)/2.0)
Np = np.floor((len(f)-1.0)/2.0)
# Compute output frequency array such that -fs/2 <= f < fs/2 and the
# corresponding Fourier coefficients
fshift[Np+1:,0] = f[:Nm:,0] + fs
fshift[0,0] = f[Nm,0]
fshift[1:Np+1:,0] = f[Nm+1:,0]
xfshift[Np+1:,0] = xf[:Nm:,0]
xfshift[0,0] = xf[Nm,0]
xfshift[1:Np+1:,0] = xf[Nm+1:,0]
return xfshift, fshift
# dftlpass ######################################################## dftlpass #
def dftlpass(xt, fs, fcut):
# Perform Discrete Fourier Transform
xf, f = dft(xt, fs, 0.0)
# Shift frequencies to -fs/2 <= f < fs/2 ... and coefficients
xfshift, fshift = fshiftn(xf, f)
# Perform filtration
xfshift = xfshift * (np.abs(fshift) <= fcut)
# Re-shift frequencies to 0 <= f < fs ... and coefficients
xfrecon, frecon = fshiftp(xfshift, fshift)
# Perform inverse Discrete Fourier Transform
yt = idft(xfrecon, fs, 0.0)
return yt.real
# zpblpass ######################################################## zpblpass #
def zpblpass(xn, fcal, fs, fcut):
bz, az = sps.butter(5, fcut/(fs/2))
# Gain calibration
Ncal = np.max([np.int(20*fs/fcal), 30000])
Nguard = np.int(0.1*Ncal)
t = np.arange(Ncal) / fs
x0_cal = 1.0 * np.cos(2*np.pi*fcal*t)
yi_cal = sps.filtfilt(bz, az, 2.0*x0_cal*np.cos(2*np.pi*fcal*t))
k = 1.0/np.mean(yi_cal[Nguard:Ncal-Nguard])
# Scaled output
yn = k * sps.filtfilt(bz, az, xn)
return yn
# bbdftsig ######################################################## bbdftsig #
def bbdftsig(f0, f1, f2, fcut, fs, N):
t = np.arange(N).reshape((N,1)) / fs
s0 = np.sin(2*np.pi*f0*t)
s1 = np.sin(2*np.pi*f1*t + 0.2)
s2 = 0.7 * np.sin(2*np.pi*f2*t + np.pi/3.0)
slow = s0 + s1
s = slow + s2
sf = dftlpass(s, fs, fcut)
sfdftv = sf.reshape((N))
sv = s.reshape((N))
slowv = slow.reshape((N))
sv = s.reshape((N))
sfzpbv = zpblpass(sv, f1, fs, fcut)
#sfzpbv = sfzpb.reshape((N))
return sv, slowv, sfdftv, sfzpbv
# plotsigs ######################################################## plotsigs #
def plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname):
n = np.arange(s.shape[0])
# Plot results
mplpp.figure(1, (5.0,2.25))
mplpp.clf()
mplpp.plot(n[Nstart:Nstop], s[Nstart:Nstop], 'm-',
n[Nstart:Nstop:4], s[Nstart:Nstop:4], 'mx',
n[Nstart:Nstop], slow[Nstart:Nstop], 'g-',
n[Nstart:Nstop:10], slow[Nstart:Nstop:10], 'gx',
n[Nstart:Nstop], sfdft[Nstart:Nstop], 'r-',
n[Nstart:Nstop:15], sfdft[Nstart:Nstop:15], 'rx',
n[Nstart:Nstop], sfzpb[Nstart:Nstop], 'b-',
linewidth=1.5)
mplpp.legend([r'$s$', r'$s$', r'$s_{\rm low}$', r'$s_{\rm low}$',
r'DFT', r'DFT', r'ZPB'], loc='upper right')
mplpp.ylabel(r'Signal')
mplpp.xlabel(r'$n$')
#mplpp.axis([-10.0, 10.0, 1.0E-2, 1.0E2])
mplpp.grid(True)
mplpp.savefig(fname, dpi=600,
bbox_inches='tight', pad_inches=0.05)
mplpp.close()
# __main__ ######################################################## __main__ #
if __name__ == '__main__':
# Initialize
f0 = 3.0
f1 = 11.5
f2 = 20.0
fcut = 15.0
fs = 1000.0
N = 5000
s, slow, sfdft, sfzpb = bbdftsig(f0, f1, f2, fcut, fs, N)
n = np.arange(s.shape[0])
# Fig. 1: full data set
Nstart = 0
Nstop = N
fname = 'full.pdf'
plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)
# Fig. 2: beginning
Nstart = 0
Nstop = 150
fname = 'beginning.pdf'
plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)
# Fig. 3: middle
Nstart = np.floor(N/2.0) - 75
Nstop = Nstart + 100
fname = 'middle.pdf'
plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)
# Fig. 4: ending
Nstart = N - 150
Nstop = N
fname = 'ending.pdf'
plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)
N= 5000fs= 1000fs/ N= 0,2f0 0, f1 1, f2f0 0= 3f1 1= 11f2= 21fc u t= 15
ssl O wsl O wf1 1. Como é bastante típico para esse tipo de processamento, temos algumas diferenças no início e no final da sequência devido a efeitos de borda e razoavelmente boa concordância entre os dois tipos de filtragem na seção intermediária.
f1f1=11.5
slow
Portanto, em conclusão, é possível usar a filtragem direta forçando os coeficientes de Fourier a zero, o que também é feito algumas vezes na detecção compressiva para reduzir o suporte de um sinal para forçar a escarsidade a um sinal. No entanto, há conseqüências disso, devido ao aumento de erros, principalmente nas bordas do sinal. Além disso, o acima é o melhor caso em que todo o sinal é tratado como uma sequência. Se o sinal precisar ser dividido em períodos de tempo, fica complicado, pois precisamos considerar uma técnica de janelas ou outra técnica para garantir a continuidade do sinal entre os quadros. Portanto, meu conselho é semelhante a alguns dos outros posts sobre a recomendação de usar normalmente um Butterworth / Elliptic / .. ou qualquer outro filtro.