Перейти к содержанию
    

Полином Тейлора методом Горнера

Здравствуйте. Подскажите пожалуйста решение в вычислении полинома Тейлора на ПЛИС.

Задача следующая:

Необходимо реализовать генератор косинуса на ПЛИС. В качестве способа вычисления выбрана аппроксимация рядом Тейлора.

Раскладываю косинус в ряд Тейлора и ограничиваю до слагаемого в 10-ой степени, что позволит аппроксимировать с высокой точностью полпериода косинуса, вторую половину периода можно получить просто умножив на -1.

 

p(x)=a0 + x^2 * a1 + x^4 * a2 + x^6 * a3 + x^8 * a4 + x^10 * a5; где a0 = 1, a1 = -1/2!, a2 = 1/4!, ....

 

Для реализации раскладываю полином по методу Горнера

 

p(x)=a0 + x^2*(a1 + x^2*(a2 + x^2*(a3 + x^2*(a4 + x^2*a5))));

 

Логику реализации схемы Горнера я понимаю так: 1. Вычисление x^2; 2. Умножение на a5 + a4; 3. Умножение на x^2 + a3 и т.д.

Не могу понять как на ПЛИС поступают с коэффициентами a0,a1,a2,a3,a4,a5, да и сам аргумент x должен меняться от 0 до pi (т.к. аппроксимирую только полпериода)

 

Вот код MATLAB реализации схемы Горнера. Изменяя deltaPHI получаем косинус различных частот. Множитель norm ввожу чтобы представить коэффициенты целыми числами. Аргумент cnt изменяется от 0 до pi. При реализации это просто счетчик с переменным шагом счета. Не понятно как привести его значения в градусах

%% служебные
clc
clear all
gr=pi/180; % перевод из радиан в градусы
%%
N=512; % количество отсчетов
deltaPHI=1; % град., приращение фазы (шаг)
% коэффициенты для схемы Горнера
norm=1; % нормирующий множитель
a0=1*norm;
a1=(-1/2*norm);
a2=(1/24*norm);
a3=(-1/720*norm);
a4=(1/40320*norm);
a5=(-1/3628800*norm);
for i=1:N
   phi(i)=mod(i*deltaPHI*gr,180*gr); % изменение фазы сигнала от 0 до pi  
    s(i)=norm*cos(phi(i));
end
%% вычисление полинома на ПЛИС
% регистры для записи промежуточных вычислений
reg1=zeros(1,N); reg2=zeros(1,N); reg3=zeros(1,N);
reg4=zeros(1,N); reg5=zeros(1,N); reg6=zeros(1,N);
for i=1:N
    cnt(i)=mod(i*deltaPHI*gr,180*gr);% счетчик аргумента
    % возведение в квадрат
    reg1(i)=(cnt(i))*(cnt(i));
    % умножение на а5 и суммирование а4
    reg2(i)= reg1(i)*a5 + a4;
    % умножение на reg2 и суммирование а3
    reg3(i)=reg2(i)*reg1(i) + a3;
    % умножение на reg3 и суммирование а2
    reg4(i)=reg3(i)*reg1(i) + a2;
    % умножение на reg3 и суммирование а1
    reg5(i)=reg4(i)*reg1(i) + a1;
    % умножение на reg3 и суммирование а1
    reg6(i)=reg5(i)*reg1(i) + a0;
end
%% формирование сигнала коммутации для умножения на 1 или -1
% при реализации на VHDL -- аналог сигналу переполнения счетчика
ssds=zeros(1,N); sd=0; 
for i=2:N
if phi(i) < phi(i-1)
    sd=not(sd);
end
ssds(i)=sd;
end

%% умножение на 1 первого полупериода и на -1 второго...
for i=1:N
   if ssds(i) == 0
    Ix4(i)= s(i);
    Ix5(i)= reg6(i);
   else
    Ix4(i)= -s(i);
    Ix5(i)= -reg6(i);
   end
end    
%% графическая часть
figure(3)
subplot(2,1,1)
plot(1:N, Ix5,'r',1:N, Ix4,'b')
legend('Gorner', 'cos')
title('время')
grid on
subplot(2,1,2)
plot(abs(fftshift(fft(Ix5))))
title('спектр')
grid on

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

А по сути вам надо намутить математический аппарат в плис, который будет работать с действительными числами. Самое простое это фиксированная точка. Если грубо, то просто умножьте все ваши значения на 1000, и считайте в целых, а потом разделите. Ну правда это очень грубо, потому что надо умножать не на 1000, и делить на другие числа и за разрядностью следить...

 

Можно также попробовать намутить модуль работы с плавающей точкой и считать в ней.

 

Можно воткнуть в ПЛИС ядро процессора и считать на нем

 

 

или я не понял вопроса?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

на счет четверти периода и DDS знаю, реализовывал.

 

А по сути вам надо намутить математический аппарат в плис, который будет работать с действительными числами. Самое простое это фиксированная точка. Если грубо, то просто умножьте все ваши значения на 1000, и считайте в целых, а потом разделите. Ну правда это очень грубо, потому что надо умножать не на 1000, и делить на другие числа и за разрядностью следить...

 

