Forum: FPGA, VHDL & Co. CORDIC in VHDL


von Benedict (Gast)


Lesenswert?

Hi! Ich versuche, einen Cordic Algorithmus in VHDL zu realisieren. Er 
soll später einmal für einen NCO eingesetzt werden. Also brauche ich die 
Sinus- und Cosinuswerte. Den Winkel nähert er gut an (also geht er auch 
in die richtigen Pfade) allerdings scheinen die shift and add 
Operationen nicht zu laufen. Auch den Cordic gain habe ich noch nicht 
rausgerechnet.

Kann mir vielleicht jemand helfen? Ich komme nicht mehr weiter.

Anmerkung: Für die meisten wird es wahrscheinlich sehr dilettantisch 
aussehen, aber ich code VHDL erst seit circa 2 Wochen...
1
LIBRARY ieee;
2
    USE ieee.std_logic_1164.all;
3
    USE ieee.std_logic_arith;
4
    USE ieee.std_logic_signed.all;
5
6
    
7
-- Eingang: Phase 12 Bits
8
-- Ausgang: sin cos 10 Bits
9
-- CORDIC Gain Konstante: 010011011011 ~=0.60725
10
11
12
ARCHITECTURE behaviour OF cordic IS
13
    signal costemp, sintemp, controlI,controlQ : std_logic_vector (9 DOWNTO 0);
14
    signal angle : std_logic_vector (breite-1 DOWNTO 0);
15
    signal count : std_logic_vector (3 DOWNTO 0);
16
    
17
    signal L : integer;
18
    signal operation : std_logic;
19
       
20
    BEGIN     
21
       
22
       PROCESS(clk,rst)
23
24
variable z, z_temp,data : std_logic_vector (breite-1 DOWNTO 0);
25
variable I_shift,Q_shift,I_temp,Q_temp,I,Q : std_logic_vector (9 DOWNTO 0);
26
27
            BEGIN
28
               IF (rst ='1') THEN
29
                  
30
                  -- Anfangswinkel einstellen
31
                  
32
                  IF (phase<"110000000000") THEN
33
                     angle<="110000000000";   -- auf  0 - j1
34
                     costemp<="0000000000";
35
                     sintemp<="1000000000";
36
                
37
                     
38
                  ELSIF (phase>"010000000000") THEN
39
                     angle<="010000000000";   -- auf  0 + j1
40
                     costemp<="0000000000";
41
                     sintemp<="0111111111";
42
               
43
                   ELSE
44
                     angle<="000000000000";   -- auf 1 + j0
45
                     costemp<="0111111111";
46
                     sintemp<="0000000000";
47
                  END IF;
48
                   
49
                  
50
                  count<="0000";
51
                  
52
                  ELSIF(clk'EVENT AND clk='1') THEN
53
                      
54
55
              
56
                     --------- Laden des nächsten Winkels
57
                     --------- shift Werte
58
                     
59
                     CASE count IS
60
                     WHEN "0000" => data := "001000000000"; -- 45.0000°
61
                                    I_shift:= (costemp(9) & costemp(9 DOWNTO 1));
62
                                    Q_shift:= (sintemp(9) & sintemp(9 DOWNTO 1));
63
                                    L<=1;
64
                     WHEN "0001" => data := "000100101110"; -- 26.5650°
65
                                    I_shift:= (costemp(9) & costemp(9) & costemp(9 DOWNTO 2));
66
                                    Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 2));
67
                                    L<=2;
68
                     WHEN "0010" => data := "000010011111"; -- 14.0362°
69
                                    I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 3));
70
                                    Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 3));
71
                                    L<=3;
72
                     WHEN "0011" => data := "000001010001"; --  7.1250°
73
                                    I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 4));
74
                                    Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 4));
75
                                    L<=4;
76
                     WHEN "0100" => data := "000000101000"; --  3.5763°
77
                                    I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 5));
78
                                    Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 5));
79
                                    L<=5;
80
                     WHEN "0101" => data := "000000010011"; --  1.7899°
81
                                    I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 6));
82
                                    Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 6));
83
                                    L<=6;
84
                     WHEN "0110" => data := "000000001010"; --  0.8951°
85
                                    I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 7));
86
                                    Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 7));
87
                                    L<=7;
88
                     WHEN "0111" => data := "000000000101"; --  0.4476°
89
                                    I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 8));
90
                                    Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 8));
91
                                    L<=8;
92
                     WHEN OTHERS => data := "000000000000";
93
                                    I_shift:= costemp;
94
                                    Q_shift:= sintemp;
95
                     END CASE;
96
                      
97
                     IF count = "1000" THEN
98
                            
99
                            -- vorher noch cordic gain!
100
                            
101
                            
102
                            
103
                            
104
                            cosout <= costemp;
105
                            sinout <= sintemp;
106
                      
107
                             ELSE
108
                            
109
                            I  := costemp;
110
                            Q  := sintemp;
111
                            z  := angle;
112
113
                               controlI<=I_shift;
114
                               controlQ<=Q_shift;
115
                               
116
                                IF((phase - z)>0)THEN
117
                           -- rotiere positiv
118
               
119
                           -- Ic_neu = Ic - (2^-L)·Qc
120
                           -- Qc_neu = Qc + (2^-L)·Ic
121
                           
122
                           -- addiere die I,Q Werte mit den geshifteten
123
                           -- gib es auf die Ausgänge
124
                           I_temp := I - Q_shift;
125
                           Q_temp := Q + I_shift;
126
                           z_temp:= z + data;
127
               
128
                           costemp<=I_temp;
129
                           sintemp<=Q_temp;
130
                           angle<=z_temp;
