DC removal

Jun 12, 2020 03:24



Предыдущий раз речь шла про оцифровку звукового сигнала в измерителе уровня. Оцифровка работает, массивы успешно заполняются. Реализовать это на STM32 стоило немалых трудов. Справедливости ради надо сказать, что STM32 сложен лишь в части программирования периферии. Когда это сделано, начинается обычное программирование, как и любого другого контроллера. Тут даже легче, потому что его высокая скорость и разрядность позволяют более вольно обходиться с алгоритмами.

Измерители уровня аудиосигнала часто строят примитивным способом, когда контроллер оцифровывает готовое постоянное напряжение. Входной сигнал в таком случае выпрямляется аппаратным детектором. Такой способ очень прост в реализации, но имеет ряд существенных недостатков. Поскольку детектор аппаратный, невозможно менять его тип и характеристики. Детектор только один, не получится сделать комбинированный измеритель (например, средний + пиковый уровень). Для детектирования малых сигналов диодный детектор не подходит по причине плохой линейности, приходится делать активный детектор на ОУ. При этом напряжение смещения ОУ ограничивает динамический диапазон детектора, и ничего с этим не поделать. При цифровой реализации процесс детектирования не вносит ошибки по постоянному напряжению. Поэтому достаточно удалить постоянную составляющую переменного входного сигнала. Чем и предстоит сейчас заняться.



Аналоговая часть измерителя уровня сведена к минимуму. Имеется лишь буферный усилитель на ОУ, который включен по схеме дифференциального усилителя.



Он сразу решает две задачи. Во-первых, он позволяет сдвинуть выходной сигнал на половину шкалы АЦП. Это необходимо по той причине, что встроенный в микроконтроллер АЦП является однополярным, его входной диапазон составляет от 0 до 3.3 В (до напряжения питания VDDA, которое является одновременно опорным напряжением). Сдвиг осуществляется на половину этого напряжения, т.е. на 1.65 В, что задается делителями R154R155 и R156R157. Раздельные делители использованы для предотвращения связи между каналами, ведь резисторный делитель - далеко не идеальный источник напряжения.



Во-вторых, он позволяет снять входной сигнал дифференциально. Измеритель уровня представляет собой в основном цифровое устройство и питается от «цифрового» источника питания +5 В. Потребляемый ток может быть весьма значительным (это суммарный ток питания светодиодов), причем он может меняться во время работы. В результате на подводящих питание проводах будет заметное падение напряжения. В том числе, и на проводе земли. Потенциал земли измерителя уровня может прыгать относительно аналоговой земли магнитофона. Если использовать обычный входной усилитель, то падение на земляном проводнике будет приложено к его входу. С дифференциальным усилителем такой проблемы нет. Несмотря на то, что источник сигнала здесь не дифференциальный, а обычный single ended, второй вход диффусилителя можно подключить к аналоговой земле. Так можно устранить влияние колебаний потенциала земли измерителя. Если же измеритель уровня делать в виде отдельного устройства, то можно реализовать балансные входы с разъемами XLR, как это принято в профессиональной аудиотехнике. На графике видно, что в звуковом диапазоне подавление синфазной помехи лучше 50 дБ, хотя в реальности оно буден немного хуже из-за разброса номиналов резисторов.



Лучше было бы применить интегральный диффусилитель (инструментальный усилитель, а в аудио его можно назвать вокально-инструментальным). Например, типа AD627. Но я не хочу усложнять жизнь радиолюбителям, применяя редкие и дорогие детали.

Обычно принято описывать удачные решения. Но в моем журнале чаще описаны неудачи, как оно и бывает в реальной жизни. С этой схемой тоже не все хорошо. Разделительные емкости на входе лучше было бы включить иначе. При разработке схемы я не подумал о таком важном параметре, как время выхода на рабочий режим. Емкости при работе здесь заряжены примерно до напряжения делителя (1.65 В). Но ток их зарядки проходит через довольно высокоомные резисторы обратной связи 100 кОм, хотя для полезного сигнала эти емкости образуют фильтр совместно с резисторами 10 кОм. Поэтому процесс зарядки растягивается на несколько секунд. В данном случае это не так страшно, потому что фактически усилитель начинает нормально работать через 0.2 - 0.3 сек. Для нормальной работы достаточно, чтобы напряжение на входах ОУ попало в допустимый диапазон. Но еще некоторое время синфазное напряжение на входах ОУ продолжает устанавливаться.



Плата уже изготовлена, вносить изменения поздно. Да я и не знаю, как именно можно изменить эту схему. Как вариант, можно просто уменьшить емкость разделительных конденсаторов C8 - C11, так как частота среза получилась излишне низкой, на частоте 20 Гц ослабление меньше 0.1 дБ. Применять тут керамические конденсаторы нежелательно из-за микрофонного эффекта, а танталовые у меня есть только на 4.7 мкФ, поэтому оставлю, как есть.



