如何使用 numpy 在频率范围内产生噪声?

Posted

技术标签:

【中文标题】如何使用 numpy 在频率范围内产生噪声?【英文标题】:How to generate noise in frequency range with numpy? 【发布时间】:2016-02-29 06:23:22 【问题描述】:

我有一个主信号,例如周期为 200 个样本的正弦信号。

我想为这个信号添加噪音。 “噪声信号部分”的周期应在 5-30 个样本的范围内。

我认为这足以在此范围内生成多个具有不同随机选择幅度的窦:

noise = np.sin(np.array(range(N))/0.7)*np.random.random(1) + np.sin(np.array(range(N))/1.1)*np.random.random(1) + np.sin(np.array(range(N))/1.5)*np.random.random(1) 

但是对于我的目的来说,这个解决方案仍然过于“确定性”。

如何产生幅度和周期随机变化的噪声?

【问题讨论】:

一种典型的方法是生成一些白噪声(例如使用np.random.randn),然后对其进行带通滤波,以便在将其添加到您的信号之前为其提供所需的频率特性。 @ali_m 是的,这是典型且完全正确的方法。你说的对。但如果可能的话,我想避免过滤。所以我想要的解决方案应该像我建议的那样简单,但结果更好(不太确定)。 为什么要“避免过滤”? @ali_m 我想用这个噪音来测试一个过滤器。根据我的经验,滤波器不会消除带通外的所有噪声,或者会延迟数据,或者还会抑制带通边界周围的频率。也许我错了,但我相信对于相对较短的数据,我会通过一些“作弊解决方案”获得比适当过滤更清晰的结果。 我只是说在将噪声添加到信号之前对噪声进行带通滤波,所以我看不出相移可能是个问题。您主要担心的似乎是噪声会泄漏到其他光谱带中,但这实际上仅取决于选择合适的带通滤波器。如果您想使用单个随机正弦曲线生成类似于带限白噪声的东西,那么您将需要很多正弦曲线(原则上,它们的数量是无限的)。如果您能在问题中解释您的确切需求,这将有所帮助。 【参考方案1】:

Here 您可以从 Aslak Grinsted 找到 matlab 代码,它会产生具有指定功率谱的噪声。它可以很容易地移植到python:

def fftnoise(f):
    f = np.array(f, dtype='complex')
    Np = (len(f) - 1) // 2
    phases = np.random.rand(Np) * 2 * np.pi
    phases = np.cos(phases) + 1j * np.sin(phases)
    f[1:Np+1] *= phases
    f[-1:-1-Np:-1] = np.conj(f[1:Np+1])
    return np.fft.ifft(f).real

您可以像这样将它用于您的情况:

def band_limited_noise(min_freq, max_freq, samples=1024, samplerate=1):
    freqs = np.abs(np.fft.fftfreq(samples, 1/samplerate))
    f = np.zeros(samples)
    idx = np.where(np.logical_and(freqs>=min_freq, freqs<=max_freq))[0]
    f[idx] = 1
    return fftnoise(f)

据我所知,似乎有效。聆听您新制造的噪音:

from scipy.io import wavfile

x = band_limited_noise(200, 2000, 44100, 44100)
x = np.int16(x * (2**15 - 1))
wavfile.write("test.wav", 44100, x)

【讨论】:

【参考方案2】:

您应该将它们与随机相位一起使用,而不是使用具有不同幅度的多个鼻窦:

import numpy as np
from functools import reduce

def band_limited_noise(min_freq, max_freq, samples=44100, samplerate=44100):
    t = np.linspace(0, samples/samplerate, samples)
    freqs = np.arange(min_freq, max_freq+1, samples/samplerate)
    phases = np.random.rand(len(freqs))*2*np.pi
    signals = [np.sin(2*np.pi*freq*t + phase) for freq,phase in zip(freqs,phases)]
    signal = reduce(lambda a,b: a+b,signals)
    signal /= np.max(signal)
    return signal

背景:白噪声意味着功率谱包含每个频率,因此如果您想要频带受限的噪声,您可以将频带内的每个频率加在一起。噪声部分来自随机相位。由于 DFT 是离散的,因此您只需要考虑给定采样率时实际出现的离散频率。

【讨论】:

【参考方案3】:

产生全谱白噪声然后过滤它就像你想把你房子的墙壁涂成白色,所以你决定把整个房子涂成白色,然后把除了墙壁之外的所有房子都涂回去。是白痴。 (但在电子方面有一定的意义)。

我制作了一个小型 C 程序,它可以在任何频率和任何带宽(假设中心频率为 16kHz 和“宽”为 2kHz)生成白噪声。 不涉及过滤。

我所做的很简单: 在主(无限)循环内,我在中心频率 +/- 一个介于 -half 带宽和 +halfbandwidth 之间的随机数生成一个正弦曲线,然后我为任意数量的样本(粒度)保持该频率,这就是结果:

在 16kHz 中心频率处 2kHz 宽的白噪声

伪代码:

while (true)


    f = center frequency
    r = random number between -half of bandwidth and + half of bandwidth

<secondary loop (for managing "granularity")>

    for x = 0 to 8 (or 16 or 32....)

    

        [generate sine Nth value at frequency f+r]

        output = generated Nth value
    



【讨论】:

以上是关于如何使用 numpy 在频率范围内产生噪声?的主要内容,如果未能解决你的问题,请参考以下文章

如何产生特定的声音频率?

频率响应是啥

如何将 NumPy 数组标准化到一定范围内?

java如何在字符串编码范围内输出频率最高的字符?

在numpy的范围内生成随机日期

iPhone SDK:如何录制带有环境噪声抑制的声音?