如何找到信号周期(自相关与快速傅里叶变换与功率谱密度)?

2023-11-24

假设有人想要找到给定正弦波信号的周期。从我在网上读到的内容来看,两种主要方法似乎采用傅里叶分析或自相关。我正在尝试使用 python 自动化该过程,我的用例是将这个概念应用于来自绕恒星运行的模拟物体的位置(或速度或加速度)时间序列的类似信号。

为了简单起见,考虑x = sin(t) for 0 ≤ t ≤ 10 pi.

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

## sample data
t = np.linspace(0, 10 * np.pi, 100)
x = np.sin(t)
fig, ax = plt.subplots()
ax.plot(t, x, color='b', marker='o')
ax.grid(color='k', alpha=0.3, linestyle=':')
plt.show()
plt.close(fig)

example sine wave

给定以下形式的正弦波x = a sin(b(t+c)) + d,正弦波的周期为2 * pi / b. Since b=1(或通过目视检查),我们的正弦波的周期是2 * pi。我可以根据此基线检查从其他方法获得的结果。

尝试 1:自相关

据我了解(如果我错了,请纠正我),相关性可用于查看一个信号是否是另一个信号的时滞副本(类似于余弦和正弦相差相位差)。因此,自相关是针对自身测试信号,以测量时滞重复所述信号的时间。使用此处发布的示例:

result = np.correlate(x, x, mode='full')

Since x and t每个由100元素和result由组成199元素,我不知道为什么我应该任意选择最后一个100元素。

print("\n autocorrelation (shape={}):\n{}\n".format(result.shape, result))  

 autocorrelation (shape=(199,)):
[ 0.00000000e+00 -3.82130761e-16 -9.73648712e-02 -3.70014208e-01
 -8.59889695e-01 -1.56185995e+00 -2.41986054e+00 -3.33109112e+00
 -4.15799070e+00 -4.74662427e+00 -4.94918053e+00 -4.64762251e+00
 -3.77524157e+00 -2.33298717e+00 -3.97976240e-01  1.87752669e+00
  4.27722402e+00  6.54129270e+00  8.39434617e+00  9.57785701e+00
  9.88331103e+00  9.18204933e+00  7.44791758e+00  4.76948221e+00
  1.34963425e+00 -2.50822289e+00 -6.42666652e+00 -9.99116299e+00
 -1.27937834e+01 -1.44791297e+01 -1.47873668e+01 -1.35893098e+01
 -1.09091510e+01 -6.93157447e+00 -1.99159756e+00  3.45267493e+00
  8.86228186e+00  1.36707567e+01  1.73433176e+01  1.94357232e+01
  1.96463736e+01  1.78556800e+01  1.41478477e+01  8.81191526e+00
  2.32100171e+00 -4.70897483e+00 -1.15775811e+01 -1.75696560e+01
 -2.20296487e+01 -2.44327920e+01 -2.44454330e+01 -2.19677060e+01
 -1.71533510e+01 -1.04037163e+01 -2.33560966e+00  6.27458308e+00
  1.45655029e+01  2.16769872e+01  2.68391837e+01  2.94553896e+01
  2.91697473e+01  2.59122266e+01  1.99154591e+01  1.17007613e+01
  2.03381596e+00 -8.14633251e+00 -1.78184255e+01 -2.59814393e+01
 -3.17580589e+01 -3.44884934e+01 -3.38046447e+01 -2.96763956e+01
 -2.24244433e+01 -1.26974172e+01 -1.41464998e+00  1.03204331e+01
  2.13281784e+01  3.04712823e+01  3.67721634e+01  3.95170295e+01
  3.83356037e+01  3.32477037e+01  2.46710643e+01  1.33886439e+01
  4.77778141e-01 -1.27924775e+01 -2.50860560e+01 -3.51343866e+01
 -4.18671622e+01 -4.45258983e+01 -4.27482779e+01 -3.66140001e+01
 -2.66465884e+01 -1.37700036e+01  7.76494745e-01  1.55574483e+01
  2.90828312e+01  3.99582426e+01  4.70285203e+01  4.95000000e+01
  4.70285203e+01  3.99582426e+01  2.90828312e+01  1.55574483e+01
  7.76494745e-01 -1.37700036e+01 -2.66465884e+01 -3.66140001e+01
 -4.27482779e+01 -4.45258983e+01 -4.18671622e+01 -3.51343866e+01
 -2.50860560e+01 -1.27924775e+01  4.77778141e-01  1.33886439e+01
  2.46710643e+01  3.32477037e+01  3.83356037e+01  3.95170295e+01
  3.67721634e+01  3.04712823e+01  2.13281784e+01  1.03204331e+01
 -1.41464998e+00 -1.26974172e+01 -2.24244433e+01 -2.96763956e+01
 -3.38046447e+01 -3.44884934e+01 -3.17580589e+01 -2.59814393e+01
 -1.78184255e+01 -8.14633251e+00  2.03381596e+00  1.17007613e+01
  1.99154591e+01  2.59122266e+01  2.91697473e+01  2.94553896e+01
  2.68391837e+01  2.16769872e+01  1.45655029e+01  6.27458308e+00
 -2.33560966e+00 -1.04037163e+01 -1.71533510e+01 -2.19677060e+01
 -2.44454330e+01 -2.44327920e+01 -2.20296487e+01 -1.75696560e+01
 -1.15775811e+01 -4.70897483e+00  2.32100171e+00  8.81191526e+00
  1.41478477e+01  1.78556800e+01  1.96463736e+01  1.94357232e+01
  1.73433176e+01  1.36707567e+01  8.86228186e+00  3.45267493e+00
 -1.99159756e+00 -6.93157447e+00 -1.09091510e+01 -1.35893098e+01
 -1.47873668e+01 -1.44791297e+01 -1.27937834e+01 -9.99116299e+00
 -6.42666652e+00 -2.50822289e+00  1.34963425e+00  4.76948221e+00
  7.44791758e+00  9.18204933e+00  9.88331103e+00  9.57785701e+00
  8.39434617e+00  6.54129270e+00  4.27722402e+00  1.87752669e+00
 -3.97976240e-01 -2.33298717e+00 -3.77524157e+00 -4.64762251e+00
 -4.94918053e+00 -4.74662427e+00 -4.15799070e+00 -3.33109112e+00
 -2.41986054e+00 -1.56185995e+00 -8.59889695e-01 -3.70014208e-01
 -9.73648712e-02 -3.82130761e-16  0.00000000e+00]

