Cmsis dsp: CMSIS DSP Software Library

Библиотека CMSIS DSP. Так ли быстр целочисленный квадратный корень?

Небольшое сравнение функции вычисления квадратного корня из библиотеки CMSIS DSP и моей реализации.

Как-то долго я не обращал внимания на эту библиотеку, но вот насталов время.

Там есть куча всяких полезностей, в том числе и быстрых математических функций. И даже вычисление целочисленного квадратного корня. Круто, я смогу отказаться от самописной реализации в пользу той, которую предлагает компания ARM.

Для начала проверим, так ли быстр армовский квадратный корень и подходит ли он именно для тех задач, для которые необходимы мне.

Функция из бибилиотеки DSP имеет два варианта, это 16 бит и 32 бита, флоат версию рассматривать не будем. Моя реализация только версию для 32 бита (на момент начала эксперимента)

С моей версией можно ознакомиться здесь, или же пройти по ссылке на мой пак для Keil’а на gitlab (В разделе «Полезные ссылки»)

О CMSIS DSP можно почитать в папке с установленным Keil, у меня это

C:/Keil_v5/ARM/PACK/ARM/CMSIS/5. 4.0/CMSIS/Documentation/DSP/html/index.html

Приступим к тестам.

Код для тестирования максимально прост, в качестве подопытного выступает Миландр 1986ВЕ92У на частоте 8 МГц.

В текстовом виде код не буду прикладывать, во время теста я не думал о написании этой заметки, а общался с товарищем в WhatsApp, вот и слал туда эти картинки.

Что мы видим? Три вида переменных x8, x16, x32 — это те числа корни которых нужно найти, я заранее посчитал их на калькуляторе и написал в комментариях.

Далее объявляем пеменные в которых будут результаты, с суфиксом _1 мои, с _2 — ARM. Они объявлены сразу, что бы и мои, и ARM функции были в одинаковых условиях.

Следующие 6 строк это вычисления. Комментарии — время выполнения каждой строчки.

Вот и результаты выполнения кода…

Что такое???

Тут нужно оговорится и сказать, переданные и полученые значения CMSIS DSP необходимо интерпретировать несколько по другому (в отличии от моих):

. ..input value. The range of the input value is [0 +1) or 0x0000 to 0x7FFF.

Входной аргумент это не просто целое число, а 32768 доля от единицы. Это значит, что in = 1000, это не что иное как 1000/32768.

В итоге имеем весьма быстрое вычисление всеми функциями. Хороший результат. А теперь подробнее об алгоритме работы.

И CMSIS DSP и мой вариант используют один и тот же метод нахождения результата, за одним исключением — это первое приближение к результату.

Вот вариант CMSIS DSP

    x0 = in/2                         [initial guess]
    x1 = 1/2 * ( x0 + in / x0)        [each iteration]

У меня же немного более хитрый вариант.

А терь посмотрим как можно ускорить мой вариант (код открыт, почему бы не попробовать)

Самым слабым местом является многократное повторение одного и того же кода:

ax = (d + value / d) >> 1;
d = (ax + value / ax) >> 1;
ax = (d + value / d) >> 1;
value = (ax + value / ax) >> 1;

Применительно к моему коду столько строк актуально для 32 разрядов, а у нас ещё 16 и 8 есть. Нужно лишь удалить несколько строк и готово. И теперь результаты будут следующими:

  • 16 бит — 0.00000475 сек, что на 0.00000100 сек быстрее моей 32 битной версии
  • 8 бит — 0.00000350 сек, что в 1,6 раза (на 0.00000175 сек) быстрее моей 32 битной версии

Неплохое достижение.

Но мои функции могут работать только на ядрах Cortex M3 и старше, тогда как библиотека

CMSIS DSP может быть использована и на M0. Наверняка вы знаете почему так — нет?

За более детальное знакомство с функцией из CMSIS DSP спасибо некому Shura Luberetsky, который в комментарии ткнул в грубой форме (за что коммент был удален) меня носом в описание функции. Если чесно, то спасибо ему, заставил меня вернуться к данной теме и почитать документацию более детально, поскольку я совсем её забросил.

