andreichk 0 18 апреля, 2011 Опубликовано 18 апреля, 2011 · Жалоба закоментируйте один выход (reg) дело не в том, что я не догадался закоментировать один из выходов, а в том, что он не влазит в мой ПЛИС из за нехватки макроячеек, я об этом написал.Поэтому и спросил про такой же ,но попроще. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
PDA 0 18 апреля, 2011 Опубликовано 18 апреля, 2011 (изменено) · Жалоба `timescale 1ns / 1ps module sin( input clock, // input clock output [15:0] sin, // sin output: signed, 16-bit output [15:0] cos // cos output: signed, 16-bit ); parameter width = 16; parameter InitCos = 32640; reg [width-1:0] sin1 = 0; reg [width-1:0] cos1 = InitCos; always @(posedge clock) begin sin1 <= sin; cos1 <= cos; end //the computator assign sin = sin1 + {{7{cos1[15]}}, cos1[15:7]}; assign cos = cos1 - {{7{sin[15]}}, sin[15:7]}; endmodule отмоделируйте. даёт отменный синус без всяких таблиц. :) объясните, почему это работает? ртл схематик + попытался переписать на VHDL library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity top is port( CLK: in std_logic; SIN_OUT: out std_logic_vector(15 downto 0); COS_OUT: out std_logic_vector(15 downto 0) ); end top; architecture Behavioral of top is constant width: integer := 16; constant InitCos: integer := 32640; signal sin : std_logic_vector(width - 1 downto 0):= CONV_STD_LOGIC_VECTOR(0,width); signal cos : std_logic_vector(width - 1 downto 0):= CONV_STD_LOGIC_VECTOR(0,width); signal sin1 : std_logic_vector(width - 1 downto 0):= CONV_STD_LOGIC_VECTOR(0,width); signal cos1 : std_logic_vector(width - 1 downto 0):= CONV_STD_LOGIC_VECTOR(InitCos,width); begin process(CLK) begin SIN_OUT <= sin; COS_OUT <= cos; if rising_edge(CLK) then sin1 <= sin; cos1 <= cos; end if; sin <= sin1 + (cos1(15) & cos1(15) & cos1(15) & cos1(15) & cos1(15) & cos1(15) & cos1(15) & cos1(15 downto 7)); cos <= cos1 - (sin(15) & sin(15) & sin(15) & sin(15) & sin(15) & sin(15) & sin(15) & sin(15 downto 7)); end process; end Behavioral; результат отличается - синусоида ломанная, как-будто при генерации ломается знак. Я правильно переписал на VHDL строки assign sin = sin1 + {{7{cos1[15]}}, cos1[15:7]}; ? Изменено 18 апреля, 2011 пользователем PDA Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба В принципе все коеффициенты для синусоиды можно "засунуть" в блочную память, а потом считывать (это обычный счетчик :)), а не хранить на распределенной логике. Возможно тогда произойдет уменьшение ресурсов. Сколько точек на период Вам необходимо? Или по другому какая точность/дискретизация получения синусоиды нужна? Какая ПЛИС у Вас? кстати здесь, рассмотрен способ построения генератора на основе мат. формулы - там это подробно расписано. Как перейти с 8 бит на 16 бит или на 32 бита - это мне не понятно? to PDA возможно это то что Вы хотели получить .... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andreichk 0 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба В принципе все коеффициенты для синусоиды можно "засунуть" в блочную память, а потом считывать (это обычный счетчик :)), а не хранить на распределенной логике. Возможно тогда произойдет уменьшение ресурсов. Сколько точек на период Вам необходимо? Или по другому какая точность/дискретизация получения синусоиды нужна? Какая ПЛИС у Вас? у меня ПЛИС XC9572 44 пина. Если схема , которую PDA привёл правильная, то она в эту плиску не влазит. Тогда я попробовал заменить все 16 битные элементы на 8 битные, после некоторых манипуляций на выходе получился треугольник , но не с ровными гранями , а по фронту немного с изгибом в одну сторону, а по спаду в другую. Синусом там и не пахнет. Косинусную часть тоже пришлось отрезать. а вот такой код заработал сходу `timescale 1 ns / 1 ps //{module {sin_generator}} module sin_generator ( clk,out ); output [15:0] out; reg [15:0] out; input clk; wire clk; reg [15:0] sin_90 = 32768; reg [15:0] sin_101_25 = 39160; reg [15:0] sin_112_5 = 45307; reg [15:0] sin_123_75 = 50972; reg [15:0] sin_135 = 55938; reg [15:0] sin_146_25 = 60013; reg [15:0] sin_157_5 = 63041; reg [15:0] sin_168_75 = 65005; reg [15:0] sin_180 = 65535;//16'b1111_1111_1111_1111; reg [15:0] sin_191_25 = 64905; reg [15:0] sin_202_5 = 63041; reg [15:0] sin_213_75 = 60013; reg [15:0] sin_225 = 55938; reg [15:0] sin_236_25 = 50972; reg [15:0] sin_247_5 = 45307; reg [15:0] sin_258_75 = 39160; reg [15:0] sin_270 = 32768; reg [15:0] sin_281_25 = 26375; reg [15:0] sin_292_5 = 20228; reg [15:0] sin_303_75 = 14563; reg [15:0] sin_315 = 9597; reg [15:0] sin_326_25 = 5522; reg [15:0] sin_337_5 = 2494; reg [15:0] sin_348_75 = 982; reg [15:0] sin_0 = 2; //16'b0000_0000_0000_0010; reg [15:0] sin_11_25 = 942; reg [15:0] sin_22_5 = 2494; reg [15:0] sin_33_75 = 5522; reg [15:0] sin_45 = 9597; reg [15:0] sin_56_25 = 14563; reg [15:0] sin_67_5 = 20228; reg [15:0] sin_78_75 = 26375; // Binary counter, 5-bits wide reg [4:0] counter = 5'b0000; always @(posedge clk) counter <= counter + 1; always @(posedge clk) case(counter) 5'b00000:out<=sin_0; 5'b00001:out<=sin_11_25; 5'b00010:out<=sin_22_5; 5'b00011:out<=sin_33_75; 5'b00100:out<=sin_45; 5'b00101:out<=sin_56_25; 5'b00110:out<=sin_67_5; 5'b00111:out<=sin_78_75; 5'b01000:out<=sin_90; 5'b01001:out<=sin_101_25; 5'b01010:out<=sin_112_5; 5'b01011:out<=sin_123_75; 5'b01100:out<=sin_135; 5'b01101:out<=sin_146_25; 5'b01110:out<=sin_157_5; 5'b01111:out<=sin_168_75; 5'b10000:out<=sin_180; 5'b10001:out<=sin_191_25; 5'b10010:out<=sin_202_5; 5'b10011:out<=sin_213_75; 5'b10100:out<=sin_225; 5'b10101:out<=sin_236_25; 5'b10110:out<=sin_247_5; 5'b10111:out<=sin_258_75; 5'b11000:out<=sin_270; 5'b11001:out<=sin_281_25; 5'b11010:out<=sin_292_5; 5'b11011:out<=sin_303_75; 5'b11100:out<=sin_315; 5'b11101:out<=sin_326_25; 5'b11110:out<=sin_337_5; 5'b11111:out<=sin_348_75; default:; endcase endmodule немного значения подшаманили , макушки и ямки сравняли и получился нормальный синус, фотки я приводил . Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба кстати здесь, рассмотрен способ построения генератора на основе мат. формулы - там это подробно расписано. Вообще-то по cсылке код не совсем корректный, тк согласно алгоритму sin и cos сдвинуты отностительно друг-друга на полтакта --> доп. ошибка в модуле sqrt(sin^2+cos^2)). Пример более честного алгоритма: module gen( input clk, output reg [10:0] s = 8, output reg [10:0] c = 970 ); wire [10:0] cc = c - {s[10],s[10],s[10],s[10],s[10:4]}; wire [10:0] ss = s + {c[10],c[10],c[10],c[10],c[10:4]}; always @(posedge clk) begin s <= s + {cc[10],cc[10],cc[10],cc[10:3]}; c <= c - {ss[10],ss[10],ss[10],ss[10:3]}; end endmodule Большую точность можно получить, если сдвиг заменить целочисленным делением (еще лучше, если с округлением), см пример: 1 >> 10 = 0 -1 >> 10 = -1 -1 div 1024 = 0 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
PDA 0 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба на основании чего берутся значения инициализации синуса и косинуса? output reg [10:0] s = 8, output reg [10:0] c = 970 output [15:0] sin, // sin output: signed, 16-bit output [15:0] cos // cos output: signed, 16-bit ); parameter width = 16; parameter InitCos = 32640; reg [width-1:0] sin1 = 0; reg [width-1:0] cos1 = InitCos; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба Свои взял методом тыка - программой перебора (пишется ~5 минут, перебирает ~5 секунд). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба Вообще-то по cсылке код не совсем корректный, тк согласно алгоритму sin и cos сдвинуты отностительно друг-друга на полтакта --> доп. ошибка в модуле sqrt(sin^2+cos^2)). Пример более честного алгоритма: module gen( input clk, output reg [10:0] s = 8, output reg [10:0] c = 970 ); wire [10:0] cc = c - {s[10],s[10],s[10],s[10],s[10:4]}; wire [10:0] ss = s + {c[10],c[10],c[10],c[10],c[10:4]}; always @(posedge clk) begin s <= s + {cc[10],cc[10],cc[10],cc[10:3]}; c <= c - {ss[10],ss[10],ss[10],ss[10:3]}; end endmodule Большую точность можно получить, если сдвиг заменить целочисленным делением (еще лучше, если с округлением), см пример: 1 >> 10 = 0 -1 >> 10 = -1 -1 div 1024 = 0 а можно ссылку на мат. часть почитать хочу. Просто интересно как Вы перешли с 16 бит на 11 бит? Откуда эти формулы? Просто не понимаю :( Свои взял методом тыка - программой перебора (пишется ~5 минут, перебирает ~5 секунд). а можно эту программу? ;) Или если не сложно поясните ее работу, плиз. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба Откуда эти формулы? Из головы. Интерполяция по первой и второй производной. а можно эту программу? Вообще-то можно, но непричесанные не люблю выкладывать. Так что позже, если получится. Там просто цикл по начальным значениям, и оценка разброса модуля вектора. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба #include <math.h> main(){ long s0, s, ss, c0, c, cc, i, d, m, max, min; long s1 = -100; long s2 = 100; long c1 = 500; long c2 = 1000; long imax=10000; // s0 = 35; // c0 = 504; for(c0=c1; c0<=c2; c0++) for(s0=s1; s0<=s2; s0++) { s=s0; c=c0; max=0; min=1000000000; for(i=0; i<=imax; i++) { // m = (long)sqrt((double)(s*s + c*c)); // printf("i=%5d s=%4d c=%4d m=%d\n",i,s,c,m); d=s*s+c*c; if(d<min) min=d; if(d>max) max=d; cc = c - (s >> 4); ss = s + (c >> 4); s = s + (cc >> 3); c = c - (ss >> 3); } d = (long)sqrt((double)max) - (long)sqrt((double)min); if(d<=20) { for(i=0; i<d; i++) printf("*"); printf("%d",d); for(i=d; i<40; i++) printf("."); printf(" %d, %d\n",s0,c0); } } } Вывод в файл назначать, конечно. Кстати, можно заменить арифметический сдвиг на целочисленное деление, и посмотреть, насколько увеличится достижимая точность ;) : cc = c - (s / 16); ss = s + (c / 16); s = s + (cc / 8); c = c - (ss / 8); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба Не вижу в программе Leka синуса. Расскажите, как эта программа работает. А, что-то типа радиуса окружности вычисляете? P.S. имел в виду "в последней программе, проверочной" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 19 апреля, 2011 Опубликовано 19 апреля, 2011 · Жалоба s - синус c - косинус Как работает - интерполяция по первой и второй производной: y(dx) = y(0) + y'(0) * dx + 1/2 * y"(0) * dx^2, расписываете и получаете, в данном случае шаг dx = 1/(1 << n). Конкретно синус-косинус для выбранных начальных условий, например: main(){ long s, ss, c, cc, i, imax; s = 35; c = 504; imax = 100; for(i=0; i<=imax; i++) { printf("i=%4d sin=%4d cos=%4d \n",i,s,c); cc = c - (s >> 4); ss = s + (c >> 4); s = s + (cc >> 3); c = c - (ss >> 3); } } А предыдущая - для поиска начальных условий. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться