Вступ

Цифрова обробка сигналів (DSP) є резервним копії сучасних вбудованих систем, що дозволяє аудіо режимі реального часу, відео, телеметрії та комунікаційних операцій. Написання ефективних кодів C для завдань DSP безпосередньо впливає на пропускну здатність системи, споживання енергії та затримки. На відміну від загального призначення, алгоритми DSP повинні виконуватися в межах суворих обмежень часу, коли максимізація використання обмежених пам'яті та ресурсів обробки. Цей посібник розширюється на принципах ядра та забезпечує дієві методи написання коду C для додатків DSP, з фіксованої точки арифметметметметика для апаратно-специфічних оптимізує.

Розуміння програм DSP в C

DSP передбачає математичні операції, такі як фільтрування, трансформи, конволюція та спектральний аналіз на вибіркових сигналах. У C програміста контролює кожен аспект представлення даних та потоку, який є критичним для детермінованого виконання. DSP-код часто працює на мікроконтролерах або цифрових процесорах сигналів, де апарат щільно закривається - наприклад, виділений MAC (багатонарахунку) юнітів або модераторів SIMD. Глибоке розуміння ієрархії цільової архітектури, набір інструкцій, і периферичні можливості є важливим для написання ефективних C-коду.

Основні характеристики DSP-коду:

  • Ремонтований арифметичне: петлі з ножем-навісними операціями домінування (наприклад, фільтри FIR).
  • Реал-часові обмеження: кожен зразок повинен бути оброблений в період зразка.
  • Data потокове:] безперервний вхід / вихід струмків вимагають ефективного буферизації та мінімального копіювання.
  • Memory пропускна здатність, що межа: багато алгоритмів DSP обмежені, як швидко можуть бути переміщені дані, а не арифметичні операції.

Для основного посилання див. Analog Devices' DSP Basics.

Фіксований-Point Arithmetic: Точність без покриття-пофарба накладна

Багато процесори DSP не мають апаратних плаваючих-точкових одиниць (FPU) або мають повільніше FPU. Фіксований-точковий арифметичне використовує цілі операції з точкою імпульсу, що забезпечує детермінатичну продуктивність і нижчу споживаність потужності. Найбільш поширене уявлення є Q позначення: Qm] nn] де ]m] біти є цілою частиною і n біт 16-фб. Наприклад, 16-фб.

Реалізація операцій фіксованого поміщення в C

Фіксований точковий додаток є прямимforward (simply add цілих), але багатозастосувань вимагає регулювання точки радіуса. Для багатозастосування Q15 продукт двох чисел Q15 потребує проміжного результату 32-bit, потім ви правою кнопкою миші на 15 біт, щоб повернутися до Q15. Приклад:

typedef int16_t q15_t;
q15_t q15_mul(q15_t a, q15_t b) {
 int32_t temp = (int32_t)a * (int32_t)b;
 return (q15_t)(temp >> 15);
}

При скупчень виникають (наприклад, у фільтрах), охоронці не допускають перелив. Використовуйте 32-бітні або навіть 64-бітні акумулятори та насичені результати. Фіксовані точкові бібліотеки, такі як ARM CMSIS-DSP забезпечують оптимізовані функції фіксованої точки, включаючи фільтрування, трансформацію та матричні операції.

Коли використовувати Фіксований-пофарбовий проти флоатинг-пофарба

Сучасні процесори з FPU (наприклад, Cortex-M4/M7) можуть виконувати плаваючі операції, як швидко, як фіксована точка. Використовуйте плаваючі точки при:

  • Динаміка Algorithm (наприклад, адаптивні фільтри).
  • Підтримуваність коду – це пріоритетний (збір нездійснюваних масштабів).
  • Обладнання для FPU є присутнім і трубопроводом може перекривати додані і багатоповерхівки.

На високооб’ємних пристроях без ФПУ, фіксована точка залишається стандартом для витратно-чутних додатків.

Оптимальний доступ до пам'яті для DSP

алгоритми DSP часто обробляють великі масиви даних послідовно. У кеш-памах і автобусних столах можна вбити продуктивність. Дотримуйтесь цих принципів:

  • Linear access: масиви траверси в контигузному порядку (рядо-маджор в C). Уникайте шаблонів доступу, якщо це необхідно алгоритмом (наприклад, FFT біт-реверсал).
  • Data вирівнювання: забезпечує масиви вирівнюються до кеш-лінії. Використовуйте атрибути компілятора, такі як або спеціальні розділи пам'яті.
  • Buffering: використовується подвійний буферинг для перекриття DMA передач з обробкою процесора. Хоча процесор працює на одному буфері, наступний блок зразка завантажується.
  • Заряджає слово: ] на токерах, щоб повідомити компілятор, який тостери не аліас, що дозволяє векторизації та кращої інструкції.

Наприклад, для того, щоб використовувати функцію фільтра FIR необхідно писати з функцією «обмеженого» при вході та виході з буферів, окремі:

void fir_lowpass(const int16_t * restrict x, int16_t * restrict y,
 const int16_t * restrict coeffs, int len, int order) {
 for (int i = 0; i < len; i++) {
 int32_t acc = 0;
 for (int j = 0; j < order; j++) {
 acc += (int32_t)x[i + j] * coeffs[j];
 }
 y[i] = (int16_t)(acc >> 15);
 }
}

Ефективний вибір алгоритму та впровадження алгоритму

