Програмне забезпечення та комп'ютерне будівництво
Написання Еффіктивного кодексу цифрової обробки сигналів в C
Table of Contents
Вступ
Цифрова обробка сигналів (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 базових станцій.