или я не понял вопроса?

Вопрос Вы поняли верно. Мат аппарат для ПЛИС хотелось бы сделать с целыми числами дабы не лезть в область действительных... Если я вас правильно понял то все вычисления необходимо свести к умножению/ делению на 2^i чтобы просто перейти к сдвигам вправо/влево? По крайней мере такая идея в голову приходила.

 

Все было бы намного проще с использованием действительных чисел. Насколько знаю подобные конструкции несинтезируемы. Или возможно использование библиотек типа library IEEE_PROPOSED;

use IEEE_PROPOSED.fixed_float_types.all;?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

1. В некоторых плисах есть математически модули и не по одному, которые легко умножают, делят, накапливают и так далее..

2. Модуль АЛУ в процессорах все же не мифический модуль, а та же схема из лог элементов, которую можно собрать на ПЛИС. То есть если вашу ПЛИС обделили математическими модулями вам надо сделать свой сумматор и умножитель.

 

то что вытекает из 1 и 2, работать проще и быстрее с фиксированной точкой, тем более что у вас явное ограничение косинус не бывает больше 1. Но если очень хочется, то можно и на плавающую точку модуль сделать.

 

Естественно все синтезируется, допустим верилог прекрасно отрабатывает A * B, и даже если среда знает что в ПЛИС есть ДСП модули, подключает их автоматом.

 

 

Все вопрос уровня абстракции и количества свободных ресурсов вашей ПЛИС

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вопросы из любопытства

Зачем это Вам нужно?

чем CORDIC не устраивает?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

1. В некоторых плисах есть математически модули и не по одному, которые легко умножают, делят, накапливают и так далее..

2. Модуль АЛУ в процессорах все же не мифический модуль, а та же схема из лог элементов, которую можно собрать на ПЛИС. То есть если вашу ПЛИС обделили математическими модулями вам надо сделать свой сумматор и умножитель.

 

то что вытекает из 1 и 2, работать проще и быстрее с фиксированной точкой, тем более что у вас явное ограничение косинус не бывает больше 1. Но если очень хочется, то можно и на плавающую точку модуль сделать.

 

Естественно все синтезируется, допустим верилог прекрасно отрабатывает A * B, и даже если среда знает что в ПЛИС есть ДСП модули, подключает их автоматом.

 

 

Все вопрос уровня абстракции и количества свободных ресурсов вашей ПЛИС

Спасибо за совет. DSP блоки на кристалле есть, подхватываются при синтезе автоматом. Мат модель вычисления косинуса получилась (пока в MATLABе) для одной четверти периода. Часть алгоритма удалось привести к сдвигам, где то просто осталось умножение на постоянный коэффициент.

 

вопросы из любопытства

Зачем это Вам нужно?

чем CORDIC не устраивает?

 

CORDIC и Тейлора рассматривал в качестве альтернативе DDS, который неоднократно реализовывал. Стало интересно попробывать CORDIC и аппроксимацию Тейлором.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

CORDIC и Тейлора рассматривал в качестве альтернативе DDS, который неоднократно реализовывал. Стало интересно попробывать CORDIC и аппроксимацию Тейлором.

Вот и я тоже не понимаю, зачем все это... Сравнивать... Вы не назвали цель всего этого.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот и я тоже не понимаю, зачем все это... Сравнивать... Вы не назвали цель всего этого.

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

В проекте стал вопрос реализации опорного генератора нескольких частот. Изначально реализовать несколько DDS не представлялось возможным ввиду отсутствия свободных ресурсов по памяти. Поэтому рассматривал возможность реализации за счет вычислительных ресурсов. В итоге за счет оптимизации остальных алгоритмов проекта и его более детального осмысления проблем для реализации DDS не стало.

Любопытство насчет CORDIC и Тейлора осталось (ранее не касался данных вопросов ввиду незначительного опыта работы с ПЛИС). Хотелось увидеть математику в работе (а именно как реализуются транцендентные функции, представленные полиномами). Да и вращение вектора в магистратуре использовал при повороте системы координат, только не знал, что такое CORDIC, "цифра-за-цифрой"...

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если ДСП блоки есть, так и фигачьте ими в чем беда то?

 

вы арифметику с фиксированной точкой понимаете? Вот прям реально? Потому что в целом все понимают, а пока ручками 1 раз не проделаешь ничего не понятно...

 

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

 

один момент, умножитель надо 32 битный, а лучше 64 битный собрать, а то на 18 битном, том что сразу дается не очень удобно выходит.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня есть реализация косинуса, где четверть периода разбивается на 32 одинаковых кусочка и в пределах кусочка выполняется квадратичная интерполяция по коэффициентам, индивидуальным для каждого кусочка. Коэффициенты оптимизированы для получения минимального пикового отклонения, которое при идеальных вычислениях приводит к погрешности примерно +-5*10^-7. Всё считается на двух 18 битовых перемножителях, коэффициенты легко лезут в LUT, точность порядка 10^-6. В отличие от альтеровского DDS, не требуется блочная память, а считает точнее:).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...