Pull to refresh

Comments 36

«иноземной фирмы Texis Instrument»
Texas Instruments

«не используя операций умножения и деления»

(r7 >> 1) — (r7 >> 6)
r7/2 — r7/64 = r7/2.065

Битовый сдвиг != умножение. В случае, если нет математического сопроцессора, умножение может занимать далеко за десяток тактов. Битовый сдвиг всегда выполняется за один такт. Опять же, в кремнии/FPGA реализация битового сдвига делается абсолютно элементарно, в отличие от умножения.
>> Битовый сдвиг != умножение.
Приведённый отрывок это программная реализация умножения (или деления — как угодно) с фиксированной точкой на конкретную константу.
Умножение не перестаёт быть умножением считаете вы его в столбик или на калькуляторе.
Это если только рассматривать умножение как самоцель и результат операции. Здесь же результат — не комбинация умножений и сложений, а отфильтрованный сигнал.
Ну тогда и не стоило заострять на этом внимание и нужно было рассматривать машинный код как блэк-бокс.
Но этот код дизассемблирован и сконвертирован на C с целью _изучить его работу_.
Моё естественное желание _обьяснить_ детали реализации натолкнулость на непонятное сопротивление.
Видимо, согласно первому комменту, людям проще поверить в магию, чем в возможность реализации умножения через сложение/сдвиг.
Я смотрю тут многим не знаком алгоритм побитового умножения через сдвиг/сложение AKA умножение в столбик =)
http://users.utcluj.ro/~baruch/book_ssce/SSCE-Shift-Mult.pdf

Именно потому, что мне этот алгоритм знаком, я и говорю, что умножение в разы более затратная операция.

Посмотрите сами, для реализации битового сдвига нам понадобится:
— Сдвиговый регистр
— 1 такт на сдвиг
Если есть возможность скоммутировать выходы регистра — достаточно обычного регистра.

Для реализации умножения нам понадобится:
— Два сдвиговых регистра
— Регистр под результат
— Сумматор
— 4 такта на умножение

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

А кто-то спорит?
Я лишь показал как именно осуществляется умножение/деление, для тех кому интересно.
Причём тут ваш комментарий про «затратность»? Где-то в моём комментарии утверждалось иное?
Я говорил что мною приведённый кусок кода это не более чем оптимизированное умножение на константу.

>> 1 такт на сдвиг
Зависит от процессора. В Pentium4 сдвиг — 4 такта.Power4/PPC970 — 2 такта.
В иных сдвиг может приводить к вызову микрокода.

Чтобы был 1 такт на сдвиг (на несколько бит) ваша схема с одним сдвиговым регистром не подходит.
А вот barrel-shifter в свою очередь это довольно массивная схема, в отличие от последовательного умножителя.

Вот тут хорошо видно, что сдвигатель больше чем _всё_ ALU и пара регистров вместе взятых.
http://daveshacks.blogspot.ru/2016/01/inside-armv1-decoding-barrel-shifter.html
Про то, что комбинационная схема сумматора будет в разы медленнее, чем сдвиговый регистр, я даже говорить не буду.
Не спорю, умножение в общем виде гораздо затратнее этой оптимизации.

Но, ради истины, здесь два сдвига, а между ними стоит вычитание (по сложности равно сложению).

Некорректно говорить, что тут умножение заменено одним лишь сдвигом.

Просто надо всегда понимать, что происходит. На той же современной x86 32-битное умножение быстрее работает, чем 2 сдвига и 3 сложения.
На это можно смотреть, как взятие только старших битов.
По аналогии считаем рубли, копейки отбрасываем.
Битовый сдвиг всегда выполняется за один такт.

Помнится, некоторые варианты процессоров выполняли битовый сдвиг в цикле.

На современной элементной базе полноценный barrel shifter дешевле, чем раскладка сдвига на много бит в цикл по одному биту.
Хотя x86 и сейчас не гарантирует быстрое выполнение для всяких нелепостей вроде RCR на несколько бит.

Битовый сдвиг != умножение.

да ну? а помоему битовый сдвиг дает те же результаты что умножение/деление на степень двойки.


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

Первое что приходит в голову — avr, нет сопроцессора, но есть однотактная умножалка 8*8. К слову, подкласс сигнальных процессоров (особенно древние) как правило имеет умножалку на борту но не имеет математический сопроцессор.

Прошу прощения, Texas Instruments, поправил

Может недостаточно точно выразился… Имелась в виду операция в смысле стандарта языка «Умножение — арифметическая бинарная операция ...»

Из-за прогрессирующего многоу́ровневого абстракционизма программисты забывают что на самом деле они не «пишут программы», а отдают приказы процессору. Умение дать такой приказ, чтобы он был выполнен эффективно и в срок, и есть искусство управления. В TI есть эффективные менеджеры (без кавычек) по управлению процессорами.
Таким образом, по виду фазовой характеристики можно сделать вывод, что данное звено является звеном 5 порядка.