131
                           operation<='0';
132
               
133
                           ELSIF((phase - z)<0) THEN
134
                           -- rotiere negativ           
135
                           
136
                           -- Ic_neu = Ic + (2^-L)·Qc
137
                           -- Qc_neu = Qc - (2^-L)·Ic
138
                           
139
                           -- addiere die I,Q Werte mit den geshifteten
140
                           -- gib es auf die Ausgänge
141
                           
142
                           I_temp := I + Q_shift;
143
                           Q_temp := Q - I_shift;
144
                           z_temp:= z - data;
145
                           
146
                           costemp<=I_temp;
147
                           sintemp<=Q_temp;
148
                           angle<=z_temp;
149
                           operation <='1';
150
               
151
                           END IF;
152
                       count  <=    count + 1;
153
                  END IF;
154
        END IF;          
155
END PROCESS;
156
157
END behaviour;

von Duke Scarring (Gast)


Lesenswert?

Hast Du eine VHDL Testbench dazu? Sonst mag ich das gar nicht erst 
dem Simulator geben...


Duke

von Benedict (Gast)


Angehängte Dateien:

Lesenswert?

Danke für die Antwort!
Sowas?
1
LIBRARY ieee  ; 
2
USE ieee.std_logic_1164.all  ; 
3
USE ieee.std_logic_arith  ; 
4
USE ieee.std_logic_signed.all  ; 
5
ENTITY cordic_tb  IS 
6
  GENERIC (breite  : integer   := 12 ); 
7
END ; 
8
 
9
ARCHITECTURE cordic_tb_arch OF cordic_tb IS
10
  SIGNAL cosout   :  std_logic_vector (9 downto 0)  ; 
11
  SIGNAL rst   :  std_logic  ; 
12
  SIGNAL phase   :  std_logic_vector (breite - 1 downto 0)  ; 
13
  SIGNAL sinout   :  std_logic_vector (9 downto 0)  ; 
14
  SIGNAL clk   :  std_logic  ; 
15
  COMPONENT cordic  
16
    GENERIC ( 
17
      breite  : integer  );  
18
    PORT ( 
19
      cosout  : out std_logic_vector (9 downto 0) ; 
20
      rst  : in std_logic ; 
21
      phase  : in std_logic_vector (breite - 1 downto 0) ; 
22
      sinout  : out std_logic_vector (9 downto 0) ; 
23
      clk  : in std_logic ); 
24
  END COMPONENT ; 
25
BEGIN
26
  DUT  : cordic  
27
    GENERIC MAP ( 
28
      breite  => breite   )
29
    PORT MAP ( 
30
      cosout   => cosout  ,
31
      rst   => rst  ,
32
      phase   => phase  ,
33
      sinout   => sinout  ,
34
      clk   => clk   ) ; 
35
36
PROCESS
37
    BEGIN
38
        clk<='1';
39
        wait for 50 ns;
40
        clk<='0';
41
        wait for 50 ns;
42
END PROCESS;
43
44
PROCESS
45
    BEGIN
46
        rst<='1';
47
        wait for 20 ns;
48
        rst<='0';
49
        wait for 10000 ns;
50
END PROCESS;
51
52
PROCESS
53
    BEGIN
54
phase<="000101010101";
55
wait for 10000 ns;
56
END PROCESS;
57
58
END ;