На вход АЦП поступает сигнал, сдвинутый примерно на 1.65 В. Примерно - потому что резисторы делителя имеют некоторый разброс. Постоянная составляющая входного сигнала отсекается разделительными емкостями, остается лишь погрешность напряжения сдвига и напряжение смещения ОУ. Хоть это и небольшие величины, но их все равно надо устранять, иначе динамический диапазон на выходе детектора будет ограничен снизу. например, даже 10 мВ напряжения смещения ограничит диапазон величиной порядка 40 дБ, что очень плохо.

Устранение постоянной составляющей в массиве данных АЦП является распространенной задачей, где ведется цифровая обработка сигналов. Простейшим фильтром, который подавляет постоянную составляющую, является дифференциатор. Он имеет один нуль на нулевой частоте. Коэффициент передачи для постоянного тока равен нулю (что и требуется), а с повышением частоты коэффициент передачи растет. Для дискретной реализации дифференциатора его разностное уравнение имеет следующий вид:

y(n) = x(n) - x(n-1)

Фактически, это простейший FIR-фильтр. При реализации надо учесть, что выходное значение должно иметь разрядность по крайней мере на 1 бит больше, чем входное. Так как входной сигнал в теории за один такт может поменяться на всю шкалу.

Схематически АЧХ дифференциатора показана на рисунке ниже (рис. A). Такой ход АЧХ не устраивает, так как в рабочем диапазоне частот коэффициент передачи будет меняться. Нам же надо получить линейную АЧХ, и только ниже некоторой частоты среза надо иметь спад. Очевидно, что для этого требуется добавить полюс на желаемой частоте среза. Сделать это можно последовательным соединением дифференциатора и звена ФНЧ 1-го порядка (его АЧХ показана на рис. B). Совместная АЧХ будет иметь нужный вид (рис. C).



Такое звено ФНЧ 1-го порядка в подобных применениях часто называют «интегратор с утечкой» (leaky integrator). Потому что в аналоговом варианте такой интегратор реализуется добавлением резистора параллельно емкости, через который она будет медленно разряжаться. Для дискретной реализации разностное уравнение идеального интегратора приведено ниже:

y(n) = y(n-1) + x(n)

Чтобы ввести утечку, надо накопленное значение умножить на некоторый коэффициент меньше единицы:

y(n) = A*y(n-1) + x(n), 0 < A < 1

Это простейший IIR-фильтр нижних частот, так его тоже можно называть. Название «интегратор с утечкой» применяют для подчеркивания того, что этот фильтр применяется несколько необычным образом - рабочая полоса частот лежит в полосе заграждения. Обычно ФНЧ применяют по-другому, в качестве рабочей используют полосу пропускания. Но это лишь особенности терминологии, которые сути не меняют.

Частота среза здесь должна быть выбрана низкой по сравнению с частотой дискретизации, а это означает, что коэффициент A должен быть близким к единице. Частоту среза можно вычислить по формуле:

f = (1 - A)*Fs/2*pi, или A = 1 - 2*pi*f/Fs, где Fs - частота дискретизации.

Общее разностное уравнение для фильтра будет иметь следующий вид:

y(n) = x(n) - x(n-1) + A*y(n-1)

Фактически это IIR-фильтр верхних частот первого порядка. Он эквивалентен дифференцирующей RC-цепочке.

Такой фильтр имеет один нуль и один полюс. Если изобразить их на z-плоскости, то нуль будет лежать в точке z = 1, а чуть левее его на оси будет лежать полюс.



Звуковая полоса частот начинается с 20 Гц. Но частоту среза желательно сделать ниже, чтобы в звуковой полосе не появлялся заметный фазовый сдвиг. Данный фильтр не является фазо-линейным, поэтому составляющие сигнала разных частот будут задержаны на разное время, результат их сложения даст другую форму, пиковый уровень сигнала будет искажен. Существуют фазо-линейные FIR-фильтры верхних частот, но для получения хорошей линейности АЧХ в полосе пропускания при низкой частоте среза они требуют очень много вычислительных ресурсов. Есть вариант фильтра для удаления постоянной составляющей на основе MAF (moving average filter). Вычислительных ресурсов он тратит не очень много, но для получения высокого отношения частоты дискретизации к частоте среза требуется большой расход памяти.

В данном случае требования к фильтру не очень жесткие. Надо удалять постоянное напряжение смещения, которое может меняться только очень медленно (например, из-за температурного дрейфа ОУ). Значительная часть компенсируемого смещения вообще постоянная, так как связана с погрешностью делителя. Поэтому можно просто сделать частоту среза пониже, минимизировав при этом сдвиг фазы. Подходящим выбором будет частота среза около 5 Гц. Совместная АЧХ входного буфера и буфера плюс ФВЧ с частотой среза 5 Гц показана на графике ниже.



