【问题标题】:Integration in Fourier or time domain傅里叶或时域积分
【发布时间】:2020-03-16 19:11:29
【问题描述】:

我很难理解信号数值积分的问题。基本上我有一个信号,我想积分或执行和反微分作为时间的函数(用于获取磁场的拾取线圈积分)。我尝试了两种不同的方法,它们原则上应该是一致的,但它们不是。我正在使用的代码如下。请注意,代码中的信号 y 之前已经使用巴特沃斯滤波进行了高通滤波(类似于此处 http://wiki.scipy.org/Cookbook/ButterworthBandpass 所做的)。信号和时间基准可以在这里下载(https://www.dropbox.com/s/fi5z38sae6j5410/trial.npz?dl=0

import scipy as sp
from scipy import integrate
from scipy import fftpack
data = np.load('trial.npz')
y = data['arr_1'] # this is the signal 
t = data['arr_0']
# integration using pfft
bI = sp.fftpack.diff(y-y.mean(),order=-1)
bI2= sp.integrate.cumtrapz(y-y.mean(),x=t)

现在这两个信号(除了可以取出的最终不同的线性趋势之外)是不同的,或者更好的是动态它们在相同的振荡时间下非常相似,但是两个信号之间的因子大约为 30,在感觉 bI2 比 bI 低 30 倍(大约)。顺便说一句,我已经减去了两个信号的平均值,以确保它们是零均值信号,并在 IDL 中执行积分(都具有等效的 cumsumtrapz 和傅立叶域)给出与 bI2 兼容的值。任何线索都非常欢迎

【问题讨论】:

  • 谢谢我没有注意到错误
  • 查看数据后,采样率似乎不是固定的。这对于时域集成来说不是问题,但我认为它可能会给频域集成带来问题。要考虑的一件事是将您的时域信号插值到一组固定时间间隔,然后再次尝试频率积分。
  • 我已经尝试在等间隔的时域上使用样条插值,但不幸的是它没有解决我的问题

标签: python scipy


【解决方案1】:

很难知道scipy.fftpack.diff() 在引擎盖下做什么。

为了尝试解决您的问题,我挖出了我前段时间写的一个旧的频域积分函数。值得指出的是,在实践中,与scipy.fftpack.diff() 提供的相比,人们通常希望对某些参数进行更多控制。例如,intf() 函数的 f_lof_hi 参数允许您对输入进行频带限制,以排除可能有噪声的非常低或非常高的频率。特别是嘈杂的低频会在积分过程中“爆炸”并压倒信号。您可能还想在时间序列的开始和结束处使用一个窗口来阻止频谱泄漏。

我计算了bI2 和一个结果bI3,使用以下代码与intf() 集成一次(为简单起见,我假设平均采样率):

import intf
from scipy import integrate
data = np.load(path)
y = data['arr_1']
t = data['arr_0']

bI2= sp.integrate.cumtrapz(y-y.mean(),x=t)
bI3 = intf.intf(y-y.mean(), fs=500458, f_lo=1, winlen=1e-2, times=1)

我绘制了 bI2 和 bI3:

这两个时间序列的数量级相同,形状大致相同,尽管 bI2 中存在明显的分段线性趋势。我知道这并不能解释 scipy 函数中发生了什么,但至少这表明频域方法没有问题。

intf 的代码完整粘贴在下面。

def intf(a, fs, f_lo=0.0, f_hi=1.0e12, times=1, winlen=1, unwin=False):
"""
Numerically integrate a time series in the frequency domain.

This function integrates a time series in the frequency domain using
'Omega Arithmetic', over a defined frequency band.

Parameters
----------
a : array_like
    Input time series.
fs : int
    Sampling rate (Hz) of the input time series.
f_lo : float, optional
    Lower frequency bound over which integration takes place.
    Defaults to 0 Hz.
f_hi : float, optional
    Upper frequency bound over which integration takes place.
    Defaults to the Nyquist frequency ( = fs / 2).
times : int, optional
    Number of times to integrate input time series a. Can be either 
    0, 1 or 2. If 0 is used, function effectively applies a 'brick wall' 
    frequency domain filter to a.
    Defaults to 1.
winlen : int, optional
    Number of seconds at the beginning and end of a file to apply half a 
    Hanning window to. Limited to half the record length.
    Defaults to 1 second.
unwin : Boolean, optional
    Whether or not to remove the window applied to the input time series
    from the output time series.

Returns
-------
out : complex ndarray
    The zero-, single- or double-integrated acceleration time series.

Versions
----------
1.1 First development version. 
    Uses rfft to avoid complex return values.
    Checks for even length time series; if not, end-pad with single zero.
1.2 Zero-means time series to avoid spurious errors when applying Hanning
    window.

"""

a = a - a.mean()                        # Convert time series to zero-mean
if np.mod(a.size,2) != 0:               # Check for even length time series
    odd = True
    a = np.append(a, 0)                 # If not, append zero to array
else:
    odd = False
f_hi = min(fs/2, f_hi)                  # Upper frequency limited to Nyquist
winlen = min(a.size/2, winlen)          # Limit window to half record length

ni = a.size                             # No. of points in data (int) 
nf = float(ni)                          # No. of points in data (float)
fs = float(fs)                          # Sampling rate (Hz)
df = fs/nf                              # Frequency increment in FFT
stf_i = int(f_lo/df)                    # Index of lower frequency bound
enf_i = int(f_hi/df)                    # Index of upper frequency bound

window = np.ones(ni)                    # Create window function
es = int(winlen*fs)                     # No. of samples to window from ends
edge_win = np.hanning(es)               # Hanning window edge 
window[:es/2] = edge_win[:es/2]
window[-es/2:] = edge_win[-es/2:]
a_w = a*window

FFTspec_a = np.fft.rfft(a_w)            # Calculate complex FFT of input
FFTfreq = np.fft.fftfreq(ni, d=1/fs)[:ni/2+1]

w = (2*np.pi*FFTfreq)                   # Omega
iw = (0+1j)*w                           # i*Omega

mask = np.zeros(ni/2+1)                 # Half-length mask for +ve freqs
mask[stf_i:enf_i] = 1.0                 # Mask = 1 for desired +ve freqs

if times == 2:                          # Double integration
    FFTspec = -FFTspec_a*w / (w+EPS)**3
elif times == 1:                        # Single integration
    FFTspec = FFTspec_a*iw / (iw+EPS)**2
elif times == 0:                        # No integration
    FFTspec = FFTspec_a
else:
    print 'Error'

FFTspec *= mask                         # Select frequencies to use

out_w = np.fft.irfft(FFTspec)           # Return to time domain

if unwin == True:
    out = out_w*window/(window+EPS)**2  # Remove window from time series
else:
    out = out_w

if odd == True:                         # Check for even length time series
    return out[:-1]                     # If not, remove last entry
else:        
    return out

【讨论】:

  • 我想测试你的代码,但是有一个变量未定义,EPS是什么?
  • 找到。你解决了我的问题。感谢您分享这段代码
  • 什么是EPS?是 machine_epsilon 吗?
  • 抱歉,忘记在函数中定义了。防止除以零错误只是一个小值
  • 我认为我将它设置为 1e-6 之类的。
猜你喜欢
  • 2012-05-18
  • 2019-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多