von Benedict (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe gerade gelesen, dass man den CORDIC Gain damit kompensieren 
kann, indem man den Anfangswert der Vektorlänge auf den reziproken Wert 
setzt.

Also, statt 0 + j1 auf 0 + j0.607

Hier ist nochmal die source als Datei.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?


von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

@Benedict:

wichtiger Tipp: verwende numeric_std!
Sonst bekommst Du folgende Warnungen (und die sind noch harmlos, nutze 
die Suchfunktion!):
1
# vcom -work work -2002 cordic.vhd
2
# Model Technology ModelSim XE III vcom 6.2g Compiler 2007.02 Feb 22 2007
3
# -- Loading package standard
4
# -- Loading package std_logic_1164
5
# -- Loading package std_logic_arith
6
# -- Loading package std_logic_signed
7
# -- Compiling entity cordic
8
# -- Compiling architecture nochmal of cordic
9
# ** Error: cordic.vhd(48): Subprogram '<' is ambiguous. Suitable definitions exist in packages 'std_logic_1164' and 'std_logic_signed'.
10
# ** Error: cordic.vhd(48):    (Use the '-explicit' option to disable the previous error check.)
11
# ** Error: cordic.vhd(54): Subprogram '>' is ambiguous. Suitable definitions exist in packages 'std_logic_1164' and 'std_logic_signed'.
12
# ** Error: cordic.vhd(54):    (Use the '-explicit' option to disable the previous error check.)
13
# ** Error: cordic.vhd(113): Subprogram '=' is ambiguous. Suitable definitions exist in packages 'std_logic_1164' and 'std_logic_signed'.
14
# ** Error: cordic.vhd(113):    (Use the '-explicit' option to disable the previous error check.)
15
# ** Error: cordic.vhd(173): VHDL Compiler exiting

So. Jetzt hab ich erstmal eine compilierbare/lauffähige Version 
(Anhang). Was ist jetzt Dein Problem?

Duke

von Benedict (Gast)


Lesenswert?

Hallo!

Also, wenn ich statt USE ieee.std_logic_arith;    USE 
ieee.std_logic_signed.all; einfach das numeric verwende, kompiliert er 
bei mir nicht mehr...
1
# ** Error: /home/heyerben/cordic-beh-2.vhd(117): No feasible entries for infix operator "-".
2
# ** Error: /home/heyerben/cordic-beh-2.vhd(117): Bad expression in left operand of infix expression.
3
# ** Error: /home/heyerben/cordic-beh-2.vhd(117): Type error resolving infix expression ">" as type boolean.
4
# ** Error: /home/heyerben/cordic-beh-2.vhd(125): No feasible entries for infix operator "-".
5
# ** Error: /home/heyerben/cordic-beh-2.vhd(125): Bad right hand side (infix expression) in variable assignment.
6
# ** Error: /home/heyerben/cordic-beh-2.vhd(126): No feasible entries for infix operator "+".
7
# ** Error: /home/heyerben/cordic-beh-2.vhd(126): Bad right hand side (infix expression) in variable assignment.
8
# ** Error: /home/heyerben/cordic-beh-2.vhd(127): No feasible entries for infix operator "+".
9
# ** Error: /home/heyerben/cordic-beh-2.vhd(127): Bad right hand side (infix expression) in variable assignment.
10
# ** Error: /home/heyerben/cordic-beh-2.vhd(134): No feasible entries for infix operator "-".
11
# ** Error: /home/heyerben/cordic-beh-2.vhd(134): Bad expression in left operand of infix expression.
12
# ** Error: /home/heyerben/cordic-beh-2.vhd(134): Type error resolving infix expression "<" as type boolean.
13
# ** Error: /home/heyerben/cordic-beh-2.vhd(143): No feasible entries for infix operator "+".
14
# ** Error: /home/heyerben/cordic-beh-2.vhd(143): Bad right hand side (infix expression) in variable assignment.
15
# ** Error: /home/heyerben/cordic-beh-2.vhd(144): No feasible entries for infix operator "-".
16
# ** Error: /home/heyerben/cordic-beh-2.vhd(144): Bad right hand side (infix expression) in variable assignment.
17
# ** Error: /home/heyerben/cordic-beh-2.vhd(145): No feasible entries for infix operator "-".
18
# ** Error: /home/heyerben/cordic-beh-2.vhd(145): Bad right hand side (infix expression) in variable assignment.
19
# ** Error: /home/heyerben/cordic-beh-2.vhd(153): No feasible entries for infix operator "+".
20
# ** Error: /home/heyerben/cordic-beh-2.vhd(153): Type error resolving infix expression "+" as type std_logic_vector.
21
# ** Error: /home/heyerben/cordic-beh-2.vhd(158): VHDL Compiler exiting

Ich benutze ModelSim 6.1


Naja, mein Problem ist, dass er nicht die richtigen Sinus und 
Cosinuswerte ausgibt, wenn der Algorithmus durchgelaufen ist. Ich 
vermute, dass der Fehler in den Shiftings steckt, aber ich weiß nicht, 
wo.

Wie du vielleicht gesehen hast, nähert sich der Winkel schon an. 
("angle" ist annähernd gleich zu "phase", wenn das Programm 
durchgelaufen ist.)

Nur die Sinus- und Cosinuswerte werden anscheinend falsch aufaddiert

von Benedict (Gast)


Lesenswert?

Übrigens: In dem Code sind noch allerhand überflüssige Signale, die ich 
zur Fehlersuche eingebaut hatte. (controli, controlq, L, operation).

von Duke Scarring (Gast)


Lesenswert?

@Benedict:

Vesuch mal die Version aus meinem Anhang. Da habe ich die Datentypen 
angepasst.

Duke

von Benedict (Gast)


Lesenswert?

Achso, dankeschön!

Könntest du das vielleicht nochmal als Code hier im Forum schreiben, 
damit ich das als Copy-Paste einfügen kann? Ich arbeite über Remote 
Desktop und kann leider die Datei nicht einfügen...

von Benedict (Gast)


Lesenswert?

Ah sorry, habs doch mit nem "Word-Umweg" hinbekommen.

von Benedict (Gast)


Lesenswert?

Ich hab's hinbekommen :D Der Fehler war, dass ich die geshifteten Werte 
schon eine Iteration zu früh hinzuaddiert habe. Da musste noch ein 
ungeshifteter Wert hinzuaddiert werden. Naja, hier ist jedenfalls die 
funktionierende Version, als Inspiration für Leute, die auch an dem 
Problem hängen:
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.all;
3
USE ieee.numeric_std.all;
4
5
--------------------------------------------------------------    
6
--------------------- CORDIC Algorithmus ---------------------
7
--------------------------------------------------------------
8
--                                                          --
9
-- CORDIC Algorithmus zum Berechnen von Sinus- und          --
10
-- Cosinuswerten                                            --
11
--                                                          --
12
-- Geschrieben von: Benedict Heyer                          --
13
--                                                          --
14
-- Eingang: Phasenwert: 12 Bits                             --
15
-- 100000000000 = -180°                                     --
16
-- 011111111111 = 180° - (180° / 2048) = 179.9121094°       --
17
--                                                          --
18
-- => Schrittweite: 0.0878°                                 --
19
--                                                          --
20
-- Ausgang: sin und cos: 10 Bits                            --
21
-- reziproker Wert der CORDIC Gain Konstante                --
22
-- bei 7 Iterationen: 010011011011 ~=0.60725                --
23
--------------------------------------------------------------
24
--------------------------------------------------------------
25
--------------------------------------------------------------
26
27
28
ENTITY cordic IS
29
    
30
    GENERIC( breite : integer := 12);
31
    
32
    PORT( phase : IN signed (breite-1 DOWNTO 0);
33
          clk,rst : In std_logic;
34
          sinout, cosout : OUT signed(9 DOWNTO 0)
35
         );
36
        
37
   END cordic;
38
39
40
41
ARCHITECTURE behaviour OF cordic IS
42
signal costemp, sintemp : signed(9 DOWNTO 0);
43
signal angle : signed(breite-1 DOWNTO 0);
44
signal count : unsigned(3 DOWNTO 0);
45
  
46
BEGIN     
47
  
48
PROCESS(clk,rst)
49
50
variable z, z_temp,data : signed(breite-1 DOWNTO 0);
51
variable I_shift,Q_shift,I_temp,Q_temp,I,Q : signed(9 DOWNTO 0);
52
53
       BEGIN
54
          IF (rst ='1') THEN
55
             
56
             -- Anfangswinkel einstellen
57
             
58
             IF (phase<"110000000000") THEN
59
                angle<="110000000000";   -- eigentlich auf  0 - j1, aber durch
60
                costemp<="0000000000";   -- Kompensieren von cordic gain: 0+j0.607
61
                sintemp<="1011001010";   -- <--- wäre eigentlich -1
62
           
63
                
64
             ELSIF (phase>"010000000000") THEN
65
                angle<="010000000000";   -- eigentlich auf  0 + j1, aber durch
66
                costemp<="0000000000";   -- Kompensieren von cordic gain: 0+j0.607
67
                sintemp<="0100110110";   -- <--- wäre eigentlich +1
68
          
69
              ELSE
70
                angle<="000000000000";   -- auf 1 + j0
71
                costemp<="0100110110";   -- <--- wäre eigentlich +1
72
                sintemp<="0000000000";
73
             END IF;
74
              
75
             
76
             count<="0000";
77
             
78
             ELSIF(clk'EVENT AND clk='1') THEN
79
                 
80
81
         
82
                --------- Laden des nächsten Winkels
83
                --------- shift Werte
84
                
85
                CASE count IS
86
                
87
                WHEN "0000" => data := "001000000000"; -- 45.0000°
88
                               I_shift:= costemp;
89
                               Q_shift:= sintemp;
90
                               
91
                WHEN "0001" => data := "000100101110"; -- 26.5650°
92
                               I_shift:= (costemp(9) & costemp(9 DOWNTO 1));
93
                               Q_shift:= (sintemp(9) & sintemp(9 DOWNTO 1));
94
                               
95
                WHEN "0010" => data := "000010011111"; -- 14.0362°
96
                               I_shift:= (costemp(9) & costemp(9) & costemp(9 DOWNTO 2));
97
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 2));
98
                               
