Source code for mosqito.utils.am_noise_generator

import numpy as np

[docs] def am_noise_generator(xmod, spl_level, print_m=False): """ Amplitude-modulated braodband noise generation This function creates an amplitude-modulated (AM) signal with Gaussian broadband (noise) carrier and arbitrary modulating signal 'xmod'. The AM signal length is the same as the length of 'xmod'. The signal level is adjusted to 'spl_level' in dB. Parameters ---------- xmod: array Modulating signal, dim(N). spl_level: float Sound Pressure Level [dB ref 20 uPa RMS] of the modulated signal. print_m: bool, optional If True, calculated modulation index is printed. If False, the modulation index is printed only in case of overmodulation (m>1) Default is False. Returns ------- y_am: numpy.array Amplitude-modulated noise signal in Pascals, dim(N). m: float Modulation index Warning ------- spl_level must be provided in dB, ref=2e-5 Pa. See Also -------- .am_sine_generator : Amplitude modulation with sine wave carrier .fm_sine_generator : Frequency modulation with sine wave carrier .sine_wave_generator : Sine wave generation Notes ----- The modulation index 'm' will be equal to the peak value of the modulating signal 'mod_signal'. Its value can be printed by setting the optional flag 'print_m' to True. For 'm' = 0.5, the carrier amplitude varies by 50% above and below its unmodulated level. For 'm' = 1.0, it varies by 100%. With 100% modulation the wave amplitude sometimes reaches zero, and this represents full modulation. Increasing the modulating signal beyond that point is known as overmodulation. Examples -------- .. plot:: :include-source: >>> from mosqito.utils import am_noise_generator >>> import matplotlib.pyplot as plt >>> import numpy as np >>> fs = 48000 >>> duration = 1 >>> t = np.linspace(0, duration, int(duration*fs)) >>> dB = 60 >>> fm = 4 >>> xmod = np.sin(2*np.pi*t*fm) >>> y_am, MI = am_noise_generator(xmod, dB, True) >>> fig, plots = plt.subplots(2, 1) >>> plots[0].set_title('Amplitude-modulated broadband noise') >>> plots[0].plot(t, xmod, 'C0', label='Modulating signal') >>> plots[0].legend(loc='upper right') >>> plots[0].grid() >>> plots[0].set_ylabel('Amplitude') >>> plots[0].set_xlim([0, duration]) >>> plots[1].plot(t, y_am, '#69c3c5', label='AM signal') >>> plots[1].legend(loc='upper right') >>> plots[1].grid() >>> plots[1].set_ylabel('Amplitude') >>> plots[1].set_xlim([0, duration]) >>> plots[1].set_xlabel('Time [s]') >>> fig.set_tight_layout('tight') """ # signal length in samples Nt = xmod.shape[0] # create vector of zero-mean, unitary std dev random samples rng = np.random.default_rng() xc = rng.standard_normal(Nt) # AM signal y_am = (1 + xmod)*xc # AM modulation index m = np.max(np.abs(xmod)) if print_m: print(f"AM Modulation index = {m}") if m > 1: print("Warning ['am_noise_generator']: modulation index m > 1\n\tSignal is overmodulated!") # normalise broadband signal energy to 'spl_level' [dB SPL ref 20 uPa] p_ref = 20e-6 A_rms = p_ref * 10**(spl_level/20) y_am *= A_rms/np.std(y_am) return y_am, m