我的功率谱可信吗?lomb-scargle和fft(scipy.signal和numpy.fft)的比较

我的功率谱可信吗?lomb-scargle和fft(scipy.signal和numpy.fft)的比较,numpy,scipy,signals,period,Numpy,Scipy,Signals,Period,有人能指出为什么我得到了非常不同的结果吗 有许多峰不应该出现。事实上,应该只有一个峰。 我是一名python新手,欢迎对我下面的代码发表评论 测试数据在这里。 您可以直接wgethttps://clbin.com/YJkwr 它的第一列是一系列光子的到达时间。光源随机发射光子。 总时间为55736秒,有67398个光子。 我试着检测光强度的某种周期性 我们可以对时间进行分类,并且光强度与每个时间分类中的光子数成正比 我尝试了scipy.signal的numpy.fft和lomb scargle来

有人能指出为什么我得到了非常不同的结果吗
有许多峰不应该出现。事实上,应该只有一个峰。
我是一名python新手,欢迎对我下面的代码发表评论

测试数据在这里。
您可以直接
wgethttps://clbin.com/YJkwr

它的第一列是一系列光子的到达时间。光源随机发射光子。 总时间为55736秒,有67398个光子。 我试着检测光强度的某种周期性
我们可以对时间进行分类,并且光强度与每个时间分类中的光子数成正比

我尝试了scipy.signal的numpy.fft和lomb scargle来制作它的功率谱,但得到了非常不同的结果

快速傅里叶变换

大疤

*********************************
谢谢你,沃伦,我很感激。谢谢你的详细回复

你说得对,这里有一个积分时间,大约是1.7秒。
有许多单次曝光。每次曝光成本为1.7秒
在一次曝光中,我们无法准确判断它的到达时间。

如果时间序列类似:
0 1.7 3.4 8.5 8.5

最后两个光子的积分时间是
1.7s
,而不是
(8.5-3.4)s
。因此我将修改部分代码。

然而,我的问题仍然存在。您可以调整多个参数,以在一定程度上获得lomb scargle峰值中的
0.024Hz
峰值。用它来指导fft中的参数

如果您不知道数字
0.024
,可能您可以使用不同的参数来获得不同的最高峰值?

如何保证每次我们都能得到正确的
num\u ls\u freqs
?您可以看到,如果我们选择不同的
num\u ls\u freqs
,最高峰值偏移量。


如果我有很多时间序列,每次我都要指定不同的参数?如何得到它们呢?功率谱是傅里叶变换平方的绝对值。如果除此之外,在FFT中去掉DC值,只绘制结果的正一半,并根据
np.直方图的输出计算仓位宽度,而不是使用一些硬编码的幻数,这就是您得到的结果:

