如何使用 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 在频率范围内产生噪声?的主要内容,如果未能解决你的问题,请参考以下文章