99
                WHEN "0011" => data := "000001010001"; --  7.1250°
100
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 3));
101
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 3));
102
                               
103
                WHEN "0100" => data := "000000101000"; --  3.5763°
104
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 4));
105
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 4));
106
                               
107
                WHEN "0101" => data := "000000010011"; --  1.7899°
108
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 5));
109
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 5));
110
                               
111
                WHEN "0110" => data := "000000001010"; --  0.8951°
112
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 6));
113
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 6));
114
                               
115
                WHEN "0111" => data := "000000000101"; --  0.4476°
116
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 7));
117
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 7));
118
                               
119
                
120
                WHEN OTHERS => data := "000000000000";
121
                               I_shift:= costemp;
122
                               Q_shift:= sintemp;
123
                END CASE;
124
                 
125
                IF count = "1000" THEN
126
                       
127
                       cosout <= costemp;
128
                       sinout <= sintemp;
129
                 
130
                        ELSE
131
                       
132
                          I  := costemp;
133
                          Q  := sintemp;
134
                          z  := angle;
135
                           
136
                          IF((phase - z)>0)THEN
137
                           -- rotiere positiv
138
                            
139
                           -- Ic_neu = Ic - (2^-L)?Qc
140
                           -- Qc_neu = Qc + (2^-L)?Ic
141
                      
142
                           -- addiere die I,Q Werte mit den geshifteten
143
                           -- gib es auf die Ausgänge
144
                           I_temp := I - Q_shift;
145
                           Q_temp := Q + I_shift;
146
                           z_temp:= z + data;
147
                            
148
                           costemp<=I_temp;
149
                           sintemp<=Q_temp;
150
                           angle<=z_temp;
151
                           
152
                           ELSIF((phase - z)<0) THEN
153
                           -- rotiere negativ           
154
                            
155
                           -- Ic_neu = Ic + (2^-L)?Qc
156
                           -- Qc_neu = Qc - (2^-L)?Ic
157
                            
158
                           -- addiere die I,Q Werte mit den geshifteten
159
                           -- gib es auf die Ausgänge
160
                            
161
                           I_temp := I + Q_shift;
162
                           Q_temp := Q - I_shift;
163
                           z_temp:= z - data;
164
                      
165
                           costemp<=I_temp;
166
                           sintemp<=Q_temp;
167
                           angle<=z_temp;
168
                            
169
                          END IF;
170
                          count  <=    count + 1;
171
                   END IF;                 -- count="1000" If-Clause
172
         END IF;                           -- clk,rst If-Clause
173
END PROCESS;
174
175
END behaviour;

von marcus (Gast)


Lesenswert?

Hallo,

ich bin gerade dabei den winkel zwischen einem cosinus und sinus signal 
aus einem resolver zu ermitteln, also genau das gegenstück zu diesem 
quellcode beispiel. hat da eventuell jemand einen satz für mich bzw. 
sogar den code. ich bin leider noch nicht hinter die funktionsweise des 
algorithmus gekommenen (mein englisch ist leider zu schlecht um die 
literatur zu verstehen)

danke schon einmal

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

