从PSD python计算时间序列

时间:2015-03-17 09:23:14

标签: python time-series fft spectrum

我的信号频谱PSD看起来像:

enter image description here

PSD的频率范围是np.linspace(0,2,500)。我想将此光谱转换为600s的时间序列。代码如下所示:

def spectrumToSeries(timeSeries,frequency,psdLoad):
    ''' 
    Function that gicen a PSD converts into a time series

    '''
    #
    #Obtian interval frequency
    df=frequency[2]-frequency[1]    

    #Obtian the spectrum amplitudes
    amplitude=np.sqrt(2*np.array(psdLoad)*df)

    #Pre allocation of matrices
    epsilon=np.zeros((len(amplitude)))
    randomSeries=np.zeros((len(amplitude)))


    #Create time series from spectrum
    #Generate random phases between [-2pi,2pi]
    epsilon=-np.pi + 2*np.pi*np.random.randn(1,len(amplitude))

    #Inverse Fourier
    randomSeries=len(timeSeries)*np.real(np.fft.ifft(amplitude*np.exp(epsilon*1j*2*np.pi))));

    return randomSeries

然而,我的最终结果如下:

timeSeries = spectrumToSeries(thrustBladed,param.frequency,analyticalThrustPSD[iwind])   

enter image description here

x轴表示时间序列的点数。但是,时间序列应该是600s。有帮助吗?谢谢

1 个答案:

答案 0 :(得分:0)

你的功能结果" spectrumToSeries"与您在np.fft.ifft中提供的数组长度相同。因为ifft函数返回与输入长度相同的数组。 所以,因为你的初始psdLoad数组有500个元素,"幅度"数组也是500个元素,而randomSeries也是一个,这是你的函数的结果。

我没有真正得到你功能的不同输入。什么是第一个称为timeSeries的参数?它是一个600个元素的空矩阵,等待函数的结果吗?

我正在尝试自己计算PSD的时间序列,所以我很乐意看到你的功能给出了好的结果!

我认为如果你想让你的时间序列为600个元素,你需要有一个"频率"和一个" psdLoad" 600个元素的数组。所以我试图用我的数据集来适应我的psdLoad函数(psdLoad = f(频率))。然后我可以将我的数组的大小设置为我想要的时间序列的长度,并计算ifft ......

我自己的数据是1Hz的记录,超过一天,所以86400个元素的数组。我必须使用PSD方法对其应用滤镜。所以我计算我的PSD,长度为129个元素,一旦我过滤了它,我想最终得到我的过滤时间序列。

这是我的代码:

######################################################################"
## Computation of spectrum values : PSD & frequency ##
######################################################################"

psd_ampl0, freq = mlab.psd(Up13_7april, NFFT=256, Fs=1, detrend=mlab.detrend_linear, window=mlab.window_hanning, noverlap=0.5, sides='onesided')

################################################"
## Computation of the time series from the PSD ##
################################################"


def PSDToSeries(lenTimeSeries,freq,psdLoad):
    ''' 
    Function that gicen a PSD converts into a time series

    '''
    #
    #Obtian interval frequency
    df=freq[2]-freq[1]    
    print('df = ', df)

    #Obtian the spectrum amplitudes
    amplitude=(2*psdLoad*df)**0.5

    #Pre allocation of matrices
    epsilon=np.zeros((len(amplitude)))
    randomSeries=np.zeros((len(amplitude)))


    #Create time series from spectrum
    #Generate random phases between [-2pi,2pi]
    epsilon=-np.pi + 2*np.pi*np.random.randn(1,len(amplitude))

    #Inverse Fourier
    randomSeries=lenTimeSeries*np.real(np.fft.ifft(amplitude*np.exp(epsilon*1j*2*np.pi)));

    return randomSeries

#-------------------------------------------------------------------------

#########################################################"
## Fitting a function on the PSD to add it more points ##
#########################################################"

#def fitting_function(freq,a,b,c,d,e,f):
    #return a*(freq**5)+b*(freq**4)+c*(freq**3)+d*(freq**2)+e*freq+f

def fitting_function(freq,a,b,c):
    return a*np.exp(freq*b)

# Look for the best fitting parameters of the choosen fitting function #

param_opt, pcov = optim.curve_fit(fitting_function,freq[1:],psd_ampl0[1:])

print('The best fitting parameters are : ',param_opt)

# Definition of the new PSD and frequency arrays extended to 86400 elements #

freq_extend = np.linspace(min(freq),max(freq), 86400)

psd_extend = fitting_function(freq_extend,param_opt[0], param_opt[1], param_opt[2])

#print(psd_allonge)

ts_length = Up13_7april.shape[0] #Length of the timeSeries I want to compute

print('ts_length = ', ts_length)

tsFromPSD = PSDToSeries(ts_length, freq_allonge, psd_allonge)

print('shape tsFromPSD : ', tsFromPSD.shape)


##################"
## Plot section ##
##################"

plt.figure(1)
plt.plot(freq[1:] ,psd_ampl0[1:],marker=',', ls='-',color='SkyBlue', label='original PSD')
plt.plot(freq_allonge, psd_allonge,  marker=',', ls='-',color='DarkGreen', label='PSD rallonge')
plt.xlabel('Frequency [Hz]')
plt.ylabel('PSD of raw velocity module [(m/s)²/Hz]')
plt.grid(True)
plt.legend()


plt.figure(2)
plt.plot_date(time7april,Up13_7april, xdate=True, ydate=False, marker=',', ls='-', c='Grey', label='Original Signal')
plt.plot_date(time7april, tsFromPSD[0],xdate=True, ydate=False, marker=',', ls='-', label='After inverse PSD')
plt.suptitle('Original and Corrected time series for the 7th of April')
plt.grid(True)
plt.legend()

plt.show()

阵列Up13_7april,是我的初始时间序列,在这段代码中,我只是试图计算PSD,然后回到时间系列来比较原始信号和最后一个。结果如下:

[抱歉无法发布任何图片,因为我是stackoverflow的新手]

所以我的过程是找到一个适合PSD的功能。我使用名为" optimize.curve_fit"的Python scipy函数。它只是为您提供最佳参数,以使您提供的功能适合您的数据。 一旦我有参数,我就会创建86400个元素的新PSD和频率数组。最后我使用你的" PSDToSeries"函数来计算timeSeries。

我对结果非常满意......我想我只需要找到更适合我的PSD:

[抱歉无法发布任何图片,因为我是stackoverflow的新手]

有什么想法吗?