Вот отображение панорамы с логарифмом, а без него почти в два раза быстрее отрисовывается
Это реально сформированный и отфильтрованный сигнал с полосой панорамы 12кГц
полоса самого фильтра 3кГц
Игорь, есть вопрос.
4897343 просмотров, 5742 ответов — стр. 65 из 383
17 сентября 2020 г. в 09:59#961
17 сентября 2020 г. в 10:03#962
коэффициенты FIR фильтра
Ну собственно это расчет этого фильтра
Ну собственно это расчет этого фильтра
17 сентября 2020 г. в 10:04#963
CMSIS DSP рулит!
Спасибо Геннадию за подсказку.
Спасибо Геннадию за подсказку.
17 сентября 2020 г. в 10:15#964
Не совсем понял что вы делаете и как рисуете спектр. Логарифм "по быстрому" можно посчитать вот как. Вначале умножаем/делим на 2 столько раз чтобы привести (нормализовать) аргумент к диапазону 1..2. А дальше делаем таблицу и кусочно-линейной аппроксимацией по ней шпарим. Т.к. умножение/деление на 2 - это сдвиги, а аппроксимация по таблице - одно сложение и сдвиг то алгоритм по сути работает без умножений и делений и позволяет эффективную реализацию
17 сентября 2020 г. в 10:37#965
Кусочик из прорисовки:
arm_sqrt_f32(pOut[ i ] * pOut[ i ] + pOut[i+1] * pOut[i+1],&pO);
uint16_t y = (uint16_t) (30 * log10f(pO));
y - это амплитуда
По итогу полноценная логарифмическая панорама получается. НО! этот лог портит скорость прорисовки.
Я тоже думал, что просто таблицу просчитать этих лог, да брать ближайший, но что-то многовато элементов.
arm_sqrt_f32(pOut[ i ] * pOut[ i ] + pOut[i+1] * pOut[i+1],&pO);
uint16_t y = (uint16_t) (30 * log10f(pO));
y - это амплитуда
По итогу полноценная логарифмическая панорама получается. НО! этот лог портит скорость прорисовки.
Я тоже думал, что просто таблицу просчитать этих лог, да брать ближайший, но что-то многовато элементов.
17 сентября 2020 г. в 10:44#966
Вначале умножаем/делим на 2 столько раз чтобы привести (нормализовать) аргумент к диапазону 1..2. А дальше делаем таблицу и кусочно-линейной аппроксимацией по ней шпарим. Т.к. умножение/деление на 2 - это сдвиги, а аппроксимация по таблице - одно сложение и сдвиг то алгоритм по сути работает без умножений и делений и позволяет эффективную реализациюЯ покурю вашу идею, спасибо
17 сентября 2020 г. в 10:51#967
но что-то многовато элементовТак вот для этого и делается нормализация умножением/делением на 2. Походу получаем вот что
log(x) = log(a*2^n) = log(a) + n*log(2) где 1<a<2
диапазон от 1 до 2 это 6дб. таблицы из 16 элементов вполне хватит
17 сентября 2020 г. в 11:30#968
Игорь, подскажите пожалуйста, по вашей части.
lg() чем можно по проще заменить?
Чисто с математической точки зрения, любая функция раскладывается в ряд Тейлора. Чем больше членов ряда используете, тем выше точность.
Вот гляньте, я пять членов ряда взял, синий - ln(x), красный - ряд Тейлора.

Перевести логарифм на любое иное основание как два пальца об асфальт....

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

