Hinzufügen von Rauschen zu einem Signal in Python

92

Ich möchte einem 100-Bin-Signal, das ich in Python simuliere, zufälliges Rauschen hinzufügen, um es realistischer zu machen.

Grundsätzlich war mein erster Gedanke, Bin für Bin zu gehen und einfach eine Zufallszahl zwischen einem bestimmten Bereich zu generieren und diese vom Signal zu addieren oder zu subtrahieren.

Ich hatte gehofft (da dies Python ist), dass es einen intelligenteren Weg gibt, dies über Numpy oder so zu tun. (Ich nehme an, dass im Idealfall auch eine Zahl aus einer Gaußschen Verteilung, die zu jedem Bin hinzugefügt wird, besser wäre.)

Vielen Dank im Voraus für alle Antworten.


Ich bin gerade dabei, meinen Code zu planen, daher habe ich nichts zu zeigen. Ich dachte nur, dass es eine ausgefeiltere Art geben könnte, das Geräusch zu erzeugen.

In Bezug auf die Ausgabe, wenn ich 10 Fächer mit den folgenden Werten hätte:

Behälter 1: 1 Behälter 2: 4 Behälter 3: 9 Behälter 4: 16 Behälter 5: 25 Behälter 6: 25 Behälter 7: 16 Behälter 8: 9 Behälter 9: 4 Behälter 10: 1

Ich habe mich nur gefragt, ob es eine vordefinierte Funktion gibt, die Rauschen hinzufügen kann, um mir so etwas wie Folgendes zu geben:

Behälter 1: 1,13 Behälter 2: 4,21 Behälter 3: 8,79 Behälter 4: 16,08 Behälter 5: 24,97 Behälter 6: 25,14 Behälter 7: 16,22 Behälter 8: 8,90 Behälter 9: 4,02 Behälter 10: 0,91

Wenn nicht, gehe ich einfach Bin für Bin und füge jedem eine aus einer Gaußschen Verteilung ausgewählte Zahl hinzu.

Danke dir.


Es ist eigentlich ein Signal von einem Radioteleskop, das ich simuliere. Ich möchte in der Lage sein, das Signal-Rausch-Verhältnis meiner Simulation zu wählen.

user1551817
quelle
2
Bitte demonstrieren Sie den Code, den Sie ausprobiert haben, oder ein bestimmtes Problem, auf das Sie stoßen. Sample-Eingaben und gewünschte Ausgaben würden ebenfalls einen langen Weg gehen.
GDDC
1
Was ist das für ein Signal? Welche Art von Lärm möchten Sie einführen? "Realistisch" hängt von der Art des Signals ab. Audio-Rauschen ist beispielsweise nicht dasselbe wie Bildrauschen.
Diego Basch

Antworten:

122

Sie können ein Rauscharray erzeugen und es Ihrem Signal hinzufügen

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
Akavall
quelle
16
In einigen Kontexten ist es möglicherweise sinnvoller, Ihr Signal mit einem Rauscharray (zentriert um 1) zu multiplizieren, als ein Rauscharray hinzuzufügen. Dies hängt jedoch natürlich von der Art des Rauschens ab, das Sie simulieren möchten.
Edward Loper
69

... und für diejenigen, die - wie ich - sehr früh in ihrer numpy Lernkurve sind,

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

Für diejenigen, die versuchen, die Verbindung zwischen SNR und einer normalen Zufallsvariablen herzustellen, die von numpy generiert wird:

[1] SNR-Verhältnis, wo es wichtig ist zu bedenken, dass P die durchschnittliche Leistung ist.

Oder in dB:
[2]SNR dB2

In diesem Fall haben wir bereits ein Signal und möchten Rauschen erzeugen, um ein gewünschtes SNR zu erhalten.

Während Rauschen je nach Modell in verschiedenen Geschmacksrichtungen auftreten kann, ist Additive White Gaussian Noise (AWGN) ein guter Anfang (insbesondere für dieses Radioteleskop-Beispiel ) . Wie in den vorherigen Antworten angegeben, müssen Sie zum Modellieren von AWGN Ihrem ursprünglichen Signal eine Gaußsche Zufallsvariable mit einem Mittelwert von Null hinzufügen. Die Varianz dieser Zufallsvariablen beeinflusst die durchschnittliche Rauschleistung.

