Python 基于对数轴fftpack的真实数据功率谱

Python 基于对数轴fftpack的真实数据功率谱,python,numpy,scipy,fft,fftpack,Python,Numpy,Scipy,Fft,Fftpack,我已经读了很多关于这个话题的讨论(,,和其他很多),但仍然无法处理它,所以我需要一些提示。 我有一个光子事件列表(检测与时间),数据可用。这些列包括时间,计数,错误,以及不同能带中的计数(您可以忽略它们)。我知道震源的周期约为8.9天=1.3*10^-6 Hz。 我想绘制功率谱密度图,显示该频率下的峰值(可能在对数x轴上)。如果我能避免一半情节(对称),那也很好。这是我到目前为止的代码,还没有到目前为止,但仍然有些东西: import numpy as np from scipy.fftpack

我已经读了很多关于这个话题的讨论(,,和其他很多),但仍然无法处理它,所以我需要一些提示。 我有一个光子事件列表(检测与时间),数据可用。这些列包括
时间
计数
错误
,以及不同能带中的计数(您可以忽略它们)。我知道震源的周期约为
8.9天=1.3*10^-6 Hz
。 我想绘制功率谱密度图,显示该频率下的峰值(可能在对数x轴上)。如果我能避免一半情节(对称),那也很好。这是我到目前为止的代码,还没有到目前为止,但仍然有些东西:

import numpy as np
from scipy.fftpack import fft, rfft, fftfreq
import pylab as plt

x,y = np.loadtxt('datafile.txt', usecols = (0,1), unpack=True)
y = y - y.mean() # Removes the large value at the 0 frequency that we don't care about

f_range = np.linspace(10**(-7), 10**(-5), 1000)
W = fftfreq(y.size, d=x[1]-x[0])

plt.subplot(2,1,1)
plt.plot(x,y)
plt.xlabel('Time (days)')

f_signal = fft(y)
plt.subplot(2,1,2)
plt.plot(W, abs(f_signal))
plt.xlabel('Frequency (Hz)')
此处生成的(无用)绘图:
以下是上述代码的改进版本:

import pyfits
import numpy as np
from scipy.fftpack import fft, rfft, fftfreq
import pylab as plt

x,y = np.loadtxt('data.txt', usecols = (0,1), unpack=True)
y = y - y.mean()

W = fftfreq(y.size, d=(x[1]-x[0])*86400)
plt.subplot(2,1,1)
plt.plot(x,y)
plt.xlabel('Time (days)')

f_signal = fft(y)
plt.subplot(2,1,2)
plt.plot(W, abs(f_signal)**2)
plt.xlabel('Frequency (Hz)')

plt.xscale('log')
plt.xlim(10**(-6), 10**(-5))
plt.show()
图中显示的是(正确的): 最高峰是我试图重现的高峰。预计还会出现第二个峰值,但功率较低(事实上是这样)。 如果使用
rfft
而不是
fft
(和
rfftfreq
而不是
fftfreq
),则复制相同的绘图(在这种情况下,可以使用频率值而不是模块)


我不想阻止这个话题,所以我会在这里问:我如何才能检索到峰值的频率?最好在峰值旁边绘制频率。

这是上述代码的改进版本:

import pyfits
import numpy as np
from scipy.fftpack import fft, rfft, fftfreq
import pylab as plt

x,y = np.loadtxt('data.txt', usecols = (0,1), unpack=True)
y = y - y.mean()

W = fftfreq(y.size, d=(x[1]-x[0])*86400)
plt.subplot(2,1,1)
plt.plot(x,y)
plt.xlabel('Time (days)')

f_signal = fft(y)
plt.subplot(2,1,2)
plt.plot(W, abs(f_signal)**2)
plt.xlabel('Frequency (Hz)')

plt.xscale('log')
plt.xlim(10**(-6), 10**(-5))
plt.show()
图中显示的是(正确的): 最高峰是我试图重现的高峰。预计还会出现第二个峰值,但功率较低(事实上是这样)。 如果使用
rfft
而不是
fft
(和
rfftfreq
而不是
fftfreq
),则复制相同的绘图(在这种情况下,可以使用频率值而不是模块)


我不想阻止这个话题,所以我会在这里问:我如何才能检索到峰值的频率?最好在峰值旁边绘制频率。

两个问题:1)我认为
fftfreq
仅适用于
fft
,而不适用于
rfft
(具有不同的频率轴);2)
rfft
给出了一个复杂的结果,因此绘制
abs(f_信号)
。谢谢汤姆。你的意思是我应该使用
f_信号=fft(y)
而不是
f_信号=rfft(y)
?这样就行了。由于信号是真实的,
fft(y)
rfft(y)
应该可以工作,但是由于
fft
fftfreq
有对应关系,
fft
可能是(反直觉地)最容易获得频率轴的方法。(同样,使用这两种方法中的任何一种,您也必须获得幅值,即使用
abs
,因为绘制真实分量并不罕见,因为功率在R和I分量之间移动,因此结果看起来像您显示的那样起伏。)您确定底部单位为
Hz
?更可能是
1/天
,因为天是数据的单位。那么最高的峰值可能在9天。也就是说,我想你基本上得到了你想要的,只要稍微按摩一下就可以了。因此:0)确保单位正确;1) 放大x轴以更好地查看感兴趣的部分;2) 可能使用rfft;3) 如果你愿意,就拿对数。功率谱实际上是DFT的平方,而不是它的模。有两个问题:1)我认为
fftfreq
只适用于
fft
,而不是
rfft
(具有不同的频率轴);2)
rfft
给出了一个复杂的结果,因此绘制
abs(f_信号)
。谢谢汤姆。你的意思是我应该使用
f_信号=fft(y)
而不是
f_信号=rfft(y)
?这样就行了。由于信号是真实的,
fft(y)
rfft(y)
应该可以工作,但是由于
fft
fftfreq
有对应关系,
fft
可能是(反直觉地)最容易获得频率轴的方法。(同样,使用这两种方法中的任何一种,您也必须获得幅值,即使用
abs
,因为绘制真实分量并不罕见,因为功率在R和I分量之间移动,因此结果看起来像您显示的那样起伏。)您确定底部单位为
Hz
?更可能是
1/天
,因为天是数据的单位。那么最高的峰值可能在9天。也就是说,我想你基本上得到了你想要的,只要稍微按摩一下就可以了。因此:0)确保单位正确;1) 放大x轴以更好地查看感兴趣的部分;2) 可能使用rfft;3) 如果你愿意,就拿对数。功率谱实际上是DFT的平方,而不是它的模。这有助于使峰顶更加引人注目。峰顶发现可能通过。然而,还有很多其他方法,根据具体情况可能会更好地发挥作用。你也可以在这个话题上提出一个新问题。这里可能还存在类似于前面所问的问题。要在图表中输入峰值信息:实际上,除非您使用多组数据,否则只需放大并从绘图中读取峰值(或您感兴趣的任何内容)的时间和值,然后使用
plt.annotate
plt.txt
将数字放入数字中。峰值查找可能通过。然而,还有很多其他方法,根据具体情况可能会更好地发挥作用。你也可以在这个话题上提出一个新问题。这里可能还存在类似于前面所问的问题。要在图表中输入峰值信息:实际上,除非您使用多组数据,否则只需放大并从绘图中读取峰值(或您感兴趣的任何内容)的时间和值,然后使用
plt.annotate
plt.txt
将数字放入图中。