Skip to content

add parameter conversion helper #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,17 @@ plot(t, [Ym Um], layout=(2,1), ylabel = ["y" "u"], legend=false)
```
Once again, the output looks identical and is therefore omitted here.

## Parameter conversion
The form of the PID controller used in this package is often referred to as ["standard form"](https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller#Standard_form). If you have PID parameters on "parallel form"
```math
K_p (br-y) + K_i (r-y)/s - K_d s y/(Tf s + 1)
```
you may convert these to the standard form
```math
K (b r - y + 1/T_i (r - y) - s T_d y/(1 + s T_d / N))
```
using the function `K, Ti, Td = parallel2standard(kp, ki, kd)` or, if a filter parameter is included, `K, Ti, Td, N = parallel2standard(kp, ki, kd, Tf)`. This function also accepts a vector of parameters in the same order, in which case a vector is returned.

## Details
- The derivative term only acts on the (filtered) measurement and not the command signal. It is thus safe to pass step changes in the reference to the controller. The parameter $b$ can further be set to zero to avoid step changes in the control signal in response to step changes in the reference.
- Bumpless transfer when updating `K` is realized by updating the state `I`. See the docs for `set_K!` for more details.
Expand Down
2 changes: 1 addition & 1 deletion examples/juliac/juliac_pid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ end

# compile using something like this, modified to suit your local paths
# cd(@__DIR__)
# run(`/home/fredrikb/repos/julia/julia --project --experimental /home/fredrikb/repos/julia/contrib/juliac.jl --output-lib juliac_pid --experimental --trim=unsafe-warn --compile-ccallable juliac_pid.jl`)
# run(`/home/fredrikb/repos/julia/julia --project --experimental /home/fredrikb/repos/julia/contrib/juliac.jl --output-lib juliac_pid --trim=unsafe-warn --experimental --compile-ccallable juliac_pid.jl`)
# run(`ls -ltrh`)
39 changes: 38 additions & 1 deletion src/DiscretePIDs.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module DiscretePIDs

export DiscretePID, calculate_control!, set_K!, set_Td!, set_Ti!, reset_state!
export DiscretePID, calculate_control!, set_K!, set_Td!, set_Ti!, reset_state!, parallel2standard

using Printf

Expand Down Expand Up @@ -201,4 +201,41 @@ function reset_state!(pid::DiscretePID)
nothing
end

"""
K, Ti, Td = parallel2standard(Kp, Ki, Kd)

Convert parameters from form "parallel" form
``K_p + K_i/s + K_d s``

to "standard" form used in DiscretePID:
``K(1 + 1/(T_i s) + T_d s)``

You may provide either three arguments or an array with three elements in the same order.
"""
function parallel2standard(Kp, Ki, Kd)
Kp == 0 && throw(DomainError("Cannot convert to standard form when Kp=0"))
return (Kp, Kp / Ki, Kd / Kp)
end

"""
K, Ti, Td, N = parallel2standard(Kp, Ki, Kd, Tf)

Convert parameters from form "parallel" form with first-order filter
``K_p (br-y) + K_i (r-y)/s - K_d s y/(Tf s + 1)``

to "standard" form used in DiscretePID:
``K (br-y + (r-y)/(T_i s) - T_d s y/(T_d / N s + 1))``

You may provide either four arguments or an array with four elements in the same order.
"""
function parallel2standard(Kp, Ki, Kd, Tf)
Kp, Ti, Td = parallel2standard(Kp, Ki, Kd)
N = Td / Tf
return (Kp, Ti, Td, N)
end

function parallel2standard(p)
return [parallel2standard(p...)...]
end

end
8 changes: 8 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,12 @@ res2 = lsim(P, ctrl, 3)
@test DiscretePID(Ts=1f0) isa DiscretePID{Float32}
@test DiscretePID(Ts=1.0) isa DiscretePID{Float64}

kpkikdTf = rand(4)
kp, ki, kd, Tf = kpkikdTf
ps = parallel2standard(kpkikdTf)
K,Ti,Td,N = ps

@test ControlSystemsBase.pid(kp, ki, kd; Tf, form = :parallel, filter_order=1) ≈ ControlSystemsBase.pid(K, Ti, Td; Tf=Td/N, form = :standard, filter_order=1)


end