从干净和嘈杂的NumPy数组中提取正弦波的频率

huangapple go评论77阅读模式
英文:

Extract frequency of sin wav from clean and noisy numpy arrays

问题

这里有一个图表,显示了一个“控制”(蓝色)和一个“记录”(橙色)信号。

从干净和嘈杂的NumPy数组中提取正弦波的频率

这两个信号都是包含10,756个项目的NumPy数组,是从一个.wav文件中获取的,使用以下代码:

from wave import open as open_wave

waveFile = open_wave(filename, 'rb')
nframes = waveFile.getnframes()
wavFrames = waveFile.readframes(nframes)
ys = np.fromstring(wavFrames, dtype=np.int16)

我有26个控制信号(字母表中的所有字母),我想要从记录的波形中找出它与哪个控制信号最相似。

我的第一个方法是使用scipy.signal.find_peaks(),它对控制信号效果非常好,对于记录信号有时有效,但效果不够好。我明白这里的问题可能是:a) 信号可能在开头/结尾处存在剪切,或b) 记录信号中的噪声可能会产生错误的峰值。

我的第二种方法是对所有控制信号减去记录数组,希望最相似的信号将导致最小的差异。这种方法也不太好(尽管我仍然对这种方法感兴趣...)。

我现在希望做的是:

  • 继续使用scipy.signal.find_peaks()来识别峰值
  • 获取信号中峰值之间的平均距离
  • 寻找一个控制信号,其中这个平均峰值距离相似

在这里,“峰值距离”当然是指正弦波的频率。

欢迎任何建议或简化方法!我意识到我正在探索一个非常丰富的信号处理领域,只是用这个玩具/有趣的示例来踏出第一步。

英文:

Here is a graph that shows a "control" (blue) and "recorded" (orange) signals.

从干净和嘈杂的NumPy数组中提取正弦波的频率

Both are numpy arrays with 10,756 items, acquired from a .wav file with the code:

from wave import open as open_wave

waveFile = open_wave(filename,'rb')
nframes = waveFile.getnframes()
wavFrames = waveFile.readframes(nframes)
ys = np.fromstring(wavFrames, dtype=np.int16)

I have 26 control signals (all letters of alphabet), and I'd like to take a recorded wave and figure out which control signal it is most similar too.

My first approach was using scipy.signal.find_peaks() which works perfectly for control signals, and sometimes for recorded signals, but not good enough. I understand the shortcoming here to be a) possible clipping of signal at beginning/end, or b) noise in the recorded signal can create false peaks.

My second approach was subtracting the recorded array from all controls, hoping the most similar would result in the smallest diff. This didn't work well either (though still interested in this approach...).

What I'm hoping to do now is:

  • continue to identify peaks with scipy.signal.find_peaks()
  • get average distance between peaks across signal
  • look for a control signal where this average peak distance is similar

Where, of course, "peak distance" is the frequency of the sin wave.

Any suggestions or streamlines appreciated! I realize I'm bumbling into a very rich world of signal processing, using this toy / fun example to dip my toes.

答案1

得分: 1

感谢 @Reinderien 提供的评论建议,我认为使用Numpy的“一维实数输入离散傅里叶变换”是一个很好的方法。

用到的代码片段:

control_tone = array([...], dtype=int16)
recorded_tone = array([...], dtype=int16)
plt.close
plt.plot(np.fft.rfft(control_tone))
plt.plot(np.fft.rfft(recorded_tone))
plt.show()

两个应该对齐的音调示例:
从干净和嘈杂的NumPy数组中提取正弦波的频率
从干净和嘈杂的NumPy数组中提取正弦波的频率

然后,一个不应该对齐的音调示例(可以看到峰值不对齐):
从干净和嘈杂的NumPy数组中提取正弦波的频率

通过比较“两者中的最高谱峰”,我可以看到确定记录信号与哪个控制信号最相似的明显途径。

更新
对我来说,从np.fft.rfft()的输出中并不立即明显的是使用np.argmax()来获取最高峰的索引:

np.argmax(control_fft) # 输出: 71
np.argmax(recorded_fft) # 输出: 72,比其他更接近,因此使用
英文:

Thanks to @Reinderien for the comment suggestions, think using Numpy's "one-dimensional discrete Fourier Transform for real input" is a great approach.

Code snippet used:

control_tone =  array([...], dtype=int16)
recorded_tone =  array([...], dtype=int16)
plt.close
plt.plot(np.fft.rfft(control_tone))
plt.plot(np.fft.rfft(recorded_tone))
plt.show()

Two examples of tones that should align:
从干净和嘈杂的NumPy数组中提取正弦波的频率
从干净和嘈杂的NumPy数组中提取正弦波的频率

And then, an example of tones that should not align (can see the peaks are off):
从干净和嘈杂的NumPy数组中提取正弦波的频率

By comparing the "the single highest spectral peak in both" I can see a clear path towards determining which control signal the recorded signal is most similar to.

UPDATE
What was not immediately obvious to me, from the output of np.fft.rfft(), was using np.argmax() to get the index of the highest peak:

np.argmax(control_fft) # output: 71
np.argmax(recorded_fft) # output: 72, which is closer than others, so use

huangapple
  • 本文由 发表于 2023年2月23日 23:56:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/75547257.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定