112 votes

ajouter du bruit à un signal en python

Je veux ajouter un bruit aléatoire à un signal de 100 cases que je simule en Python, pour le rendre plus réaliste.

Au niveau de base, ma première idée était de procéder bac par bac et de générer un nombre aléatoire compris dans une certaine fourchette, puis de l'ajouter ou de le soustraire au signal.

J'espérais (comme il s'agit de python) qu'il y aurait un moyen plus intelligent de le faire via numpy ou quelque chose comme ça. (Je suppose qu'idéalement, un nombre tiré d'une distribution gaussienne et ajouté à chaque bin serait également mieux).

Merci d'avance pour toute réponse.


Je suis juste au stade de la planification de mon code, donc je n'ai rien à montrer. Je pensais juste qu'il pourrait y avoir une façon plus sophistiquée de générer le bruit.

En termes de résultats, si j'avais 10 cases avec les valeurs suivantes :

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

Je me demandais juste s'il existait une fonction prédéfinie qui pourrait ajouter du bruit pour me donner quelque chose comme :

Bac 1 : 1,13 Bin 2 : 4,21 Bin 3 : 8.79 Bin 4 : 16,08 Bin 5 : 24,97 Bac 6 : 25,14 Bac 7 : 16,22 Case 8 : 8.90 Bac 9 : 4,02 Bac 10 : 0,91

Sinon, je vais simplement procéder bac par bac et ajouter à chacun d'eux un nombre choisi dans une distribution gaussienne.

Merci.


C'est en fait le signal d'un radiotélescope que je simule. Je veux pouvoir éventuellement choisir le rapport signal/bruit de ma simulation.

151voto

Akavall Points 7357

Vous pouvez générer un tableau de bruit et l'ajouter à votre 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

85voto

tmcdevitt Points 840

Pour ceux qui essaient de faire le lien entre SNR et une variable aléatoire normale générée par numpy :

[1] SNR ratio où il est important de garder à l'esprit que P est moyennement le pouvoir.

Ou en dB :
[2] SNR dB2

Dans ce cas, nous avons déjà un signal et nous voulons générer du bruit pour obtenir le SNR souhaité.

Le bruit peut se présenter sous différentes formes saveurs en fonction de ce que vous modélisez, un bon début (surtout pour cet exemple de radiotélescope) est Bruit blanc gaussien additif (AWGN) . Comme indiqué dans les réponses précédentes, pour modéliser l'AWGN, vous devez ajouter une variable aléatoire gaussienne de moyenne nulle à votre signal original. La variance de cette variable aléatoire affectera la valeur de moyennement la puissance sonore.

Pour une variable aléatoire gaussienne X, la puissance moyenne Ep aussi connu comme le deuxième moment c'est
[3] Ex

Donc pour le bruit blanc, Ex et la puissance moyenne est alors égale à la variance Ex .

Pour modéliser cela en python, vous pouvez soit
1. Calculez la variance sur la base d'un SNR souhaité et d'un ensemble de mesures existantes, ce qui fonctionne si vous vous attendez à ce que vos mesures aient des valeurs d'amplitude assez cohérentes.
2. Vous pouvez également régler la puissance du bruit à un niveau connu pour correspondre à quelque chose comme le bruit du récepteur. Le bruit du récepteur peut être mesuré en pointant le télescope dans l'espace libre et en calculant la puissance moyenne.

Dans tous les cas, il est important de s'assurer que vous ajoutez du bruit à votre signal et que vous prenez des moyennes dans l'espace linéaire et non en unités dB.

Voici un code pour générer un signal et tracer la tension, la puissance en Watts et la puissance en 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

Voici un exemple d'ajout d'AWGN en fonction d'un SNR souhaité :

# 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

Et voici un exemple d'ajout d'AWGN basé sur une puissance de bruit connue :

# 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

75voto

Noel Evans Points 939

... Et pour ceux qui, comme moi, en sont au tout début de leur apprentissage de numpy,

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

12voto

MedAli Points 6050

Pour ceux qui souhaitent ajouter du bruit à un ensemble de données multidimensionnel chargé dans un dataframe pandas ou même un ndarray numpy, voici un exemple :

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
"""

2voto

Neitzke Points 21

AWGN similaire à la fonction 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X