在python中向信号添加噪声

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14058340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 10:19:34  来源:igfitidea点击:

adding noise to a signal in python

python

提问by user1551817

I want to add some random noise to some 100 bin signal that I am simulating in Python - to make it more realistic.

我想在 Python 中模拟的一些 100 bin 信号中添加一些随机噪声 - 使其更逼真。

On a basic level, my first thought was to go bin by bin and just generate a random number between a certain range and add or subtract this from the signal.

在基本层面上,我的第一个想法是逐个 bin 并生成一个特定范围之间的随机数,然后从信号中添加或减去它。

I was hoping (as this is python) that there might a more intelligent way to do this via numpy or something. (I suppose that ideally a number drawn from a gaussian distribution and added to each bin would be better also.)

我希望(因为这是 python)可能有一种更智能的方法通过 numpy 或其他东西来做到这一点。(我认为理想情况下,从高斯分布中提取并添加到每个 bin 中的数字也会更好。)

Thank you in advance of any replies.

提前感谢您的任何答复。



I'm just at the stage of planning my code, so I don't have anything to show. I was just thinking that there might be a more sophisticated way of generating the noise.

我只是在规划我的代码的阶段,所以我没有任何东西可以展示。我只是在想可能有一种更复杂的方式来产生噪音。

In terms out output, if I had 10 bins with the following values:

在输出方面,如果我有 10 个具有以下值的 bin:

Bin 1: 1 Bin 2: 4 Bin 3: 9 Bin 4: 16 Bin 5: 25 Bin 6: 25 Bin 7: 16 Bin 8: 9 Bin 9: 4 Bin 10: 1

Bin 1: 1 Bin 2: 4 Bin 3: 9 Bin 4: 16 Bin 5: 25 Bin 6: 25 Bin 7: 16 Bin 8: 9 Bin 9: 4 Bin 10: 1

I just wondered if there was a pre-defined function that could add noise to give me something like:

我只是想知道是否有一个预定义的函数可以添加噪音来给我类似的东西:

Bin 1: 1.13 Bin 2: 4.21 Bin 3: 8.79 Bin 4: 16.08 Bin 5: 24.97 Bin 6: 25.14 Bin 7: 16.22 Bin 8: 8.90 Bin 9: 4.02 Bin 10: 0.91

分档 1:1.13 分档 2:4.21 分档 3:8.79 分档 4:16.08 分档 5:24.97 分档 6:25.14 分档 7:16.22 分档 8:8.90 分档 9:4.02 分档 10:0.91

If not, I will just go bin-by-bin and add a number selected from a gaussian distribution to each one.

如果没有,我将逐个 bin 并从高斯分布中选择一个数字添加到每个数字。

Thank you.

谢谢你。



It's actually a signal from a radio telescope that I am simulating. I want to be able to eventually choose the signal to noise ratio of my simulation.

它实际上是来自我正在模拟的射电望远镜的信号。我希望能够最终选择我的模拟的信噪比。

采纳答案by Akavall

You can generate a noise array, and add it to your signal

您可以生成一个噪声数组,并将其添加到您的信号中

import numpy as np

noise = np.random.normal(0,1,100)

# 0 is the mean of the normal distribution you are choosing from
# 1 is the standard deviation of the normal distribution
# 100 is the number of elements you get in array noise

回答by Noel Evans

... And for those who - like me - are very early in their numpy learning curve,

......对于那些 - 像我一样 - 在他们麻木的学习曲线中非常早的人,

import numpy as np
pure = np.linspace(-1, 1, 100)
noise = np.random.normal(0, 1, pure.shape)
signal = pure + noise

回答by Mohamed Ali JAMAOUI

For those who want to add noise to a multi-dimensional dataset loaded within a pandas dataframe or even a numpy ndarray, here's an example:

对于那些想要在 Pandas 数据帧甚至 numpy ndarray 中加载的多维数据集添加噪声的人,这里有一个例子:

import pandas as pd
# create a sample dataset with dimension (2,2)
# in your case you need to replace this with 
# clean_signal = pd.read_csv("your_data.csv")   
clean_signal = pd.DataFrame([[1,2],[3,4]], columns=list('AB'), dtype=float) 
print(clean_signal)
"""
print output: 
    A    B
0  1.0  2.0
1  3.0  4.0
"""
import numpy as np 
mu, sigma = 0, 0.1 
# creating a noise with the same dimension as the dataset (2,2) 
noise = np.random.normal(mu, sigma, [2,2]) 
print(noise)

