Генерация с изменением амплитуды
Во второй части работы необходимо создать звук, в котором будет изменятся амплитуда сигнала по какому-то закону. В качестве искомого результата было выбрано создать шум океана, который плавно перетекает из одного канала в другой. В таблице 2 приведён список переменных, используемых в данной работе, а в листинге 2 – созданный программный код.
Таблица 2. Список используемых переменных
Название |
Тип |
Описание |
Sample_rate |
Целочисленный |
Частота дискретизации звука |
duration |
Целочисленный |
Продолжительность аудиофайла |
Output_signal |
Двумерный массив |
Сгенерированный сигнал |
X1 |
Двумерный массив |
Источник белого шума |
F1_low, F1_up |
Целочисленный |
Нижняя/верхняя граница фильтрации |
B, A |
Массивы |
Параметры для фильтрации сигнала |
Y1 |
Двумерный массив |
Отфильтрованный белый шум |
Y12 |
Двумерный массив |
Результат применения функций к шуму |
Листинг 2. Перетекающий шум океана на Python
def left_right_ocean(rate, duration, detailed_data: bool = False): N = duration*rate x1 = np.random.rand(N, 2) f1_low, f1_up = 400, 900 b, a = signal.butter(2, [f1_low, f1_up], btype='bandpass', fs=sample_rate) y1 = signal.lfilter(b, a, x1, axis=0) y2 = np.zeros_like(y1) for i in range(N): y2[i,0] = np.sin(2*np.pi*i/N) y2[i,1] = np.cos(2*np.pi*i/N) y12 = y1 * y2 output_signal = amplitude_norm(y12, 0.5)
if detailed_data: filter(b, a, sample_rate) afr(output_signal[:,0], sample_rate) return output_signal
sample_rate, duration = 44100, 10 output_signal = left_right_ocean(sample_rate, duration, detailed_data=True) visualize(output_signal, sample_rate) io.wavfile.write("4/ocean_noise.wav", sample_rate, output_signal) plt.show() |
Далее необходимо запустить данную программу и изучить получаемые результаты. На рисунке 4 показан АЧХ созданного фильтра, на рисунке 5 – частотная характеристика созданного сигнала и на рисунке 6 – визуализация получившегося сигнала.
Рисунок 4 – АЧХ фильтра
Рисунок 5 – АЧХ сигнала
Рисунок 6 – Визуализация шума
При прослушивании данной записи возникло ощущения шума океана, который перемещается из одного уха в другое, т.е. получилось ровно то, что и планировалось изначально. Однако второй слушатель заявил, что это больше похоже на шум ветра в лесу, который также перемещается из одного уха в другое.
Реалистичный шумовой сигнал
В качестве заключительного этапа при выполнении лабораторной работы необходимо реализовать наиболее реалистичный вариант звуковой дорожки. В качестве образца была выбрана сирена пожарной машины [3]. Для начала, на рисунке 7 показан АЧХ эталонной сирены, а на рисунке 8 – визуализация данного сигнала.
Рисунок 7 – АЧХ эталонного сигнала
Рисунок 8 – Визуализация сигнала
Далее, была разработана программа, позволяющая попытаться воссоздать данный сигнал при помощи имеющегося инструментария. В таблице 3 приведён список используемых переменных, а в листинге 3 – исходный программный код.
Таблица 3. Список используемых переменных
Название |
Тип |
Описание |
Sample_rate |
Целочисленный |
Частота дискретизации звука |
duration |
Целочисленный |
Продолжительность аудиофайла |
Output_signal |
Двумерный массив |
Сгенерированный сигнал |
volume |
Дробное |
Громкость звука |
F1, F2 |
Целочисленный |
Нижняя/верхняя частота сигнала |
Signal_low/high |
Двумерные массивы |
Нижняя/верхняя частота сигнала |
Span |
Дробное |
Время в с. длительность одной частоты |
Dn, up |
Дробные |
Границы фильтрации для частот |
Листинг 3. Имитация сирены пожарной машины
def ambulance_siren(rate: int, duration: int, volume: float, eps: float): N = rate*duration f1, f2 = 614, 1844 span = 0.5 dn, up = 1 - eps, 1 + eps
signal_low = check_filter(sample_rate, duration, volume, "bandpass", 2, [dn*f1, up*f1]) signal_high = check_filter(sample_rate, duration, volume, "bandpass", 2, [dn*f2, up*f2])
result = np.zeros_like(signal_low, dtype=np.float64) up = True for i in range(1, N+1): if up: result[i:,] = signal_high[i:,] else: result[i:,] = signal_low[i:,] if i % (sample_rate*span) == 0: up = not up print(f"Прогресс: {i/N * 100:.2f}%") result[i:,] *= np.exp(-2*i/N) result = amplitude_norm(result, 0.5) return result
sample_rate, duration = 44100, 10 output_signal = ambulance_siren(sample_rate, duration, 0.5, 0.01) afr(output_signal[:,0], sample_rate) visualize(output_signal, sample_rate) io.wavfile.write("4/ambulance_noise.wav", sample_rate, output_signal.astype(np.int16)) plt.show() |
Далее, на рисунках 9 и 10 показаны АЧХ и визуализация сгенерированного сигнала соответственно.
Рисунок 9 – АЧХ сигнала
Рисунок 10 – Визуализация сигнала
Из рисунка 10 видно, что со временем сигнал затухает. Это было сделано намеренно для того, чтобы создать эффект удаления сирены от слушателя. При прослушивании и сравнении данного сигнала с эталонным разница очень велика. Например, в сгенерированном сигнале при изменении с одной частоты на другую происходит какой-то щелчок, которого нету в эталонном. Также, получившиеся частоты не очень совпадают с теми, которые используются в исходном. Таким образом можно сказать, что сирена получилась, но с рядом недостатков.
Выводы
Подводя итоги к проделанной работе, можно сделать вывод о том, что в ходе выполнения данной лабораторной работы я изучил методологию создания шумоподобных сигналов на основе формирующих фильтров. Сперва был сгенерирован и оценён аналог цветного шума, а именно фиолетового. Далее был создан более трудный сигнал – создан шум океана (листвы в ветренном лесу) перетекающий из одного звукового канала в другой. И наконец, был создан сигнал, имитирующий объект из реального мира – сирена пожарной машины.