реклама на сайте
подробности

 
 
> stm32 - генерация точной частоты таймера, задачка школьной программы
Sprite
сообщение May 17 2015, 07:49
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414



Здравствуйте, уважаемые форумчане!

Задача в следующем: есть таймер, например, 5-й, питается от 72 мГц шины. Требуется генерировать ШИМ частотой в пределах от 10 до 2000 Гц с минимально возможной погрешностью (разницы нет - в большую или меньшую сторону). Когда частота кратна 72 - все прекрасно, но если требуется вывести частоту, например, 13 Гц, то возникает погрешность. Настройка соответственно происходит регистрами PSC и ARR, комбинаций их может быть достаточно много. Самое первое, что приходит в голову - это тупой перебор всех возможных комбинаций с вычислением ошибки и выбором пары PSC и ARR с наименьшей их них, но это не наш метод wink.gif
Может существует формула для расчета? Или на крайний случай таблица значений регистров для каждой частоты с минимальной погрешностью?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
_Pasha
сообщение May 17 2015, 16:34
Сообщение #2


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



В общем-то решается не только цепными дробями.
Я тут тоже посидел, по случаю, накрапал вот:
CODE
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

static unsigned int fast_sqrt(unsigned int arg)
{
unsigned int one,res = 0;
for(one = 1UL << (sizeof(one)*8 - 2); one > arg; one >>=2);

while(one)
{
unsigned int k= res+one;
if(arg >= k)
{
arg -= k;
res += 2*one;
}
res >>= 1;
one >>= 2;
}
return res;
}

unsigned int factorize(unsigned int arg, unsigned int initial)
{
unsigned int j, limit = fast_sqrt(arg);
if(initial == 1) initial += 1;
for(j=initial; (j<=limit)&&(arg%j);++j);
return (j<=limit)?j:0;
}

void get_mpys(uint16_t *a, uint16_t *b, unsigned int num)
{
unsigned int koeff=1;
*a = *b = 1;
while(koeff)
{
unsigned int k = factorize(num,koeff);
if(k)
{
koeff = k;
num /= k;
}
else
{
k = num;
koeff = 0;
}

if(*a * k < 65536)
*a *= k;
else
{
if(*b * k < 65536)
*b *= k;
else
{
*a=*b=0;
return;
}
}
}
}

/*test*/
int main()
{
uint16_t xa,xb;
unsigned int nnn= 7200000/7;
get_mpys(&xa,&xb, nnn);
printf("numb %d a= %d b= %d a*b = %d\n",nnn,xa,xb,xa*xb);
return 0;
}


Вкратце. Имеем static unsigned int fast_sqrt(unsigned int arg) - быстрый целочисленный квадратный корень . Он нам нужен для оценки верхнего предела факторизации, то бишь разложения на множители.
Далее, сам факторизатор - unsigned int factorize(unsigned int arg, unsigned int initial)
Работает тупым перебором, находит множитель начиная с числа initial для параметра arg
Наконец, void get_mpys(uint16_t *a, uint16_t *b, unsigned int num) - тут уже идет последовательное нахождение коэффициентов и домножение их к a или b
То есть a*b=num
Если число не помещается в 16 разрядов - пардон, пользуемся ARR 32 бита. smile3046.gif
Можно сравнить погрешности если кто цепные дроби подымет здесь для тестинга.

Сообщение отредактировал _Pasha - May 17 2015, 16:37
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 21 2015, 17:16
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(_Pasha @ May 17 2015, 22:34) *
Я тут тоже посидел, по случаю, накрапал вот:
...
unsigned int factorize(unsigned int arg, unsigned int initial)
{
unsigned int j, limit = fast_sqrt(arg);
if(initial == 1) initial += 1;
for(j=initial; (j<=limit)&&(arg%j);++j);
return (j<=limit)?j:0;
}

Это у Вас разложение на простые множители?
При разложении большого arg будет много лишних операций деления.
Возможно лучше после оценки предела (посредством sqrt()), найти все простые числа до него с помощью "решета Сундарама" и пытаться делить только на них.

PS: Кстати - в какую сторону даёт погрешность fast_sqrt()? Если в меньшую - надо быть осторожным при разложении arg == n * n, где n - простое число.
Увеличить бы предел на неск. процентов: limit = fast_sqrt(arg) * 11 / 10 или использовать: limit = 1 << (32 - __CLZ(arg) + 1) / 2
Go to the top of the page
 
+Quote Post
_Pasha
сообщение May 21 2015, 17:56
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(jcxz @ May 21 2015, 20:16) *
PS: Кстати - в какую сторону даёт погрешность fast_sqrt()? Если в меньшую - надо быть осторожным при разложении arg == n * n, где n - простое число.

кстати да. нужна финальная проверка.


