\documentclass[a4paper,fontsize=14bp]{article}

\input{../common-preamble}
\input{../bmstu-preamble}
\input{../fancy-listings-preamble}
\numerationBottom
\newcolumntype{s}{>{\tiny{}}c}

\begin{document}
\thispagestyle{empty}
\makeBMSTUHeader

\makeReportTitle{домашней}{3}{Звуковой эффект}{Микропроцессорные устройства обработки сигналов}{}{проф. каф. ИУЗ, д.т.н. \\В.С. Выхованец}
\newpage
\thispagestyle{empty}
\tableofcontents
\addtocontents{toc}{\vspace{2ex}}

\newpage
\pagestyle{fancy}
\section{Постановка задачи}
Целью домашнего задания является разработка алгоритма звукового эффекта «Контроллер динамического диапазона». Для выполнения домашнего задания необходимо:
\begin{itemize}
\item ознакомиться с рекомендованной литературой \cite{dsp:lectures};
\item привести в отчете описание звукового эффекта;
\item описать алгоритм обработки сигналов и данных.
\end{itemize}
При разработке алгоритма необходимо учесть, что исходный звуковой сигнал поступает на обработку от звукового кодека по одному отсчету, получаемому при вызове функции \code{sam = GetSample()}, где \code{sam} – текущий входной отсчет звукового сигнала в формате с фиксированной запятой. Обработанные отсчеты передаются звуковому кодеку обратно путем вызова функции \code{PutSample(res)}, где \code{res} – текущий выходной отсчет звукового сигнала в формате с фиксированной запятой.

\section{Выполнение}
\subsection{Описание звукового эффекта}
Контроллер динамического диапазона - это адаптивная регулировка динамического диапазона сигнала. Динамический диапазон - это соотношение между наибольшими и наименьшими значениями, которые может принять определенная величина. Существует несколько типов контроллеров. В данной лабораторной работе будет рассматриваться ограничитель. Назначение ограничителя состоит в том, чтобы обеспечить контроль над самыми высокими пиками сигнала, но при этом, как можно меньше изменять динамику сигнала. Это достигается за счёт использования характеристической кривой с бесконечным отношением \cite[с. 109]{dsp:dafx}. Ограничитель динамического диапазона подавляет громкость звуков, пересекающих заданный порог (рисунок \hrf{pic:limiter}).

\begin{figure}[H]
  \captionsetup{labelsep=endash}
  \centering
  \def\svgwidth{100mm}
  \input{pics/02-dsp-03lab-limiter.pdf_tex}
  \caption{Иллюстрация работы ограничителя сигнала}
  \label{pic:limiter}
\end{figure}

Для достижения плавности кривой применяемого ослабления громкости используются такие параметры, как время атаки и высвобождения. Время атаки и время высвобождения соответствуют времени, за которое сигнал увеличивается или уменьшается до конечного значения (рисунок \hrf{pic:limiter-explain}).  На рисунке видно, что при отсутствии времени атаки и освобождения усиление применяется сразу, создавая неплавные «обрезанные» кривые (жёсткое урезание).

\begin{figure}[H]
  \captionsetup{labelsep=endash}
  \centering
  \def\svgwidth{170mm}
  \input{pics/02-dsp-03lab-limiter-explain.pdf_tex}
  \caption{Иллюстрация влияния времени атаки и освобождения}
  \label{pic:limiter-explain}
\end{figure}

Ограничитель обычно используется для того, чтобы «поймать» самые громкие моменты источника, уменьшив их таким образом, чтобы защитить от нежелательных искажений и сохранить целостность общего баланса звука.

\subsection{Математическое описание ограничителя}
\label{sect:description}
Динамическая обработка выполняется усилительными устройствами, где коэффициент усиления автоматически регулируется уровнем входного сигнала. Динамическая обработка проходит в несколько этапов:
\begin{enumerate}[label=\arabic*),ref=\arabic*]
\item Сначала используется схема определения амплитуды/уровня по алгоритму PEAK \cite[с. 107]{dsp:dafx}.

В начале алгоритма значение переменной $X_{peak}$ равно нулю. Далее сравнивается модуль поступающего сигнала $|x(n)|$ с предыдущим значением $X_{peak}$. В случае если значение модуля поступающего сигнала больше, то значение $X_{peak}$ для текущего элемента вычисляется с использованием коэффициента $AT$, которое используется, как сокращение для времени атаки (attack time). В ином случае вычисление значения $X_{peak}$ для текущего элемента производится с помощью коэффициента $RT$, то есть времени освобождения (release time). Математическая формула описанного выше алгоритма

\begin{equation}
  X_{p}(n) = \begin{cases}
    (1 - AT) \times X_{p}(n - 1) + AT \times |X(n)|, |X(n)| > X_{p}(n - 1)\\
    (1 - RT) \times X_{p}(n - 1), |X(n)| \leq X_{p}(n - 1),
  \end{cases}