marcus schrieb:
> Hallo,
>
> ich bin gerade dabei den winkel zwischen einem cosinus und sinus signal
> aus einem resolver zu ermitteln, also genau das gegenstück zu diesem
> quellcode beispiel. hat da eventuell jemand einen satz für mich bzw.
> sogar den code. ich bin leider noch nicht hinter die funktionsweise des
> algorithmus gekommenen (mein englisch ist leider zu schlecht um die
> literatur zu verstehen)
>
> danke schon einmal

Ein mathemaitscher Ansatz ist, das Sinus mit dem Cosinus Signal zu 
ermitteln. Dabei entsteht ein Signal mit der Doppelten Frequenz und dem 
Gleichanteil. Der Gleichanteil entspricht dem Winkel zwischen den 
Signalen. Die Doppelte Frequenz lässt sich mit einem Tiefpassfilter 
entfernen.

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Hallo Benedict
für 14 Tage VHDL sieht das schon ganz gut aus.
Ich habe keinen Simulator, jedoch habe ich versucht deinen Code zu 
verstehen.

Hinweise:
Der Name von RST ist unglücklich gewählt. Es ist besser "load" für diese 
Signal geeignet.

An Anfang des Prozesse prüfst du in welchen Quadranten dein Winkel 
liegt. Da sehe ich nur drei Quadranten. Es gibt aber vier Quadranten. 
Was ist mit dem Fall -1+j0?

Für das Schieben gibt es seit VHDL-93 die Befehle srl, sll, sra, sla
 shift (left, right) (logic, arithmetic).

Ansonsten viel Spaß mit VHDL

von Gast (Gast)


Lesenswert?

Koennte mir mal bitte jemand erklären, wie dieser Core angesteuert 
werden soll? Ich habe mir eine TB geschrieben, die den core antriggert 
und bekomme uach daten raus. Allerdings sind es immer dieselben. Ich 
sehe nicht, dass die Ergebnisse mitlaufen mit der eingespeisten phase.

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Ich habe das Teil nicht geschrieben, trotzdem kann ich dir es erklären.

Mit rst='1' wird die Phase(Winkel) geladen. Nachdem rst='0' wieder ist, 
werden mit jedem Takt der Cosinus- und Sinuswert genauer.

So sollte es sein ich habe schon bemerkt, dass rst hier als Namensgebung 
unglücklich gewählt ist.
Da ich keine Simulation habe, ist es interessant was hier rauskommt. 
Interessiert mich auch.

Bis bald.

von Benedict (Gast)


Angehängte Dateien:

Lesenswert?

Hi, Leute! Kam durch Zufall wieder hierhin, als ich nach was Anderem 
gesucht habe :D

Also, zuerst: slr und sll hatte ich mal probiert, ging aber nicht. Weiß 
nicht mehr, wieso :)

Zu den Quadranden: Der CORDIC kann von seinem Startpunkt +/- 90° 
ansteuern, von daher reichen drei Startpunkte, womit 2 Quadranten sogar 
doppelt angesteuert werden könnten.

Ich habe hier mal eine kleine Testbench angefügt, die auch Ergebnisse 
auspuckt. Die Ergebnisseder ModelSim Simulation habe ich als Bild 
angefügt.

TB:
1
LIBRARY ieee  ; 
2
USE ieee.std_logic_1164.all  ; 
3
USE ieee.std_logic_arith  ; 
4
USE ieee.std_logic_signed.all  ; 
5
ENTITY cordic_tb  IS 
6
  GENERIC (
7
    breite  : integer   := 12 ); 
8
END ; 
9
 
10
ARCHITECTURE cordic_tb_arch OF cordic_tb IS
11
  SIGNAL cosout   :  std_logic_vector (9 downto 0)  ; 
12
  SIGNAL rst   :  std_logic  ; 
13
  SIGNAL phase   :  std_logic_vector (breite - 1 downto 0):="000000000000"  ; 
14
  SIGNAL sinout   :  std_logic_vector (9 downto 0)  ; 
15
  SIGNAL clk   :  std_logic  ; 
16
  COMPONENT cordic  
17
    GENERIC ( 
18
      breite  : integer  );  
19
    PORT ( 
20
      cosout  : inout std_logic_vector (9 downto 0) ; 
21
      rst  : in std_logic ; 
22
      phase  : in std_logic_vector (breite - 1 downto 0) ; 
23
      sinout  : inout std_logic_vector (9 downto 0) ; 
24
      clk  : in std_logic ); 
25
  END COMPONENT ; 
26
BEGIN
27
  DUT  : cordic  
28
    GENERIC MAP ( 
29
      breite  => breite   )
30
    PORT MAP ( 
31
      cosout   => cosout  ,
32
      rst   => rst  ,
33
      phase   => phase  ,
34
      sinout   => sinout  ,
35
      clk   => clk   ) ; 
36
37
process
38
begin
39
    clk<='1';
40
    wait for 20 ns;
41
    clk<='0';
42
    wait for 20 ns;
43
end process;
44
45
process
46
begin
47
    rst<='1';
48
    wait for 50 ns;
49
    rst<='0';
50
    wait for 400 ns;
51
end process;
52
53
process
54
    begin
55
    phase <= phase + "000000100000";
56
    wait for 450 ns;
57
end process;
58
59
END ;

von Benedict (Gast)


Lesenswert?

Ach ja: Ich hatte damals noch eine kleine Änderung gemacht: Sollte das 
hier jemand ausprobieren, wird er sehen, dass der Wert vom Cosinus auf 
seinem Maximum einen Einknick hat. Das hatte mit dem Anfangswert zur 
CORDIC-Gain Kompensation zu tun. Da habe ich noch eine kleine Abfrage 
eingefügt (im Code unter dem shifting Teil):
1
IF count = "1000" THEN
2
                       