На этом всё. Хорошего кодинга.

Please enable JavaScript to view the comments powered by Disqus.

Программная библиотека CMSIS DSP

В этом руководстве пользователя описывается программная библиотека CMSIS DSP, набор общих функций обработки сигналов для использования на устройствах на базе процессоров Cortex-M и Cortex-A.

Библиотека разделена на ряд функций, каждая из которых охватывает определенную категорию:

  • Базовые математические функции
  • Быстрые математические функции
  • Сложные математические функции
  • Функции фильтрации
  • Матричные функции
  • Функции преобразования
  • Функции управления двигателем
  • Статистические функции
  • Вспомогательные функции
  • Функции интерполяции
  • Функции машины опорных векторов (SVM)
  • Функции байесовского классификатора
  • Функции расстояния
  • Кватернионные функции

Библиотека, как правило, имеет отдельные функции для работы с 8-битными целыми числами, 16-битными целыми числами, 32-битными целыми числами и 32-битными значениями с плавающей запятой.

Библиотека предоставляет векторизованные версии большинства алгоритмов для Helium и большинства алгоритмов f32 для Neon.

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

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

Библиотека выпущена в исходном виде. Настоятельно рекомендуется скомпилировать библиотеку с параметром -Ofast для достижения наилучшей производительности.

Функции библиотеки объявлены в общедоступном файле arm_math.h , который находится в папке Include . Просто включите этот файл. Если вы не хотите включать все, вы также можете полагаться на заголовки в папке Include/dsp и использовать только то, что вам нужно.

Библиотека поставляется с рядом примеров, демонстрирующих использование функций библиотеки.

Теперь библиотека тестируется при сборке быстрых моделей с помощью cmake. Тестируются ядра M0, M4, M7, M33, M55, A32.

Каждый библиотечный проект имеет разные макросы препроцессора.

  • ARM_MATH_BIG_ENDIAN:

Определите макрос ARM_MATH_BIG_ENDIAN для создания библиотеки для целей с прямым порядком байтов. По умолчанию библиотека строится для целей с прямым порядком байтов.

  • ARM_MATH_MATRIX_CHECK:

Определить макрос ARM_MATH_MATRIX_CHECK для проверки входных и выходных размеров матриц

  • ARM_MATH_ROUNDING:

Определить макрос ARM_MATH_ROUNDING для округления опорных функций

  • ARM_MATH_LOOPUNROLL:

Определите макрос ARM_MATH_LOOPUNROLL для включения ручного развертывания цикла в функциях DSP

  • ARM_MATH_NEON:

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

  • ARM_MATH_NEON_EXPERIMENTAL:

Определите макрос ARM_MATH_NEON_EXPERIMENTAL, чтобы включить экспериментальные версии Neon некоторых функций DSP. Экспериментальные версии Neon в настоящее время не имеют лучших характеристик, чем скалярные версии.

  • ARM_MATH_HELIUM:

Подразумеваются флаги ARM_MATH_MVEF и ARM_MATH_MVEI и ARM_MATH_MVE_FLOAT16.

  • ARM_MATH_HELIUM_EXPERIMENTAL:

Учитывается, только если определены ARM_MATH_MVEF, ARM_MATH_MVEI или ARM_MATH_MVE_FLOAT16. Включите некоторые векторные версии, которые могут иметь худшую производительность, чем скалярные, в зависимости от конфигурации ядра/компилятора.

  • ARM_MATH_MVEF:

Выберите Helium версии алгоритмов f32. Это подразумевает ARM_MATH_FLOAT16 и ARM_MATH_MVEI.

  • ARM_MATH_MVEI:

Выберите версии Helium для алгоритмов int и с фиксированной точкой.

  • ARM_MATH_MVE_FLOAT16:

Реализации некоторых алгоритмов MVE Float16 (требуется расширение MVE).

  • DISABLEFLOAT16:

