Skip to content

Commit 6450135

Browse files
authored
Merge pull request #6 from JuliaControl/fp
Fixed-point arithmetic
2 parents bafb150 + acd4bdb commit 6450135

File tree

4 files changed

+38
-16
lines changed

4 files changed

+38
-16
lines changed

Project.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
name = "DiscretePIDs"
22
uuid = "c1363496-6848-4723-8758-079b737f6baf"
33
authors = ["Fredrik Bagge Carlson"]
4-
version = "0.1.1"
5-
6-
[deps]
4+
version = "0.1.2"
75

86
[compat]
97
julia = "1.7"
108

119
[extras]
1210
ControlSystems = "a6e380b2-a6ca-5380-bf3e-84a91bcd477e"
11+
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
1312
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1413

1514
[targets]
16-
test = ["Test", "ControlSystems"]
15+
test = ["Test", "ControlSystems", "FixedPointNumbers"]

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,19 @@ The figure should look more or less identical to the one above, except that we p
116116
- Bumpless transfer when updating `K` is realized by updating the state `I`. See the docs for `set_K!` for more details.
117117
- The total control signal $u(t)$ (PID + feed-forward) is limited by the integral anti-windup.
118118

119+
## Simulation of fixed-point arithmetic
120+
If the controller is ultimately to be implemented on a platform without floating-point hardware, you can simulate how it will behave with fixed-point arithmetics using the `FixedPointNumbers` package. The following example modifies the first example above and shows how to simulate the controller using 16-bit fixed-point arithmetics with 10 bits for the fractional part:
121+
```julia
122+
using FixedPointNumbers
123+
T = Fixed{Int16, 10} # 16-bit fixed-point with 10 bits for the fractional part
124+
pid = DiscretePID(; K = T(K), Ts = T(Ts), Ti = T(Ti), Td = T(Td))
125+
res_fp = lsim(P, ctrl, Tf)
126+
plot([res, res_fp], plotu=true, lab=["Float64" "" string(T) ""]); ylabel!("u + d", sp=2)
127+
```
128+
![Fixed-point simulation result](https://user-images.githubusercontent.com/3797491/249722782-2157d625-7eb0-4f77-b630-69199237f164.png)
129+
130+
The fixed-point controller behaves roughly the same in this case, but artifacts are clearly visible. If the number of bits used for the fractional part is decreased, the controller will start to misbehave.
131+
119132
## See also
120133
- [TrajectoryLimiters.jl](https://github.com/baggepinnen/TrajectoryLimiters.jl) To generate dynamically feasible reference trajectories with bounded velocity and acceleration given an instantaneous reference $r(t)$ which may change abruptly.
121134
- [SymbolicControlSystems.jl](https://github.com/JuliaControl/SymbolicControlSystems.jl) For C-code generation of LTI systems.

src/DiscretePIDs.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,19 @@ U(s) = K \\left( bR(s) - Y(s) + \\dfrac{1}{sT_i} \\left( R(s) Y(s) \\right) - \\
5151
See also [`calculate_control`](@ref), [`set_K!`](@ref), [`set_Ti!`](@ref), [`set_Td!`](@ref)
5252
"""
5353
function DiscretePID(;
54-
K = 1f0,
54+
K::T = 1f0,
5555
Ti = false,
5656
Td = false,
57-
Tt = Ti > 0 && Td > 0 ? (Ti*Td) : 10,
58-
N = 10f0,
59-
b = 1f0,
60-
umin = -float(typeof(K))(Inf),
61-
umax = float(typeof(K))(Inf),
57+
Tt = Ti > 0 && Td > 0 ? typeof(K)((Ti*Td)) : typeof(K)(10),
58+
N = typeof(K)(10),
59+
b = typeof(K)(1),
60+
umin = typemin(K),
61+
umax = typemax(K),
6262
Ts,
63-
I = 0.0f0,
64-
D = 0.0f0,
65-
yold = 0.0f0,
66-
)
63+
I = zero(typeof(K)),
64+
D = zero(typeof(K)),
65+
yold = zero(typeof(K)),
66+
) where T
6767
if Ti > 0
6868
bi = K * Ts / Ti
6969
else
@@ -83,9 +83,9 @@ function DiscretePID(;
8383
ad = Td / (Td + N * Ts)
8484
bd = K * N * ad
8585

86-
T = promote_type(typeof.((K, Ti, Td, Tt, N, b, umin, umax, Ts, bi, ar, bd, ad, I, D, yold))...)
86+
T2 = promote_type(typeof.((K, Ti, Td, Tt, N, b, umin, umax, Ts, bi, ar, bd, ad, I, D, yold))...)
8787

88-
DiscretePID(T.((K, Ti, Td, Tt, N, b, umin, umax, Ts, bi, ar, bd, ad, I, D, yold))...)
88+
DiscretePID(T2.((K, Ti, Td, Tt, N, b, umin, umax, Ts, bi, ar, bd, ad, I, D, yold))...)
8989
end
9090

9191
"""

test/runtests.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ res2 = lsim(P, ctrl, Tf)
6767
@test res.y res2.y rtol=0.02
6868
# plot([res, res2])
6969

70+
## Test with FixedPointNumbers
71+
using FixedPointNumbers
72+
T = Fixed{Int16, 10} # 16-bit signed fixed-point with 11 bits for the fractional part
73+
pid = DiscretePID(; K = T(K), Ts = T(Ts), Ti = T(Ti), Td = T(Td))
74+
@test pid isa DiscretePID{T}
75+
76+
res3 = lsim(P, ctrl, Tf)
77+
78+
@test res.y res3.y rtol=0.05
79+
7080

7181
## PI control with sp weighting
7282
Tf = 10

0 commit comments

Comments
 (0)