Алгоритм сжатия потока данных 12-битного АЦП в микроконтроллере Cortex M0

В моем приложении микроконтроллер Cortex M0 в настоящее время отбирает сигнал АЦП с частотой 10 кГц и отправляет результат через последовательный кабель USB на компьютер.

Теперь я хочу увеличить частоту дискретизации до более чем 100 кГц и добавить второй канал.

USB-последовательный канал ограничен 1-3 Мбит/с, поэтому физически невозможно вести потоковую передачу с такой скоростью при 12-битном значении АЦП и 2 байтах, необходимых для передачи каждого семпла. Для двух каналов АЦП с частотой дискретизации 100 кГц требуемая скорость передачи данных составляет примерно 4 Мбит/с:

б я т _ р а т е "=" 2 с час × 2 б у т е с × 10 б я т с × 100 × 10 3 "=" 4 × 10 6 б п с

Я знаю, что могу уместить 2 выборки АЦП в 3 байта, но я хочу несколько сжать данные АЦП.

Какие алгоритмы сжатия подходят для работы в микроконтроллере Cortex M0?

Существуют десятки алгоритмов сжатия, но я ищу то, что может работать на платформе с ограниченными ресурсами.

просто удостовериться: вычислительные накладные расходы по-прежнему позволят вам сделать все достаточно быстро?
не много знаю о сжатии, но я думаю, что с уже двоичными данными в потоке, тем не менее, у вас будут проблемы со сжатием этих данных без потери информации значимым образом. Действительно ли необработанные 12-битные данные 100 000 раз в секунду — это то, что вам нужно? Я думаю, что это также поставит ваш компьютер на колени, если вы захотите что-то вычислить со значениями. Нет ли возможности комбинировать значения? Я предполагаю, что ваши 12-битные значения будут иметь много шума. Почему бы не сделать среднее/среднеквадратичное значение/что-то еще по нескольким выборкам данных и передать результат?
Это кора головного мозга M0 (фиксированная точка), работающая на частоте около 64 МГц. Он способен примерно на 60 DMIPS.
@jwsc Эта частота дискретизации необходима для захвата быстрых переходных процессов.
Какова пропускная способность данных при быстром переходном процессе? Будет ли у вас достаточно «тихого времени», чтобы средняя пропускная способность была меньше узкого места USB?
64 МГц для передачи 4 Мбит? 16 тактов на каждый отправленный бит? Я думаю, вам придется считать циклы каждой функции, которая у вас есть. Я не эксперт, возможно, кто-то может подтвердить, но это звучит... проблематично. Сжатие данных даже на ПК имеет видимый индикатор выполнения. Это непростая задача.
А если "прислать" только "разницу" в 1 байт? С обновлением "время от времени"?
Является ли вход полностью произвольным белым шумом или имеет ограниченное отношение dV/dt? Если последнее, можете ли вы периодически отправлять кадр и, исходя из этого, всего несколько битов на выборку, насколько увеличивается или уменьшается это значение? Подобно многим алгоритмам сжатия видео со случайными ключевыми кадрами и только между ними.
Найдите сжатие Lempel-Ziv, если вашим приложениям требуется сжатие данных без потерь. В выпуске IEEE Spectrum May 2021 есть действительно хороший исторический обзор развития этого алгоритма.

Ответы (4)

Это на самом деле аудио приложение? Не могли бы вы заменить все это выделенным аудиоинтерфейсом, который решит все эти проблемы за вас, или вам нужен точный уровень постоянного тока? Стерео 96kps вполне достижимо.