timepoints=np.loadtxt('timesequence',usecols=(0,),unpack=True,delimiter=",")
binshu=50000
t, _=np.histogram(timepoints,bins=binshu)
interd = _[1] - _[0]
sp = np.fft.fft(t)
freq = np.fft.fftfreq(len(t),d=interd)
n = len(freq)
pl.xlabel("frequency(Hz)")
pl.plot(freq[1:n//2],(sp*sp.conj())[1:n//2])


这看起来非常,非常类似于你的Lombscagle周期图。大峰值的位置存在失配,在基于FFT的频谱中约为0.32,在LombScagle输出中更像是0.4x。不确定那里发生了什么,但我不完全理解你的频率计算,特别是在Lombscagle的情况下…

看来50000个垃圾箱是不够的。如果您更改binshu
,您将看到尖峰的位置会发生变化,而不仅仅是一点点

在深入研究FFT或Lomb Scargle之前,我发现先研究原始数据是有用的。以下是文件的开头和结尾:

0,1,3.77903
0,1,4.96859
0,1,1.69098
1.74101,1,4.87652
1.74101,1,5.15564
1.74101,1,2.73634
3.48202,1,3.18583
3.48202,1,4.0806
5.2229,1,1.86738
6.96394,1,7.27398
6.96394,1,3.59345
8.70496,1,4.13443
8.70496,1,2.97584
...
55731.7,1,5.74469
55731.7,1,8.24042
55733.5,1,4.43419
55733.5,1,5.02874
55735.2,1,3.94129
55735.2,1,3.54618
55736.9,1,3.99042
55736.9,1,5.6754
55736.9,1,7.22691
有相同到达时间的集群。(这是光子探测器的原始输出,还是以某种方式对该文件进行了预处理?)

因此,第一步是在同一时间将这些簇合并成一个数字,使数据看起来像(时间点、计数),例如:

以下内容将完成该计数:

times, inv = np.unique(timepoints, return_inverse=True)
counts = np.bincount(inv)
现在,
times
是一个不断增加的唯一时间值数组,
counts
是此时检测到的光子数。(注意,我猜这是对数据的正确解释!)

让我们看看取样是否接近均匀。到达间隔时间的数组是

dt = np.diff(times)
如果采样完全一致,则
dt
中的所有值都相同。我们可以使用上面在
时间点上使用的相同模式来查找
dt
中的唯一值(及其出现频率):

dts, inv = np.unique(dt, return_inverse=True)
dt_counts = np.bincount(inv)
例如,如果我们打印
dts
,它会是什么样子:

[  1.7       1.7       1.7       1.7       1.74      1.74      1.74      1.74
   1.74      1.74      1.74088   1.741     1.741     1.741     1.741
   1.741     1.741     1.741     1.74101   1.74102   1.74104   1.7411
   1.7411    1.7411    1.7411    1.7411    1.742     1.742     1.742
   1.746     1.75      1.8       1.8       1.8       1.8       3.4       3.4
   3.4       3.4       3.48      3.48      3.48      3.48      3.48      3.482
   3.482     3.482     3.482     3.482     3.4821    3.483     3.483     3.49
   3.49      3.49      3.49      3.49      3.5       3.5       5.2       5.2
   5.2       5.2       5.22      5.22      5.22      5.22      5.22      5.223
   5.223     5.223     5.223     5.223     5.223     5.23      5.23      5.23
   5.3       5.3       5.3       5.3       6.9       6.9       6.9       6.9
   6.96      6.96      6.964     6.964     6.9641    7.        8.7       8.7
   8.7       8.7       8.7       8.71     10.4      10.5      12.2    ]
(明显的重复值实际上是不同的。没有显示数字的全部精度。)如果采样完全一致,那么列表中只有一个数字。相反,我们看到的是一组数字,没有明显的主导值。(1.74倍的倍数占优势——这是探测器的特征吗?)

基于这一观察,我们将从Lomb Scargle开始。下面的脚本包括用于计算和绘制(
时间
计数
)数据的Lomb Scarge周期图的代码。给定给
lombscagle
的频率从
1/trange
1/dt.min()
不等,其中
trange
是数据的完整时间跨度。频率数为16000(
num_ls_freqs
)。一些试验和错误表明,这大概是解析光谱所需的最小数量。小于此值时,峰值开始移动。除此之外,光谱变化不大。计算表明,在0.0242 Hz处有一个峰值。其他峰值是该频率的谐波

既然我们有了基频的估计值,我们就可以用它来指导在FFT计算中使用的
时间点
直方图中的仓位大小的选择。我们将使用一个导致基频过采样8倍的箱子大小。(在下面的脚本中,这是
m
)也就是说,我们这样做了

m = 8
nbins = int(m * ls_peak_freq * trange + 0.5)
hist, bin_edges = np.histogram(timepoints, bins=nbins, density=True)
timepoints
是从文件中读取的原始时间集;它包括许多重复的时间值,如上所述。)

然后我们将FFT应用于
hist
。(我们将实际使用
numpy.fft.rfft
)以下是使用fft计算的频谱图:

正如预期的那样,在0.0242 Hz处有一个峰值

以下是脚本:

import numpy as np
from scipy.signal import lombscargle
import matplotlib.pyplot as plt


timepoints = np.loadtxt('timesequence', usecols=(0,), delimiter=",")

# Coalesce the repeated times into the `times` and `counts` arrays.
times, inv = np.unique(timepoints, return_inverse=True)
counts = np.bincount(inv)

# Check the sample spacing--is the sampling uniform?
dt = np.diff(times)
dts, inv = np.unique(dt, return_inverse=True)
dt_counts = np.bincount(inv)
print dts
# Inspection of `dts` shows that the smallest dt is about 1.7, and there
# are many near multiples of 1.74,  but the sampling is not uniform,
# so we'll analyze the spectrum using lombscargle.


# First remove the mean from the data.  This is not essential; it just
# removes the large value at the 0 frequency that we don't care about.
counts0 = counts - counts.mean()

# Minimum interarrival time.
dt_min = dt.min()

# Total time span.
trange = times[-1] - times[0]

# --- Lomb-Scargle calculation ---
num_ls_freqs = 16000
ls_min_freq = 1.0 / trange
ls_max_freq = 1.0 / dt_min
freqs = np.linspace(ls_min_freq, ls_max_freq, num_ls_freqs)
ls_pgram = lombscargle(times, counts0, 2*np.pi*freqs)

ls_peak_k = ls_pgram.argmax()
ls_peak_freq = freqs[ls_peak_k]
print "ls_peak_freq  =", ls_peak_freq


# --- FFT calculation of the binned data ---
# Assume the Lomb-Scargle calculation gave a good estimate
# of the fundamental frequency.  Use a bin size for the histogram
# of timepoints that oversamples that period by m.
m = 8
nbins = int(m * ls_peak_freq * trange + 0.5)
hist, bin_edges = np.histogram(timepoints, bins=nbins, density=True)
delta = bin_edges[1] - bin_edges[0]

fft_coeffs = np.fft.rfft(hist - hist.mean())
fft_freqs = np.fft.fftfreq(hist.size, d=delta)[:fft_coeffs.size]
# Hack to handle the case when hist.size is even.  `fftfreq` puts
# -nyquist where we want +nyquist.
fft_freqs[-1] = abs(fft_freqs[-1])

fft_peak_k = np.abs(fft_coeffs).argmax()
fft_peak_freq = fft_freqs[fft_peak_k]
print "fft_peak_freq =", fft_peak_freq


# --- Lomb-Scargle plot ---
plt.figure(1)
plt.clf()
plt.plot(freqs, ls_pgram)
plt.title('Spectrum computed by Lomb-Scargle')
plt.annotate("%6.4f Hz" % ls_peak_freq, 
             xy=(ls_peak_freq, ls_pgram[ls_peak_k]),
             xytext=(10, -10), textcoords='offset points')
plt.xlabel('Frequency (Hz)')
plt.grid(True)


# --- FFT plot ---
plt.figure(2)
plt.clf()
plt.plot(fft_freqs, np.abs(fft_coeffs)**2)
plt.annotate("%6.4f Hz" % fft_peak_freq,
             xy=(fft_peak_freq, np.abs(fft_coeffs[fft_peak_k])**2),
             xytext=(10, -10), textcoords='offset points')
plt.title("Spectrum computed by FFT")
plt.grid(True)

plt.show()

lomb scargle的中间时间是
[  1.7       1.7       1.7       1.7       1.74      1.74      1.74      1.74
   1.74      1.74      1.74088   1.741     1.741     1.741     1.741
   1.741     1.741     1.741     1.74101   1.74102   1.74104   1.7411
   1.7411    1.7411    1.7411    1.7411    1.742     1.742     1.742
   1.746     1.75      1.8       1.8       1.8       1.8       3.4       3.4
   3.4       3.4       3.48      3.48      3.48      3.48      3.48      3.482
   3.482     3.482     3.482     3.482     3.4821    3.483     3.483     3.49
   3.49      3.49      3.49      3.49      3.5       3.5       5.2       5.2
   5.2       5.2       5.22      5.22      5.22      5.22      5.22      5.223
   5.223     5.223     5.223     5.223     5.223     5.23      5.23      5.23
   5.3       5.3       5.3       5.3       6.9       6.9       6.9       6.9
   6.96      6.96      6.964     6.964     6.9641    7.        8.7       8.7
   8.7       8.7       8.7       8.71     10.4      10.5      12.2    ]
m = 8
nbins = int(m * ls_peak_freq * trange + 0.5)
hist, bin_edges = np.histogram(timepoints, bins=nbins, density=True)
import numpy as np
from scipy.signal import lombscargle
import matplotlib.pyplot as plt


timepoints = np.loadtxt('timesequence', usecols=(0,), delimiter=",")

# Coalesce the repeated times into the `times` and `counts` arrays.
times, inv = np.unique(timepoints, return_inverse=True)
counts = np.bincount(inv)

# Check the sample spacing--is the sampling uniform?
dt = np.diff(times)
dts, inv = np.unique(dt, return_inverse=True)
dt_counts = np.bincount(inv)
print dts
# Inspection of `dts` shows that the smallest dt is about 1.7, and there
# are many near multiples of 1.74,  but the sampling is not uniform,
# so we'll analyze the spectrum using lombscargle.


# First remove the mean from the data.  This is not essential; it just
# removes the large value at the 0 frequency that we don't care about.
counts0 = counts - counts.mean()

# Minimum interarrival time.
dt_min = dt.min()

# Total time span.
trange = times[-1] - times[0]

# --- Lomb-Scargle calculation ---
num_ls_freqs = 16000
ls_min_freq = 1.0 / trange
ls_max_freq = 1.0 / dt_min
freqs = np.linspace(ls_min_freq, ls_max_freq, num_ls_freqs)
ls_pgram = lombscargle(times, counts0, 2*np.pi*freqs)

ls_peak_k = ls_pgram.argmax()
ls_peak_freq = freqs[ls_peak_k]
print "ls_peak_freq  =", ls_peak_freq


# --- FFT calculation of the binned data ---
# Assume the Lomb-Scargle calculation gave a good estimate
# of the fundamental frequency.  Use a bin size for the histogram
# of timepoints that oversamples that period by m.
m = 8
nbins = int(m * ls_peak_freq * trange + 0.5)
hist, bin_edges = np.histogram(timepoints, bins=nbins, density=True)
delta = bin_edges[1] - bin_edges[0]

fft_coeffs = np.fft.rfft(hist - hist.mean())
fft_freqs = np.fft.fftfreq(hist.size, d=delta)[:fft_coeffs.size]
# Hack to handle the case when hist.size is even.  `fftfreq` puts
# -nyquist where we want +nyquist.
fft_freqs[-1] = abs(fft_freqs[-1])

fft_peak_k = np.abs(fft_coeffs).argmax()
fft_peak_freq = fft_freqs[fft_peak_k]
print "fft_peak_freq =", fft_peak_freq


# --- Lomb-Scargle plot ---
plt.figure(1)
plt.clf()
plt.plot(freqs, ls_pgram)
plt.title('Spectrum computed by Lomb-Scargle')
plt.annotate("%6.4f Hz" % ls_peak_freq, 
             xy=(ls_peak_freq, ls_pgram[ls_peak_k]),
             xytext=(10, -10), textcoords='offset points')
plt.xlabel('Frequency (Hz)')
plt.grid(True)


# --- FFT plot ---
plt.figure(2)
plt.clf()
plt.plot(fft_freqs, np.abs(fft_coeffs)**2)
plt.annotate("%6.4f Hz" % fft_peak_freq,
             xy=(fft_peak_freq, np.abs(fft_coeffs[fft_peak_k])**2),
             xytext=(10, -10), textcoords='offset points')
plt.title("Spectrum computed by FFT")
plt.grid(True)

plt.show()