Is it possible to use symbolic variables when defining a discrete time control system?
The following code fails:
using ControlSystemsBase, ModelingToolkit
@parameters Ts
# Ts = 0.01
Ku = 200/5e6
K2 = 5e6
num = [Ku * Ts]
den = [1, -1]
P = tf(num, den, Ts) # plant
with the error message:
ERROR: LoadError: TypeError: non-boolean (Num) used in boolean context
Stacktrace:
[1] Discrete
@ ~/.julia/packages/ControlSystemsBase/4kZY4/src/types/TimeEvolution.jl:9 [inlined]
[2] Discrete
@ ~/.julia/packages/ControlSystemsBase/4kZY4/src/types/TimeEvolution.jl:19 [inlined]
[3] tf(num::Vector{Num}, den::Vector{Int64}, Ts::Num)
@ ControlSystemsBase ~/.julia/packages/ControlSystemsBase/4kZY4/src/types/tf.jl:49
[4] top-level scope
@ ~/repos/WindSpeedEstimators/mwes/mwe_09.jl:10
[5] include(fname::String)
@ Base.MainInclude ./client.jl:489
[6] top-level scope
@ REPL[2]:1
in expression starting at /home/ufechner/repos/WindSpeedEstimators/mwes/mwe_09.jl:10
Found the answer myself: Yes, it is possible using: GitHub - JuliaControl/SymbolicControlSystems.jl: C-code generation and an interface between ControlSystems.jl and SymPy.jl
This works:
using ControlSystemsBase, ModelingToolkit, SymbolicControlSystems
@vars Ts Ku K2
num = [Ku * Ts]
den = [1, -1]
P = tf(num, den, Ts) # plant
and has as output:
TransferFunction{ControlSystemsBase.Discrete{SymPy.Sym}, ControlSystemsBase.SisoRational{SymPy.Sym}}
(Ku*Ts)
-----------
(1)z + (-1)
Sample Time: Ts (seconds)
Discrete-time transfer function model
But the following code fails:
using ControlSystemsBase, ModelingToolkit, SymbolicControlSystems
@vars Ts Ku K2
num = [Ku * Ts]
den = [1, -1]
P = tf(num, den, Ts) # plant
C = K2
sys = feedback(P, C)
with the error message:
[ Info: Precompiling SymbolicControlSystems [886cb795-8fd3-4b11-92f6-8071e46f71c5]
[ Info: Skipping precompilation since __precompile__(false). Importing SymbolicControlSystems [886cb795-8fd3-4b11-92f6-8071e46f71c5].
ERROR: LoadError: PyError ($(Expr(:escape, :(ccall(#= /home/ufechner/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:43 =# @pysym(:PyObject_Call), PyPtr, (PyPtr, PyPtr, PyPtr), o, pyargsptr, kw))))) <class 'sympy.polys.polyerrors.GeneratorsNeeded'>
GeneratorsNeeded("Cannot initialize from 'dict' without generators")
File "/home/ufechner/.julia/conda/3/x86_64/lib/python3.10/site-packages/sympy/polys/polytools.py", line 182, in __new__
return cls._from_expr(rep, opt)
File "/home/ufechner/.julia/conda/3/x86_64/lib/python3.10/site-packages/sympy/polys/polytools.py", line 312, in _from_expr
return cls._from_dict(rep, opt)
File "/home/ufechner/.julia/conda/3/x86_64/lib/python3.10/site-packages/sympy/polys/polytools.py", line 249, in _from_dict
raise GeneratorsNeeded(
Stacktrace:
[1] pyerr_check
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/exception.jl:75 [inlined]
[2] pyerr_check
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/exception.jl:79 [inlined]
[3] _handle_error(msg::String)
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/exception.jl:96
[4] macro expansion
@ ~/.julia/packages/PyCall/1gn3u/src/exception.jl:110 [inlined]
[5] #107
@ ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:43 [inlined]
[6] disable_sigint
@ ./c.jl:473 [inlined]
[7] __pycall!
@ ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:42 [inlined]
[8] _pycall!(ret::PyCall.PyObject, o::PyCall.PyObject, args::Tuple{SymPy.Sym}, nargs::Int64, kw::Ptr{Nothing})
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:29
[9] _pycall!
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:11 [inlined]
[10] (::PyCall.PyObject)(args::SymPy.Sym)
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:86
[11] tf(sys::SymPy.Sym, h::ControlSystemsBase.Discrete{SymPy.Sym})
@ SymbolicControlSystems ~/.julia/packages/SymbolicControlSystems/wPScY/src/SymbolicControlSystems.jl:86
[12] convert(::Type{TransferFunction{…}}, G::TransferFunction{ControlSystemsBase.Discrete{…}, ControlSystemsBase.SisoRational{…}})
@ ControlSystemsBase ~/.julia/packages/ControlSystemsBase/4kZY4/src/types/conversion.jl:37 [inlined]
[13] _promote
@ ./promotion.jl:370 [inlined]
[14] promote
@ ./promotion.jl:393 [inlined]
[15] feedback(sys1::TransferFunction{…}, sys2::SymPy.Sym; kwargs::@Kwargs{})
@ ControlSystemsBase ~/.julia/packages/ControlSystemsBase/4kZY4/src/types/Lti.jl:33
[16] top-level scope
@ ~/repos/WindSpeedEstimators/mwes/mwe_09.jl:12
[17] include(fname::String)
@ Base.MainInclude ./client.jl:489
[18] top-level scope
@ REPL[1]:1
in expression starting at /home/ufechner/repos/WindSpeedEstimators/mwes/mwe_09.jl:12
Some type information was truncated. Use `show(err)` to see complete types.
Any idea?
Depending on what you want to do, you might not need SymbolicContorlSystems. You can pass Ts = 1
here tf(num, den, 1)
if you’re only interested in algebraic manipulations. The only time the Ts
there is relevant is when you need to compute the response in frequency or time.