У вас не так много MIPS для работы, поэтому я собираюсь предложить следующую схему кодирования. Это технически переменный битрейт, так что лучше надеяться, что транзиенты редки. Он работает для сэмплов до 15 бит.

  • Следите за предыдущим образцом
  • Вычтите следующую выборку из предыдущей выборки, назовите результат D
  • Проверьте биты выше 7. Либо они все единицы, либо все нули, либо смесь (указывающая на переходный процесс или большой размах).
  • Для случаев со всеми единицами или всеми нулями: замаскируйте нижние 7 бит, передайте на хост.
  • Для переходного случая: передайте старший байт выборки (не D) с верхним битом, установленным в «1», затем младший байт.
  • Периодически (например, через каждые 256 выборок) все равно отправляйте всю выборку с установкой верхнего бита в 1. Это позволяет восстановиться после ошибок.

Реконструкция проста:

  • если старший бит байта равен 0, удлините оставшиеся 7 битов по знаку и добавьте их к предыдущей выборке, чтобы получить следующую выборку.
  • если старший бит равен 1, маскируйте его, читайте следующий байт и собирайте результат в слово.
Я нахожу эту идею интересной. Это не аудиоприложение, а текущее приложение для семплирования. В большинстве случаев разница между одним семплом и другим будет меньше 7 бит. Если я правильно понял ваш ответ, большинство образцов будут представлены в виде одного байта?
Да, большинство выборок будет состоять из 1 байта.
Но я повторяю предупреждение о переменном битрейте - если в пакете много переходных процессов, возможно, ссылка не будет поддерживаться. В среднем догонит. Это может иметь значение, если вы пытаетесь выполнить синхронизацию с чем-то другим.
Хорошо, это в основном вдвое уменьшает требуемую скорость передачи данных с 4 Мбит/с до 2. Переходные процессы добавят немного больше, но мне нравится эта идея, так как накладные расходы невелики.
Также очень полезно иметь явный маркер потери синхронизации/переполнения.

Есть несколько «простых» шагов, которые вы можете предпринять, чтобы уменьшить необходимую скорость передачи данных:

  1. Вам действительно нужно разрешение 12 бит? Если вы можете пожертвовать 4 младшими битами (которые могут быть только шумом), вы уменьшите требуемую полосу пропускания на 33% и одновременно сэкономите несколько операций.

  2. на какую величину сигнал «обычно» изменяется между двумя последовательными выборками. Например, если в 95% случаев разница только в 6 младших битах, вы можете отправить:

  • если разница меньше 6 бит, разница закодирована как целое число со знаком в 7 битах (с 1 как самый старший (8-й) бит) - если разница больше 6 бит, вы отправляете все новое значение в 2 байтов (так что в самом старшем байте будет 4 нуля заголовка, что упрощает идентификацию)

Наконец, одна интересная вещь, которую вы сказали в комментариях, заключается в том, что вам нужна такая высокая частота дискретизации, потому что вы хотите наблюдать переходные процессы.

