使用python从频率数组中进行音调扫描

Posted

技术标签:

【中文标题】使用python从频率数组中进行音调扫描【英文标题】:Tone sweep from array of frequencies with python 【发布时间】:2021-07-21 14:59:08 【问题描述】:

我有一个带有频率值的数组,并且想要生成带有在给定值之间扫描的音调的 wav 文件。说

freqs = [100, 100, 200, 400, 1000, 100, 50]
duration = 7

我想要持续时间为 7 秒的 WAV。所以从 T=0 到 T=1s 音调应该是 100Hz,从 T=1 到 T=2 从 100Hz 扫描到 200Hz 等等。

如何生成要传递给 scipy.io.wavfile.write 的波形?

【问题讨论】:

【参考方案1】:

以下是对两个任意频率执行此操作的方法:

import numpy as np
from scipy.signal import chirp
from scipy.io.wavfile import write

interval_length = 1 # in seconds
fs = 16000 # sampling of your signal
f0 = 100   # frequency 1
f1 = 200   # frequency 2
t = np.linspace(0, interval_length, int(fs * interval_length))
w = chirp(t, f0=f0, f1=f0, t1=interval_length, method='linear') # check also other methods
write('test.wav', fs, w)

我留给你一个练习,让你在你拥有的一组频率循环中执行此操作。

【讨论】:

我不是 python 开发人员,但我印象深刻 scipy.signal 有一个非常酷的扫频合成器docs.scipy.org/doc/scipy/reference/generated/… 是的,但是当频率几乎相同(比如 100Hz 和 100.5Hz)时会出现问题:组合啁啾会导致拼接点出现相位误差和噪声 @user3317803 我觉得效果不会很明显,你总是可以平滑拼接点。 @dcoder_mm 你试过了吗?如果您遇到工件或其他问题,请发布代码和结果。 @LukaszTracewski 是的,我遇到了相位不匹配,导致拼接点出现广谱噪声(听起来像咔哒声)。我相信最好的解决方案是计算相移并通过 chirp() 的 phi 参数应用它。我会在几天后重新审视这个项目并在这里发布结果【参考方案2】:

作为Lukasz Tracewski said,这可以通过np.chirp()来完成:

import numpy as np
from scipy.signal import chirp
from scipy.io.wavfile import write

duration = 30 
Fs = 16000
freqs = [100, 100, 300, 300, 600, 100, 100]

segment = int(Fs * duration /  (len(freqs)-1))
f = np.array(freqs) / Fs
wav = np.array(1)
for f0, f1 in zip(f[:-1], f[1:]):
    wav = np.append(wav, chirp(np.arange(segment), f0=f0, t1=segment, f1=f1))

write('test.wav', Fs, wav)

这给出了很好的频谱图: 听这里:https://soundcloud.com/dcoder_mm/npchip/s-Kx8L2vN0nfv

它有效,但您会注意到(在频谱上和聆听时)一些咔哒声。

让我们尝试更低的频率:

freqs = [100, 100, 300, 300, 600, 100, 100]

听这里:https://soundcloud.com/dcoder_mm/dj-npchirp-feat-low-frequencies/s-fNsA61bJ0Wk

事情变得更糟了。为什么?

由于两个啁啾组合点处的相位误差:

为了摆脱这个,我们需要计算相位校正。根据wiki 阶段的最后一点(对于 linear 啁啾声!)将是:

phi = T*(f1+f0)/2

这样就可以了:

import numpy as np
from scipy.signal import chirp
from scipy.io.wavfile import write

duration = 30 
Fs = 16000
freqs = [100, 100.5, 99, 99.3, 100.1, 100]

segment = int(Fs * duration / (len(freqs)-1))
f = np.array(freqs) / Fs
wav = np.array(1)

phase = 0
for f0, f1 in zip(f[:-1], f[1:]):
    wav = np.append(wav, chirp(np.arange(segment), f0=f0, t1=segment, f1=f1, phi=phase))
    phase = phase + 360*(segment*(f0+f1)/2)

write('test3.wav', Fs, wav)

收听:https://soundcloud.com/dcoder_mm/dj-npchirp-feat-low-frequencies-phase-c/s-XneSWRlojLD

注意 phi = T*(f1+f0)/2 仅适用于线性啁啾。对于其他方法,您需要不同的相位公式。另见this question

【讨论】:

以上是关于使用python从频率数组中进行音调扫描的主要内容,如果未能解决你的问题,请参考以下文章

使用python为音调添加随机噪声

如何从 DTMF 音调中获得低频 [关闭]

如何将多个不同频率的音调混合为一个

检测原始音频 (PCM) 中的特定频率/音调

在java中录制音频并确定实时是不是播放了x频率的音调,如果是这样的话

频率与音调的关系-十二平均律