Para quem está tentando fazer a conexão entre SNR e uma variável aleatória normal gerada por numpy:
[1]
, onde é importante ter em mente que P é a potência média .
Ou em dB:
[2]
Nesse caso, já temos um sinal e queremos gerar ruído para nos dar o SNR desejado.
Embora o ruído possa vir em diferentes sabores dependendo do que você está modelando, um bom começo (especialmente para este exemplo de radiotelescópio) é o ruído gaussiano branco aditivo (AWGN) . Conforme declarado nas respostas anteriores, para modelar AWGN você precisa adicionar uma variável aleatória gaussiana de média zero ao seu sinal original. A variância dessa variável aleatória afetará a média potência ruído.
Para uma variável aleatória gaussiana X, a potência média
, também conhecida como segundo momento , é
[3] 
Portanto, para o ruído branco,
a potência média é então igual à variância
.
Ao modelar isso em Python, você pode:
1. Calcular a variância com base em um SNR desejado e um conjunto de medições existentes, o que funcionaria se você esperasse que suas medições tivessem valores de amplitude razoavelmente consistentes.
2. Como alternativa, você pode definir a potência do ruído para um nível conhecido para corresponder a algo como o ruído do receptor. O ruído do receptor pode ser medido apontando o telescópio para o espaço livre e calculando a potência média.
De qualquer forma, é importante certificar-se de adicionar ruído ao seu sinal e tirar as médias no espaço linear e não em unidades dB.
Aqui está um código para gerar um sinal e representar a tensão, a potência em Watts e a potência em dB:
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()

Aqui está um exemplo para adicionar AWGN com base em um SNR desejado:
target_snr_db = 20
sig_avg_watts = np.mean(x_watts)
sig_avg_db = 10 * np.log10(sig_avg_watts)
noise_avg_db = sig_avg_db - target_snr_db
noise_avg_watts = 10 ** (noise_avg_db / 10)
mean_noise = 0
noise_volts = np.random.normal(mean_noise, np.sqrt(noise_avg_watts), len(x_watts))
y_volts = x_volts + noise_volts
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()
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()

E aqui está um exemplo para adicionar AWGN com base em uma potência de ruído conhecida:
target_noise_db = 10
target_noise_watts = 10 ** (target_noise_db / 10)
mean_noise = 0
noise_volts = np.random.normal(mean_noise, np.sqrt(target_noise_watts), len(x_watts))
y_volts = x_volts + noise_volts
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()
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()
