Python中的Fourier变换时间序列

rfbsl7qr  于 2023-04-19  发布在  Python
关注(0)|答案(2)|浏览(154)

我得到了一个太阳黑子数量的时间序列,其中太阳黑子的平均数量是按月计算的,我试图使用傅里叶变换从时域转换到频域。使用的数据来自https://wwwbis.sidc.be/silso/infosnmtot。首先我感到困惑的是如何将采样频率表示为每月一次。我是否需要将其转换为秒,例如。1/(30天内的秒数)?以下是我到目前为止得到的:

fs = 1/2592000
#the sampling frequency is 1/(seconds in a month)

fourier = np.fft.fft(sn_value)
#sn_value is the mean number of sunspots measured each month
freqs = np.fft.fftfreq(sn_value.size,d=fs)

power_spectrum = np.abs(fourier)

plt.plot(freqs,power_spectrum)

plt.xlim(0,max(freqs))
plt.title("Power Spectral Density of the Sunspot Number Time Series")
plt.grid(True)

我不认为这是正确的--因为我不知道x轴的刻度是多少,但我知道在(11年)^-1处应该有一个峰值。
我想知道的第二件事是为什么这个图似乎有两条线-一条是y=0上方的水平线。当我将x轴边界更改为:plt.xlim(0,1).

我是否错误地使用了傅立叶变换函数?

gcuhipw9

gcuhipw91#

你可以使用任何你想要的单位。随意将你的采样频率表示为fs=12(样本/年),那么x轴将是1/年单位。或者使用fs=1(样本/月),那么单位将是1/月。
你发现的额外的一行来自你绘制数据的方式。看看np.fft.fftfreq调用的输出。该数组的前半部分包含从0到1.2e6左右的正值,另一半包含从-1.2e6到几乎0的负值。通过绘制所有数据,你得到一条从0到右边的数据线,然后是从最右边的点到最左边的点的直线,然后数据线的其余部分回到零。您的xlim调用使它这样做,所以您看不到绘制的一半数据。
通常情况下,只绘制数据的前半部分,只需裁剪freqspower_spectrum数组。

ubof19bj

ubof19bj2#

要将频率的步长设置为一年,请确定有多少个样本代表此持续时间(12),然后对参数d取反:

freqs = sf.rfftfreq(n=N, d=1/12)

此外,您可以通过以下方式改进频率范围:

  • 使用周期而不是频率
  • 反转刻度方向以在左侧显示小周期。
  • 限制绘制的频率范围(例如前50个分量),以便查看更长周期的分量的详细信息。两个周期分别为11年和80-90年。

import numpy as np
import pandas as pd
import scipy.fft as sf
import matplotlib.pyplot as plt
import matplotlib.ticker as tck

# Read values, select columns, convert to numpy array
df = pd.read_excel(fp)
df = df.take([3, 1, 4], axis=1)
data = df.to_numpy()

# Sort by date, extract columns in invidual views, remove DC offset
data = data[data[:,0].argsort()]
year = data[:,1]
spots = data[:,2]
spots = spots - spots.mean()

# Get positive DFT of AQI
N = year.shape[0]
X = sf.rfft(spots) / N
freqs = sf.rfftfreq(n=N, d=1/12) # unit = 1/12 of sampling period

# Plot signal
fig, axes = plt.subplots(figsize=(15,3), ncols=2)
ax=axes[0]
ax.plot(year, spots)
ax.xaxis.set_major_locator(tck.MultipleLocator(50))
#ax.grid()

# Plot DFT
ax=axes[1]
extent = 50#N
ax.set_xlabel('period, years')
ax.stem(freqs[:extent], abs(X[:extent]))
ticks = ax.get_xticks()
ax.set_xticklabels([f'{1/tick:.1f}' if tick!=0 else '$\infty$' for tick in ticks])
ax.invert_xaxis()
ax.grid()

相关问题