3
                       if(costemp = "0100110110" AND sintemp = "0000000000")then
4
                          cosout <= "0111111111";
5
                          sinout <= sintemp;
6
                       else
7
                          cosout <= costemp;
8
                          sinout <= sintemp;
9
                       end if;

von Gast (Gast)


Lesenswert?

Danke! das probiere ich gleich aus.

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Hallo Bendict,

wenn du hier angemeldest bist, kannst du einen Haken setzen bei E-Mail 
Benachrichtigung.

Dann bekommst du automatisch eine Email, wenn jemand hier antwortet.



Was baust du als nächstes?

Du hattes eine interessante Idee.

von Gast (Gast)


Lesenswert?

irgendwie ist das nicht komplett!

was ist z.B. mit dem Fall

ELSIF((phase - z)=0) THEN

der ist nicht formuliert

von Gast (Gast)


Lesenswert?

die testbench benutzt auch inout, passt also nicht

das hast du im leben nicht simuliert, denn dann hättest du das sofort 
gemerkt

von Gast (Gast)


Lesenswert?

ausserdem hat der core cordic die typen signed waehrend die testbench 
stdlogic verwendet

vielleicht postest du nochmal core und testbench komplett zueinnder 
passend

von Benedict (Gast)


Lesenswert?

TB
1
LIBRARY ieee  ; 
2
USE ieee.std_logic_1164.all  ; 
3
USE ieee.std_logic_arith  ; 
4
USE ieee.std_logic_signed.all  ; 
5
ENTITY cordic_tb  IS 
6
  GENERIC (
7
    breite  : integer   := 12 ); 
8
END ; 
9
 
10
ARCHITECTURE cordic_tb_arch OF cordic_tb IS
11
  SIGNAL cosout   :  std_logic_vector (9 downto 0)  ; 
12
  SIGNAL rst   :  std_logic  ; 
13
  SIGNAL phase   :  std_logic_vector (breite - 1 downto 0):="000000000000"  ; 
14
  SIGNAL sinout   :  std_logic_vector (9 downto 0)  ; 
15
  SIGNAL clk   :  std_logic  ; 
16
  COMPONENT cordic  
17
    GENERIC ( 
18
      breite  : integer  );  
19
    PORT ( 
20
      cosout  : inout std_logic_vector (9 downto 0) ; 
21
      rst  : in std_logic ; 
22
      phase  : in std_logic_vector (breite - 1 downto 0) ; 
23
      sinout  : inout std_logic_vector (9 downto 0) ; 
24
      clk  : in std_logic ); 
25
  END COMPONENT ; 
26
BEGIN
27
  DUT  : cordic  
28
    GENERIC MAP ( 
29
      breite  => breite   )
30
    PORT MAP ( 
31
      cosout   => cosout  ,
32
      rst   => rst  ,
33
      phase   => phase  ,
34
      sinout   => sinout  ,
35
      clk   => clk   ) ; 
36
37
process
38
begin
39
    clk<='1';
40
    wait for 20 ns;
41
    clk<='0';
42
    wait for 20 ns;
43
end process;
44
45
process
46
begin
47
    rst<='1';
48
    wait for 50 ns;
49
    rst<='0';
50
    wait for 400 ns;
51
end process;
52
53
process
54
    begin
55
    phase <= phase + "000000100000";
56
    wait for 450 ns;
57
end process;
58
59
END ;

Code
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.all;
3
USE ieee.std_logic_arith;
4
USE ieee.std_logic_signed.all;
5
    
6
7
ENTITY cordic IS
8
    
9
    GENERIC( breite : integer := 12);
10
    
11
    PORT( phase : IN std_logic_vector (breite-1 DOWNTO 0);
12
          clk,rst : In std_logic;
13
          sinout, cosout : INOUT std_logic_vector(9 DOWNTO 0)
14
         );
15
        
16
   END cordic;
17
18
ARCHITECTURE behaviour OF cordic IS
19
signal costemp, sintemp : std_logic_vector(9 DOWNTO 0);
20
signal angle : std_logic_vector(breite-1 DOWNTO 0);
21
signal count : std_logic_vector(3 DOWNTO 0);
22
 
23
begin 
24
PROCESS(clk,rst)
25
26
variable z, z_temp,data : std_logic_vector(breite-1 DOWNTO 0);
27
variable I_shift,Q_shift,I_temp,Q_temp,I,Q : std_logic_vector(9 DOWNTO 0);
28
29
       BEGIN
30
          IF (rst ='1') THEN
31
             
32
             -- Anfangswinkel einstellen
33
             
34
             IF (phase<"110000000000") THEN
35
                angle<="110000000000";   -- eigentlich auf  0 - j1, aber durch
36
                costemp<="0000000000";   -- Kompensieren von cordic gain: 0+j0.607
37
                sintemp<="1011001010";   -- <--- wäre eigentlich -1
38
           
39
                
40
             ELSIF (phase>"010000000000") THEN
41
                angle<="010000000000";   -- eigentlich auf  0 + j1, aber durch
42
                costemp<="0000000000";   -- Kompensieren von cordic gain: 0+j0.607
43
                sintemp<="0100110110";   -- <--- wäre eigentlich +1
44
          
45
              ELSE
46
                angle<="000000000000";   -- auf 1 + j0
47
                costemp<="0100110110";   -- <--- wäre eigentlich +1
48
                sintemp<="0000000000";
49
             END IF;
50
              
51
             
52
             count<="0000";
53
             