尝试 2:傅立叶

由于我不知道从上次的尝试到哪里去,我寻求新的尝试。据我了解,傅立叶分析基本上将信号从时域转移到时域(x(t) vs t) 到/从频域 (x(t) vs f=1/t);频率空间中的信号应显示为随时间衰减的正弦波。该周期是从最常观察到的频率获得的,因为这是频率分布峰值的位置。

由于我的值都是实值,应用傅里叶变换应该意味着我的输出值都是复值。我不认为这是一个问题,除了以下事实:scipy 有实值方法。我不完全理解所有不同 scipy 方法之间的差异。这使得遵循中提出的算法这个发布的解决方案我很难理解(即,如何/为什么选择阈值?)。

omega = np.fft.fft(x)
freq = np.fft.fftfreq(x.size, 1)
threshold = 0
idx = np.where(abs(omega)>threshold)[0][-1]
max_f = abs(freq[idx])
print(max_f)

这输出0.01,意味着周期是1/0.01 = 100。这也没有道理。

尝试 3:功率谱密度

根据scipy 文档,我应该能够使用周期图来估计信号的功率谱密度(psd)(其中,根据维基百科,是自相关函数的傅里叶变换)。通过选择主频率fmax信号达到峰值时,信号的周期可由下式获得:1 / fmax.

freq, pdensity = signal.periodogram(x)

fig, ax = plt.subplots()
ax.plot(freq, pdensity, color='r')
ax.grid(color='k', alpha=0.3, linestyle=':')
plt.show()
plt.close(fig)

下面显示的周期图峰值位于49.076...频率为fmax = 0.05. So, period = 1/fmax = 20。这对我来说没有意义。我感觉这与采样率有关,但不知道是否足以确认或进一步进展。

