BMSTU/02-dspmd-03-lab-report.tex

264 lines
17 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[a4paper,fontsize=14bp]{article}
\input{../common-preamble}
\input{../bmstu-preamble}
\input{../fancy-listings-preamble}
\numerationTop
\begin{document}
\thispagestyle{empty}
\makeBMSTUHeader
% ... работе, номер, тема, предмет, ?а, кто
\makeReportTitle{лабораторной}{3}{Звуковой эффект}{Микропроцессорные устройства обработки сигналов}{}{А.И. Германчук}
\newpage
\thispagestyle{empty}
\tableofcontents
\newpage
\pagestyle{fancy}
\section{Цель}
Целью работы является разработка и исследование программы обработки сигналов на языке программирования Си, реализующей звуковой эффект, определенный в индивидуальном задании (контроллер динамического диапазона, ограничитель).
\section{Описание звукового эффекта}
Контроллер динамического диапазона - это адаптивная регулировка динамического диапазона сигнала. Динамический диапазон - это соотношение между наибольшими и наименьшими значениями, которые может принять определенная величина. Существует несколько типов контроллеров. В данной лабораторной работе будет рассматриваться ограничитель. Назначение ограничителя состоит в том, чтобы обеспечить контроль над самыми высокими пиками сигнала, но при этом, как можно меньше изменять динамику сигнала. Это достигается за счёт использования характеристической кривой с бесконечным отношением \cite[с. 109]{dsp:dafx}. Ограничитель динамического диапазона подавляет громкость звуков, пересекающих заданный порог (рисунок \hrf{pic:limiter}).
\begin{figure}[H]
\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]
\centering
\def\svgwidth{170mm}
\input{pics/02-dsp-03lab-limiter-explain.pdf_tex}
\caption{Иллюстрация влияния времени атаки и освобождения}
\label{pic:limiter-explain}
\end{figure}
Ограничитель обычно используется для того, чтобы «поймать» самые громкие моменты источника, уменьшив их таким образом, чтобы защитить от нежелательных искажений и сохранить целостность общего баланса звука.
\section{Математическое описание ограничителя}
\label{sect:description}
Динамическая обработка выполняется усилительными устройствами, где коэффициент усиления автоматически регулируется уровнем входного сигнала. Динамическая обработка проходит в несколько этапов.
\begin{enumerate}
\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}
где
\begin{itemize}
\item [] $X_{p}$ - пиковое значение $X_{peak}$;
\item [] $AT$ время атаки;
\item [] $RT$ время освобождения;
\item [] $n$ номер текущего элемента.
\end{itemize}
\item После определения значения $X_{peak}$ выполняется функция для получения коэффициента усиления $f$ по формуле
\begin{equation}
f(n) = min \bigg( 1; \frac{lt}{X_{peak}n} \bigg),
\end{equation}
где
\begin{itemize}
\item [] $n$ номер текущего элемента;
\item [] $lt$ пороговое значение.
\end{itemize}
\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]
\centering
\def\svgwidth{165mm}
\input{pics/02-dsp-03lab-limiter-scheme.pdf_tex}
\caption{Принципиальная схема алгоритма работы ограничителя}
\label{pic:limiter-scheme}
\end{figure}
\section{Алгоритм обработки сигналов}
Алгоритм реализован на основе раздела \hrf{sect:description}. В реализации алгоритма учитывается средняя частота дискретизации современных аудиофайлов 44,1 КГц. Алгоритм буферизует отсчёты на 6 миллисекунд, то есть если 44 отсчета - это одна милисекунда, то величина буфера должна быть $44 * 6 = 264$ отсчётов.
На вход алгоритма, вычисляющего значение коэффициента, принимается единичный отсчёт. Пороговое значение задаётся константой \code{LT} в теле функции.
\subsection{Основная программа \code{main}}
Функция \code{main} вызывается при запуске программы и реализует следующие шаги:
\begin{enumerate}
\item инициализация кодека;
\item чтение из кодека текущего отсчета сигнала по прерыванию от интерфейса I2S \code{x}, \code{x = I2S2_W0_MSW_R};
\item вычисление и корректировка коэффициента g и сохранение текущего отсчёта в буфер;
\item получение выходного отсчета сигнала \code{y}, путём умножения буферизованного отсчёта на вычисленный на текущем шаге коэффициент \code{_smpy(g, leftBuffer[qRead++]};
\item смещение флагов чтения и записи данных в буфер, ожидание готовности контроллера прерываний;
\item запись значений обоих каналов обратно в контроллер I2S;
\item переход на шаг 2.
\end{enumerate}
\subsection{Функция ограничителя}
Фактически, функция ограничителя разделена на две части:
\begin{enumerate}
\item приём отсчёта, буферизация и вычисление коэффициента ограничителя;
\item чтение из очереди и умножение буферизованного отсчёта на коэффициент.
\end{enumerate}
Функция расчёта коэффициента реализует следующие шаги алгоритма:
\begin{enumerate}
\item получение входного значения \code{x};
\item получение модуля отсчёта;
\item определение коэффициента \code{cfc} для вычисления уровня;
\item вычисление уровня \code{xpeak}, \code{xpeak = (1 - cfc) * xpeak + coeff * x};
\item определение коэффициента усиления \code{f}, \code{f = min(1, LT / xpeak)};
\item определение коэффициента \code{cfc} для вычисления управляющего коэффициента \code{g = (1 - cfc) * g + cfc * f};
\item возврат коэффициента \code{g} из функции.
\end{enumerate}
Код, вызывающий функцию, кроме буферизации прочитанного значения (\code{leftBuffer[qWrite++] = left;}) осуществляет умножение ранее буферизованного отсчёта на текущее скорректированное значение коэффициента фильтра \code{out_left = _smpy(g, leftBuffer[qRead++])} и запись выходного отсчета на шину контроллера I2S \code{I2S2_W0_MSW_W = out_left;}
\section{Выводы}
В результате выполнения работы была разработана программа обработки сигнала на языке программирования Си, реализующая звуковой эффект - контроллер динамического диапазона, а именно, ограничитель. В ходе работы были получены графики входных и выходных отсчетов и по ним исследован результат применения звукового эффекта на входной сигнал.
\nocite{gost:texts}
\newpage
\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1]
\newpage
\appendix
\section*{Приложения}
\addcontentsline{toc}{section}{Приложения}
\renewcommand{\thesubsection}{\Alph{subsection}}
\subsection{Полные листинги программ}
\label{appendix:fulls}
\begin{lstlisting}[language=C,style=CCodeStyle,caption={Функция вычисления коэффициента ограничителя}, label=code:prog-coeff]
Int16 oneCountCoefficient(Int16 x) {
const Int16 LT = 28576;
Int16 at_cfc = 9830;
Int16 rt_cfc = 328;
Int16 a = abs(x); // <@\lh{dkgreen}{модуль значения текущего отсчёта}@>
Int16 cmp;
xpeak = (a > xpeak) // <@\lh{dkgreen}{коэффициент x пиковое}@>
? (_smpy((32767 - at_cfc), xpeak) + _smpy(at_cfc, a))
: _smpy((32767 - rt_cfc), xpeak);
if (abs(LT) > abs(xpeak)) // <@\lh{dkgreen}{коэффициент cmp}@>
cmp = (Int16)(((Int32) LT << 15) / ((Int32) xpeak));
Int16 f = (cmp < 32767) ? cmp : 32767;
Int16 cfc = (f < g) ? at_cfc : rt_cfc; // <@\lh{dkgreen}{коэффициент cfc}@>
// <@\lh{dkgreen}{возврат вычисленного коэффициента g}@>
return _smpy((32767 - cfc), g) + _smpy(cfc, f);
}
\end{lstlisting}
\begin{lstlisting}[language=C,style=CCodeStyle,caption={Полный листинг программы на языке С}, label=code:prog-c]
// DSP, board libraries
#include "C5515.h"
#include "gpio.h"
#include "i2c.h"
#include "i2s.h"
#include "stdio.h"
// <@\lh{dkgreen}{заголовок с функцией oneCountCoefficient}@>
#include "mylimiter.h"
#define AIC3204_I2C_ADDR 0x18
#define Rcv 0x08
#define Xmit 0x20
extern Int16 aic3204_stereo_in1();
volatile Int16 xpeak = 1;
volatile Int16 g = 1;
Int16 oneCountCoefficient(Int16 x);
void main(void) {
// <@\lh{dkgreen}{инициализация}@>
c5515_init();
// <@\lh{dkgreen}{конфигурирование параллельного порта}@>
SYS_EXBUSSEL &= ~0x7000;
SYS_EXBUSSEL |= 0x1000;
// <@\lh{dkgreen}{конфигурирование последовательного порта}@>
SYS_EXBUSSEL &= ~0x0C00;
SYS_EXBUSSEL |= 0x0400;
c5515_GPIO_init();
c5515_GPIO_setDirection(GPIO10, GPIO_OUT);
c5515_GPIO_setOutput(GPIO10, 1); // <@\lh{dkgreen}{вывод AIC3201 из reset}@>
I2C_init(); // <@\lh{dkgreen}{инициализация I2C}@>
// <@\lh{dkgreen}{I2S настройки}@>
I2S2_SRGR = 0x0015;
I2S2_ICMR = 0x0028;
I2S2_CR = 0x8012;
// Режим стерео входа
aic3204_stereo_in1();
#define BUF_LENGTH 264
Int16 left, right; // <@\lh{dkgreen}{отсчеты до примененого эффекта}@>
Int16 out_left = 0; // <@\lh{dkgreen}{отсчеты после примененого эффекта}@>
Int16 leftBuffer[BUF_LENGTH]; // <@\lh{dkgreen}{буфер}@>
Int16 qWrite = 0;
Int16 qRead = -255;
while(1){
// <@\lh{dkgreen}{Ожидание прерывания по получению отсчёта}@>
while ((Rcv & I2S2_IR) == 0);
left = I2S2_W0_MSW_R; // <@\lh{dkgreen}{16-битное значение левого канала}@>
right = I2S2_W1_MSW_R; // <@\lh{dkgreen}{16-битное значение правого канала}@>
g = oneCountCoefficient(left); // <@\lh{dkgreen}{текущий коэффициент}@>
leftBuffer[qWrite++] = left; // <@\lh{dkgreen}{буферизация отсчёта}@>
if (qWrite == BUF_LENGTH)
qWrite = 0; // <@\lh{dkgreen}{не дать флагу записи переполниться}@>
if (qRead >= 0) {
// <@\lh{dkgreen}{прочитать из буфера и умножить на коэффициент}@>
out_left = _smpy(g, leftBuffer[qRead++]);
if (qRead == BUF_LENGTH)
qRead = 0; // <@\lh{dkgreen}{не дать флагу чтения переполниться}@>
} else {
++qRead;
}
while ((Xmit & I2S2_IR) == 0); // <@\lh{dkgreen}{Ждём контроллер прерывания}@>
// <@\lh{dkgreen}{записать изменённое}@>
I2S2_W0_MSW_W = out_left;
// <@\lh{dkgreen}{записать не изменённое}@>
I2S2_W1_MSW_W = right;
}
}
\end{lstlisting}
\end{document}