Cortex m4 dsp

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Cortex m4 dsp

Сообщение menzoda »

Пользоваться библиотеками, которые используют эти преимущества (той же CMSIS DSP Software Library), или пользоваться средством разработки, которое позволяет писать на ассемблере.

Кстати, в модуле FPU тоже нет волшебных инструкций, только базовые арифметические операции, разве что только инструкция вычисления квадратного корня.
Реклама
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

Да, кажись стал догонять. Вот тут вроде все функции даны с их описанием. Причём как я понял есть как для девайсов с FPU так и без. Там же определены соответствующие типы данных. Всем большое спасибо за помощь. Буду курить описание дальше, может чё и откроется.
P.S.
Кому интересно в книжке "The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors" оказывается есть глава посвящённая DSP на кортексах. Правда она достаточна скупа на мой взгляд... но хотя бы без этих сра... дурацких ASF функций :kill:
Реклама
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

Снова здравствуйте, появился ещё вопрос, а именно: среди CMSIS ф-ций есть одна для расчёта значений синуса/косинуса - q31_t arm_sin_q31 (q31_t x), при том работает она с фиксированной запятой. В описании на функцию написано, что её аргумент должен быть выражен в радианах, т.е. допустим я захочу найти синус 180 градусов (да, знаю что он равен 0) т.е. в радиана это запишется так x = sin(3.14159265358979). Но как я понял, тип q31_t может принимать значения [-1; 1 - 2^-(n-1)] или примерно [-1;1]. Если же я засуну в эту ф-цию константу PI, то процессор начнёт обрабатывать плавающую запятую. т.к. #define PI 3.14159265358979f. Что делать то? :dont_know:
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Cortex m4 dsp

Сообщение menzoda »

Там написано, что оно не в радианах, а в приведенных радианах (scaled). Полуинтервал [0, 1) отображается на полуинтервал [0, 2·pi). Про отрицательные числа в описании я ничего не нашел.

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

Код: Выделить всё

arm_sin_q31(0.5f)
в надежде получить синус pi, потому что значения с фиксированной точкой хранятся в виде целых чисел, и чтобы получить синус pi в данном случае нужно делать вот так:

Код: Выделить всё

arm_sin_q31(1073741824) // 1073741824 = 0.5 · 2^31
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

надеюсь ничего, что я на ты
Ничего ничего, так даже лучше :)))
надеюсь ты (надеюсь ничего, что я на ты) не собрался вызывать эту функцию к примеру вот так
В том то и дело что не собрался. То, что числа с фиксированной запятой представляются целыми числами я осознал, но вот как связать целые и дробные пока не допёр... Уже несколько статей прочёл но так и не понял. В книге про ядра кортекс написано, что для того что бы представить дробное число в виде q31_t нужно фот такую ф-лу посчитать F= I/2^(n-1), где:
F - дробное число к пересчёту;
I - целое число которым представляется F;
n - разрядность.
Ну вот я и считал I = 3,1415 * 2147483648 = 6746319880,192 - число опять дробное... Ну я подставил 6746319880... ф-ция выдала число, я его пересчитал той же формулкой - какая то бяка... короче печаль тоска. Надо повнимательней про эту фиксированную запятую почитать. Спасибо за помощь сейчас поэкспериментирую.
P.S.
Слову "scaled" значения не придал - то ли трудности перевода, то ли увидел, что для функции с float просто радианы... Вообщем ещё раз спасибо, буду про scaled radians в купе с q31_t читать.
P.S.2
Вы совершенно правы, с числом 1073741824 ф-ция выдаёт 0 :shock:
Реклама
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Cortex m4 dsp

Сообщение menzoda »

Грендайзер писал(а):нужно фот такую ф-лу посчитать F= I/2^(n-1)... Ну вот я и считал I = 3,1415 * 2147483648 = 6746319880,192
Всё правильно считал.
Грендайзер писал(а):I = 3,1415 * 2147483648 = 6746319880,192 - число опять дробное...
Это нормально, не все числа могут быть точно представлены в двоичном формате с фиксированной точкой. В данном случае получившееся 6746319880.192 нужно округлить до ближайшего целого 6746319880. Понятно, что оно не будет точно представлять исходное 3.1415, это можно проверить проделав обратную операцию - разделив 6746319880 на 2³². В итоге мы получим число 3.141499999(9), а с полученной погрешностью придется смириться.

