Pythonで信号にノイズを追加する


95

Pythonでシミュレートしている100ビンの信号にランダムノイズを追加して、より現実的にしたいと思います。

基本的なレベルでは、私の最初の考えは、ビンごとに移動し、特定の範囲の間で乱数を生成し、これを信号に加算または減算することでした。

私は(これはpythonなので)numpyか何かを介してこれを行うためのよりインテリジェントな方法があるかもしれないことを望んでいました。(理想的には、ガウス分布から抽出され、各ビンに追加された数値の方が良いと思います。)

返信をお待ちしております。


私はコードを計画している段階にあるので、何も表示する必要はありません。もっと洗練された方法でノイズを発生させる方法があるのではないかと思っていました。

出力に関しては、次の値を持つ10個のビンがある場合:

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

ノイズを追加して次のようなものを与えることができる事前定義された関数があるかどうか疑問に思いました。

ビン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

そうでない場合は、ビンごとに移動し、ガウス分布から選択した数値をそれぞれに追加します。

ありがとうございました。


私がシミュレートしているのは、実際には電波望遠鏡からの信号です。最終的に、シミュレーションの信号対雑音比を選択できるようにしたいと考えています。


2
試したコード、または発生している特定の問題を示してください。サンプル入力と目的の出力も大いに役立ちます。
gddc 2012

2
どんな信号ですか?どんなノイズを導入したいですか?「リアル」は信号の種類によって異なります。たとえば、オーディオノイズはイメージノイズと同じではありません。
ディエゴバッシュ2012

回答:


125

ノイズ配列を生成し、それを信号に追加できます

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
状況によっては、ノイズ配列を追加するよりも、信号にノイズ配列(1を中心とする)を掛けた方が理にかなっている場合がありますが、もちろんそれは、シミュレートしようとしているノイズの性質によって異なります。
エドワードローパー2012

69

...そして、私のように、学習曲線が非常に早い人にとっては、

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

57

SNRとnumpyによって生成された正規確率変数を接続しようとしている人のために:

[1] SNR比、ここで、Pは平均パワーであることを覚えておくことが重要です。

またはdB単位:
[2]SNR dB2

この場合、すでに信号があり、ノイズを生成して目的のSNRを実現したいと考えています。

ノイズはモデリング対象に応じてさまざまな種類がありますが、(特にこの電波望遠鏡の例では)加法性ホワイトガウスノイズ(AWGN)から始めることをお勧めします。前の回答で述べたように、AWGNをモデル化するには、元の信号に平均ゼロのガウス確率変数を追加する必要があります。その確率変数の分散は、平均ノイズパワーに影響します。

ガウス確率変数Xの場合Ep、2次モーメントとも呼ばれる平均パワーは
[3]です。 例

したがって、ホワイトノイズの場合例、平均パワーは分散に等しくなり例ます。

これをPythonでモデル化する場合、次のいずれかを実行できます
。1。目的のSNRと既存の測定値のセットに基づいて分散を計算します。これは、測定値がかなり一貫した振幅値を持つと予想される場合に機能します。
2.または、受信機のノイズなどに一致するように、ノイズ電力を既知のレベルに設定することもできます。受信機のノイズは、望遠鏡を自由空間に向けて平均電力を計算することで測定できます。

いずれにせよ、信号にノイズを追加し、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()

生成された信号

目的の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()

ターゲットSNRの信号

そして、既知のノイズパワーに基づいて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()

ターゲットノイズレベルの信号


8

pandasデータフレームまたはnumpyndarray内にロードされた多次元データセットにノイズを追加したい場合は、次の例を参照してください。

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

実生活では、ホワイトノイズのある信号をシミュレートしたいと考えています。正規ガウス分布を持つランダムポイントを信号に追加する必要があります。単位/ SQRT(Hz)で与えられる感度を持つデバイスについて話す場合、それからのポイントの標準偏差を考案する必要があります。ここでは、これを行う関数「white_noise」を提供します。残りのコードはデモンストレーションであり、それが適切に機能するかどうかを確認します。

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

ノイズのある信号

PSD


0

上記の素晴らしい答え。最近、シミュレーションデータを生成する必要がありました。これを使用して着陸しました。他の人にも役立つケース内の共有、

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関数に似た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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.