python'da sinyale gürültü eklemek


95

Python'da simüle ettiğim 100 bin sinyale biraz rastgele gürültü eklemek istiyorum - daha gerçekçi hale getirmek için.

Temel düzeyde, ilk düşüncem, ikiye bölmek ve belirli bir aralık arasında rastgele bir sayı oluşturmak ve bunu sinyale eklemek veya çıkarmaktı.

Bunu (bu python olduğu için) numpy veya başka bir şey yoluyla yapmanın daha akıllıca bir yolu olabileceğini umuyordum. (Sanırım ideal olarak bir gauss dağılımından alınan ve her bölmeye eklenen bir sayı da daha iyi olurdu.)

Herhangi bir yanıt için şimdiden teşekkür ederim.


Kodumu planlama aşamasındayım, bu yüzden gösterecek hiçbir şeyim yok. Gürültüyü üretmenin daha karmaşık bir yolu olabileceğini düşünüyordum.

Çıktı açısından, aşağıdaki değerlere sahip 10 kutum olsaydı:

Bölme 1: 1 Bölme 2: 4 Bölme 3: 9 Bölme 4:16 Bölme 5:25 Bölme 6: 25 Bölme 7:16 Bölme 8: 9 Bölme 9: 4 Bölme 10: 1

Bana şöyle bir şey vermek için gürültü ekleyebilecek önceden tanımlanmış bir işlev olup olmadığını merak ettim:

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

Değilse, bin-bin gideceğim ve her birine bir gauss dağılımından seçilen bir sayı ekleyeceğim.

Teşekkür ederim.


Aslında simüle ettiğim bir radyo teleskopundan gelen bir sinyal. Sonunda simülasyonumun sinyal-gürültü oranını seçebilmek istiyorum.


2
Lütfen denediğiniz kodu veya karşılaştığınız belirli bir sorunu gösterin. Örnek girdiler ve istenen çıktılar da uzun bir yol kat eder.
gddc

2
Bu ne tür bir sinyal? Ne tür bir gürültü tanıtmak istersiniz? "Gerçekçi", sinyalin türüne bağlıdır. Örneğin, ses gürültüsü görüntü gürültüsü ile aynı değildir.
Diego Basch

Yanıtlar:


125

Bir gürültü dizisi oluşturabilir ve bunu sinyalinize ekleyebilirsiniz

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

17
Bazı bağlamlarda, sinyalinizi bir gürültü dizisi eklemek yerine bir gürültü dizisi (1 civarında ortalanmış) ile çarpmak daha mantıklı olabilir, ancak bu, simüle etmeye çalıştığınız gürültünün doğasına bağlıdır.
Edward Loper

69

... Ve - benim gibi - uyuşuk öğrenme eğrisinde çok erken olanlar için,

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

58

SNR ile numpy tarafından oluşturulan normal bir rastgele değişken arasında bağlantı kurmaya çalışanlar için :

[1] SNR oranı, P'nin ortalama güç olduğunu akılda tutmak önemlidir .

Veya dB cinsinden:
[2]SNR dB2

Bu durumda, zaten bir sinyalimiz var ve bize istenen bir SNR'yi vermek için gürültü üretmek istiyoruz.

Gürültü, modellediğiniz şeye bağlı olarak farklı tatlarda olabilirken, iyi bir başlangıç ​​(özellikle bu radyo teleskop örneği için) Eklemeli Beyaz Gauss Gürültüsüdür (AWGN) . Önceki cevaplarda belirtildiği gibi, AWGN'yi modellemek için orijinal sinyalinize sıfır ortalamalı bir gauss rastgele değişkeni eklemeniz gerekir. Bu rastgele değişkenin varyansı, ortalama gürültü gücünü etkileyecektir .

Bir Gauss rastgele değişken X için, ortalama güç Ep, aynı zamanda, ikinci olarak da bilinen, an , bir
[3] Eski

Yani beyaz gürültü Eskiiçin ortalama güç varyansa eşittir Eski.

Bunu python'da modellerken,
1. Varyansı istenen bir SNR ve bir dizi mevcut ölçüm temelinde hesaplayabilirsiniz; bu, ölçümlerinizin oldukça tutarlı genlik değerlerine sahip olmasını bekliyorsanız işe yarar.
2. Alternatif olarak, alıcı gürültüsü gibi bir şeye uyması için gürültü gücünü bilinen bir seviyeye ayarlayabilirsiniz. Alıcı gürültüsü, teleskopu boş alana doğrultarak ve ortalama güç hesaplanarak ölçülebilir.

Her iki durumda da, sinyalinize gürültü eklediğinizden ve ortalamaları dB birimlerinde değil doğrusal uzayda aldığınızdan emin olmak önemlidir.

İşte bir sinyal ve grafik voltajı, Watt cinsinden güç ve dB cinsinden güç oluşturmak için bazı kodlar:

# 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()

Oluşturulan Sinyal

İstenen SNR'ye göre AWGN eklemek için bir örnek:

# 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()

Hedef SNR ile sinyal

Ve bilinen bir gürültü gücüne dayalı olarak AWGN eklemek için bir örnek:

# 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()

Hedef gürültü seviyesine sahip sinyal


8

Pandas veri çerçevesine veya hatta bir ndarray'e yüklenen çok boyutlu bir veri kümesine gürültü eklemek isteyenler için, işte bir örnek:

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

1

Gerçek hayatta beyaz gürültülü bir sinyali simüle etmek istersiniz. Sinyalinize Normal Gauss dağılımına sahip rastgele noktalar eklemelisiniz. Birim / SQRT (Hz) cinsinden verilen hassasiyete sahip bir cihazdan bahsedersek, puanlarınızın standart sapmasını ondan hesaplamanız gerekir. Burada bunu sizin için yapan "white_noise" işlevini veriyorum, bir kodun geri kalanı göstermedir ve yapması gerekeni yapıp yapmadığını kontrol eder.

%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()

Gürültülü sinyal

PSD


0

Yukarıda harika cevaplar. Son zamanlarda simüle edilmiş veriler üretmeye ihtiyacım vardı ve bunu kullanmaya başladım. Başkaları için de yararlı olan durumları paylaşmak,

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

0

Matlab İşlevine Benzer AWGN

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.