54
             ELSIF(clk'EVENT AND clk='1') THEN
55
                 
56
57
         
58
                --------- Laden des nächsten Winkels
59
                --------- shift Werte
60
                
61
                CASE count IS
62
                
63
                WHEN "0000" => data := "001000000000"; -- 45.0000°
64
                               I_shift:= costemp;
65
                               Q_shift:= sintemp;
66
                               
67
                WHEN "0001" => data := "000100101110"; -- 26.5650°
68
                               I_shift:= (costemp(9) & costemp(9 DOWNTO 1));
69
                               Q_shift:= (sintemp(9) & sintemp(9 DOWNTO 1));
70
                               
71
                WHEN "0010" => data := "000010011111"; -- 14.0362°
72
                               I_shift:= (costemp(9) & costemp(9) & costemp(9 DOWNTO 2));
73
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 2));
74
                               
75
                WHEN "0011" => data := "000001010001"; --  7.1250°
76
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 3));
77
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 3));
78
                               
79
                WHEN "0100" => data := "000000101000"; --  3.5763°
80
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 4));
81
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 4));
82
                               
83
                WHEN "0101" => data := "000000010011"; --  1.7899°
84
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 5));
85
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 5));
86
                               
87
                WHEN "0110" => data := "000000001010"; --  0.8951°
88
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 6));
89
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 6));
90
                               
91
                WHEN "0111" => data := "000000000101"; --  0.4476°
92
                               I_shift:= (costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9) & costemp(9 DOWNTO 7));
93
                               Q_shift:= (sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9) & sintemp(9 DOWNTO 7));
94
                               
95
                
96
                WHEN OTHERS => data := "000000000000";
97
                               I_shift:= costemp;
98
                               Q_shift:= sintemp;
99
                END CASE;
100
                 
101
                IF count = "1000" THEN
102
                       
103
                       if(costemp = "0100110110" AND sintemp = "0000000000")then
104
                          cosout <= "0111111111";
105
                          sinout <= sintemp;
106
                       else
107
                          cosout <= costemp;
108
                          sinout <= sintemp;
109
                       end if;
110
                 
111
                        ELSE
112
                       
113
                          I  := costemp;
114
                          Q  := sintemp;
115
                          z  := angle;
116
                           
117
                          IF((phase - z)>0)THEN
118
                           -- rotiere positiv
119
                            
120
                           -- Ic_neu = Ic - (2^-L)?Qc
121
                           -- Qc_neu = Qc + (2^-L)?Ic
122
                      
123
                           -- addiere die I,Q Werte mit den geshifteten
124
                           -- gib es auf die Ausgänge
125
                           I_temp := I - Q_shift;
126
                           Q_temp := Q + I_shift;
127
                           z_temp:= z + data;
128
                            
129
                           costemp<=I_temp;
130
                           sintemp<=Q_temp;
131
                           angle<=z_temp;
132
                           
133
                           ELSIF((phase - z)<0) THEN
134
                           -- rotiere negativ           
135
                            
136
                           -- Ic_neu = Ic + (2^-L)?Qc
137
                           -- Qc_neu = Qc - (2^-L)?Ic
138
                            
139
                           -- addiere die I,Q Werte mit den geshifteten
140
                           -- gib es auf die Ausgänge
141
                            
142
                           I_temp := I + Q_shift;
143
                           Q_temp := Q - I_shift;
144
                           z_temp:= z - data;
145
                      
146
                           costemp<=I_temp;
147
                           sintemp<=Q_temp;
148
                           angle<=z_temp;
149
                            
150
                          END IF;
151
                          count  <=    count + 1;
152
                   END IF;                 -- count="1000" If-Clause
153
         END IF;                           -- clk,rst If-Clause
154
END PROCESS;
155
156
157
END behaviour;

So funktioniert's.

Momentan arbeite ich an nem BPSK Demodulator. Um die Carrier Frequenz zu 
strippen, benutze ich aber nicht den CORDIC, da der viel zu viele 
Iterationen brauch und ich nicht auf eine genaue Phase angewiesen bin. 
Deswegen hab ichs mit Lookup realisiert.

Der CORDIC war sowieso nur zur Übung. Gibt es ja auch im Xilinx CoreGEN 
und der hat viel bessere Werte.

von CS (Gast)


Lesenswert?

Hallo,

kann jemand bitte erklären, woher die Binärzahlen kommen?

IF (phase<"110000000000") THEN
                angle<="110000000000";
                costemp<="0000000000";
                sintemp<="1011001010"; -- das hier?

und für jede Winkel

WHEN "0001" => data := "000100101110"; -- 26.5650°??
                I_shift:= (costemp(9) & costemp(9 DOWNTO 1));
                Q_shift:= (sintemp(9) & sintemp(9 DOWNTO 1));

Danke für die Hilfe

viele Grüsse

von berndl (Gast)


Lesenswert?

CS schrieb:
> IF (phase<"110000000000") THEN
>                 angle<="110000000000";
>                 costemp<="0000000000";
>                 sintemp<="1011001010"; -- das hier?
>
> und für jede Winkel
>
> WHEN "0001" => data := "000100101110"; -- 26.5650°??
>                 I_shift:= (costemp(9) & costemp(9 DOWNTO 1));
>                 Q_shift:= (sintemp(9) & sintemp(9 DOWNTO 1));

Hi,
kein Problem, bin an sowas auch seit 2 Tagen dran.

Oberer Teil:
Du selektierst den Quadranten in dem du dich gerade aufhaelst 
(phase(11:10)=00 ist 'rechts oben', 01 ist links oben und so weiter)

