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

Цифровая "синусойда"

закоментируйте один выход (reg)

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

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


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

`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]}; ?

post-53001-1303130449_thumb.png

Изменено пользователем PDA

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


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

В принципе все коеффициенты для синусоиды можно "засунуть" в блочную память, а потом считывать (это обычный счетчик :)), а не хранить на распределенной логике. Возможно тогда произойдет уменьшение ресурсов. Сколько точек на период Вам необходимо? Или по другому какая точность/дискретизация получения синусоиды нужна? Какая ПЛИС у Вас?

 

кстати здесь, рассмотрен способ построения генератора на основе мат. формулы - там это подробно расписано. Как перейти с 8 бит на 16 бит или на 32 бита - это мне не понятно?

 

to PDA возможно это то что Вы хотели получить ....

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


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

В принципе все коеффициенты для синусоиды можно "засунуть" в блочную память, а потом считывать (это обычный счетчик :)), а не хранить на распределенной логике. Возможно тогда произойдет уменьшение ресурсов. Сколько точек на период Вам необходимо? Или по другому какая точность/дискретизация получения синусоиды нужна? Какая ПЛИС у Вас?

у меня ПЛИС 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

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

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


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

кстати здесь, рассмотрен способ построения генератора на основе мат. формулы - там это подробно расписано.

Вообще-то по 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

 

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


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

на основании чего берутся значения инициализации синуса и косинуса?

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;

 

 

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


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

Свои взял методом тыка - программой перебора (пишется ~5 минут, перебирает ~5 секунд).

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


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

Вообще-то по 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 секунд).

а можно эту программу? ;) Или если не сложно поясните ее работу, плиз.

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


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

Откуда эти формулы?

Из головы. Интерполяция по первой и второй производной.

 

а можно эту программу?

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

 

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


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

#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);

 

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


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

Не вижу в программе Leka синуса.

Расскажите, как эта программа работает.

А, что-то типа радиуса окружности вычисляете?

 

P.S. имел в виду "в последней программе, проверочной"

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


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

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); 
        }
}

 

А предыдущая - для поиска начальных условий.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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