python - 如何找到脉冲的频率?
问题描述
我目前面临关于脉冲频率检测的问题。我有一个程序以这种方式记录设备的网络活动。
"device": {
"mac": "b8:27:eb:5c:27:13",
"activity": [
{
"ip" : "224.0.0.251",
"port" : "5353",
"history" : [
{
"timestamp" : "2019-09-23T09:34:30.898836",
"pktsSent" : 6,
"pktsReceived" : 0,
"duration" : "3.972347"
},
...
]
}
]
}
我目前正在尝试实现的是使用其历史来检测活动的频率(如果它不是周期性的,则不检测)。想起我的工程学习课程,我想到了 FFT。这是我到目前为止在 Python 中的内容:
import numpy as np
import dateutil.parser as dateutil
class FrequencyAnalyzer:
...
def analyze(self, device_mac, activity) -> int:
if not 'history' in activity:
raise FrequencyAnalyzerError("No history could be found for the device '%s' and its activity '%s:%s'" %(device_mac, activity['ip'], activity['port']))
start = int(dateutil.parse(activity['history'][0]['timestamp']).timestamp())
stop = int(dateutil.parse(activity['history'][-1]['timestamp']).timestamp())
size = stop - start
# Array of timestamps
timestamps = np.fromiter( [dateutil.parse(history['timestamp']).timestamp() for history in activity['history'] ], int)
# Array of data, setting 1 if there was an activity at this timestamp, else 0
data = np.fromiter( [ 1 if x in timestamps and x != start else 0 for x in range(start, stop)], int)
# Framerate of 1Hz
frate = 1
fft = np.fft.fft(data)
freqs = np.fft.fftfreq(len(fft))
print(freqs.min(), freqs.max())
# Find the peak in the coefficients
idx = np.argmax(np.abs(fft))
freq = freqs[idx]
freq_in_hertz = abs(freq * frate)
print("Freq in Hz = %s" %str(freq_in_hertz))
精度不是那么重要。现在我已将其固定为 1 秒,但也可能是 1 分钟。
在我正在测试的活动中,每 3 分钟和其他时间戳有一个 mDNS 活动。我想返回所有相关的频率,但现在我想得到 1 个正确的频率。
找到的频率始终为零。我记得使用 FFT 分析诸如音频之类的信号,但不适用于脉冲。不应该是同一个方信号(谐波分解)吗?
我想知道这是否是正确的方法。因为它应该在嵌入式系统中运行,所以我不希望使用像 SciPy 这样有点重的框架。
有什么建议吗?
解决方案
0-Hz 峰值是平均值。因为你的冲动只是积极的,所以平均值也是积极的。所以你应该忽略那个频率。
另一个问题是在执行 FFT 之前您没有对数据应用任何窗口函数。这将导致看起来非常嘈杂的频谱。窗函数将权衡光谱灵敏度(基本上,峰有多窄)以提高信噪比。一个有效且非常容易实现的窗口是Hann 函数。
另一件需要注意的事情是,如果您希望能够检测一个周期为 1 秒的 1 Hz 信号,您需要在数十秒内执行 FFT 以获得该频率附近的合理频谱分辨率。如果你想检测每 3 分钟发生一次的事情,那么你应该对大约一小时的数据进行 FFT。
如果您认为 SciPy 对于您的嵌入式设备来说已经太重了,那么您应该考虑将您的程序移植到 C 或 C++,并完全摆脱 Python。另一个问题是您的日志显然是 JSON 格式,编码和解码可能需要相当长的时间,而且它不是最紧凑的格式。考虑使用像MessagePack这样的二进制格式,或者只是以pcap格式存储数据包日志并直接在峰值检测器程序中处理它。许多编程语言都有处理这些格式的库。
推荐阅读
- vb.net - 我可以为“值类型”函数启用“函数不会在所有代码路径上返回值”警告吗?
- angular - 如何删除 ngx 日期选择器中的自动更正?
- c# - 如何将 numpy .npz 文件直接读入 C#
- c - opengl不显示renderFunction的输出
- java - 使用 foreach 将 arrayList 与自身进行比较,不包括重复项
- airflow-scheduler - 气流 - 如何仅“填充 DagBag”一次
- c# - C# Windows 服务无法连接到 MySQL
- java - 如何获得以毫秒为单位的本地时间和以毫秒为单位的 unix 时间之间的差异?(从 unixtimestamp 的转变)
- django - Django:管理员的LOGOUT_REDIRECT_URL工作流程与普通用户不同
- html - 使用 javascript 标签在引导模型中渲染一个 html 元素