По первому вопросу не вникал. Яснопонятно, что это все дороговатые операции, однако, таких приложений сферических , чтобы генерить произвольную частоту - еще поискать нужно.
Проще таблицу простых чисел заиметь во флеше, например
http://integraloff.net/simple/table_simpl_ch.php
до 10**4 это всего-то 2460 байт

Код
unsigned int factorize(unsigned int arg, unsigned int initial)
{
unsigned int j, limit = fast_sqrt(arg);
if(initial == 1) initial += 1;
if(limit*limit < arg) limit +=1;
for(j=initial; (j<=limit)&&(arg%j);++j);
return (j<=limit)?j:0;
}
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 21 2015, 18:56
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(_Pasha @ May 21 2015, 23:56) *
Проще таблицу простых чисел заиметь во флеше, например
http://integraloff.net/simple/table_simpl_ch.php
до 10**4 это всего-то 2460 байт

Для решета Сундарама нужно всего 4килобайта ОЗУ для поиска всех простых чисел в диапазоне до 65536. А этого достаточно для разложения на множители любого 32-битного числа.
И алгоритм использует только умножения-сложения.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение May 21 2015, 19:22
Сообщение #6


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(jcxz @ May 21 2015, 21:56) *
Для решета Сундарама нужно всего 4килобайта ОЗУ для поиска всех простых чисел в диапазоне до 65536. А этого достаточно для разложения на множители любого 32-битного числа.
И алгоритм использует только умножения-сложения.

Интересно. А у нас же ж факторизуемое число уменьшается и нижний предел поиска натуральных чисел растет.
Получается, что и столько озу ему может быть не нужно.
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 22 2015, 07:47
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(_Pasha @ May 22 2015, 01:22) *
Интересно. А у нас же ж факторизуемое число уменьшается и нижний предел поиска натуральных чисел растет.
Получается, что и столько озу ему может быть не нужно.

Нет. Для этого алгоритма надо сначала его полностью выполнить чтобы найти все простые не превышающие некоторого.
Нельзя им найти одно простое, его использовать, а потом искать следующее. Только сразу все.

Цитата(adnega @ May 22 2015, 03:46) *
Если это число не будет простым.

Любого - означает что даже если оно само будет простым.

Цитата(_Pasha @ May 22 2015, 08:57) *
yeah.gif Вчера мы не сообразили, что есть же еще компромисс, а именно:
если таблицу всех простых чисел представить битовым полем, то до 65536 нужно 8к флеша. и это без RLE.

Вы на шаг приблизились к господину Сундараму. rolleyes.gif
Там именно карта флагов и используется (можно битовую)..
А если-бы Вы хотя-бы набрали в гугле "решето Сундарама", то узнали-бы, что для представления всех простых до 65536 нужно не 8К, а только 4К, о чём я и писал выше. rolleyes.gif
Можно и так конечно - посчитать эту таблицу решетом на компе, а прошить как есть во флешь.
Go to the top of the page
 
+Quote Post
adnega
сообщение May 22 2015, 09:11
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(jcxz @ May 22 2015, 10:47) *
Любого - означает что даже если оно само будет простым.

А какой толк от такого разложения?
В результате ведь нужно получить два числа так, чтобы их произведение равнялось некому числу,
а каждое было не более 16-бит, причем, если вариантов много, то нужен какой-то дополнительный критерий выбора?

Почему не подходит аппаратно-программный способ генерации частоты с точным делителем? Вопрос к ТС.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Sprite   stm32 - генерация точной частоты таймера   May 17 2015, 07:49
- - Эдди   Подсказываю: есть цепные дроби. Я, кстати, активно...   May 17 2015, 12:32
- - adnega   Цитата(Sprite @ May 17 2015, 10:49) есть ...   May 17 2015, 15:49
- - BaN   Цитата(Эдди @ May 17 2015, 18:32) Подсказ...   May 17 2015, 16:07
||- - _Pasha   Цитата(jcxz @ May 22 2015, 10:47) Нет. Дл...   May 22 2015, 08:44
|- - adnega   Цитата(jcxz @ May 21 2015, 21:56) А этого...   May 21 2015, 21:46
|- - _Pasha   Цитата(jcxz @ May 21 2015, 21:56) Для реш...   May 22 2015, 02:57
- - basileus_   предложу следующее решение: CODE #include <math...   May 19 2015, 09:27
- - adnega   Как вариант, для низких частот (когда делитель не ...   May 19 2015, 12:11
- - Sprite   Спасибо всем за советы! Сейчас буду перемалыва...   May 20 2015, 12:21
- - _Pasha   вишенка на торте Кодchar isPrime(uint_least16_...   May 22 2015, 04:50
- - _Pasha   А знаете ли вы, что ... http://cyberleninka.ru/art...   May 22 2015, 09:43


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th July 2025 - 19:39
Рейтинг@Mail.ru


Страница сгенерированна за 0.01457 секунд с 7
ELECTRONIX ©2004-2016