Алегоритмічна складність безпосередньо перекладається на час виконання і потужність. Завжди оберіть найбільш ефективний алгоритм завдання:

  • Fast Fourier Transform (FFT): ] використання Cooley-Tukey radix-2 або спліт-редекс для живлення-два довжини. Уникайте наївного DFT який є O(N2). Передкомп'ютерні фактори та магазин в ROM.
  • Фільтри FIR: використовують поліфазну декомпозицію для децимації / інтерполяції; використовують симетрію для лінійно-фазних фільтрів для занурення кількості багатозастосувань.
  • IIR filters: використовується прямий форма II для кращої чисельної стабільності; використання каскадованих двоквадних секцій (секунди другого порядку) для зменшення чутливості до кількісної квантизації коефіцієнта.
  • Convolution: для довгих послідовностей, використання методу перекриття фFT або перекриття, а не прямого з’єднання.

Бібліотека для посилання на сучасні техніки FFT (хоча не в C, його принципи широко скопіюються в вбудованих бібліотеках DSP).

Особливості обладнання для Leveraging: SIMD і DSP Інструкція

Практично всі сучасні мікроконтролери включають SIMD (Single Instruction Кілька даних) або DSP-проявленої інструкції. Наприклад:

  • ARM Cortex-M4/M7: SIMD (SADD, SMUAD та ін.), насичені арифметметичними та фракційними операціями (QADD, QSUB). Використовуйте вбудовані функції CMSIS-DSP.
  • TI C6000 DSP: вісім ножометрів, подвійний MAC і трубопровід програмного забезпечення. TI DSP Оптимізація керівництво забезпечує детальні методи.
  • RISC-V з P-виразками: майбутні ядра матимуть DSP-подібні інструкції.

Для використання цих функцій в C, напишіть код, який компілятор може автоматично векторізувати (наприклад, прості петлі без залежностей) або використовувати компіляторні функції. Приклад використання ARM CMSIS-DSP для фільтра FIR:

#include "arm_math.h"
arm_fir_instance_f32 S;
float32_t firState[128];
arm_fir_init_f32(&S, numTaps, coeffs, firState, blockSize);
arm_fir_f32(&S, input, output, blockSize);

Такі бібліотеки ручні для максимальної продуктивності. Завжди профілюйте до і після переходу з генеричних функцій до бібліотеки.

Технології оптимізації локонів

Оскільки алгоритми DSP є петля-символи, оптимізуються на рівні петлі, оплачують великі діоди:

  • Пов’язка: вручну або з компілятором прагми (`#pragma unroll N`) для зменшення петля накладної та підвищення паралельності рівня інструкції.
  • Програма за допомогою: реструктуризації петель, так що багаторазові ітерації знаходяться в польоті одночасно. Деякі компілятори роблять це автоматично; використовуйте `-O3` і архітектурні прапори.
  • Використання гілочок: заміня умов з арифметметичною (наприклад, хв/максом з використанням ternary), або використання таблиць для нелінійних функцій.
  • Використовувати локальні змінні: зберігати дані в реєстрах, декларуючи змінні всередині петлі або використовуючи підказку `register`.
  • Minimize Divisions: заміну поділу за допомогою постійного з багатозастосування за допомогою reciprocal; використання зсуву для живлення двох.

Передача константів і лущів

DSP функції, такі як тригонометричні значення, коефіцієнти та фактори подвійного зв’язку повинні бути попередньо зібрані в автономному режимі і зберігатися як постійні масиви в ROM. Для нереального запуску можна комп’ютерувати їх один раз і повторно. Приклад: для 1024-точкового FFT, передкомп’ютером sine/cosine значення для кожного етапу. Це виключає оцінку часу і зменшує потужність.

У таблиці пошуку (LUTs) також допомагають функції, такі як корінь квадрата, експонент та журнал, що використовуються в DSP (наприклад, у процесі мовної обробки). Використовуйте лінійне міжпокриття між записами таблиці для торгівлі пам'яті проти точності.

Профілактика та настроювання

Не оптимізація завершена без вимірювання. Використовуйте ці методи для виявлення пляшок:

  • Cycle-accurate профілювання: використання на борту цикл лічильників (наприклад, DWT CYCCNT на Cortex-M) для вимірювання тривалості функції.
  • Статистичное профілювання: вибірка лічильника (PC) для перегляду функцій, які споживають час процесора.
  • Memory профілювання: використання інструментів для моніторингу пропусків кешу (якщо є) і автобусних транзакцій.
  • => увімкнути звіти про оптимізацію компілятора (`-fopt-info-vec-optimized` у GCC) для перегляду, якщо векторовані петлі.

Ветературі: вимір, зміна, вимірювання знову. Часто найбільші вигоди прибувають від поліпшення моделей доступу пам'яті, а не вимочування арифмететики.

Практичний підсумок: Принесіть його все разом

Написання ефективних DSP-кодів в C вимагає цілісного підходу:

  • Виберіть правильне представлення даних (фіксовано-точна точка проти плаваючого точки).
  • Проектування структури даних для послідовного доступу та вирівнювання.
  • Виберіть алгоритми з низькою складністю (ФФФТ, поліфазний).
  • Використовуйте бібліотеки DSP, які доступні.
  • Непрокрутка петель і зменшення розгалуження.
  • Попередньокомп'ютерні константи в ROM.
  • Профілактика несхожого і нехай компілятор допоможе.

За допомогою цих принципів розробники можуть досягати пропускної здатності сигналу, що порівняно з ручним складанням, зберігаючи при цьому портабельність і підтримуваність. Результат надійний, в режимі реального часу DSP системи, які задовольняють вимоги сучасних вбудованих продуктів—від слухових апаратів до 5G базових станцій.