11export pid, pid_tf, pid_ss, pid_2dof, pid_ss_2dof, pidplots, leadlink, laglink, leadlinkat, leadlinkcurve, stabregionPID, loopshapingPI, placePI, loopshapingPID
22
33"""
4- C = pid(param_p, param_i, [param_d]; form=:standard, state_space=false, [Tf], [Ts])
4+ C = pid(param_p, param_i, [param_d]; form=:standard, state_space=false, [Tf], [Ts], filter_order=2 )
55
66Calculates and returns a PID controller.
77
@@ -13,11 +13,14 @@ The `form` can be chosen as one of the following (determines how the arguments `
1313If `state_space` is set to `true`, either `Kd` has to be zero
1414or a positive `Tf` has to be provided for creating a filter on
1515the input to allow for a state-space realization.
16- The filter used is `1 / (1 + s*Tf + (s*Tf)^2/2)`, where `Tf` can typically
17- be chosen as `Ti/N` for a PI controller and `Td/N` for a PID controller,
16+
17+ The filter used is either
18+ - `filter_order = 2` (default): `1 / (1 + s*Tf + (s*Tf)^2/2)` in series with the controller
19+ - `filter_order = 1`: `1 / (1 + s*Tf)` applied to the derivative term only
20+
21+ `Tf` can typically be chosen as `Ti/N` for a PI controller and `Td/N` for a PID controller,
1822and `N` is commonly in the range 2 to 20.
19- A balanced state-space realization is returned, unless `balance = false`
20- in which case a controllable canonical form is used.
23+ A balanced state-space realization is returned, unless `balance = false`.
2124
2225For a discrete controller a positive `Ts` can be supplied.
2326In this case, the continuous-time controller is discretized using the Tustin method.
@@ -32,11 +35,11 @@ C3 = pid(2., 3, 0; Ts=0.4, state_space=true) # Discrete
3235The functions `pid_tf` and `pid_ss` are also exported. They take the same parameters
3336and is what is actually called in `pid` based on the `state_space` parameter.
3437"""
35- function pid (param_p, param_i, param_d= zero (typeof (param_p)); form= :standard , Ts= nothing , Tf= nothing , state_space= false , balance= true )
38+ function pid (param_p, param_i, param_d= zero (typeof (param_p)); form= :standard , Ts= nothing , Tf= nothing , state_space= false , balance= true , filter_order = 2 )
3639 C = if state_space # Type instability? Can it be fixed easily, does it matter?
37- pid_ss (param_p, param_i, param_d; form, Tf, balance)
40+ pid_ss (param_p, param_i, param_d; form, Tf, filter_order, balance)
3841 else
39- pid_tf (param_p, param_i, param_d; form, Tf)
42+ pid_tf (param_p, param_i, param_d; form, Tf, filter_order )
4043 end
4144 if Ts === nothing
4245 return C
4851
4952@deprecate pid (; kp= 0 , ki= 0 , kd= 0 , series = false ) pid (kp, ki, kd; form= series ? :series : :parallel )
5053
51- function pid_tf (param_p, param_i, param_d= zero (typeof (param_p)); form= :standard , Tf= nothing )
54+ function pid_tf (param_p, param_i, param_d= zero (typeof (param_p)); form= :standard , Tf= nothing , filter_order = 2 )
5255 Kp, Ki, Kd = convert_pidparams_to_parallel (param_p, param_i, param_d, form)
53- if isnothing (Tf)
54- if Ki != 0
55- return tf ([Kd, Kp, Ki], [1 , 0 ])
56- else
56+ filter_order ∈ (1 ,2 ) || throw (ArgumentError (" Filter order must be 1 or 2" ))
57+ if isnothing (Tf) || (Kd == 0 && filter_order == 1 )
58+ if Ki == 0
5759 return tf ([Kd, Kp], [1 ])
60+ else
61+ return tf ([Kd, Kp, Ki], [1 , 0 ])
5862 end
5963 else
60- if Ki != 0
61- return tf ([Kd, Kp, Ki], [Tf^ 2 / 2 , Tf, 1 , 0 ])
64+ if Ki == 0
65+ if filter_order == 1
66+ tf ([Kd* Tf + Kd, Kd], [Tf, 1 ])
67+ else
68+ return tf ([Kd, Kp], [Tf^ 2 / 2 , Tf, 1 ])
69+ end
6270 else
63- return tf ([Kd, Kp], [Tf^ 2 / 2 , Tf, 1 ])
71+ if filter_order == 1
72+ return tf ([Kd + Kp* Tf, Ki* Tf + Kp, Ki], [Tf, 1 , 0 ])
73+ else
74+ return tf ([Kd, Kp, Ki], [Tf^ 2 / 2 , Tf, 1 , 0 ])
75+ end
6476 end
6577 end
6678end
6779
68- function pid_ss (param_p, param_i, param_d= zero (typeof (param_p)); form= :standard , Tf= nothing , balance= true )
80+ function pid_ss (param_p, param_i, param_d= zero (typeof (param_p)); form= :standard , Tf= nothing , balance= true , filter_order )
6981 Kp, Ki, Kd = convert_pidparams_to_parallel (param_p, param_i, param_d, form)
7082 if ! isnothing (Tf)
71- if Ki != 0
72- A = [0 1 0 ; 0 0 1 ; 0 - 2 / Tf^ 2 - 2 / Tf]
73- B = [0 ; 0 ; 1 ]
74- C = 2 / Tf^ 2 * [Ki Kp Kd]
83+ if Ki == 0
84+ if filter_order == 1
85+ A = [- 1 / Tf;;]
86+ B = [- Kd/ Tf^ 2 ]
87+ C = [1.0 ;;]
88+ D = [Kd/ Tf + Kp;;]
89+ else # 2
90+ A = [0 1 ; - 2 / Tf^ 2 - 2 / Tf]
91+ B = [0 ; 1 ]
92+ C = 2 / Tf^ 2 * [Kp Kd]
93+ D = [0.0 ;;]
94+ end
7595 else
76- A = [0 1 ; - 2 / Tf^ 2 - 2 / Tf]
77- B = [0 ; 1 ]
78- C = 2 / Tf^ 2 * [Kp Kd]
96+ if filter_order == 1
97+ A = [0 0 ; 0 - 1 / Tf]
98+ B = [Ki; - Kd/ Tf^ 2 ]
99+ C = [1.0 1 ]
100+ D = [Kd/ Tf + Kp;;]
101+ else # 2
102+ A = [0 1 0 ; 0 0 1 ; 0 - 2 / Tf^ 2 - 2 / Tf]
103+ B = [0 ; 0 ; 1 ]
104+ C = 2 / Tf^ 2 * [Ki Kp Kd]
105+ D = [0.0 ;;]
106+ end
79107 end
80- D = 0
81108 elseif Kd == 0
82109 if Ki != 0
83- A = 0
84- B = 1
85- C = Ki # Ti == 0 would result in division by zero, but typically indicates that the user wants no integral action
86- D = Kp
110+ A = [ 0.0 ;;]
111+ B = [ 1.0 ;;]
112+ C = [Ki;;] # Ti == 0 would result in division by zero, but typically indicates that the user wants no integral action
113+ D = [Kp;;]
87114 else
88115 return ss ([Kp])
89116 end
@@ -155,13 +182,12 @@ function pid_ss_2dof(param_p, param_i, param_d=zero(typeof(param_p)); form=:stan
155182 A = [- (1 / Tf);;]
156183 B = [- kd* c/ (Tf^ 2 ) kd/ (Tf^ 2 )]
157184 C = [1.0 ]
158- D = [kd* c/ Tf+ kp* b - (kd/ Tf + kp)]
159185 else
160186 A = [0 0 ; 0 - (1 / Tf)]
161187 B = [ki - ki; - kd* c/ Tf^ 2 kd/ Tf^ 2 ]
162188 C = [1.0 1 ]
163- D = [kd* c/ Tf+ kp* b - (kd/ Tf + kp)]
164189 end
190+ D = [kd* c/ Tf+ kp* b - (kd/ Tf + kp)]
165191 K = ss (A, B, C, D)
166192 balance ? first (balance_statespace (K)) : K
167193end
@@ -229,7 +255,7 @@ function pidplots(P::LTISystem, args...;
229255 pzmap (Ts; title= " Pole-zero map" , kwargs... ) |> display
230256 end
231257 if :controller ∈ args
232- bodeplot (Cs, ω; lab= labels, title= " Controller bode plot" , kwargs... ) |> display
258+ bodeplot (Cs, ω; lab= repeat ( labels, inner = ( 1 , 2 )) , title= " Controller bode plot" , kwargs... ) |> display
233259 end
234260end
235261
0 commit comments