Операции над сигналами

Учимся комбинировать сигналы: из этих операций собираются все сложные обработчики.

Операции над сигналами — поэлементные (сложение, умножение, масштаб) и по оси времени (сдвиг, инверсия, прореживание) преобразования последовательностей отсчётов.

Сложный эффект — это всегда комбинация простых операций. Эхо — это сложение с задержанной копией. Эквалайзер — взвешенная сумма отфильтрованных версий. Чтобы строить такие схемы, надо твёрдо владеть базовыми операциями.

Поэлементные операции

Складываем и умножаем сигналы поотсчётно; масштабируем амплитуду умножением на число.

a = [1, 2, 3, 4]
b = [10, 20, 30, 40]

add = [x + y for x, y in zip(a, b)]    # сумма (смешивание)
mul = [x * y for x, y in zip(a, b)]    # произведение (модуляция/окно)
scale = [3 * x for x in a]             # масштаб амплитуды

print("сумма:  ", add)
print("произвед:", mul)
print("масштаб:", scale)

Вывод:

сумма:   [11, 22, 33, 44]
произвед: [10, 40, 90, 160]
масштаб: [3, 6, 9, 12]

Сложение — это микширование (два голоса в одной дорожке). Умножение на другой сигнал — модуляция или наложение окна. Масштаб — регулятор громкости.

Операции по оси времени

Сдвиг задерживает или опережает сигнал; инверсия разворачивает его во времени; прореживание выбрасывает часть отсчётов (понижает частоту дискретизации).

def shift(x, k):
    # k>0 — задержка (вправо), нули слева
    if k >= 0:
        return ([0] * k + x)[:len(x)]
    k = -k
    return (x[k:] + [0] * k)

x = [1, 2, 3, 4, 5]
print("исходный:       ", x)
print("задержка на 2:  ", shift(x, 2))
print("опережение на 1:", shift(x, -1))
print("инверсия:       ", x[::-1])
print("прореживание /2:", x[::2])

Вывод:

исходный:        [1, 2, 3, 4, 5]
задержка на 2:   [0, 0, 1, 2, 3]
опережение на 1: [2, 3, 4, 5, 0]
инверсия:        [5, 4, 3, 2, 1]
прореживание /2: [1, 3, 5]

Линейная комбинация: простое эхо

Соберём из этих операций эффект эха: сигнал плюс его задержанная и ослабленная копия.

def shift(x, k):
    return ([0] * k + x)[:len(x)]

x = [10, 8, 0, 0, 0, 0, 0, 0]   # короткий «хлопок»
delay, gain = 3, 0.5
echo = [round(s + gain * d, 1) for s, d in zip(x, shift(x, delay))]
print("Сигнал с эхом:", echo)

Вывод:

Сигнал с эхом: [10.0, 8.0, 0.0, 5.0, 4.0, 0.0, 0.0, 0.0]

Исходный хлопок в начале, а через 3 отсчёта — его половинная копия. Это и есть эхо, собранное из сдвига, масштаба и сложения.

Как работает под капотом

Ключевое свойство операций — линейность. Сложение и умножение на константу сохраняют принцип суперпозиции: реакция системы на сумму сигналов равна сумме реакций. Именно поэтому из этих кирпичей строят линейные системы, которые так удобно анализировать. А вот умножение двух сигналов (не на константу) — операция нелинейная: она создаёт новые частоты (суммарную и разностную). На этом основана модуляция, которую разберём в следующем уроке. Прореживание опасно: выбрасывая отсчёты, мы понижаем fs и без предварительной фильтрации легко получаем алиасинг.

Частые ошибки

  • Сдвигать без обнуления краёв. При задержке слева должны появиться нули, иначе сигнал «зациклится» или сдвинется некорректно.
  • Прореживать без антиалиасингового фильтра. Понижение fs требует сначала срезать высокие частоты, иначе они наложатся.
  • Путать сложение и умножение сигналов. Сложение микширует и линейно; умножение модулирует и создаёт новые частоты.

Итог

  • Поэлементные операции: сложение (микс), умножение (модуляция/окно), масштаб (громкость).
  • Операции по времени: сдвиг (задержка), инверсия, прореживание.
  • Сложные эффекты (эхо, эквалайзер) — линейные комбинации этих операций.
  • Сложение и масштаб линейны; умножение двух сигналов нелинейно и рождает новые частоты.
Проверьте себя
1. Что делает сдвиг сигнала на k>0 отсчётов вправо?
AУскоряет сигнал
BЗадерживает сигнал, добавляя нули слева
CУдваивает амплитуду
DМеняет частоту
2. Почему прореживание (выбрасывание отсчётов) опасно?
AОно увеличивает объём данных
BОно понижает fs и без фильтра вызывает алиасинг
CОно меняет амплитуду
DОно ничего не меняет
3. Какая операция над двумя сигналами НЕлинейна и создаёт новые частоты?
AСложение
BМасштаб на константу
CПоэлементное умножение двух сигналов
DСдвиг