
Полная версия
Цифровая обработка сигналов на Python. От инженера к разработчику.
Сгенерируйте сигнал с частотой, плавно возрастающей от 1 000 до 30 000 Гц. Оцифруйте его с частотой 44 100 Гц без антиалиасингового фильтра и прослушайте. Вы услышите, как тон сначала повышается, а потом, после пересечения частоты Найквиста, начинает понижаться и уходит вниз. Это классическая демонстрация алиасинга, которая даёт интуитивное понимание эффекта.
В следующей главе мы познакомимся с преобразованием Фурье — главным инструментом анализа звука. Мы узнаем, почему любой звук можно разложить на сумму простых синусоид, и проверим это утверждение кодом. Мы напишем наивное дискретное преобразование Фурье с нуля — оно будет работать правильно, но очень медленно. Мы поймём, почему медленно, и это понимание подготовит нас к третьей главе, где мы ускорим алгоритм в сотни раз с помощью быстрого преобразования Фурье.
Глава 2. Синусоиды, из которых состоит всё
О чём эта глава
В предыдущей главе мы разобрались с тем, как звук становится цифровым. Мы узнали, что микрофон превращает колебания воздуха в электрический сигнал, а аналого-цифровой преобразователь измеряет этот сигнал много тысяч раз в секунду, создавая массив чисел. Но мы пока не ответили на главный вопрос: что с этими числами делать дальше? Как из последовательности измерений громкости понять, какой перед нами звук — голос, музыка, шум ветра или тишина? Как отличить высокий тон от низкого, если оба записаны в виде чисел?
Ответ на этот вопрос даёт преобразование Фурье. Это математический инструмент, который берёт сигнал — любой сигнал, каким бы сложным он ни был — и раскладывает его на составные части. На элементарные кирпичики, из которых построен звук. И эти кирпичики — синусоиды. Чистые, гладкие, математически идеальные волны. Преобразование Фурье говорит нам: «Вот из каких частот состоит твой звук и насколько громка каждая из них». Это как если бы вы взяли оркестровую запись и волшебным образом разделили её на отдельные инструменты — скрипки, виолончели, флейты, барабаны, — показав, кто и когда играл.
В этой главе мы начнём с самого простого: поймём, что такое синусоида и почему именно она является универсальным строительным блоком для любого звука. Затем мы познакомимся с идеей разложения сигнала на частоты — спектральным анализом. Мы узнаем, что такое комплексные числа, зачем они нужны в обработке звука, и поймём их через простую метафору с вращающейся стрелкой. После этого мы напишем наше первое дискретное преобразование Фурье — DFT — с нуля, на чистом Python. Оно будет работать правильно, но очень медленно. Мы поймём, почему медленно, и это понимание подготовит нас к следующей главе, где мы ускорим алгоритм в сотни раз.
Синусоида: простейший звук во вселенной
Самый простой звук, который можно себе представить, — это чистый тон. Звук камертона. Звук телефонного гудка. Гладкое, ровное колебание без резких скачков и изломов. В математике такой звук описывается функцией синуса — отсюда и название «синусоида».
Почему именно синус? Потому что синус описывает идеальное колебание. Представьте себе грузик на пружине. Если оттянуть его вниз и отпустить, он начнёт колебаться вверх-вниз. График его движения — это синусоида. Представьте себе точку на ободе вращающегося колеса. Если смотреть на неё сбоку, её движение вверх-вниз — тоже синусоида. Представьте себе маятник старинных часов. Его отклонение от центра — синусоида. Колебания пронизывают природу, и все они, от вибрации атомов до орбит планет, описываются синусоидами или их комбинациями.
У синусоиды есть три главных параметра. Первый — частота. Это количество полных колебаний в секунду, измеряется в герцах. Частота определяет, насколько высоким или низким мы слышим звук. Синусоида с частотой 440 Гц — это нота «ля» первой октавы, стандартный камертон. Синусоида с частотой 220 Гц — «ля» малой октавы, вдвое ниже. Синусоида с частотой 880 Гц — «ля» второй октавы, вдвое выше. Зависимость между частотой и воспринимаемой высотой звука логарифмическая: увеличение частоты вдвое всегда воспринимается как повышение на одну октаву, независимо от того, с какой частоты мы начали.
Второй параметр — амплитуда. Это размах колебаний, максимальное отклонение от нуля. Амплитуда определяет громкость звука. В цифровом аудио амплитуда измеряется в условных единицах от -1 до 1, где -1 и 1 — это максимально возможная громкость без искажений. Когда мы делаем звук громче в коде, мы просто умножаем все числа в массиве на коэффициент больше единицы — увеличиваем амплитуду. Когда делаем тише — умножаем на коэффициент меньше единицы.
Третий параметр — фаза. Это начальное положение колебания в момент времени ноль. Две синусоиды одинаковой частоты и амплитуды, но с разными фазами, будут сдвинуты друг относительно друга. Если сдвинуть синусоиду ровно на половину периода, она превратится в косинусоиду — ту же форму волны, но начинающуюся не с нуля, а с максимума. Фаза важна, когда несколько звуков складываются вместе: две синусоиды в фазе усиливают друг друга, в противофазе — гасят.
Давайте создадим синусоиду в коде и посмотрим на неё. Заодно послушаем, как звучит чистый тон.
python
import numpy as np
import soundfile as sf
# Параметры
duration = 2.0 # две секунды
sample_rate = 44100 # CD-качество
freq = 440.0 # нота "ля"
# Создаём массив моментов времени
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
# Создаём синусоиду
y = np.sin(2 * np.pi * freq * t)
# Сохраняем в файл
sf.write('sine_440.wav', y, sample_rate)
print(f"Создана синусоида: частота {freq} Гц, длительность {duration} сек")
print(f"Количество отсчётов: {len(y)}")
print(f"Диапазон значений: от {np.min(y):.4f} до {np.max(y):.4f}")
Запустите этот код и откройте полученный файл в любом аудиоплеере. Вы услышите чистый, ровный тон. Не очень интересный музыкально, но очень важный для понимания. Именно из таких тонов, только разных частот и с разными амплитудами, состоит любой звук.
Сложение синусоид: как рождается сложный звук
В реальном мире чистые синусоиды встречаются редко. Разве что камертон или генератор сигналов издают что-то близкое к чистому тону. Большинство звуков гораздо сложнее. Но вот ключевая идея: любой сложный звук можно представить как сумму простых синусоид. Эту идею впервые высказал французский математик Жозеф Фурье в начале XIX века, и она произвела революцию в науке.
Сам Фурье занимался проблемой распространения тепла, а не звука. Он показал, что любое периодическое колебание — неважно, насколько сложное, — можно разложить на сумму синусоид с частотами, кратными основной частоте. Основная частота определяет высоту звука, а дополнительные частоты — обертоны — определяют тембр. Благодаря обертонам мы отличаем скрипку от флейты, даже когда они играют одну и ту же ноту. У скрипки один набор обертонов, у флейты — другой.
Давайте проверим эту идею на практике. Создадим несколько синусоид с кратными частотами и сложим их. Посмотрим, что получится.
python
import numpy as np
import soundfile as sf
duration = 2.0
sample_rate = 44100
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
# Основная частота — 220 Гц (нота "ля" малой октавы)
f0 = 220.0
# Создаём основную синусоиду и обертоны
fundamental = np.sin(2 * np.pi * f0 * t) # основная частота
harmonic_2 = 0.5 * np.sin(2 * np.pi * f0 * 2 * t) # второй обертон (вдвое выше)
harmonic_3 = 0.33 * np.sin(2 * np.pi * f0 * 3 * t) # третий обертон (втрое выше)
harmonic_4 = 0.25 * np.sin(2 * np.pi * f0 * 4 * t) # четвёртый обертон
harmonic_5 = 0.2 * np.sin(2 * np.pi * f0 * 5 * t) # пятый обертон
# Складываем все синусоиды
y_complex = fundamental + harmonic_2 + harmonic_3 + harmonic_4 + harmonic_5
# Сохраняем основной тон и сложный звук для сравнения
sf.write('fundamental_220.wav', fundamental, sample_rate)
sf.write('complex_tone_220.wav', y_complex, sample_rate)
print("Созданы файлы: fundamental_220.wav и complex_tone_220.wav")
print("Прослушайте оба. Основной тон звучит ровно и скучно.")
print("Сложный тон — богаче, с характером, похож на простой музыкальный инструмент.")
Прослушайте оба файла. Основной тон — чистый, гладкий, sterile. Сложный тон звучит иначе — он теплее, богаче, более музыкально. Похоже на простой синтезатор или орган. Но обратите внимание: высота звука та же самая. И в том, и в другом случае это нота «ля». Потому что высоту определяет основная частота, а тембр — набор и соотношение обертонов.
Спектр: портрет звука в частотной области
Когда мы смотрим на аудиосигнал как на массив чисел — то есть во временной области, — мы видим, как громкость меняется со временем. Это полезное представление, но оно не говорит нам, из каких частот состоит звук. Глядя на волновую форму сложного тона, вы не сможете сказать, сколько в нём обертонов и какой они амплитуды. Для этого нужно другое представление — частотное.
Спектр — это график, который показывает, какая энергия приходится на каждую частоту. По горизонтальной оси откладывается частота в герцах, по вертикальной — амплитуда или энергия. Спектр чистого тона 440 Гц — это один пик на частоте 440 Гц и больше ничего. Спектр сложного тона, который мы только что создали, — это несколько пиков на частотах 220, 440, 660, 880 и 1100 Гц, убывающих по амплитуде.
Спектр — это не просто красивая картинка. Это мощнейший диагностический инструмент. Глядя на спектр записи, вы можете увидеть фоновый гул на 50 Гц (наводка от электросети), шипение на высоких частотах (шум микрофона), резонансы помещения (усиленные частоты, на которых комната «гудит»). Вы можете понять, почему голос звучит глухо — не хватает высоких частот — или резко — слишком много верхней середины. Спектр показывает то, что ухо слышит, но не может выразить в числах.
Как же получить спектр из временного сигнала? Для этого и нужно преобразование Фурье. Оно переводит сигнал из временной области в частотную.
Дискретное преобразование Фурье: основная идея
Дискретное преобразование Фурье, или DFT, — это алгоритм, который берёт массив из N чисел, представляющих сигнал во времени, и выдаёт массив из N комплексных чисел, представляющих сигнал в частоте. Каждое число в выходном массиве соответствует определённой частоте и говорит нам: «На этой частоте сигнал имеет такую-то амплитуду и такую-то фазу».
Как DFT это делает? Идея проста и гениальна одновременно. Представьте, что вы хотите узнать, есть ли в сигнале частота 100 Гц. Вы берёте синусоиду с частотой 100 Гц, умножаете её на ваш сигнал и суммируете результат. Если в сигнале есть 100 Гц, синусоида будет с ним совпадать, и после умножения и суммирования получится большое число. Если 100 Гц нет — синусоида будет не в такт с сигналом, умножение даст то положительные, то отрицательные значения, и в сумме они погасят друг друга. Повторите эту процедуру для всех частот, которые вас интересуют — и вы получите спектр.
Формально DFT записывается так. Для каждой частоты k мы вычисляем:
X[k] = сумма по n от 0 до N-1 от x[n] умножить на e в степени минус j умножить на 2π умножить на k умножить на n, делённое на N.
Не пугайтесь этой формулы. Сейчас мы разберём её по кусочкам и превратим в работающий код. Вы увидите, что за страшными символами скрывается простая и красивая идея.
Комплексные числа: вращающаяся стрелка
В формуле DFT есть загадочная буква j и экспонента. Это комплексная экспонента, и она пугает многих новичков. Но комплексные числа — это не что-то сверхъестественное. Это просто удобный математический инструмент для описания вращения.
Представьте себе стрелку на плоскости. У неё есть длина и направление. Обычные числа могут описать длину стрелки, но не направление. Комплексные числа описывают и то, и другое. Комплексное число состоит из двух частей: действительной и мнимой. Действительная часть — это проекция стрелки на горизонтальную ось. Мнимая — проекция на вертикальную ось. Длина стрелки — это модуль комплексного числа. Угол, который стрелка образует с горизонтальной осью, — это фаза.
Когда мы умножаем сигнал на комплексную экспоненту e в степени минус j умножить на 2π умножить на k умножить на n, делённое на N, мы делаем вот что. Мы берём стрелку единичной длины и начинаем её вращать. Частота вращения зависит от k. Для k=0 стрелка стоит на месте. Для k=1 стрелка делает один полный оборот за N отсчётов. Для k=2 — два оборота. И так далее. Умножая сигнал на эту вращающуюся стрелку, мы проверяем, насколько сигнал похож на вращение с данной скоростью. Если сигнал колеблется с той же частотой, что и вращение стрелки, они будут синхронны, и после суммирования получится большое число. Если нет — они будут расходиться, и сумма будет близка к нулю.
Конец ознакомительного фрагмента.
Текст предоставлен ООО «Литрес».
Прочитайте эту книгу целиком, купив полную легальную версию на Литрес.
Безопасно оплатить книгу можно банковской картой Visa, MasterCard, Maestro, со счета мобильного телефона, с платежного терминала, в салоне МТС или Связной, через PayPal, WebMoney, Яндекс.Деньги, QIWI Кошелек, бонусными картами или другим удобным Вам способом.