"""
print output: 
array([[-0.11114313,  0.25927152],
       [ 0.06701506, -0.09364186]])
"""
signal = clean_signal + noise
print(signal)
"""
print output: 
          A         B
0  0.888857  2.259272
1  3.067015  3.906358
""" 

回答by tmcdevitt

For those trying to make the connection between SNRand a normal random variable generated by numpy:

对于那些试图在SNR和由 numpy 生成的正常随机变量之间建立联系的人:

[1] SNR ratio, where it's important to keep in mind that P is averagepower.

[1] 信噪比,重要的是要记住 P 是平均功率

Or in dB:
[2] SNR dB2

或以 dB 为单位:
[2]信噪比 dB2

In this case, we already have a signal and we want to generate noise to give us a desired SNR.

在这种情况下,我们已经有了一个信号,我们想要产生噪声来为我们提供所需的 SNR。

While noise can come in different flavorsdepending on what you are modeling, a good start (especially for this radio telescope example) is Additive White Gaussian Noise (AWGN). As stated in the previous answers, to model AWGN you need to add a zero-mean gaussian random variable to your original signal. The variance of that random variable will affect the averagenoise power.

虽然噪声可以根据您建模的内容呈现不同的风格,但一个好的开始(特别是对于这个射电望远镜示例)是加性高斯白噪声 (AWGN)。如前面的答案所述,要对 AWGN 进行建模,您需要向原始信号添加一个零均值高斯随机变量。该随机变量的方差将影响平均噪声功率。

For a Gaussian random variable X, the average power Ep, also known as the second moment, is
[3] Ex

对于高斯随机变量 X,平均功率EP,也称为二阶,为
[3] 前任

So for white noise, Exand the average power is then equal to the variance Ex.

所以对于白噪声,前任平均功率就等于方差前任

When modeling this in python, you can either
1. Calculate variance based on a desired SNR and a set of existing measurements, which would work if you expect your measurements to have fairly consistent amplitude values.
2. Alternatively, you could set noise power to a known level to match something like receiver noise. Receiver noise could be measured by pointing the telescope into free space and calculating average power.

在 python 中建模时,您可以
1. 根据所需的 SNR 和一组现有测量计算方差,如果您希望您的测量具有相当一致的幅度值,这将起作用。
2. 或者,您可以将噪声功率设置为已知水平以匹配诸如接收器噪声之类的东西。接收器噪声可以通过将望远镜指向自由空间并计算平均功率来测量。

Either way, it's important to make sure that you add noise to your signal and take averages in the linear space and not in dB units.

无论哪种方式,重要的是要确保向信号添加噪声并在线性空间中取平均值,而不是以 dB 为单位。

Here's some code to generate a signal and plot voltage, power in Watts, and power in dB:

下面是一些生成信号并绘制电压、功率(瓦特)和功率(dB)的代码:

# Signal Generation
# matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(1, 100, 1000)
x_volts = 10*np.sin(t/(2*np.pi))
plt.subplot(3,1,1)
plt.plot(t, x_volts)
plt.title('Signal')
plt.ylabel('Voltage (V)')
plt.xlabel('Time (s)')
plt.show()

x_watts = x_volts ** 2
plt.subplot(3,1,2)
plt.plot(t, x_watts)
plt.title('Signal Power')
plt.ylabel('Power (W)')
plt.xlabel('Time (s)')
plt.show()

x_db = 10 * np.log10(x_watts)
plt.subplot(3,1,3)
plt.plot(t, x_db)
plt.title('Signal Power in dB')
plt.ylabel('Power (dB)')
plt.xlabel('Time (s)')
plt.show()

Generated Signal

产生的信号

Here's an example for adding AWGN based on a desired SNR:

以下是基于所需 SNR 添加 AWGN 的示例:

# Adding noise using target SNR

# Set a target SNR
target_snr_db = 20
# Calculate signal power and convert to dB 
sig_avg_watts = np.mean(x_watts)
sig_avg_db = 10 * np.log10(sig_avg_watts)
# Calculate noise according to [2] then convert to watts
noise_avg_db = sig_avg_db - target_snr_db
noise_avg_watts = 10 ** (noise_avg_db / 10)
# Generate an sample of white noise
mean_noise = 0
noise_volts = np.random.normal(mean_noise, np.sqrt(noise_avg_watts), len(x_watts))
# Noise up the original signal
y_volts = x_volts + noise_volts