Отключить алгоритмы float16, когда __fp16 не поддерживается для конкретной конфигурации компилятора/ядра. Это справедливо только для скаляра. Когда векторная архитектура поддерживает f16, ее нельзя отключить.

  • ARM_MATH_AUTOVECTORIZE:

В Helium или Neon отключите использование векторизованного кода со встроенными функциями C и вместо этого используйте чистый C. Затем компилятор выполняет векторизацию.


The following files relevant to CMSIS-DSP are present in the ARM::CMSIS

Pack directories:

File/Folder Content
CMSIS\Documentation\DSP This documentation
CMSIS \ DSP \ Примеры Пример проектов, демонстрирующих использование библиотечных функций
CMSIS \ DSP \ включает DSP \ DSP and INCADE DSP -адрес DSP\PrivateInclude Частные включаемые файлы DSP_Lib для сборки библиотеки
CMSIS\DSP\Lib Двоичные файлы DSP_Lib
CMSIS\DSP\Source Исходные файлы DSP_Lib

См. Историю изменений CMSIS-DSP.

cmsisdsp · PyPI

Это оболочка Python для CMSIS-DSP с открытым исходным кодом Arm, совместимая с NumPy .

CMSIS-DSP доступен на нашем GitHub или в виде пакета CMSIS.

Идея состоит в том, чтобы максимально точно следовать C CMSIS-DSP API, чтобы упростить переход к окончательной реализации на плате.

Таким образом, цепочка обработки сигналов может быть протестирована и разработана в среде Python, а затем легко преобразована в реализацию C, работающую на плате Cortex-M или Cortex-A.

Также доступно руководство, но с меньшими подробностями, чем в этом README: https://developer.arm.com/documentation/102463/latest/

Эта оболочка также содержит сценарии для новой инфраструктуры вычислительных графов (CG) CMSIS-DSP.

CG также включает несколько узлов для связи с Modelica с использованием блоков VHT Modelica, разработанных как часть наших демонстраций VHT-SystemModeling.

История изменений этой оболочки доступна в конце файла README.

Протестированные конфигурации

Сборка этого пакета была протестирована в Windows с установкой Python с python.org и Microsoft Visual 2017.

Он также был протестирован с cygwin . В этом случае также необходимо установить python-devel . На Mac это было протестировано со стандартной установкой XCode.

Для запуска примеров scipy и 9Также необходимо установить 0045 matplotlib .

Другие конфигурации должны работать, но файл setup.py необходимо улучшить.

Необходимо использовать Python 3.

Установка и сборка

Установка

Рекомендуется делать это в виртуальной среде Python. Затем в виртуальной среде вы можете просто выполнить:

 pip install cmsisdsp
 

У вас должен быть последний pip (для автоматической установки зависимостей, таких как NumPy ), и у вас должен быть компилятор, который Python может найти при сборке пакета.

Примеры DSP доступны в папке примеров CMSIS-DSP PythonWrapper.

Примеры синхронных потоков данных доступны в папке ComputeGraph CMSIS-DSP.

Вы также можете установить и запустить его из Google Colab:

Эта ссылка откроет блокнот Jupyter в Google Colab для тестирования. Эта записная книжка взята из примеров в репозитории CMSIS-DSP GitHub.

Сборка

Если он не работает (поскольку мы не можем протестировать все конфигурации), вы можете попытаться собрать и установить оболочку вручную.

Рекомендуется сделать это в виртуальной среде

Поскольку оболочка CMSIS-DSP использует NumPy , вы должны сначала установить ее в виртуальной среде.

 > pip установить numpy
 

После установки NumPy вы можете создать оболочку Python CMSIS-DSP. Перейти в папку CMSIS/DSP .

Теперь вы можете установить пакет cmsisdsp в редактируемом режиме:

 > pip install -e .
 

Перед использованием этой команды необходимо перестроить библиотеку CMSIS-DSP, которая больше не создается сценарием setup. py .

Для этого есть CMakeLists.txt в папке PythonWrapper . В папках build в PythonWrapper приведены некоторые примеры параметров, которые можно использовать с 9Команда 0045 cmake для создания Makefile и сборки библиотеки.