我意识到我在理解这些东西如何运作方面缺少一些基本的差距。网上资源很多,但大海捞针却很难。有人可以帮助我了解更多相关信息吗?

periodogram


让我们首先看看你的信号(我已经添加了endpoint=False使划分均匀):

t = np.linspace(0, 10*np.pi, 100, endpoint=False)
x = np.sin(t)

让我们划分弧度(本质上是通过取t /= 2*np.pi)并通过与频率相关来创建相同的信号:

fs = 20 # Sampling rate of 100/5 = 20 (e.g. Hz)
f = 1 # Signal frequency of 1 (e.g. Hz)
t = np.linspace(0, 5, 5*fs, endpoint=False)
x = np.sin(2*np.pi*f*t)

这使得它更加突出f/fs == 1/20 == 0.05(即信号的周期正好是 20 个样本)。正如您已经猜到的那样,数字信号中的频率始终与其采样率相关。请注意,无论 的值是多少,实际信号都是完全相同的f and fs是,只要它们的比率相同:

fs = 1 # Natural units
f = 0.05
t = np.linspace(0, 100, 100*fs, endpoint=False)
x = np.sin(2*np.pi*f*t)

下面我将使用这些自然单位(fs = 1)。唯一的区别在于t以及生成的频率轴。

自相关

您对自相关函数作用的理解是正确的。它检测信号与其自身的时滞版本的相关性。它通过将信号滑过自身来实现这一点,如右列所示(来自维基百科):

Autocorrelation

请注意,由于相关函数的两个输入相同,所得信号必然是对称的。这就是为什么输出np.correlate通常是从中间切开:

acf = np.correlate(x, x, 'full')[-len(x):]

现在索引 0 对应于信号的两个副本之间的 0 延迟。

接下来,您需要找到呈现最大相关性的索引或延迟。由于重叠缩小,默认情况下索引也为 0,因此以下内容将不起作用:

acf.argmax() # Always returns 0

相反,我建议找到最大的peak相反,峰值被定义为值大于其直接邻居的任何索引:

inflection = np.diff(np.sign(np.diff(acf))) # Find the second-order differences
peaks = (inflection < 0).nonzero()[0] + 1 # Find where they are negative
delay = peaks[acf[peaks].argmax()] # Of those, find the index with the maximum value

Now delay == 20,它告诉您信号的频率为1/20其采样率:

signal_freq = fs/delay # Gives 0.05

傅里叶变换

您使用以下公式来计算 FFT:

omega = np.fft.fft(x)
freq = np.fft.fftfreq(x.size, 1)

这些函数针对复值信号重新设计。它们适用于实值信号,但您将获得对称输出,因为负频率分量将与正频率分量相同。 NumPy 为实值信号提供单独的函数:

ft = np.fft.rfft(x)
freqs = np.fft.rfftfreq(len(x), t[1]-t[0]) # Get frequency axis from the time axis
mags = abs(ft) # We don't care about the phase information here

我们来看一下:

plt.plot(freqs, mags)
plt.show()

FFT

请注意两件事:峰值位于频率 0.05 处,轴上的最大频率为 0.5(奈奎斯特频率,恰好是采样率的一半)。如果我们选择了fs = 20,这将是 10。

现在让我们找出最大值。您尝试过的阈值方法can工作,但目标频率仓是盲目选择的,因此该方法在存在其他信号的情况下会受到影响。我们可以只选择最大值:

signal_freq = freqs[mags.argmax()] # Gives 0.05

然而,如果例如我们有一个大的直流偏移(因此索引 0 中有一个大的分量),这就会失败。在这种情况下,我们可以再次选择最高峰,以使其更加稳健:

inflection = np.diff(np.sign(np.diff(mags)))
peaks = (inflection < 0).nonzero()[0] + 1
peak = peaks[mags[peaks].argmax()]
signal_freq = freqs[peak] # Gives 0.05

如果我们选择了fs = 20,这会给signal_freq == 1.0由于生成频率轴的时间轴不同。

周期图

这里的方法本质上是一样的。自相关函数为x具有相同的时间轴和周期x,所以我们可以使用上面的 FFT 来找到信号频率:

pdg = np.fft.rfft(acf)
freqs = np.fft.rfftfreq(len(x), t[1]-t[0])

