[python] 파이썬에서 신호에 잡음 추가

저는 파이썬에서 시뮬레이션하고있는 100 개의 빈 신호에 임의의 노이즈를 추가하여 좀 더 현실적으로 만들고 싶습니다.

기본 수준에서 첫 번째 생각은 bin 단위로 이동하여 특정 범위 사이의 임의의 숫자를 생성하고 신호에서 이것을 더하거나 빼는 것입니다.

나는 (파이썬이기 때문에) numpy 또는 무언가를 통해 이것을 수행하는 더 지능적인 방법이 있기를 바랬습니다. (이상적으로는 가우스 분포에서 추출하여 각 빈에 추가하는 숫자도 더 좋을 것이라고 생각합니다.)

답변에 미리 감사드립니다.


코드를 계획하는 단계에 있기 때문에 보여줄 내용이 없습니다. 나는 소음을 생성하는 더 정교한 방법이있을 것이라고 생각했습니다.

출력 측면에서 다음 값을 가진 10 개의 빈이있는 경우 :

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

다음과 같이 노이즈를 추가 할 수있는 미리 정의 된 함수가 있는지 궁금합니다.

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

그렇지 않은 경우 빈 단위로 이동하여 가우스 분포에서 선택한 숫자를 각 분포에 추가합니다.

감사합니다.


실제로 시뮬레이션하고있는 전파 망원경의 신호입니다. 결국 시뮬레이션의 신호 대 잡음비를 선택할 수 있기를 원합니다.



답변

노이즈 배열을 생성하여 신호에 추가 할 수 있습니다.

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


답변

… 그리고 저와 같은 사람들은 멍청한 학습 곡선에서 아주 초기에

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


답변

SNR 과 numpy에 의해 생성 된 일반 랜덤 변수를 연결하려는 사람들을 위해 :

[1] SNR 비율, 여기서 P는 평균 전력 이라는 점을 명심해야합니다 .

또는 dB :
[2]SNR dB2

이 경우에는 이미 신호가 있고 원하는 SNR을 제공하기 위해 노이즈를 생성하려고합니다.

모델링하는 항목에 따라 노이즈가 다른 풍미로 올 수 있지만 좋은 시작 (특히이 전파 망원경 예제의 경우)은 AWGN (Additive White Gaussian Noise) 입니다. 이전 답변에서 언급했듯이 AWGN을 모델링하려면 원래 신호에 제로 평균 가우스 확률 변수를 추가해야합니다. 해당 랜덤 변수의 분산은 평균 잡음 전력에 영향을 미칩니다 .

가우스 랜덤 변수 X의 Ep경우 2 차 모멘트 라고도 하는 평균 검정력 은
[3]입니다. 전의

따라서 백색 잡음의 전의경우 평균 전력은 분산과 같습니다 전의.

파이썬에서 이것을 모델링 할 때 다음 중 하나를 수행 할 수 있습니다
. 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()

목표 소음 수준이있는 신호


답변

pandas 데이터 프레임 또는 numpy ndarray 내에로드 된 다차원 데이터 세트에 노이즈를 추가하려는 사람들을 위해 다음과 같은 예가 있습니다.

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


답변

실제 생활에서는 백색 잡음이있는 신호를 시뮬레이션하고 싶습니다. 정규 가우스 분포가있는 임의의 점을 신호에 추가해야합니다. 단위 / 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


답변

위의 멋진 답변. 최근에 시뮬레이션 된 데이터를 생성해야했는데 이것이 제가 사용하게 된 것입니다. 다른 사람에게도 도움이되는 경우 공유,

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


답변

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