Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PID with fixed point numbers

Status
Not open for further replies.

mbago

Newbie level 3
Joined
Nov 19, 2014
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
56
Hello Everybody,
I made a PID controller modul in VHDL, but I have a problem with the integral part. I'm using sfixed datatype. The problem is with this part:

if(I>MAX_Range) then I<=MAX_Range;
elsif(I<MIN_Range) then I<=MIN_Range;
else I<=resize(Ki*error+I,16,-4);
end if;

All of the parameters are sfixed signals and constant. Ki=0.5 error=100

When I load into the FPGA it runs fine up to MAX_Range, but after that the value change to zero and stay zero instead of MAX_Range.
I can't find out what could be the problem. Does anyone have idea?

Thanks,
Marcell
 

If you want it to saturate at MAX_Range then just change the first line to:
Code:
if (I >= MAX_Range) then I <= MAX_Range;

Of course once it reaches MAX_Range it will never change, unless you add code to reset I to something else.

- - - Updated - - -

I also don't understand your usage of resize?

numeric_std only defines it for:
function RESIZE (ARG: SIGNED; NEW_SIZE: NATURAL) return SIGNED;
function RESIZE (ARG: UNSIGNED; NEW_SIZE: NATURAL) return UNSIGNED;

Oops, I see now that resize is overloaded in sfixed, nevermind.
 

If you want it to saturate at MAX_Range then just change the first line to:
Code:
if (I >= MAX_Range) then I <= MAX_Range;

Of course once it reaches MAX_Range it will never change, unless you add code to reset I to something else.

- - - Updated - - -

I also don't understand your usage of resize?

numeric_std only defines it for:
function RESIZE (ARG: SIGNED; NEW_SIZE: NATURAL) return SIGNED;
function RESIZE (ARG: UNSIGNED; NEW_SIZE: NATURAL) return UNSIGNED;

Oops, I see now that resize is overloaded in sfixed, nevermind.

Thanks for the reply in the test condition the error signal is constant. That means the integer of this constant will increase with time. Of course I can't let to increase infinitly that is why I use max value. Like in analog way the output of the opa is limited by the voltage supply. I can't saturated the signal in your way because when I use with the real system than the error will change and if I saturated this signal than it wil cause wrong control.
Regards,
Marcell
 

Thanks for the reply in the test condition the error signal is constant. That means the integer of this constant will increase with time. Of course I can't let to increase infinitly that is why I use max value. Like in analog way the output of the opa is limited by the voltage supply. I can't saturated the signal in your way because when I use with the real system than the error will change and if I saturated this signal than it wil cause wrong control.
Regards,
Marcell

Then your vague problem statement is to blame for my useless answer. State the problem with examples showing the error and the desired result for those same examples, either that or supply the testbench and the code showing the error and a detailed description of what you wanted the code to do instead.
 

I made a new code for testing. It contains only the PID modul and the dac modul for Digilent PMOD-DA2 (I use the official code from the website).
Here is the code of the PID:


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library ieee_proposed;
use ieee_proposed.fixed_pkg.all;
 
entity PID_Controller is
Port (
PCLK : in STD_LOGIC;
enable : in STD_LOGIC;
PRST : in STD_LOGIC;
PSEN : in integer range 0 to 3000;
PSET : in integer range 0 to 3000;
POUT : out STD_LOGIC_VECTOR(11 downto 0)
);
end PID_Controller;
 
architecture Behavioral of PID_Controller is
;
signal error:sfixed(12 downto 0):=(others=>'0');
signal proportional:sfixed(16 downto 0):=(others=>'0');
signal integral:sfixed(16 downto -4):=(others=>'0');
signal derivative:sfixed(16 downto 0):=(others=>'0');
signal actuator:sfixed(16 downto -4):=(others=>'0');
 
begin
 