Вернемся к нашем синусам. Дело в том, что 6746319880, которое как бы 3.14149, не может быть представлено в формате Q31. Под записью Qxx подразумевается, что значение хранится в виде 32-битного целого числа со знаком, которое может представлять диапазон от -2³¹ до 2³¹-1, а у нас целых 6 миллиардов - перебор. Теоретически, 3.14149 можно поместить Q29 или меньше, но к нашему случаю с функцией синуса это все не относится, потому что она принимает не радианы, а 2*pi радианы!

Это означает, что для вычисления sin(2*pi) нужно в качестве аргумента передать единицу, но единица тоже не может быть представлена в формате Q31. Однако, синус - периодическая функция и sin(2*pi) равен sin(0), то есть все значения выходящие за границы первого периода синуса должны быть отображены на него (вместо 2*pi нужно подставлять ноль). Теперь подытожим, что нужно сделать для использования этой функции:

1) Отобразить весь диапазон (-∞;+∞) входных значений на один период синуса [0, 2pi).
2) Перевести полученное значение в 2pi радианы, разделив его на 2pi.
3) Перевести полученное значение в формат Q31 умножив его на 2^31 и округлив до целого.
4) Только после всех этих шагов передавать итоговое значение в функцию.

Замечу, что переводить в Q31 можно где угодно, хоть в самом начале, только тогда не забудь подправить все последующие вычисления:
Грендайзер писал(а):Вы совершенно правы, с числом 1073741824 ф-ция выдаёт 0 :shock:
Потому что:
1) 1073741824(Q31) = 0.5
2) arm_sin_q31(1073741824) = sin(0.5*2*pi) = sin(pi) = 0
Последний раз редактировалось menzoda Пн авг 24, 2015 18:27:59, всего редактировалось 1 раз.
Реклама
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

menzoda, огромное спасибо за Ваш комментарий :beer: . К сожалению сегодня уже мозг отключился и информацию не усваивает. Но завтра обязательно всё переварю.
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

menzoda, спасибо ещё раз, всё получилось :))) . Наблюдаю на осциллографе ровненькую синусоиду частотой примерно 17 кГц. Правда после вычисления значений ф-цией пришлось сдвигать результат в право, что б обеспечить разрядность ЦАП. И сейчас вот дотумкал, что наверное надо было брать ф-цию arm_sin_q15 а не arm_sin_q31, один хрен ЦАП 12-ти разрядный... :tea:
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

Снова здравствуйте. Опять упёрся. Чувствую, что разгатка где то рядом, а понять не могу. Вот есть у меня АЦП 12бит. Допустим, что я хочу принять из него данные, умножить их скажем на 0,7 и передать в ЦАП, опять таки 12 - ти разрядный. Как мне следует интерпретировать данные поступающие с АЦП и передаваемые на ЦАП. Т.е. Пусть данные с цап int data_adc, тогда для того, что бы умножить эти данные на 0,7 необходимо data_adc представить в формате скажем q15_t или data_adc(int) = (data_adc * 2^15)(q15_t). 0,7(10) = 0,7 * 2^15 = 22937. Тогда если данные для ЦАП int data_dac, то data_dac = (data_adc(q15_t) * 22937) >> 2^15. Однако в этом случае, наступает переполнение. Если же, данные поступающие с АЦП я интерпретирую как уже имеющие вид Q15 то всё нормально, однако если мне не нужно ничего ни на что умножать, то выходит: data_dac = data_adc(q15_t) >> 2^15 а в этом случае выходит, что данные пришедшие на ЦАП без умножения на 0,7 меньше, чем с умножением, что не верно. Читал про формат данных Qn однако, так и не дошёл до истины. :(
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Cortex m4 dsp

Сообщение menzoda »

Рассуждения по большей части верные. Первый вариант (как ты и описал) выглядит так:
  • 1) перевести значение АЦП в формат Qn: XQn=Xadc * 2^n
    2) перевести множитель в тот же формат: KQn=K * 2^n
    3) перемножить получившиеся значения: YQn=KQn * XQn / 2^n
    4) перевести произведение в целое число: YDAC=YQn / 2^n
