menambahkan noise ke sinyal dengan python

95

Saya ingin menambahkan beberapa gangguan acak ke beberapa sinyal 100 bin yang saya simulasikan dengan Python - agar lebih realistis.

Pada tingkat dasar, pikiran pertama saya adalah pergi bin demi bin dan hanya menghasilkan nomor acak antara kisaran tertentu dan menambah atau mengurangi ini dari sinyal.

Saya berharap (karena ini python) bahwa mungkin ada cara yang lebih cerdas untuk melakukan ini melalui numpy atau sesuatu. (Saya kira idealnya angka yang diambil dari distribusi gaussian dan ditambahkan ke setiap bin akan lebih baik juga.)

Terima kasih sebelumnya atas balasan apa pun.


Saya hanya pada tahap merencanakan kode saya, jadi saya tidak punya apa-apa untuk ditampilkan. Saya hanya berpikir bahwa mungkin ada cara yang lebih canggih untuk menghasilkan kebisingan.

Dari segi output, jika saya memiliki 10 bin dengan nilai berikut:

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

Saya hanya ingin tahu apakah ada fungsi yang telah ditentukan sebelumnya yang dapat menambahkan noise untuk memberi saya sesuatu seperti:

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

Jika tidak, saya hanya akan pergi bin-by-bin dan menambahkan nomor yang dipilih dari distribusi gaussian untuk masing-masing.

Terima kasih.


Ini sebenarnya sinyal dari teleskop radio yang saya simulasi. Saya ingin akhirnya dapat memilih sinyal untuk rasio kebisingan simulasi saya.

pengguna1551817
sumber
2
Harap tunjukkan kode yang Anda coba, atau masalah khusus yang Anda hadapi. Contoh masukan dan keluaran yang diinginkan akan sangat bermanfaat juga.
gddc
2
Sinyal macam apa itu? Jenis suara apa yang ingin Anda kenalkan? "Realistis" tergantung pada jenis sinyalnya. Noise audio tidak sama dengan noise gambar, misalnya.
Diego Basch

Jawaban:

125

Anda dapat menghasilkan derau derau, dan menambahkannya ke sinyal Anda

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
sumber
17
Dalam beberapa konteks, mungkin lebih masuk akal untuk mengalikan sinyal Anda dengan derau derau (berpusat di sekitar 1), daripada menambahkan derau derau, tapi tentu saja itu bergantung pada sifat derau yang Anda coba simulasikan.
Edward Loper
69

... Dan bagi mereka yang - seperti saya - sangat awal dalam kurva belajar yang sulit,

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

Bagi mereka yang mencoba membuat koneksi antara SNR dan variabel acak normal yang dihasilkan oleh numpy:

[1] Rasio SNR, penting untuk diingat bahwa P adalah kekuatan rata - rata .

Atau dalam dB:
[2]SNR dB2

Dalam hal ini, kami sudah memiliki sinyal dan kami ingin menghasilkan derau untuk memberi kami SNR yang diinginkan.

Meskipun derau dapat datang dalam berbagai rasa bergantung pada apa yang Anda modelkan, awal yang baik (terutama untuk contoh teleskop radio ini) adalah Aditif Gaussian Putih Kebisingan (AWGN) . Seperti yang dinyatakan dalam jawaban sebelumnya, untuk memodelkan AWGN Anda perlu menambahkan variabel acak gaussian nol ke sinyal asli Anda. Varians dari variabel acak tersebut akan mempengaruhi kekuatan kebisingan rata - rata .

Untuk variabel acak Gaussian X, kekuatan rata-rata Ep, juga dikenal sebagai momen kedua , adalah
[3] Ex

Jadi untuk white noise, Exdan daya rata-rata kemudian sama dengan varians Ex.

Saat memodelkan ini dengan python, Anda dapat
1. Menghitung varians berdasarkan SNR yang diinginkan dan serangkaian pengukuran yang ada, yang akan berfungsi jika Anda mengharapkan pengukuran Anda memiliki nilai amplitudo yang cukup konsisten.
2. Sebagai alternatif, Anda dapat mengatur daya derau ke tingkat yang diketahui untuk mencocokkan sesuatu seperti derau penerima. Kebisingan penerima dapat diukur dengan mengarahkan teleskop ke ruang bebas dan menghitung daya rata-rata.

Bagaimanapun, penting untuk memastikan bahwa Anda menambahkan noise ke sinyal Anda dan mengambil rata-rata dalam ruang linier dan bukan dalam unit dB.

Berikut beberapa kode untuk menghasilkan tegangan sinyal dan plot, daya dalam Watt, dan daya dalam 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()

Sinyal yang Dihasilkan

Berikut adalah contoh untuk menambahkan AWGN berdasarkan SNR yang diinginkan:

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

Sinyal dengan SNR target

Dan berikut adalah contoh untuk menambahkan AWGN berdasarkan kekuatan derau yang diketahui:

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

Sinyal dengan tingkat kebisingan target

tmcdevitt
sumber
8

Bagi mereka yang ingin menambahkan noise ke kumpulan data multi-dimensi yang dimuat dalam bingkai data pandas atau bahkan ndarray numpy, berikut ini contohnya:

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
sumber
1

Dalam kehidupan nyata, Anda ingin mensimulasikan sinyal dengan derau putih. Anda harus menambahkan titik acak sinyal yang memiliki distribusi Gaussian Normal. Jika kita berbicara tentang perangkat yang memiliki sensitivitas yang diberikan dalam satuan / SQRT (Hz) maka Anda perlu menyusun deviasi standar poin Anda darinya. Di sini saya memberikan fungsi "white_noise" yang melakukan ini untuk Anda, sisa kode adalah demonstrasi dan memeriksa apakah ia melakukan apa yang seharusnya.

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

Sinyal dengan kebisingan

PSD

drgrujic.dll
sumber
0

Jawaban luar biasa di atas. Saya baru-baru ini memiliki kebutuhan untuk menghasilkan data simulasi dan inilah yang saya gunakan. Berbagi dalam kasus membantu orang lain juga,

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
sumber
0

AWGN Mirip dengan Fungsi 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
Neitzke
sumber