А докам, значит, вы не склонны верить — мало ли что они там понапишут чтобы специально запутать:


; Freq_Stop: 2.5KHz, Attenuation_Stop: 40dB
; Freq_Pass: 1.4KHz, Attenuation_Pass: 1dB
; Order of filter = 5

Ну и ради исследовательского эксперимента можно в любой тулзе по проектированию фильтров (хоть тот же filterBuilder в Матлабе, да сотни их) вбить эти характеристики и поиграться с типами, в том числе и Баттерворта.

Да бросьте придраться.
Человек способны в «рукопашную» разобрать происходящие процессы, а равно как и способный доходчиво объяснить. Достоин, как минимум, уважения.
А ваш способ, больше годится для работы. Т.е. когда надо просто подобрать компоненты или в поисках проблемы, если таковая возникнет… ну и прочее.
Так, что автору спасибо. Просвещайте дальше. Может появятся ещё инженеры которые понимают, что делают, а не лепят типовые решения.
Из анализа импульсной характеристики видно, что фильтр не лишен недостатков. Импульсная характеристика содержит незатухающие колебания, амплитудой одна дискрета.
Это не недостаток, а фича — это же БИХ. При желании, этот бесконечный хвост можно было бы обрезать, добавив соответствующую логику.

"Недостатки" скорее всего вызваны округлением коэффициентов фильтра до 2^(-n), чтобы стало возможным отказаться от использования умножения и деления, и заменить их на операции сдвига.

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

А что за форум? Английский? Ссылку не дадите — поделюсь с англоязычными коллегами
Если поискать в гугле .word 4f16h SciFi, то приводит прямиком сюда http://caxapa.ru/720400.html
Будничность первого курса. Ностальгия :-)

С одной стороны умные ребята работают в TI, с другой стороны достаточную документацию не пишут. Страдал в свое время работая с их ЦСП.

UFO just landed and posted this here

OpenMP + ndk на 6678 по отдельности работают замечательно. Вместе требуют притирки в виде правильной инициализации менеджера очереди qmss. При этом из документации есть только пример с OpenMP 1.0 и работа с семафорами. Нормальная инициализация найдена через 2 недели на полу открытом git хранилище. При этом нужно поправить немало исходников mcsdk (в гайдах написано неподходящее решение), а уж про добавление какого-нибудь srio к первым двум технологиям и говорить страшно. Про забагованность ccs и говорить не хочется, но стоит отдать должное, что компилятор и линковщик замечательно описаны в гайдах.

UFO just landed and posted this here

Великолепно! Формулы, как обычно, вызывают печаль (у меня, так как забыты уже чуть менее, чем полностью за невостребованностью), но читал как детектив.

структурная схема фильтра из статьи:
image

развернутая реализация для вещественных чисел:
double filtd(double x)
{
static double fltmem[5];
double out_f = (-1.515625*fltmem[4]-1.109375*fltmem[2]+0.515625*fltmem[0]+0.109375*x)*.5;
double new_flt3 = -(fltmem[4]*0.515625+fltmem[0]*0.484375);
fltmem[4] = fltmem[3];
fltmem[3] = new_flt3;
//
double new_flt1 = -(0.109375*fltmem[2]+0.890625*x);
fltmem[2] = fltmem[1];
fltmem[1] = new_flt1;
fltmem[0] = x;
return out_f;
};
Больше интересует применения этого «куцего» фильтра. Наверное, есть места, где его характеристики достаточно вписываются в ТЗ.
Удваиваю предыдущего оратора — как этот код применять в качестве фильтра?

Тут дана функция, ок. Допустим, у нас есть некий АЦП, на выходе имеем некий массив с отсчётами этого АЦП за определённый период времени, дальше что? Скармливать этой функции по одному значению из массива?

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

Вызывая данную функцию с частотой F и передавая ей в качестве аргумента входной сигнал, на выходе мы получим выходной сигнал, соответствующий реакции фильтра с указанными частотными характеристиками, частота среза по уровню 0.707 будет равняться 0,25*F

еще раз, другими словами

АЦП опрашивается с частотой 1кГц
значения АЦП скармливаюся функции фильтра
по результатам строится осциллограмма

  • на вход АЦП подаем синусоиду амплитудой 1000 дискрет с частотой 100Гц, на осциллограмме имеем синусоиду амплитудой 999 дискрет
  • на вход АЦП подаем синусоиду амплитудой 1000 дискрет с частотой 250Гц, на осциллограмме имеем синусоиду амплитудой 707 дискрет
  • на вход АЦП подаем синусоиду амплитудой 1000 дискрет с частотой 400Гц, на осциллограмме имеем синусоиду амплитудой где-то 20 дискрет
  • на вход АЦП подаем синусоиду амплитудой 1000 дискрет с частотой 900Гц, на осциллограмме имеем синусоиду амплитудой 999 дискрет, частоту 100Гц, ничего не поделаешь теорема Котельникова

Sign up to leave a comment.

Articles