Skip to main content

FIR-фильтры в SuperCollider

Если вы хотите протестировать, как будет работать тот или иной фильтр "вживую", можно использовать SuperCollider. Увы, для этого фильтр должен брать только сигналы, использующий только текущий и прошлые семплы :(

Например, возьмем простейший low-pass фильтр, имеющий ядро $\left\{ 1/2, 1/2, 0, 0, 0, \cdots \right\}$ Т.е. отфильтрованный сигнал будет равен $f'_{n} = \frac{1}{2} f_{n} + \frac{1}{2} f_{n-1}$

Формально этот фильтр можно представить в time-domain в виде функции $f(t) = \frac{1}{2}\delta (t) + \frac{1}{2} \delta (t + \frac {2 \pi}{\omega_{0}})$, где $\omega_{0}$ — частота дискретизации.

Преобразование Фурье равно $F(\xi) = \frac{1}{2} + \frac{1}{2} e^{-\frac {2 \pi}{\omega_{0}} i\xi}$

Модуль этой функции — АЧХ нашего фильтра $\left| F(\omega) \right| = \sqrt{F^{*}F} = \sqrt {1/2 (1 + cos (\frac{2 \pi}{\omega_{0}} \omega}))$

Для $\omega = 0$ получаем $\left| F \right| = 1$ и для $\omega = \omega_{0}/2$ получаем $\left| F \right| = 0$ — как я и говорил, low-pass фильтр.

АЧХ фильтра. По горизонтальной оси — частота в единицах $\omega_{0}$


Теперь мы как будто не верим полученному результату и хотим его протестировать на Supercollider. Для этого есть UGen Convolution2. Смотрим код:

 // Аллоцируем буфер на сервере  
 b = Buffer.alloc (s, 2)  
 a = [0.5, 0.5]  
 // Копируем туда коэффициенты фильтра  
 b.setn (0, a)  
 // Шлем SynthDef на сервер, сворачивающий вход на шине 0 с ядром kernel  
 SynthDef (\flt, {|kernel| ReplaceOut.ar (0, Convolution2.ar (In.ar (0), kernel))}).send (s)  
 // Играем белый шум  
 {WhiteNoise.ar}.play  
 // И фильтруем его  
 f = Synth (\flt, [\kernel, b], addAction: \addToTail)  

В итоге через freqscope видим картину:


Верхние частоты идут на спад, как и ожидалось

Comments

Popular posts from this blog

Гладкая сшивка кусочно-постоянной функции.

Накануне мне понадобилось найти гладкую функцию, определенную на $\textbf{R}[a,c]$, равную единице на одном отрезке числовой оси, скажем, $[a, b-\epsilon]$ и нулю на другом, скажем $[b+\epsilon, c]$. Для того, чтобы гладко склеить эти два кусочка, я решил найти монотонно убывающий многочлен $f(x)$, равный $f(0) = 1$ и $f(1) = 0$, а потом "вставить" его в отрезок $[b-\epsilon, b+\epsilon]$. Для гладкости сшивки должны выполняться условия $f'(0) = f'(1) = 0$. Я решил пойти далее и положить $f^{(n)}(0) = f^{(n)}(1) = 0$ для всех $n = 1,2,\cdots,N$. То есть первые N производных должны быть равны нулю в т. $x = 0$ и $x = 1$. Понятно, что это легко сделать при наперед известном N, но как найти общую формулу? Я некоторое время промучился над этой задачей, пока не решил её следующим способом. Пусть искомая функция $f(x) = 1 + x^{N+1}L_{1}(x)$, где $L_{1}(x)$ — некий многочлен. Тогда у нас выполняется условие $f(0) = 1$ и $f^{(n)}(0) = 0$ (так как первая производная будет...

На что влияет размер (глубина) семпла?

В этом посте я разберу ещё одну характеристику представления аудио на компьютере — размер или глубину семпла. В теореме Шеннона, с которой мы ознакомились в первом посте, сказано, что семплы нужно брать с определенной частотой, чтобы восстановить исходный сигнал. Однако, в ней ничего не сказано о том, сколько памяти компьютера нужно выделить на один семпл. По сути  ней семплы — это обычные вещественные числа. В компьютере же семплы чаще всего представляются целыми числами в диапазоне от $-2^{n-1}$ до $2^{n-1}-1$ (целые числа со знаком), где $n$ — количество бит на один семпл (bps, bits per sample). С количеством бит на семпл связана другая величина — динамический диапазон (или отношение сигнал-шум, что в данном случае то же самое). Он измеряется в децибелах определяется так: $DR = 20 \lg (2^{n}) \approx 6 n$ Динамический диапазон показывает логарифм отношения самого сильного сигнала к самому слабому. Теперь, что будет, если мы выберем $n$ маленьким? Если взять синусоидальную ...

Частичное решение задачи в Sanitarium

В предыдущем посте я рассмотрел задачу из игры Sanitarium, связанную с открытием зацепов, удерживающих камень. Я пришел к выводу, что задача частично сводится к нахождению многочленов $p(x)$, имеющих обратный по отношению к операции умножения, т.е. $p(x)q(x)=1$ на кольце $F_{2}[x]/(x^8+1)$. Был получен результат, что не каждый многочлен имеет обратный, так как генерирующий многочлен факторкольца разлагается на множители: $(x^8+1) = (x+1)^8$. Логично искать обратимые многочлены среди относительно простых по отношению к $x^8+1$, т.е. тех, которые не делятся на $x+1$. Проверим несколько многочленов: $1$ — крестовина из одного элемента, тривиальное решение. $x$ — аналогично. $x+1$ — делится на $x+1$. $x^2$ — опять крестовина из одного элемента. $x^2+1$ — делится на $x+1$. $x^2+x+1$ — не тривиальное решение и не делится на $x+1$ — наш клиент! Написав на своем любимом лиспике простую программку, я подобрал обратный многочлен $q(x) = x^7 + x^5 + x^4 + x^2 + x$. Как это работает? Н...