Затем эта библиотека используется сценарием setup.py для создания расширения Python.

Запуск примеров

Установите несколько пакетов для запуска примеров

 > pip install numpy
> пип установить scipy
> pip установить matplotlib
 

В зависимости от примера вам может потребоваться установить дополнительные пакеты.

Примеры находятся в папке примеров CMSIS-DSP PythonWrapper.

Вы можете протестировать сценарии testdsp.py и example.py и попробовать запустить их из этой виртуальной среды. example.py требует загрузки файла данных из Интернета. См. ссылку ниже в этом документе.

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

Идея состоит в том, чтобы максимально точно следовать API CMSIS-DSP, чтобы упростить переход к окончательной реализации на плате.

Сначала вам нужно импортировать модуль

 > импортировать cmsisdsp как dsp
 

Если вы используете numpy:

 > импортируйте numpy как np
 

Если вы используете функции обработки сигналов scipy:

 > из сигнала импорта scipy
 

Функции без аргументов экземпляра

Вы можете использовать функцию CMSIS-DSP с массивами numpy:

 > r = dsp.arm_add_f32(np.array([1.,2,3]),np.array([4.,5,7]))
 

Функцию также можно вызвать проще:

 > r = dsp.arm_add_f32([1.,2,3],[4. ,5,7])
 

Результатом функции CMSIS-DSP всегда будет пустой массив, какими бы ни были аргументы (пустой массив или список).

Функции с аргументами экземпляра

Когда функции CMSIS-DSP требуется структура данных экземпляра, ее использование немного сложнее:

Сначала вам нужно создать этот экземпляр:

 > firf32 = dsp.arm_fir_instance_f32()
 

Затем вам нужно вызвать функцию инициализации:

 > dsp.arm_fir_init_f32(firf32,3,[1.,2,3],[0,0,0,0,0,0,0])
 

Третий аргумент этой функции — состояние. Поскольку все аргументы (кроме аргументов экземпляра) в этом Python API доступны только для чтения, это состояние никогда не будет изменено! Он просто используется для передачи длины массива состояний, который должен быть выделен функцией инициализации. Этот аргумент является обязательным, поскольку он присутствует в API CMSIS-DSP, а в окончательной реализации C вам потребуется выделить массив состояний с правильным размером.

Поскольку цель состоит в том, чтобы максимально приблизиться к C API, API принудительно использует этот аргумент.

Единственное изменение по сравнению с C API заключается в том, что переменные размера (например, blockSize для фильтра) вычисляются автоматически из других аргументов. Этот выбор был сделан, чтобы упростить использование массива numpy с API.

Теперь вы можете проверить правильность инициализации экземпляра.

 > печать (firp32.numTaps())
 

Затем вы можете фильтровать с помощью CMSIS-DSP:

 > печать (dsp.arm_fir_f32 (firf32, [1,2,3,4,5]))
 

Размер этого сигнала должен быть blockSize . blockSize был выведен из размера массива состояний: numTaps + blockSize — 1 в соответствии с CMSIS-DSP. Итак, здесь сигнал должен иметь 5 отсчетов.

Если вы хотите отфильтровать более 5 сэмплов, вы можете просто вызвать функцию еще раз. Переменная состояния внутри fiRF32 гарантирует, что она работает так же, как в коде C CMSIS-DSP.

 > печать (dsp.arm_fir_f32 (firf32, [6,7,8,9,10]))
 

Если вы хотите сравнить с scipy, это легко, но предупреждение: коэффициенты для фильтра в scipy находятся в обратном порядке:

 > filtered_x = signal. lfilter([3,2,1.], 1.0, [1,2 ,3,4,5,6,7,8,9,10])
> печать (отфильтровано_x)
 

Принципы одинаковы для всех других API.

БПФ

Вот пример использования БПФ из интерфейса Python:

Давайте определим сигнал, который вы будете использовать для БПФ.

 > количество = 16
> сигнал = np.cos (2 * np.pi * np.arange (nb) / nb)
 

