确定波的频率和周期

信息处理 频率 海浪
2021-12-22 08:05:24

我正在从冰箱收集温度数据。数据看起来像一个波浪。我想确定波的周期和频率(以便我可以测量对冰箱的修改是否有任何影响)。

我正在使用 R,我认为我需要对数据使用 FFT,但我不确定从那里去哪里。我对 R 和信号分析非常陌生,因此将不胜感激任何帮助!

这是我正在制作的波浪:

我的波

到目前为止,这是我的 R 代码:

require(graphics)
library(DBI)
library(RSQLite)

drv <- dbDriver("SQLite")
conn <- dbConnect(drv, dbname = "s.sqlite3")

query <- function(con, query) {
  rs <- dbSendQuery(con, query)
  data <- fetch(rs, n = -1)
  dbClearResult(rs)
  data
}

box <- query(conn, "
SELECT id,
       humidity / 10.0 as humidity,
       temp / 10.0 as temp,
       ambient_temp / 10.0 as ambient_temp,
       ambient_humidity / 10.0 as ambient_humidity,
       created_at
FROM measurements ORDER BY id DESC LIMIT 3600
")

box$x <- as.POSIXct(box$created_at, tz = "UTC")

box$x_n <- box$temp - mean(box$temp)
png(filename = "normalized.png", height = 750, width = 1000, bg = "white")
plot(box$x, box$x_n, type="l")

# Pad the de-meaned signal so the length is 10 * 3600
N_fft  <- 3600 * 10
padded <- c(box$x_n, seq(0, 0, length= (N_fft - length(box$x_n))))
X_f    <- fft(padded)
PSD    <- 10 * log10(abs(X_f) ** 2)

png(filename = "PSD.png", height = 750, width = 1000, bg = "white")
plot(PSD, type="line")

zoom <- PSD[1:300]

png(filename = "zoom.png", height = 750, width = 1000, bg = "white")
plot(zoom, type="l")

# Find the index with the highest point on the left half
index <- which(PSD == max(PSD[1:length(PSD) / 2]))

# Mark it in green on the zoomed in graph
abline(v = index, col="green")

f_s     <- 0.5 # sample rate in Hz
wave_hz <- index * (f_s / N_fft)
print(1 / (wave_hz * 60))

我在这里发布了 R 代码和 SQLite 数据库。

这是归一化图的图(删除了平均值):

归一化图

到目前为止,一切都很好。这是光谱密度图:

光谱密度

然后我们放大图的左侧并用绿线标记最高索引(即 70):

放大光谱图

最后我们计算波的频率。此波非常慢,因此我们将其转换为每个周期的分钟数,并打印出该值,即 17.14286。

如果其他人想尝试,这是我的制表符分隔格式的数据。

谢谢您的帮助!这个问题(对我来说)很难,但我玩得很开心!

3个回答

你在那里进行的有趣项目!:-)

从信号分析 POV 来看,这实际上是一个简单的问题 - 是的,您将使用 FFT 来解决这个频率估计问题是对的。

我对 R 不熟悉,但您本质上想要做的是对温度信号进行 FFT。由于您的信号是真实的,您将得到一个复杂的结果作为 FFT 的输出。您现在可以取复数 FFT 结果的绝对幅度平方(因为我们不关心相位)。那是,re一种l2+一世一种G2. 这是您的功率谱密度。

然后,非常简单,找到您的 PSD 所在位置的最大值。该最大值的横坐标将对应于您的频率。

警告 Emptor,我给你一个总体前景,我怀疑 R 中 FFT 的结果将是归一化频率,在这种情况下,你必须知道你的采样率(你知道),以便将其转换回来成赫兹。我遗漏了许多其他重要细节,例如您的频率分辨率、FFT 大小,以及您可能想首先对信号进行去均值处理这一事实,但最好先查看图表。

编辑:

让我们考虑您的信号。在我贬低它之后,它看起来像这样:

在此处输入图像描述

您想要去均值,因为 DC 偏置在技术上是 0 Hz 的频率,并且您不希望它淹没其他感兴趣的频率。让我们称这个贬义信号X[n].

现在,当您进行 FFT 时,您必须注意一些细节。我使用的 FFT 长度是信号长度的 10 倍,所以我们可以说ñFF=10*3600=36000。任何大于原始信号大小的 FFT 大小都具有在频域内插 FFT 结果的效果。虽然这不会从信息论 POV 中为您添加任何信息,但它确实可以帮助您更好地辨别真正的峰值在哪里,尤其是在它位于两个频率区间之间的情况下。要获得真正更好的频率分辨率,您需要获得更多数据。(即让传感器运行更长的时间)。

继续前进,从文本文件中,我看到您的传感器每 2 秒读取一次温度读数。这意味着您的采样率,或Fs=0.5Hz

因此,让我们取一个 FFTX[n],并调用该结果X(F). 这个结果会很复杂,实际上它是共轭对称的,但这并不重要。(这只是为了您的目的,其中一半是多余的)。现在如果我们采取10lG10(|X(F)|2),这是功率谱密度(对数刻度)。结果如下所示:

在此处输入图像描述

你可以看到它是如何对称的。如果你忽略后半部分,只看前半部分并放大你,可以看到:

在此处输入图像描述

所以你有一个指数 70 的峰值!但实际频率方面的索引 70 是什么?这是您想要频率分辨率的地方。为了计算它,我们只需取FsñFF=1.3889e-005Hz. 这仅仅意味着每个索引都代表一个频率,该频率是该数字的倍数。索引 0 是0*1.3889e-005=0Hz. 索引 1 是1*1.3889e-005=1.3889e-005Hz. 索引 70 是70*1.3889e-005=9.7222e-004Hz.

我们快完成了。现在你有了这个数字,我们可以把它转换成更可口的东西。这个数字只是说你的信号每秒完成 9.7222e-004 个周期。所以我们可以问,计算一个周期需要多少分钟?因此,1(9.7222e-004)*60=17.14每个周期的分钟数。

不需要做任何复杂的事情:只需测量波形峰值之间的持续时间。这是时期。频率只是 1 除以周期。

大约 8 个周期超过 2 小时,频率为每小时 4 个周期,或约 1 mHz。

对于这种平滑和静止的波形,在某个平均阈值的正向交叉之间计数样本点将为您提供周期估计。查看几个阈值交叉期以获得更平均的估计或检测任何趋势。