# Plot signal with noise
plt.subplot(2,1,1)
plt.plot(t, y_volts)
plt.title('Signal with noise')
plt.ylabel('Voltage (V)')
plt.xlabel('Time (s)')
plt.show()
# Plot in dB
y_watts = y_volts ** 2
y_db = 10 * np.log10(y_watts)
plt.subplot(2,1,2)
plt.plot(t, 10* np.log10(y_volts**2))
plt.title('Signal with noise (dB)')
plt.ylabel('Power (dB)')
plt.xlabel('Time (s)')
plt.show()

Signal with target SNR

具有目标 SNR 的信号

And here's an example for adding AWGN based on a known noise power:

以下是基于已知噪声功率添加 AWGN 的示例:

# Adding noise using a target noise power

# Set a target channel noise power to something very noisy
target_noise_db = 10

# Convert to linear Watt units
target_noise_watts = 10 ** (target_noise_db / 10)

# Generate noise samples
mean_noise = 0
noise_volts = np.random.normal(mean_noise, np.sqrt(target_noise_watts), len(x_watts))

# Noise up the original signal (again) and plot
y_volts = x_volts + noise_volts

# Plot signal with noise
plt.subplot(2,1,1)
plt.plot(t, y_volts)
plt.title('Signal with noise')
plt.ylabel('Voltage (V)')
plt.xlabel('Time (s)')
plt.show()
# Plot in dB
y_watts = y_volts ** 2
y_db = 10 * np.log10(y_watts)
plt.subplot(2,1,2)
plt.plot(t, 10* np.log10(y_volts**2))
plt.title('Signal with noise')
plt.ylabel('Power (dB)')
plt.xlabel('Time (s)')
plt.show()

Signal with target noise level

具有目标噪声水平的信号

回答by Pramit

Awesome answers above. I recently had a need to generate simulated data and this is what I landed up using. Sharing in-case helpful to others as well,

楼上的回答真棒。我最近需要生成模拟数据,这就是我使用的。分享对他人有帮助的案例,

import logging
__name__ = "DataSimulator"
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

import numpy as np
import pandas as pd

def generate_simulated_data(add_anomalies:bool=True, random_state:int=42):
    rnd_state = np.random.RandomState(random_state)
    time = np.linspace(0, 200, num=2000)
    pure = 20*np.sin(time/(2*np.pi))

    # concatenate on the second axis; this will allow us to mix different data 
    # distribution
    data = np.c_[pure]
    mu = np.mean(data)
    sd = np.std(data)
    logger.info(f"Data shape : {data.shape}. mu: {mu} with sd: {sd}")
    data_df = pd.DataFrame(data, columns=['Value'])
    data_df['Index'] = data_df.index.values

    # Adding gaussian jitter
    jitter = 0.3*rnd_state.normal(mu, sd, size=data_df.shape[0])
    data_df['with_jitter'] = data_df['Value'] + jitter

    index_further_away = None
    if add_anomalies:
        # As per the 68-95-99.7 rule(also known as the empirical rule) mu+-2*sd 
        # covers 95.4% of the dataset.
        # Since, anomalies are considered to be rare and typically within the 
        # 5-10% of the data; this filtering
        # technique might work 
        #for us(https://en.wikipedia.org/wiki/68%E2%80%9395%E2%80%9399.7_rule)
        indexes_furhter_away = np.where(np.abs(data_df['with_jitter']) > (mu + 
         2*sd))[0]
        logger.info(f"Number of points further away : 
        {len(indexes_furhter_away)}. Indexes: {indexes_furhter_away}")
        # Generate a point uniformly and embed it into the dataset
        random = rnd_state.uniform(0, 5, 1)
        data_df.loc[indexes_furhter_away, 'with_jitter'] +=  
        random*data_df.loc[indexes_furhter_away, 'with_jitter']
    return data_df, indexes_furhter_away

回答by Neitzke

AWGN Similar to Matlab Function

AWGN 类似于 Matlab 函数

def awgn(sinal):
    regsnr=54
    sigpower=sum([math.pow(abs(sinal[i]),2) for i in range(len(sinal))])
    sigpower=sigpower/len(sinal)
    noisepower=sigpower/(math.pow(10,regsnr/10))
    noise=math.sqrt(noisepower)*(np.random.uniform(-1,1,size=len(sinal)))
    return noise