plt.plot(freqs, abs(pdg))
plt.show()

Periodogram

这条曲线显然与直接 FFT 的特性略有不同x,但主要要点是相同的:频率轴的范围是0 to 0.5*fs,我们在与之前相同的信号频率处找到一个峰值:freqs[abs(pdg).argmax()] == 0.05.

Edit:

测量实际的周期性np.sin,我们可以只使用我们传递给的“角度轴”np.sin生成频率轴时代替时间轴:

freqs = np.fft.rfftfreq(len(x), 2*np.pi*f*(t[1]-t[0]))
rad_period = 1/freqs[mags.argmax()] # 6.283185307179586

虽然这看起来毫无意义,对吧?我们传入2*np.pi我们得到2*np.pi。然而,我们可以对任何常规时间轴做同样的事情,而不需要预先假设pi在任何一点:

fs = 10
t = np.arange(1000)/fs
x = np.sin(t)
rad_period = 1/np.fft.rfftfreq(len(x), 1/fs)[abs(np.fft.rfft(x)).argmax()] # 6.25

当然,现在真正的价值位于两个箱子之间。这就是插值的用武之地以及选择合适的窗口函数的相关需求。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何找到信号周期(自相关与快速傅里叶变换与功率谱密度)? 的相关文章

  • Python:使用 string.format() 将单词大写

    是否可以使用字符串格式将单词大写 例如 user did such and such format user foobar 应该返回 Foobar 做了这样那样的事情 请注意 我很清楚 capitalize 但是 这是我正在使用的代码 非常
  • Python GTK + webkit - 在 gtk.main() 之后插入 JavaScript

    我在终端中尝试了这个 一切正常 但是如果我在脚本内运行这个 我无法在 gtk main 之后插入 JavaScript import gtk import webkit w gtk Window b webkit WebView w add
  • 最小二乘法拟合直线 python 代码

    我有一个由 X 和 Y 坐标组成的散点图 我想使用直线的最小二乘拟合来获得最佳拟合线 直线最小二乘拟合是指 如果 x 1 y 1 x n y n 是测量数据对 则最佳直线是y A Bx 这是我的Python代码 number of poin
  • 组和平均 NumPy 矩阵

    假设我有一个任意的 numpy 矩阵 如下所示 arr 6 0 12 0 1 0 7 0 9 0 1 0 8 0 7 0 1 0 4 0 3 0 2 0 6 0 1 0 2 0 2 0 5 0 2 0 9 0 4 0 3 0 2 0 1 0
  • Python 的 mysqldb 晦涩文档

    Python 模块 mysqldb 中有许多转义函数 我不理解它们的文档 而且我努力查找它们也没有发现任何结果 gt gt gt print mysql escape doc escape obj dict escape any speci
  • 使用 pandas 将字符串对象转换为 int/float

    import pandas as pd path1 home supertramp Desktop 100 life 180 data csv mydf pd read csv path1 numcigar Never 0 1 5 Ciga
  • Perl 是否有相当于 Python 的 `if __name__ == '__main__'` 的功能?

    有没有一种方法可以确定当前文件是否是 Perl 源中正在执行的文件 在 Python 中 我们使用以下结构来做到这一点 if name main This file is being executed raise NotImplemente
  • 在Python中以交互方式执行多行语句

    我是 Python 世界的新手 这是我用 Python 编写的第一个程序 我来自 R 世界 所以这对我来说有点不直观 当我执行时 In 15 import math import random random random math sqrt
  • Django 模型字段默认基于另一个模型字段

    我使用 Django Admin 构建一个管理站点 有两张表 一张是ModelA其中有数据 另一个是ModelB里面什么也没有 如果一个模型字段b b in ModelB为None 可以显示在网页上 值为ModelA的场a b 我不知道该怎
  • Tensorflow 不分配完整的 GPU 内存

    Tensorflow 默认分配所有 GPU 内存 但我的新设置实际上只有 9588 MiB 11264 MiB 我预计大约 11 000MiB 就像我的旧设置一样 张量流信息在这里 from tensorflow python client
  • 返回上个月的日期时间对象

    如果 timedelta 在它的构造函数中有一个月份参数就好了 那么最简单的方法是什么 EDIT 正如下面指出的那样 我并没有认真考虑这一点 我真正想要的是上个月的任何一天 因为最终我只会获取年份和月份 因此 给定一个日期时间对象 返回的最
  • 在 Linux 上的 Python 中使用受密码保护的 Excel 工作表

    问题很简单 我每周都会收到一堆受密码保护的 Excel 文件 我必须解析它们并使用 Python 将某些部分写入新文件 我得到了文件的密码 当在 Windows 上完成此操作时 处理起来很简单 我只需导入 win32com 并使用 clie
  • 如何将类添加到 LinkML 中的 SchemaDefinition?

    中的图表https linkml io linkml model docs SchemaDefinition https linkml io linkml model docs SchemaDefinition and https link
  • Python 3在for循环中更改字典键的值不起作用

    我的 python 3 代码没有按预期工作 def addFunc x y print x y def subABC x y z print x y z def doublePower base exp print 2 base exp d
  • 如何使用 Celery 多工作人员启用自动缩放?

    命令celery worker A proj autoscale 10 1 loglevel info启动具有自动缩放功能的工作人员 当创建多个工人时 me mypc projects x celery multi start mywork
  • Django Rest Framework POST 更新(如果存在或创建)

    我是 DRF 的新手 我阅读了 API 文档 也许这是显而易见的 但我找不到一个方便的方法来做到这一点 我有一个Answer与 a 具有一对一关系的对象Question 在前端 我曾经使用 POST 方法来创建发送到的答案api answe
  • 更新 SQLAlchemy 中的特定行

    我将 SQLAlchemy 与 python 一起使用 我想更新表中等于此查询的特定行 UPDATE User SET name user WHERE id 3 我通过 sql alchemy 编写了这段代码 但它不起作用 session
  • 沿轴 0 重复 scipy csr 稀疏矩阵

    我想重复 scipy csr 稀疏矩阵的行 但是当我尝试调用 numpy 的重复方法时 它只是将稀疏矩阵视为对象 并且只会将其作为 ndarray 中的对象重复 我浏览了文档 但找不到任何实用程序来重复 scipy csr 稀疏矩阵的行 我
  • 如何更改matplotlib中双头注释的头大小?

    Below figure shows the plot of which arrow head is very small 我尝试了下面的代码 但它不起作用 它说 引发 AttributeError 未知属性 s k 属性错误 未知属性头宽
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似

