Я хочу добавить случайный шум к сигналу из 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
Если нет, я просто буду бин за бункером и добавляю число, выбранное из гауссовского распределения, к каждому из них.
Спасибо.
На самом деле это сигнал радиотелескопа, который я моделирую. Я хочу иметь возможность в конечном итоге выбрать соотношение сигнал / шум для моей симуляции.
Ответы:
Вы можете создать массив шума и добавить его в свой сигнал
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] , где важно помнить, что P - это средняя мощность.
Или в дБ:
[2]
В этом случае у нас уже есть сигнал, и мы хотим сгенерировать шум, чтобы получить желаемое SNR.
Хотя шум может иметь разные вкусы в зависимости от того, что вы моделируете, хорошим началом (особенно для этого примера радиотелескопа) является аддитивный белый гауссовский шум (AWGN) . Как указано в предыдущих ответах, для моделирования AWGN вам необходимо добавить гауссовскую случайную величину с нулевым средним к исходному сигналу. Дисперсия этой случайной величины повлияет на среднюю мощность шума.
Для гауссовой случайной величины X средняя мощность , также известная как второй момент , равна
[3]
Итак, для белого шума средняя мощность равна дисперсии .
При моделировании этого на python вы можете:
1. Вычислить дисперсию на основе желаемого отношения сигнал / шум и набора существующих измерений, что будет работать, если вы ожидаете, что ваши измерения будут иметь достаточно согласованные значения амплитуды.
2. В качестве альтернативы вы можете установить мощность шума на известный уровень, чтобы соответствовать чему-то вроде шума приемника. Шум приемника можно было измерить, направив телескоп в свободное пространство и вычислив среднюю мощность.
В любом случае, важно убедиться, что вы добавляете шум в свой сигнал и принимаете средние значения в линейном пространстве, а не в единицах дБ.
Вот код для генерации сигнала и графика напряжения, мощности в ваттах и мощности в дБ:
# 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()
Вот пример добавления AWGN на основе желаемого SNR:
# 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()
А вот пример добавления 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 (Гц), тогда вам необходимо определить стандартное отклонение ваших точек от него. Здесь я привожу функцию 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()
источник
Замечательные ответы выше. Недавно мне потребовалось сгенерировать смоделированные данные, и это то, что я использовал. Обмен информацией в случае полезен и для других,
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
источник
AWGN, похожий на функцию 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
источник