Сдвиг фазы на частоте 20 Гц составляет около 17 градусов, что можно считать вполне приемлемым. На более детальном графике ниже показана ФЧХ (вверху) и АЧХ (внизу) в диапазоне частот 20 Гц - 2 кГц.



Результат вполне удовлетворяет, можно обойтись таким простейшим фильтром. Осталось его реализовать. Если использовать плавающую арифметику, то вообще никаких проблем не возникает. Но при реализации фильтра в целочисленной арифметике имеется ряд проблем. Необходимо следить за диапазонами чисел на всех этапах вычислений, чтобы не возникло переполнение. Дифференциатор и интегратор с утечкой можно соединять в любой последовательности. Но чтобы избежать переполнения, первым следует включать дифференциатор.

Еще одна проблема, более коварная, связана с ошибками округления. Для частоты среза фильтра 5 Гц при частоте дискретизации 96 кГц значение коэффициента A = 0.999673. Чтобы провести вычисления с таким коэффициентом с хорошей точностью, требуется переходить к повышенной разрядности. Обратный переход будет представлять собой квантование с более крупным шагом, что приводит к появлению ошибки, или шума квантования. В результате действия такой ошибки в фильтре на выходе может появиться паразитная постоянная составляющая, которая даже больше той, которую мы подавляем. Такая ошибка может сделать фильтр неработоспособным. Как показала практическая проверка, без коррекции ошибки квантования фильтр на самом деле не работает.

У нас АЦП 12-разрядный, входные и выходные отсчеты с запасом помещаются в 16-разрядные целые числа со знаком. Запас тут необходим для защиты от переполнения. Умножение будет делаться в 32-разрядной сетке. Тогда при переходе от 32-разрядного промежуточного результата к 16-разрядному будет возникать ошибка квантования. В одной из публикаций предлагается дополнить фильтр формирователем спектра шума квантования путем ведения обратной связи по ошибке (заглавный рисунок поста).

При внешне пугающей форме реализация этого метода оказывается очень простой. Я сделал свою реализацию, которая использует тот же принцип коррекции ошибки.

static const double POLE = 0.999673;
static const int32_t A = (int32_t)(UINT16_MAX * POLE);
static int32_t acc = 0;
static int16_t xx = 0;
static int16_t yy = 0;

x = Input;
acc = LO_W(acc) + A * yy;
yy = x - xx + HI_W(acc);
xx = x;
Output = yy;

Квантование происходит путем отбрасывания младшей половины 32-разрядного числа. Отброшенное значение - это ошибка квантования. Исходное число знаковое, но ошибка всегда имеет положительные значения. Например, если у положительного числа младшие разряды заменить нулями, число уменьшится, для коррекции ошибки надо будет добавить некоторое положительное число. Если у отрицательного числа младшие разряды заменить нулями, число станет по модулю большим, оставаясь отрицательным. Это означает, что для коррекции ошибки снова надо будет добавить некоторое положительное число. Поэтому ошибку можно извлечь из исходного 32-разрядного числа, просто обнулив старшую его половину вместе со знаковым разрядом.

Для проверки цифровой обработки сигнала очень удобно использовать ЦАП, тогда осциллографом можно посмотреть, что там на самом деле происходит с сигналом. Выводить отсчеты в ЦАП надо с тем же темпом, с которым работает АЦП. Моя структура с заполнением буфера с помощью DMA и последующей обработкой для отладки не годится. Пришлось временно это все убрать и организовать прерывание от таймера, который раньше запускал DMA. Теперь вместо запуска DMA выполняется обработчик прерывания, в котором читаю АЦП, обрабатываю данные и вывожу в ЦАП.

Первым делом проверил связку АЦП-ЦАП с прямым выводом в ЦАП кодов АЦП. На вход подал смещение на половину шкалы АЦП и сигнал с выхода генератора. Вот так выглядит сигнал 5 кГц на выходе ЦАП:



Для проверки нашего фильтра надо подать на вход что-то более низкочастотное, так как ФВЧ с частотой среза 5 Гц на сигнал 5 кГц влияния оказывать практически не будет. Для наглядности я подал на вход меандр частотой 20 Гц. Вот так он выглядит на выходе ЦАП без фильтра:



Если теперь включить в тракт фильтр, картина получается такая:



Типичная форма сигнала для дифференцирующей RC-цепочки. Чтобы убедиться в правильности работы фильтра, надо бы сравнить форму с полученной на модели. Тут бы помог MATLAB, но, увы, я им не владею. Выручает то, что данный фильтр имеет свой аналоговый прототип. А его можно смоделировать в PSpice. Результат получил идентичный:



Если кручу подстроечник смещения на входе АЦП, нулевая линия на мгновение уходит, затем снова возвращается на место. Все работает как положено. Чтобы считать этот фильтр, процессор тратит 1.4 мкс своего времени. Вот так в цифре реализуется RC-цепочка.

программирование, reel-to-reel, electronics, stm32, магнитофон, катушечник, микроконтроллер, Электроника-004

Previous post Next post
Up