Für eine Gaußsche Zufallsvariable X beträgt die durchschnittliche Leistung Ep, auch als zweiter Moment bekannt ,
[3]. Ex

Also für weißes Rauschen, Exund die durchschnittliche Leistung ist dann gleich der Varianz Ex.

Wenn Sie dies in Python modellieren, können Sie entweder
1. die Varianz basierend auf einem gewünschten SNR und einer Reihe vorhandener Messungen berechnen. Dies würde funktionieren, wenn Sie erwarten, dass Ihre Messungen ziemlich konsistente Amplitudenwerte aufweisen.
2. Alternativ können Sie die Rauschleistung auf einen bekannten Pegel einstellen, um etwa dem Empfängerrauschen zu entsprechen. Das Empfängerrauschen könnte gemessen werden, indem das Teleskop in den freien Raum gerichtet und die durchschnittliche Leistung berechnet wird.

In jedem Fall ist es wichtig sicherzustellen, dass Sie Ihrem Signal Rauschen hinzufügen und Durchschnittswerte im linearen Raum und nicht in dB-Einheiten ermitteln.

Hier ist ein Code zum Erzeugen eines Signals und zum Zeichnen der Spannung, der Leistung in Watt und der Leistung in 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()

Generiertes Signal

Hier ist ein Beispiel für das Hinzufügen von AWGN basierend auf einem gewünschten SNR:

# 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 mit Ziel-SNR

Und hier ist ein Beispiel für das Hinzufügen von AWGN basierend auf einer bekannten Rauschleistung:

# 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 mit Zielrauschpegel

tmcdevitt
quelle
8

Für diejenigen, die einem mehrdimensionalen Datensatz, der in einem Pandas-Datenrahmen oder sogar einem numpy ndarray geladen ist, Rauschen hinzufügen möchten, ist hier ein Beispiel:

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
""" 
Mohamed Ali JAMAOUI
quelle
0

Tolle Antworten oben. Vor kurzem musste ich simulierte Daten generieren, und das ist es, worauf ich gelandet bin. Teilen für den Fall hilfreich für andere,

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
Pramit
quelle
0

AWGN Ähnlich wie die Matlab-Funktion

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
Neitzke
quelle
0

Im wirklichen Leben möchten Sie ein Signal mit weißem Rauschen simulieren. Sie sollten Ihrem Signal zufällige Punkte hinzufügen, die eine normale Gaußsche Verteilung haben. Wenn es sich um ein Gerät handelt, dessen Empfindlichkeit in Einheit / SQRT (Hz) angegeben ist, müssen Sie eine Standardabweichung Ihrer Punkte davon festlegen. Hier gebe ich die Funktion "white_noise", die dies für Sie erledigt. Der Rest eines Codes ist eine Demonstration und prüfe, ob er das tut, was er sollte.

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

"""
parameters: 
rhp - spectral noise density unit/SQRT(Hz)
sr  - sample rate
n   - no of points
mu  - mean value, optional

returns:
n points of noise signal with spectral noise density of rho
"""
def white_noise(rho, sr, n, mu=0):
    sigma = rho * np.sqrt(sr/2)
    noise = np.random.normal(mu, sigma, n)
    return noise

rho = 1 
sr = 1000
n = 1000
period = n/sr
time = np.linspace(0, period, n)
signal_pure = 100*np.sin(2*np.pi*13*time)
noise = white_noise(rho, sr, n)
signal_with_noise = signal_pure + noise

f, psd = signal.periodogram(signal_with_noise, sr)

print("Mean spectral noise density = ",np.sqrt(np.mean(psd[50:])), "arb.u/SQRT(Hz)")

plt.plot(time, signal_with_noise)
plt.plot(time, signal_pure)
plt.xlabel("time (s)")
plt.ylabel("signal (arb.u.)")
plt.show()

plt.semilogy(f[1:], np.sqrt(psd[1:]))
plt.xlabel("frequency (Hz)")
plt.ylabel("psd (arb.u./SQRT(Hz))")
#plt.axvline(13, ls="dashed", color="g")
plt.axhline(rho, ls="dashed", color="r")
plt.show()

Signal mit Rauschen

PSD

drgrujic
quelle