18 сентября 2020 г. в 08:00#969
Да, Игорь , спасибо. Но у меня нет опыта в алгебре. С института прошло более 20 лет, хотя по матану всегда было отлично.
Я не смогу адаптировать ln в lg
Инет внятного ответа не даёт за десятичный логарифм. Есть ещё проблема. Учитывая, что алгоритм работает в критичном по времени месте, то возведение в степень может дать серьезную задержку. Хотя, фактически это умножение, а в stm32 стоит мат сопроцессор , который умножает два числа с плавающей запятой за 18 тактов (без fpu за 900 тактов)
Я не смогу адаптировать ln в lg
Инет внятного ответа не даёт за десятичный логарифм. Есть ещё проблема. Учитывая, что алгоритм работает в критичном по времени месте, то возведение в степень может дать серьезную задержку. Хотя, фактически это умножение, а в stm32 стоит мат сопроцессор , который умножает два числа с плавающей запятой за 18 тактов (без fpu за 900 тактов)
18 сентября 2020 г. в 08:59#970
Надо просто масштабировать
ln(a)= lg(a)/lg(e) ---> lg(a)=ln(a)*0,43429448190325...
ln(a)= lg(a)/lg(e) ---> lg(a)=ln(a)*0,43429448190325...
18 сентября 2020 г. в 09:13#971
Чисто с математической точки зрения, любая функция раскладывается в ряд Тейлора. Чем больше членов ряда используете, тем выше точность.Ряд Тейлора - красивая математика, но в данном случае она будет требовать излишних ресурсов. Тут ведь надо приблизительно получить значение логарифма. Мой метод со сдвигами и таблицей будет работаь в РАЗЫ быстрее. Более того, если мы работаем с плавающей точкой то там и сдвиги не особо нужны, потому что плавающее уже представлено в виде мантиссы и порядка, при этом мантисса всегда нормализирована. Для мантиссы тоже делаем lookup таблицу и тогда все вычисление логарифма уложится в два lookup'а, одно умножение и одно сложение
PS и вообще - гугль рулит. запрос "fast log approximation" выдает сразу то что надо:
https://www.flipcode.com/archives/Fast_log_Function.shtml
https://stackoverflow.com/questions/39821367/very-fast-approximate-logarithm-natural-log-function-in-c
https://tech.ebayinc.com/engineering/fast-approximate-logarithms-part-i-the-basics/
https://tech.ebayinc.com/engineering/fast-approximate-logarithms-part-iii-the-formulas/
Обратите внимание что в оптимизированных версиях используется именно то что я и предложил - с таблицами

18 сентября 2020 г. в 10:06#972
ra0ahc, а спектрограмму тобишь водопад вы сдвигом части дисплея делаете?
18 сентября 2020 г. в 10:12#973
https://tech.ebayinc.com/engineering/fast-approximate-logarithms-part-i-the-basics/
вот этот быстрее чем родной.
остальные имеет непонятки.
вот этот быстрее чем родной.
остальные имеет непонятки.
ra0ahc, а спектрограмму тобишь водопад вы сдвигом части дисплея делаете?нет еще , с фильтрами разбираюсь. Это же все должно "на лету" делаться если дсп в процессоре делать.
18 сентября 2020 г. в 10:37#974
Надо просто масштабировать
ln(a)= lg(a)/lg(e) ---> lg(a)=ln(a)*0,43429448190325...
Вот-вот, 8 класс средней школы...

18 сентября 2020 г. в 11:09#975
Этот алгоритм тоже работает быстрее чем стандартный
Кстати, это как раз то о чем говорил Андрей.
//log2
#define LogPrecisionLevel 2
#define LogTableSize 0b100
double log_table[LogTableSize];
//
void init_log_table(void) {
for (int i = 0; i < LogTableSize; i++) {
log_table = log2(1 + (double)i /LogTableSize);
}
}
double fast_log2(double x) { // x>0
unsigned long long t = *(unsigned long long*)&x;
int exp = (t >> 52) - 0x3ff;
int mantissa = (t >> (52 - LogPrecisionLevel)) & (LogTableSize - 1);
return exp + log_table[mantissa];
}
Кстати, это как раз то о чем говорил Андрей.
//log2
#define LogPrecisionLevel 2
#define LogTableSize 0b100
double log_table[LogTableSize];
//
void init_log_table(void) {
for (int i = 0; i < LogTableSize; i++) {
log_table = log2(1 + (double)i /LogTableSize);
}
}
double fast_log2(double x) { // x>0
unsigned long long t = *(unsigned long long*)&x;
int exp = (t >> 52) - 0x3ff;
int mantissa = (t >> (52 - LogPrecisionLevel)) & (LogTableSize - 1);
return exp + log_table[mantissa];
}