\end{equation}
где $X_{p}$ - пиковое значение $X_{peak}$, $AT$ – время атаки, $RT$ – время освобождения, $n$ – номер текущего элемента.

\item После определения значения $X_{peak}$ выполняется функция для получения коэффициента усиления $f$ по формуле
  \begin{equation}
    f(n) = min \bigg( 1; \frac{lt}{X_{peak}n} \bigg),
  \end{equation}
где $n$ – номер текущего элемента, $lt$ – пороговое значение.

\item После вычисления коэффициента усиления используется сглаживающий фильтр для предотвращения слишком резких изменений усиления. Для его реализации используется формула
\begin{equation}
  cfc = \begin{cases}
    AT, f(n) < f(n-1)\\
    RT, f(n) \geq f(n-1),
  \end{cases}
\end{equation}
где $n$ – номер текущего элемента.

\item Далее вычисляется множитель для регулирования входного сигнала по формуле
  \begin{equation}
g(n) = (1 - cfc) \times g(n - 1) + cfc \times f(n)    
  \end{equation}
\item После получения искомого множителя входного сигнала, его значение умножается на задержанный в буфере задержки входной сигнал. Сигнал задерживается для того, чтобы компенсировалась любая задержка при вычислении множителя \cite[с. 106]{dsp:dafx}.
\end{enumerate}

Результирующая комбинированная система, схематично демонстрирующая все шаги преобразования, изображена на рисунке \hrf{pic:limiter-scheme} \cite[с. 109]{dsp:dafx}.

\begin{figure}[H]
  \captionsetup{labelsep=endash}
  \centering
  \def\svgwidth{165mm}
  \input{pics/02-dsp-03lab-limiter-scheme.pdf_tex}
  \caption{Принципиальная схема алгоритма работы ограничителя}
  \label{pic:limiter-scheme}
\end{figure}

\subsection{Алгоритм обработки сигналов}
Алгоритм реализован на основе раздела \hrf{sect:description}. Основная реализующая алгоритм функция приведена в приложении \hrf{appendix:dyn-control-func}.

На вход алгоритма принимается массив с отсчетами. Пороговое значение задаётся константой \code{LT} в теле функции.

\subsubsection{Основная программа \code{main}}
Функция \code{main} вызывается при запуске программы и реализует следующие шаги: 
\begin{enumerate}[label=\arabic*),ref=\arabic*]
\item Инициализация кодека;
\item Чтение из кодека текущего отсчета сигнала;
\item Получение выходного отсчета сигнала;
\item Переход на шаг 2.
\end{enumerate}

\subsubsection{Функция ограничителя \code{dynDiaCtrl}}
Функция ограничителя получает в качестве аргумента текуший отсчет \code{х} и возвращает его модифицированное значение \code{у}. Функция реализует следующие шаги алгоритма.
\begin{enumerate}[label=\arabic*),ref=\arabic*]
\item Получение модуля входного значения;
\item Определение коэффициента для вычисления уровня;
\item Вычисление уровня; 
\item Определение коэффициента усиления;
\item Определение коэффициента для вычисления управляющего коэффициента; 
\item Запись выходного отсчета; 
\item Возврат из функции.
\end{enumerate}
Функция использует математические функции из стандартной библиотеки для корректной работы с числами в формате с фиксированной запятой.

\section{Выводы}
В результате выполнения домашнего задания изучен звуковой эффект «Контроллер динамического диапазона», на примере ограничителя, для которого разработан и описан реализующий его алгоритм.
\nocite{gost:texts}

\newpage
\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1]

\newpage
\begin{appendices}
  \renewcommand{\thesubsection}{\Asbuk{subsection}}
  \subsection{Функция контроллера динамического диапазона}
  \label{appendix:dyn-control-func}
  \begin{lstlisting}[language=C,style=CCodeStyle]
volatile Int16 xpeak = 0;
volatile Int16 g = 1;
void dynDiaCtrl(Int16 *x, Int16 *y, Int16 nx) {
    const Int16 at_cfc = 9830;
    const Int16 rt_cfc = 328;

    int i;
    for (i = 0; i < nx; i++) {
        // step 1
        Int16 a = abs(x[i]);
        xpeak = (a > xpeak)
            ? (_smpy((32767 - at_cfc), xpeak) + _smpy(at_cfc, a))
            : _smpy((32767 - rt_cfc), xpeak);

        // step 2    
        Int16 cmp = LT / xpeak;
        Int16 f = (cmp < 1) ? cmp : 1;
        // step 3
        Int16 cfc = (f < g) ? at_cfc : rt_cfc;
        // step 4
        g = _smpy((1 - cfc), g) + _smpy(cfc, f);
        y[i] = _smpy(g, x[i]);
    }
  \end{lstlisting}
\end{appendices}

\end{document}