随机推荐

  • 要在 Scala 中映射的案例类

    有没有好的方法可以转换 Scalacase class实例 例如 case class MyClass param1 String param2 String val x MyClass hello world 成某种映射 例如 getCC
  • 无法将 null 分配给隐式类型变量

    根据 Visual Studio 的说法 这是不行的 var foo null 但这没关系 var foo false double null null 为什么 是个 double null也影响到null在 else 分支中 隐式类型变量
  • x86-64 REX 前缀中的“REX”代表什么?

    From 英特尔的SDM 第 2 2 1 节指定 REX 前缀用于 指定 GPR 和 SSE 寄存器 指定 64 位操作数大小 指定扩展控制寄存器 但缩写词中的字母 REX 代表什么 这个2002年热门薯条演示AMD 扩展了幻灯片 10 上
  • Structuremap 是否支持开箱即用的 Lazy?

    结构图是否允许您以惰性方式进行构造函数注入 意思是在使用之前不创建注入的对象 UPDATE StructureMap v3 开箱即用地实现了这一点 因此不再需要这个技巧 StructureMap 版本 2 没有 但通过一些技巧 您可以让它完
  • Square 和 Rectangle 继承有什么问题?

    我读过一些关于将 Square 作为 Rectangle 类的继承类是一种不好的做法的文章 说它违反了 LSP 里氏替换原则 我还是不明白 我用Ruby做了一个示例代码 class Rectangle attr accessor width
  • Delphi 自动 Format Source 损坏匿名程序

    昨天我发现了 Delphi 中的 Format Source 功能 它节省了我很多时间 然而 我发现它破坏了匿名过程的布局 有没有什么设置可以改善这个结果 例如 如果我有以下代码 procedure TServerThread cbUpda
  • C/C++ 中的 asc 和 chr 等效项

    好吧 标题几乎概括了这一点 我想在 C 中使用类似 asc 0 的东西 并且想让程序平台独立 所以不想使用 48 任何帮助表示赞赏 您可以简单地使用单引号来使字符常量 char c a 字符类型is数字类型 所以没有真正的需要asc and
  • 在一个套接字上订阅多个多播组(Linux、C)

    是否可以在单个套接字上从多个多播组接收数据 例如 void AddGroup int sock const char mc addr str int mc port const char interface struct sockaddr
  • Ninject 使用 WCF Web API Preview 5

    有人能为我指出正确的方向 让 Ninject 与 WCF Web API Preview 5 一起使用吗 我已在我的 ASP NET MVC 3 项目以及使用 Ninject Extensions Wcf 库的另一个内部 WCF 服务中成功
  • 如何在 IE 中使用 javascript 从客户端获取文件大小?

    我使用了以下方法 HTML
  • Android,Glide 显示错误图像约一秒

    我正在使用 Glide 库从 URL 加载图像 这是我从 Graph Request Facebook 获得的 它用在 RecyclerAdapter 中 当我滚动时 每个 ImageView 显示错误的图片大约不到一秒 然后纠正一张 这是
  • 如何设置 DT_RPATH 或 DT_RUNPATH?

    在 Linux 上 ld so 8 手册页讨论了动态库的搜索顺序 它说DT RPATH已被弃用 并且还提到DT RUNPATH 没有提到 rpath链接器选项 The ld 1 手册页提到了 rpath and rpath link选项 但
  • 如何用 pandas DataFrame 中的前一个或下一个值替换 NaN?

    假设我有一个 DataFrame 其中包含一些NaNs gt gt gt import pandas as pd gt gt gt df pd DataFrame 1 2 3 4 None None None None 9 gt gt gt
  • 如何将 HTML 和文本复制到剪贴板?

    我试图同时放入 HTML 和纯文本的剪贴板片段 以便支持 HTML 的编辑器可以粘贴 HTML 而其他编辑器可以使用纯文本 Clipboard SetData DataFormats Html htmlWithHeader Clipboar
  • 在其父级边界之外显示用户控件内的控件

    我有一个带有文本框和列表框的用户控件 它使用它们为用户提供自动完成功能 但是 我希望将列表框绘制在用户控件边界之外 以便在必须将列表框绘制在用户控件边缘附近时不会被截断 关于如何做到这一点有什么建议吗 本质上 我想要一个列表框浮动在其容器控
  • Dart 中双数的正则表达式

    从我之前的问题来看 我试图只允许双精度格式的数字进入文本字段 我浏览了整个网络 没有找到 dart 的正则表达式 TextFormField inputFormatters WhitelistingTextInputFormatter Re
  • Android GridView像listview一样添加页眉和页脚

    也许你想打电话addHeaderView or addFooterView in GridView 它没有 我们自然希望将页眉视图或页脚视图添加到GridView 也许你和我一样苦苦寻找了很久 却最终没有找到解决办法 这里我给出一个解决方案
  • BCP 错误“无法打开 BCP 主机数据文件”

    我刚刚在我的 sqlserver 名称导出表中创建了一个新表 现在我尝试使用 cmd bcp 推出 但出现以下错误 SQLState S1000 NativeError 0 错误 Microsoft ODBC 驱动程序 13 对于 SQL
  • 蓝牙 LE 的 txPower 到底是什么以及如何使用它?

    我正在尝试了解 txPower 到底是什么以及如何使用它 因为我计划开发使用 Beacons 的 Android 应用程序 我在网上看到了2个定义 1 信标的发射功率 2 距信标1米处的接收功率 这两个定义有何关系 此外 当使用 Quick
  • 如何找到信号周期(自相关与快速傅里叶变换与功率谱密度)?

    假设有人想要找到给定正弦波信号的周期 从我在网上读到的内容来看 两种主要方法似乎采用傅里叶分析或自相关 我正在尝试使用 python 自动化该过程 我的用例是将这个概念应用于来自绕恒星运行的模拟物体的位置 或速度或加速度 时间序列的类似信号