У данного решения есть несколько особенностей, которые и вылились в переполнение. Во-первых, перед переводом значения АЦП и множителя в формат с фиксированной точкой нужно выбрать правильное значение n, чтобы эти числа могли быть представлены в этом формате. В нашем случае с этим проблем нет - максимальное значение 12 битного АЦП равно 4095, что укладывается в формат Q15. Множитель 0.7 тоже туда укладывается.

Во-вторых, если мы хотим перемножать числа, то нужно выбрать такое n, чтобы результат произведения туда поместился. Кстати, совершенно необязательно иметь произведение в том же формате, что и множители. Более того, в разных форматах могут быть и оба множителя. В этом случае формула умножения будет выглядеть вот так:
Qp = Qq * Qr / 2^(q+r-p)
Но нам не нужны такие усложения, потому что оба множителя и произведение могут быть представлены в одном формате - Q15 вполне подходит. Этот вариант я привел просто для справки.

Теперь подходим к причине переполнения. Даже если исходные множители и произведение представимы в формате Qn, то промежуточный результат, который получается после умножения KQn на XQn, но до деления на 2^n может превосходить 32 бита. Проверяем с нашими цифрами:
4095 * 2^15 = 134184960
0.7 * 2^15 = 22938
134184960 * 22938 = 3077934612480 > 2^31
Это гораздо больше, чем может вместить 31-битное целое число со знаком, поэтому промежуточный результат нужно приводить к 64-битному знаковому типу:

Код: Выделить всё

Y = (int32_t)(((int64_t)X * K) >> 15)
Как видишь, можно сделать как написано выше и всё заработает, но можно так не делать. Значение АЦП необязательно переводить в формат с фиксированной точкой, потому что целое число, умноженное на любое Qn (по тем же самым правилам с последующим делением на 2^n) есть целая часть произведения. Обращаю внимание, что в случае с множителем 0.7 промежуточный результат не нужно будет приводить к 64-битному типу, однако в общем случае это делать нужно: стоит множителю увеличиться до некоторого значения и у нас опять возникнет промежуточный результат, не помещающийся в 32 бита. В итоге алгоритм выглядит так:
  • 1) переводим множитель в подходищий формат Qn: KQn=K * 2^n
    2) умножаем значение АЦП на множитель (не забывая про приведение к int64_t): YDAC=KQn * XADC / 2^n
    3) всё
Есть более сложные способы умножения чисел с фиксированной точкой, которые округляют результат, тем самым увеличивая точность вычислений, но к этому лучше переходить после того, как разберешся с простейшими операциями.
Последний раз редактировалось menzoda Ср авг 26, 2015 17:22:54, всего редактировалось 1 раз.
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

Я так и думал, что где то, именно промежуточная операция всё портит, но вот к int64_t так и не пришёл :) Теперь вроде всё прояснилось. menzoda, спасибо, снова всё разжевали! :)))
P.S.
menzoda, Вы опять правы. Действительно всё прекрасно заработало. :))
Аватара пользователя
Грендайзер
Мучитель микросхем
Сообщения: 479
Зарегистрирован: Вт июн 02, 2009 22:38:40
Откуда: Город-герой Москва

Re: Cortex m4 dsp

Сообщение Грендайзер »

Снова здравствуйте. Появился новый вопрос по функциям CMSIS DSP, а именно по arm_fir_q15, которая реализует КИХ фильтр. Функция принимает следующие аргументы:
onst arm_fir_instance_q15 * S - указатель на какую то там структуру (с ней всё более мене ясно);
q15_t * pSrc - указатель на массив входных данных;
q15_t * pDst - указатель на массив, куда будут помещены данные с выхода фильтра;
uint32_t blockSize - количество отсчётов, которое должна будит сгенерить ф-ция после её вызова.
Вопросов несколько, а именно:
1) Не понятно как заталкивать данные в ф-цию, т.е. Вот я получил некоторое число с АЦП, я его записываю в массив Src, скажем он имеет 32 элемента. Затем я передал его ф-ции, она мне его посчитала и что дальше? Мне нужно ещё 32 значения с АЦП копить, или сдвигать имеющиеся?
2) Количество отсчётов которые сгенерит ф-ция... то же не совсем ясно... Вот у неё есть 32 входных отсчёта, если смотреть по структуре фильтра, то она мне должне по идее и выдать 32... или нет?
Ответить

Вернуться в «ARM»