Друзья, привет!
На прошлой неделе меня постигло глубокое разочарование! Оказалось, что недорогие китайские микроконтроллеры на архитектуре RISC-V, серии CH32V003, на которые я возлагал большие ожидания, не поддерживают аппаратного умножения! Кто бы мог подумать! Это провал!
Нет, конечно в сравнении с ATTiny13 наш китаец выше на голову как по скорости, так и по возможностям, но мне, по наивности, даже в голову придти не могло, что 32-разрядный микроконтроллер может не иметь аппаратной поддержки умножения. Зачем тогда вообще нужно 32 бита?!
В спецификации CH32V003 прямо на первой странице присутствует неприметная фраза. Вот так она выглядит.
Обратите внимание, на аббревиатуру RV32EC. Здесь RV32E обозначает базовый набор инструкций для встраиваемых систем. Это значит, что во-первых, количество доступных регистров микроконтроллера урезано в 2 раза (доступно только 16 регистров вместо 32-х), а во-вторых, отсутствует аппаратная поддержка операций умножения. Символ "C", следующий далее означает поддержку сжатых инструкций, кодируемых 16-ю битами вместо 32-х, что позволяет более рационально использовать память.
Целочисленное аппаратное умножение поддерживается, например, в серии контроллеров CH32V203. Тоже недорогие контроллеры, но, к сожалению, 8-пиновых корпусов, так мною любимых, в серии нет! Минимум 20-пиновые. А вот, например серия CH32V303 поддерживает даже аппаратное умножение с плавающей точкой. Но там уже серьезные чипы, с большим объемом памяти и высокими тактовыми частотами...
А почему я было приуныл? Да потому, что очень хотел попробовать алгоритмы цифровой обработки сигналов на этих малышах. Например, фильтрацию. 32 разряда меня очень вдохновляли! Но для таких вещей умножение обязательно! Хотя... А почему не принять этот вызов, и не попробовать выжать все возможные соки из микроконтроллера, к которому я уже, по правде, успел привязаться!
Решено! Будем пробовать создавать цифровой фильтр для речевого сигнала. Например для SSB-приемника или передатчика. И создавать его будем на микроконтроллере CH32V003, начисто лишенного аппаратной поддержки умножения.
Основы цифровой фильтрации
Во избежание мозговых спазмов моих дорогих читателей я не буду глубоко залезать в теоретические дебри цифровой фильтрации. Приведу лишь минимально необходимые сведения.
Итак, из всех возможных методов цифровой фильтрации я остановился на программной реализации фильтра с конечной импульсной характеристикой (КИХ-фильтр, или по-английски FIR-filter - finite impulse response). Главное достоинство таких фильтров - их крайняя устойчивость. Это вполне объяснимо - фильтр не содержит петель обратной связи. Благодаря этому КИХ-фильтры не накапливают ошибок, связанных с погрешностью вычислений. Этот факт для нас очень важен. Почему - будет понятно чуть позже.
Структура цифрового КИХ-фильтра может быть представлена в следующем виде.
Слева на вход фильтра поступает последовательность отсчетов входного сигнала X. Пусть, например с АЦП. Блоки с символом Z-1 внутри обозначают задержку на один отсчет. Так, если текущий отсчет имеет номер Xn, то предыдущий будет Xn-1. С программной точки зрения входной сигнал удобно представлять в виде одномерного массива-очереди, длиной N последовательных отсчетов входного сигнала. Слева хвост очереди, справа - голова. При поступлении очередного отсчета на вход фильтра последовательность сдвигается вправо. Отсчеты сигнала умножаются на коэффициенты импульсной характеристики фильтра - A0...AN. Результаты перемножения складываются, образуя отсчет выходного сигнала - Yn.
Таким образом, для получения текущего отсчета выходного сигнала нужно произвести N+1 операций умножения и N операций суммирования.
С суммированием-то проблем, естественно, не будет, а вот с умножением... Ведь N+1 операция умножения должна быть выполнена каждый отсчет входного сигнала. А число таких операций напрямую зависит от качества фильтрации. Чем лучше фильтрующая способность фильтра, тем большее количество коэффициентов содержит его импульсная характеристика. Но, об этом чуть позже.
Самым страшным врагом цифрового фильтра является алиасинг. Это негативное явление присущее аналого-цифровым преобразователям. Его суть в переносе высокочастотных колебаний в низкочастотную область. Общеизвестно, что для более-менее точного представления сигнала частота его верхней спектральной границы не должна превышать половину частоты дискретизации. Но что будет, если на АЦП попадет более высокочастотный сигнал? Попробую наглядно проиллюстрировать суть происходящих при этом процессов.
На вход АЦП поступает сигнал (черный цвет), частота которого превышает частоту дискретизации (зеленые отсчеты). Результат оцифровки - низкочастотное колебание! Для снижения влияния высокочастотных колебаний на входе АЦП следует устанавливать специальные антиалиасинговые фильтры, подавляющие высокие частоты входного сигнала. Стоп! Но мы же для этого и делаем фильтр! Что, еще один нужен? Да, но не такой качественный, как проектируемый нами. Для наглядности представим происходящее в частотной области.
Несмотря на то, что спектр колебаний звуковых волн заканчивается на 15...16 кГц (кто как слышит), это не значит, что дальше ничего нет! Есть и шумы и помехи и гармоники. А если, например говорить о радиоприеме, то при детектировании в область звуковых частот может переносится значительный участок высокочастотных колебаний. Например, если речь идет о любительских КВ-диапазонах, то в полосу переносимых частот может спокойно попасть больше десятка радиостанций (ширина полосы частот SSB-сигнала - около 3 кГц). Но нас интересует только одна, находящаяся на частоте настройки. Представьте, что мы хотим отфильтровать ее сигнал при помощи высокодобротного цифрового фильтра с амплитудно-частотной характеристикой (АЧХ) как на рисунке выше (АЧХ цифрового фильтра). В начале мы должны сигнал оцифровать при помощи АЦП, работающего с частотой дискретизации Fд. Зная о явлении алиасинга мы можем представить, что в область низких частот попадут и отзеркаленные области, расположенные рядом с частотой Fд, а также 2Fд, 3Fд... Получится мешанина, в которой будет сложно что-то разобрать!
Получается, что на вход АЦП мы должны подавать предварительно отфильтрованный сигнал, в котором частоты выше Fд-Fв не будут оцифрованы. Идеальный антиалиасинговый фильтр вообще не должен пропускать частоты выше чем Fd/2, но для нашего случая достаточно, чтобы выполнялось условие:
Fа < Fд-Fв,
поскольку частоты перенесенные частоты между Fд/2 и Fа, будут отфильтрованы уже самим цифровым фильтром.
Поскольку нам не хотелось бы делать антиалиасинговый фильтр слишком сложным (в идеале вообще обойтись бы RC-цепочкой), а обеспечить хорошее подавление на частоте Fа нужно, то неплохо было бы увеличить частоту дискретизации. Если сделать ее достаточно большой, то даже пологий спад RC-цепи обеспечит нужное подавление. Но тут другая беда. Точнее две.
Во-первых, помните алгоритм цифровой фильтрации? На каждый отсчет сигнала нужно делать множество умножений. Может быть десятки и сотни! Значит требования к вычислительным мощностям микроконтроллера резко возрастают. А во-вторых, Чем больше частота дискретизации тем более длинной должна быть импульсная характеристика, а значит тем больше умножений потребуется. Тут так: при увеличении частоты дискретизации вдвое, число умножений в единицу времени возрастает вчетверо! Я напомню - наш микроконтроллер CH32V003 вообще не поддерживает аппаратные умножения. Это еще вопрос - что мы с него сможем получить!
Значит, частоту дискретизации нужно снижать. Но, тогда возрастают требования к антиалиасинговому фильтру. Его тоже не хотелось бы делать слишком сложным для получения передаточной характеристики близкой к прямоугольной. Кстати, у таких характеристик есть своя неприятность - время групповой задержки для различных частот может сильно отличаться, внося искажения в сигнал.
Опускаю дальнейшие рассуждения. Сразу покажу результат моих раздумий, расчетов и экспериментов. Я остановился на следующих параметрах:
- Частота дискретизации 15625 Гц. Это компромиссное число, которое учитывает как коэффициент деления счетчика микроконтроллера, так и его аппаратные возможности в плане умножения.
- Антиалиасинговый фильтр Баттерворта 3-го порядка на встроенном операционном усилителе. При выбранной частоте дискретизации и Fв = 3 кГц он должен обеспечить подавление частот вблизи частоты дискретизации не хуже 60 дБ (1000 раз).
- Цифровой фильтр для фильтрации SSB-сигнала любительских коротковолновых радиостанций с Fв около 3 кГц с максимально прямоугольной характеристикой, но подавлением не ниже 40 дБ (100 раз) для частоты 4кГц.
Мечты, мечты...
Практическая реализация цифрового фильтра SSB-сигнала
Для расчетов, прикидок и последующей оптимизации я использовал несколько онлайн-программ. Ссылки не даю, поскольку открываются с VPN, но если интересно - напишите, дам в комментариях. Или на скриншоте ниже можно посмотреть.
Основная задача, которую я ставил перед собой - достижение приличных характеристик. Не хуже 50 дБ подавления на октаву. Чтобы достичь таких параметров в реале нужно очень постараться.
После первых прикидок меня устроила следующая модель.
Срез фильтра примерно на частоте 2,4 кГц. Подавление на частоте 3,5 кГц не хуже 40 дБ. Для реализации такого фильтра требуется 25 отсчетов импульсной характеристики, то есть 25 умножений.
Программа выдает коэффициенты фильтра в формате с плавающей точкой и высокой размерностью. Пришлось их масштабировать до 8-разрядного представления с учетом знака (7 плюс знак = 8).
Так, а что у нас с умножениями. Прежде всего, я выяснил - сколько умножений способен сделать микроконтроллер за время одного отсчета сигнала. Оказалось, что умножение для нашего малыша является операцией колоссальной сложности. Я то было сначала хотел использовать возможности 32-разрядной арифметики на полную, но оказалось, что перемножает 32-разрядные операнды микроконтроллер очень медленно. Тут ничего удивительного. Ведь по сути, длительность программной эмуляции умножения напрямую зависит от разрядности умножаемых чисел. Так вот, 32-разрядная арифметика в умножении оказалось неприемлемой! Пришлось остановится на минимально комфортном уровне быстродействия. Для этого, представление отсчетов сигнала и импульсной характеристики (ИХ) фильтра выбрано 8-битным. Этого, в принципе, достаточно для воспроизведения звука с приемлемым качеством, но страдает динамический диапазон. Возможно, потребуется в будущем сделать программный компрессор 10-битного отсчета в 8-битное представление для снижения потерь динамического диапазона. Но это потом.
Кроме того, оказалось, что на быстродействие умножения влияет последовательность сомножителей. Это также вполне объяснимо, поскольку умножение заменяется последовательностью сдвигов и сложений. Число сдвигов и сложений будет разным в зависимости от того, какой сомножитель взять для организации цикла. Например нужно перемножить два числа: 5 и 10. Двоичное представление 5 - 101, а 10 - 1010. Если цикл образуется 5-кой, то потребуется 3 сдвига и 2 сложения, а если 10-кой, то 4 сдвига и тоже два сложения. В результате оказалось, что нужно в качестве первого сомножителя выбирать тот, который в среднем больше, а второй, который меньше. В нашем случае в среднем больше отсчеты сигнала, чем отсчеты импульсной характеристики.
Еще один фактор. Эмуляция умножения не терпит отрицательных чисел! В них все разряды значимые! Значит, умножать нужно положительные числа, а знак добавлять только при накоплении суммы. Выручает тот факт, что отсчеты сигнала все положительные. А знак импульсной характеристики можно хранить в отдельном двоичном числе, используя его по мере формирования суммы. Но если знак хранится отдельно, то один разряд ИХ фильтра освобождается! Появляется возможность передать его сигналу! Тогда представление сигнала становится 9-разрядным! А если еще и знак сигнала хранить отдельно, то потенциально сигнал можно обрабатывать в разрядности АЦП, то есть в 10-разрядном представлении с максимально возможным динамическим диапазоном. Но это оставим на потом... Если интересно - подписывайтесь.
Все о чем было сказано я, прежде всего, попробовал смоделировать в Excel. Полученные результаты представлены на следующем скриншоте.
Как видно, модельные значения АЧХ, в целом, подтверждают расчетные показатели. Осталось проверить на практике.
Результаты испытаний цифрового фильтра
Для предварительных испытаний я не стал делать антиалиасинговый фильтр. Хотелось оценить результат как можно быстрее. С фильтром заморочимся чуть позже, когда прикрутим его к реальному приемнику.
Для испытаний я, как обычно использовал свою макетную плату с платой расширения. На вход АЦП сигнал подавался через аттенюатор с моего самодельного генератора. В качестве выхода использовался модулированный ШИМ-сигнал, подававшийся на вход компьютерной звуковой карты с частотой дискретизации 48 кГц. Вот так установка выглядела в реале.
Слева - вход, справа - выход. На красную панельку с транзистором не обращайте внимания. Она осталась с прошлого раза. Для измерения АЧХ на вход подавался как сигнал качающейся частоты, так и сигнал белого шума. Результаты были примерно одинаковыми. Вот как выглядел спектр сигнала после фильтра.
Картина вполне объяснимая. Четко видно очертания АЧХ фильтра и всплеск около 15625 Гц, связанный с присутствием модулированного ШИМ-сигнала. На практике эти частоты можно не убирать. Они находятся практически за пределом слышимости.
Конечно 40 дБ подавления на 4 кГц здесь не наблюдается (около 26...27). Но это вполне можно отнести, во-первых, на счет отсутствия входного антиалиасингового фильтра, а во-вторых, на несовершенство метода измерений, поскольку частота дискретизации аудиокарты (48 кГц) явно недостаточна для точной оценки фронтов ШИМ-сигнала, а соответствующего фильтра на выходе не установлено.
Что касается нагрузки на микроконтроллер, то я решил оценить ее устанавливая один из его выходов в 1 перед началом цикла обработки и сбрасывая после. Вот что получилось.
Как видно, загрузка составляет 84% на 25 операциях умножения (кстати, уже знаю как довести ее до 75!). Нетрудно подсчитать, что при тактовой частоте 48 МГц на одно умножение приходится около 80 тактов микроконтроллера. Много. Вот был бы встроенный блок умножения, все происходило бы в 80 раз быстрее! Вот это были бы характеристики!
В целом эксперимент можно считать успешным, а полученные характеристики обнадеживающими. Остается проверить наш фильтр в условиях приема реальных коротковолновых радиостанций совместно с антиалиасинговым фильтром. Ох, интересные эксперименты нас ждут!
Исходный код программы доступен для скачивания по ссылке.
Спасибо, что читаете-смотрите Terrabyte! Подписывайтесь, если вам интересна радиолюбительская тематика, микроконтроллеры, мини-ПК, необычные компьютерные решения и инновационные разработки! Спасибо всем, кто поддерживает меня своими комментариями и лайками!
Группа ВК: https://vk.com/terrabyte
Канал на VK-Video: https://vk.com/video/@terrabyte/all
Интересные самоделки.