Das 'case' statement ist auch einfach: Das sind die Faelle fuer arctan 
1, 1/2, 1/4, 1/8, usw... Das ergibt halt bestimmte Winkel. Und die 
werden jeweils berechnet und addiert oder subtrahiert.

@originalposter: Dein Problem mit den Nullstellen/Uebergaengen kannst du 
ganz einfach loesen: Anstatt 'IF' und 'ELSIF' zu schreiben reicht es, 
anstatt ELSIF einfach ein ELSE zu verwenden. Die Sonderbehandlung geht 
dann naemlich automatisch.

Ausserdem ist der Code ziemlich grottig, sowas wuerde ich mich nicht 
abzuliefern trauen...

... Aber prinzipiell funktioniert es, also nicht schlecht

von Sigurt (Gast)


Lesenswert?

Ist es denn so schlimm, wenn der Code schlecht ist? Wird das nicht durch 
die Synthese gltt gebügelt?

von berndl (Gast)


Angehängte Dateien:

Lesenswert?

Hi, der Thread ist ja jahrealt mittlerweile. Aber ich habe damals den 
Code hier als Basis benutzt, ihn dann doch nicht benoetigt. Aber jetzt 
brauche ich ihn...

Hier mal als Anhang, was ich aus dem 'rotating' CORDIC gerade gemacht 
habe.

Ich habe den redundanten Code mal eingedampft, dabei das Timing deutlich 
verbessern koennen.

Ich bin deshalb wieder auf diesen alten Thread gestossen, weil ich jetzt 
was mit 'CORDIC vectoring mode' machen muss, also von per ADC gelesenen 
Sinuessen und Cosinuessen den Winkel berechnen... Deshalb hab' ich den 
alten 'CORDIC' hier nochmal ausgegraben. Die TB dreht nur den CORDIC 
kurz in positive Richtung, dann in negative Richtung. Bei 'sinout' und 
'cosout' sollte man also passende Signale finden...

Nur falls es jemanden hier interessiert...

von K. L. (Gast)


Lesenswert?

Ein thread von 2009 - wow, der Zombie lebt :-)

Finde ich aber gut, dass mal jemand ein Thema zum Abschluss bringt. Habe 
den thread abboniert, weil mich das auch interessiert. Ich bastle 
nämlich auch gerade mit CORDIC.

Läuft Deine Version denn so, wie oben gepostet?

von berndl (Gast)


Lesenswert?

im cordic.vhd muss noch was geaendert werden:
1
when "11" =>                           -- 270..360 degree, start with 270
2
   sintemp <= '1' & gainy_n; -- Signbit korrigiert
3
   costemp <= '0' & VAL_0;   -- Signbit korrigiert

von W.S. (Gast)


Lesenswert?

Klaus L. schrieb:
> Ein thread von 2009 - wow, der Zombie lebt :-)

Ja, ist auch dringend nötig.

Schau dich doch mal um, was es denn sonst so gibt. Firmen wie Xilinx 
haben in ihrem IP Portfolio zwar auch sowas, aber ohne Einblick in den 
echten Quellcode.

Und anderweitig sucht man sich die Augen wund, ohne wirklich was 
Brauchbares zu finden - es gibt nur Zeugs zuhauf, wo sich jemand "über" 
den CORDIC-Algo ausläßt, aber ohne ihn jemals tatsächlich konkret 
durchzuexerzieren. Das ist genau so wie z.B. das Gelaber über den 
DES-Algo, der ja auch seit langem veröffentlicht ist, aber auch (wie 
CORDIC) ohne daß es konkrete und zugleich verständliche (quasi 
"knuffige") Realisierungen gibt.

Natürlich kann man sich hinsetzen, das Ganze an den theoretischen 
Formeln durchackern und sich daraus seinen Code selbst schreiben. Jaja, 
das wäre die selbständigste Methode, aber gelegentlich sucht man einfach 
nur nach einer fertigen Teillösung, damit der Aufwand für ein Projekt 
noch vom Einzelnen stemmbar bleibt und man nicht bei Adam&Eva beginnen 
muß.

W.S.

von berndl (Gast)


Lesenswert?

Klaus L. schrieb:
> Läuft Deine Version denn so, wie oben gepostet?

ja, simuliert sowohl mit GHDL/Gtkwave als auch mit Modelsim. Und mit 
einem anderen cordic_top gebe ich ueber DACs die Ergebnisse aus, 
Plattform ist S3E und S6 von Xilinx sowie CycIII von Altera.

von K. L. (Gast)


Lesenswert?

Ich komme nochmal drauf zurück:

Läuft der Code korrekt? Liesse der sich als Basis nehmen, um ihn zu 
pipelinen und schneller zu machen?

Ich suche eine Lösung, die schneller ist, als die von Xilinx!

Der Core hat eine enorme Latenz!

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Die o.g. Schaltung läuft klassisch sequenziell. Kaum anzunehmen, dass es 
schneller ist, als der Core. Aus der Erinnerung benötigt der je Bit für 
die Genauigkeit eine weitereren zusätzlichen Takt.

von J. S. (engineer) Benutzerseite


Lesenswert?

Mir persönlich ist das native VHDL aber trotzdem symphatischer, weil Ich 
dann genau solche Dinge wie die Auflösung in der Hand habe. Außerdem 
lässt sich der Code für wenige Iterationstiefen auch parallelisieren und 
damit beschleunigen - wer's braucht. Das geht mit dem fertigen CORE 
nicht. Wie Ich an anderer Stelle beschrieben hatte, war es mal nötig den 
CORDIC durch einen schnellen, manuellen ARCTAN zu ersetzen:

Beitrag "Re: Implementierung eines schnellen ARCUS TANGENS"

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.