Поэтому я вижу 2 решения, немного более сложных, но которые могут значительно снизить скорость передачи данных, необходимую для вашего конкретного приложения:

  1. Если вам нужны только переходные процессы: почему бы не «запустить» их? Вы сохраняете все свои измерения в скользящем буфере (используя DMA, если можете). Затем вы используете некоторые программные вычисления для определения переходного процесса (например, разницы больше, чем X, между измерениями N и N-N0). Если вы обнаружите его, вы отправляете только значения, близкие к измерению N. Если ваши переходные процессы редки, ваша требуемая скорость передачи данных становится очень низкой. NB: в этой версии вы видите ТОЛЬКО переходные процессы, а не все остальное (может соответствовать вашим потребностям или нет, если нет, см. Решение 4)

  2. Другое решение — не отправлять выборки с регулярными временными интервалами: вы по-прежнему производите выборку с частотой 100 кГц (хранится во внутреннем буфере с помощью DMA), но вы передаете только часть данных: когда данные быстро меняются, вы отправляете много данных, когда они меняется медленно, вы отправляете мало. Например :

  • скажем, последним отправленным измерением является M[N0] (измерение при выборке #N0, 12 бит)
  • давайте назовем N текущим измерением (значение = M[N]. Если N-N0 == 16, то X, где 12 младших битов X равны M[N], а 4 старших бита равны N-N0- 1 = 15 = 0b1111
  • иначе, если abs(M[N]-M[N0]) > threshold : отправлено X (2 байта), с M[N] для 12 младших значащих бит и N-N0-1 для 4 старших значащих битов (т.е. количество измерений, которые вы пропустили)
  • еще : ничего не отправлять.

Таким образом, в основном на принимающей стороне вы получаете значение в форме A[0:3].M[0:12], где A — количество пропущенных выборок (поэтому (A+1) sample_period — время, прошедшее с момента последней выборки ) , а M значение этого образца. Если ваш сигнал меняется достаточно медленно и переходные процессы редки, у вас будет среднее значение A между 14 и 15 (давайте будем консервативны и скажем 14), поэтому у вас есть средняя скорость передачи 2 канала 16 бит * 100000 Гц/15 = 213 кбит/с . s : это легко сделать на UART со скоростью 1 Мбит/с.

эй, мне нравится твоя идея обнаружения переходных процессов. Например, выборочные данные всегда с высокой скоростью, но отправляются медленнее и реже, отправляются только во время переходных процессов. Это аккуратное решение, основанное на конкретном назначении устройства. Умный.
Примечательно, что SAC ADC обычно занимает больше времени для завершения 12-битного чтения, чем 8/10-битного чтения, поэтому, если вы пожертвуете разрешением, это может автоматически означать более высокую частоту дискретизации.

Это потребует значительных вычислительных затрат, поэтому вам нужно убедиться, что вы можете сделать все вовремя. Вам придется просмотреть все данные несколько раз, это порядка O (n). Потому что вы, очевидно, не можете сделать это, не просмотрев все данные хотя бы один раз, и с ними тоже нужно что-то делать. Возможно, вы можете сэкономить время на автоматизации процедуры отправки - вы можете регулярно запускать прерывания по таймеру, а затем запускать передачу данных с помощью DMA. Это высвободит часть вычислительной мощности. Если вам это нужно, может быть, вы можете справиться с этим проще и все же сделать это. (вы даже не опубликовали MCU и частоту, на которой он работает, на момент написания этого)

У вас может быть как статический, так и динамический словарь сжатия (что чем заменяет). Если он статичен, вы можете жестко закодировать его на принимающей стороне для распаковки. Если он динамический, для его генерации потребуется больше вычислений на стороне MCU, и вам также нужно будет передать его в виде данных на принимающую сторону (ПК), потому что ему необходимо его декодировать.

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

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

Выполните обработку на ARM и отправьте обработанный результат

Вам нужна полнополосная связь с ПК только в том случае, если вы планируете, что ARM будет просто тупым USB-АЦП и всеми умными вещами, происходящими на ПК. Если вы поместите обработку на ARM, вы сможете отправлять данные обратно на ПК медленнее.

Вы говорите, что ищете транзиентов. По сути, тогда мы говорим о дифференциации (поиске быстрой скорости изменений). Проделав это недавно с работой (дифференцируя позицию, чтобы дать скорость и ускорение, а затем запуская управление положением-скоростью-ускорением с обратной связью), я могу сказать вам, что сэмплирование зашумлено, и вам нужны значительные уровни фильтрации, когда вы смотрите по скорости изменения. Если вы этого не сделаете, то ложные срабатывания из-за шума убьют ваш дизайн. (Фильтры нижних частот Бесселя FTW из-за минимального перерегулирования и твердой групповой задержки в полосе пропускания; также посмотрите на преобразование MZTi для лучшего отклика, когда ваша постоянная времени фильтра приближается к Найквисту.)

Теперь у нас есть кое-что с более полезными данными для работы ПК. Но также у нас есть кое-что, что можно отправить обратно на ПК медленнее, потому что, если вы отфильтровали свои данные с помощью фильтра нижних частот, вам не нужно отправлять эти данные быстрее, чем удвоить вашу новую пропускную способность.