sub:process(PCLK,enable,PRST)
begin
if rising_edge(PCLK) then
if(enable='1') then
if(PRST='0') then error<=(others=>'0');
else error<=To_sfixed(PSEN-PSET,12,0);
end if;
end if;
end if;
end process;
 
Prop:process(PCLK,enable,PRST,error)
variable P:sfixed(16 downto 0):=(others=>'0');
constant Kp:sfixed(4 downto 0):="00010";
constant Max_P:sfixed(16 downto 0):="01111111111110000";
constant Min_P:sfixed(16 downto 0):="10000000000010000";
begin
if rising_edge(PCLK) then
if(enable='1') then
if(PRST='0') then P:=(others=>'0');
else
if(P>Max_P) then P:=Max_P;
elsif(P<Min_P) then P:=Min_P;
else P:=resize(Kp*error,16,0);
end if;
end if;
proportional<=P;
end if;
end if;
end process;
 
Int:process(PCLK,enable,PRST,error)
--0,0.5,0.25,0.125,0.0625
constant Ki:sfixed(0 downto -4):="00001";
constant Max_I:sfixed(16 downto -4):="011111111111100000000";
constant Min_I:sfixed(16 downto -4):="111110000000000010000";
variable I:sfixed(16 downto -4):=(others=>'0');
begin
if rising_edge(PCLK) then
if(enable='1') then
if(PRST='0') then I:=(others=>'0'); 
else
if(I>Max_I) then I:=Max_I;
elsif(I<Min_I) then I:=Min_I;
else I:=resize(Ki*error+I,16,-4);
end if;
end if;
integral<=I;
end if;
end if;
end process;
 
Der:process(PCLK,enable,PRST,error)
constant Kd:sfixed(6 downto 0):="0000010";
constant Max_D:sfixed(16 downto 0):="01111111111110000";
constant Min_D:sfixed(16 downto 0):="10000000000010000";
variable D:sfixed(16 downto 0):=(others=>'0');
variable D_old,D_new:sfixed(12 downto 0):=(others=>'0');
begin
if rising_edge(PCLK) then
if(enable='1') then
if(PRST='0') then D:=(others=>'0'); D_old:=(others=>'0'); D_new:=(others=>'0');
else
if(D>Max_D) then D:=Max_D;
elsif(D<Min_D) then D:=Min_D;
else 
 
D_new:=error;
D:=resize(Kd*(D_new-D_old),16,0);
D_old:=D_new;
 
end if;
end if;
derivative<=D;
end if;
end if;
end process;
 
Sum:process(PCLK,enable,PRST,proportional,integral,derivative)
constant Max_U:sfixed(16 downto -4):="011111111111100000000";
variable U:sfixed(16 downto -4):=(others=>'0');
begin
if rising_edge(PCLK) then
if(enable='1') then
if(PRST='0') then U:=(others=>'0');
else
if(proportional+integral+derivative>Max_U) then U:=Max_U;
elsif(proportional+integral+derivative<0) then U:=(others=>'0');
else U:=resize(proportional+integral+derivative,16,-4);
end if;
end if;
actuator<=U;
end if;
end if;
end process;
 
scale:process(PCLK,enable,PRST,actuator)
constant unit:sfixed(0 downto -4):="00001";
variable tmp:integer range 0 to 4095:=0;
begin
if rising_edge(PCLK) then
if(enable='1') then
if(PRST='0') then POUT<=(others=>'0');
else tmp:=to_integer(actuator*unit);
end if;
POUT<=std_logic_vector(to_unsigned(tmp,POUT'length));
end if;
end if;
 
end process;
end Behavioral;



Here is the simulation:
simulation.jpg

The error is constant at the moment so I would like to see that the output is rising till the max level and then hold that value. In the simulation I can see this (last signal dacInput). But in practice the voltage rising till 3.2V and after that change to 0V.
I can't see the dac parameters in the simulation so I only know that the input is correct for the dac. I tried to set the input of the dac to the max level with a constant and then it worked.

regards,
Marcell
 
Last edited by a moderator:

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top