Для cfft CMSIS-DSP требуются сложные сигналы с определенным размещением в памяти.

Чтобы максимально приблизиться к C API, мы не используем комплексные числа в оболочке. Таким образом, сложный сигнал должен быть преобразован в реальный. Функция imToReal1D определена в testdsp.py

 > signalR = imToReal1D(signal)
 

Затем вы создаете экземпляр FFT с помощью:

 > cfftf32=dsp.arm_cfft_instance_f32()
 

Вы инициализируете экземпляр с помощью функции инициализации, предоставленной оболочкой:

 > status=dsp.arm_cfft_init_f32(cfftf32, nb)
> распечатать (статус)
 

Вы вычисляете БПФ сигнала с помощью:

 > resultR = dsp. arm_cfft_f32(cfftf32,signalR,0,1)
 

Вы конвертируете обратно в сложный формат для сравнения с scipy:

 > resultI = realToIm1D(resultR)
> распечатать (результат)
 

Матрица

Для матрицы переменные экземпляра маскируются API Python. Мы решили, что только для матрицы нет смысла иметь видимые экземпляры CMSIS-DSP, поскольку они содержат ту же информацию, что и массив numpy (выборки и размерность).

Таким образом, использовать матричную функцию CMSIS-DSP очень просто:

 > a=np.array([[1.,2,3,4],[5,6,7,8],[9 ,10,11,12]])
> b=np.array([[1.,2,3],[5.1,6,7],[9.1,10,11],[5,8,4]])
 

Результат NumPy в качестве ссылки:

 > печать (np.dot (a, b))
 

Результат CMSIS-DSP:

 > v=dsp.arm_mat_mult_f32(a,b)
> печатать (v)
 

В реальном коде C указатель на структуру данных для результата v должен быть передан в качестве аргумента функции.

example.py

Этот пример зависит от файла данных, который можно скачать здесь:

https://archive. physionet.org/pn3/ecgiddb/Person_87/rec_2.dat

Этот сигнал был создан для мастера диссертация:

Луговая Т.С. Биометрическая идентификация человека на основе электрокардиограммы. [магистерская работа] Факультет вычислительных технологий и информатики, Электротехнический университет «ЛЭТИ», Санкт-Петербург, Российская Федерация; Июнь 2005 г.

и является частью базы данных PhysioNet

Голдбергер А.Л., Амарал Л.А., Гласс Л., Хаусдорф Дж.М., Иванов П.Ч., Марк Р.Г., Миетус Дж.Е., Муди ГБ, Пэн С.К., Стэнли Х.Э. PhysioBank, PhysioToolkit и PhysioNet: компоненты нового исследовательского ресурса для сложных физиологических сигналов. Тираж 101(23):e215-e220 [Электронные страницы тиража; http://circ.ahajournals.org/cgi/content/full/101/23/e215]; 2000 г. (13 июня).

Подмодули

Оболочка Python содержит три подмодуля: с фиксированной точкой , mfcc и тип данных

фиксированная точка проверяет некоторые инструменты, помогающие генерировать ожидаемые значения фиксированной точки с помощью CMSIS-DSP.

mfcc создает некоторые инструменты для создания фильтров MEL, DCT и оконных коэффициентов. ожидается реализацией CMSIS-DSP MFCC.

Фильтры MEL представлены в виде 3 массивов для кодирования разреженного массива.

тип данных — это API поверх с фиксированной точкой для обеспечения большего повторного использования при преобразовании между форматами данных.

Оболочка теперь содержит сценарии Python для вычислительных графов, и вам следует обратиться к документации в папке DSP/ComputeGraph , чтобы узнать, как использовать эти инструменты.

Версия 1.9.6:

  • Исправления в API RFFT
  • Больше гибкости в графе вычислений для указания дополнительных аргументов планировщика и узлов
  • Возможность установки коэффициента масштабирования FIFO на уровне FIFO (в асинхронном режиме)

Версия 1.9.5:

То же, что и 1.9.4, но будет работать в Google Colab.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *