# Converting a symbolic transfer function to a TransferFunction

**URL:** <https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740>\
**Category:** Modelling & Simulations\
**Tags:** question, symbolics, controlsystems\
**Created:** [September 11, 2023, 1:04pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740 "2023-09-11T13:04:43Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [September 11, 2023, 1:04pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/1 "2023-09-11T13:04:43Z")

</div>

Hello,  
any idea how to convert the following transfer function:

```julia
julia> res
(-9.770075179266223e-8(s^4) - 2.543931256784638e-6(s^5) - 3.198336516372632e-5(s^6) - 0.00019354918819587642(s^7) - 0.000453357561824716(s^8)) / ((0.00013932867142612727 + 0.0124908808235244s + s^3 + 0.2134619608161619(s^2))^3)
julia> typeof(res)
Num

```

into a transfer function with the type TransferFunction ?

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [September 11, 2023, 1:33pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/2 "2023-09-11T13:33:26Z")

</div>

I mean, I can convert it manually:

```julia
using ControlSystemsBase
num = [0.0007205235056679737, 0.00029812769938757924, 4.8098814990661017e-5, 3.763125715852026e-6, 1.4315223278917721e-7,0,0,0,0]
den = [0.206882701981523, 0, 0, 1, 0, 0.011977460042917651, 0.0001334537369270392]
tf(num, den)

```

But it should also be possible automatically somehow, I think…

---

<div class="post-metadata">

**Author:** ![Dictino](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dictino/32/217281_2.png) [@Dictino](https://discourse.julialang.org/u/Dictino)\
**Post date:** [September 11, 2023, 8:58pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/3 "2023-09-11T20:58:53Z")

</div>

One (untestested) idea is to create a function

`f=build_function(res, [s])`

`f = eval(f[1])`

And then evaluate with the transfer function “s”

`S=tf([1.0, 0.0],[1.0])`

`H=f(S)`

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [September 12, 2023, 5:53am UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/4 "2023-09-12T05:53:28Z")

</div>

[SymbolicControlSystems.jl](https://github.com/JuliaControl/SymbolicControlSystems.jl) contains a number of functions for converting to and from sympy, but the support for Symbolics.jl is not that well developed. However, it does look like the following works

```julia
julia> using Symbolics

julia> @variables s;

julia> (s+1) / (s+2);

julia> using SymbolicControlSystems

julia> G = (s+1) / (s+2)
(1 + s) / (2 + s)

julia> tf(G)
TransferFunction{Continuous, ControlSystemsBase.SisoRational{Float64}}
1.0s + 1.0
----------
1.0s + 2.0

Continuous-time transfer function model

```

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 9, 2023, 1:21pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/5 "2023-10-09T13:21:59Z")

</div>

This works:

```julia
using Symbolics, ControlSystemsBase

@variables s

import SymbolicControlSystems

G = (s+1) / (s+2)
tf(G)

```

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 9, 2023, 1:40pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/6 "2023-10-09T13:40:30Z")

</div>

Isn’t this exactly what the previous post did?

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 9, 2023, 1:50pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/7 "2023-10-09T13:50:57Z")

</div>

Well, you forgot to import ControlSystemBase, and you wrote `using SymbolicControlSystems`, not `import SymbolicControlSystems`…

Using results in a warning because `s` is alreay defined.

But I have another problem: After executing `import SymbolicControlSystems` my linear algebra code fails.

This line of my code then fails:

```julia
 G1 = (C*inv(M)*B + D)

```

with

```julia
ERROR: MethodError: no method matching oneunit(::Type{Any})

Stacktrace:
 [1] oneunit(#unused#::Type{Any})
   @ Base .\missing.jl:106
 [2] inv(A::Matrix{Any})
   @ LinearAlgebra C:\Users\uwefechner\.julia\juliaup\julia-1.9.3+0.x64.w64.mingw32\share\julia\stdlib\v1.9\LinearAlgebra\src\dense.jl:910

```

Is `SymbolicControlSystems` doing some type piracy?

I thought that `import` is safe and should not impact already defined functions…

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 9, 2023, 1:55pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/8 "2023-10-09T13:55:09Z")

</div>

> [@ufechner7](#):
>
> Is `SymbolicControlSystems` doing some type piracy?

I don’t think so, in particular, we do not define any methods for neither `inv` nor `oneunit`. Maybe SymPy or Latexify does?

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 9, 2023, 1:55pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/9 "2023-10-09T13:55:39Z")

</div>

I will check…

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 9, 2023, 2:59pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/10 "2023-10-09T14:59:47Z")

</div>

I use an external script now:

```julia
# script to convert symbolic expression into a TransferFunction
using Symbolics, ControlSystemsBase, JLD2
import SymbolicControlSystems

expr = load("data/H_num.jld2")["H_num"]
H_tf = tf(expr)
jldsave("data/H_tf.jld2"; H_tf)

```

and execute it with:

```julia
jldsave("data/H_num.jld2"; H_num)
# execute conversion script ...
mycommand = `julia --project -e "include(\"src/convert_to_tf.jl\")"`
run(mycommand)
H_tf = load("data/H_tf.jld2")["H_tf"]

```

I am open for suggestions how to do this in a more elegant way, but at least this approach works…

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 9, 2023, 3:01pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/11 "2023-10-09T15:01:24Z")

</div>

What is `M`, it looks like it’s a Matrix of `Any` in your stack trace. What is `M` if you do not load SymbolicControlSystems?

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 9, 2023, 3:03pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/12 "2023-10-09T15:03:16Z")

</div>

A matrix of symbolic expressions:

```julia
julia> M
2×2 Matrix{Num}:
 s + (-Pge(t) - Pgc(t) + 0.5A*(U^3)*b*Γ*ρ) / (J*(ω(t)^2)) 0
      -(0.5A*R*(U^2)*a*Γ*ρ - 0.5A*R*a*(Uest(t)^2)*Γest*ρ)*Ku s - (-1.5A*(b*Uest(t) + R*a*ω(t))*Uest(t)*Γest*ρ + 0.5A*R*a*ω(t)*Uest(t)*Γest*ρ)*Ku

```

And the same if I load SymbolicControlSystems… Only matrix operations fail…

Update:  
At some point in time the type of the matrix changes to 2×2 Matrix{Any}, even though each element  
is still of type Num…

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [November 1, 2023, 5:23pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/13 "2023-11-01T17:23:20Z")

</div>

Much more elegant and much faster:

```julia
using Symbolics, ControlSystemsBase

@variables R a b c d Γ ρ U J Q s

input = 2s + 4U*a*s^3 + Q*(J*s+s)/(4Γ*U*s + 2a)

function split_s(input)
    inp = simplify(input, expand=true)
    vcat([Num(Symbolics.coeff(inp, s^i)) for i in Symbolics.degree(inp, s):-1:1],
    substitute(inp, s => 0))
end

function symbolic2tf(expr::Num)
    numerator, denominator = Symbolics.arguments(Symbolics.value(simplify(expr)))
    num = split_s(numerator)
    den = split_s(denominator)
    num, den
    tf(num, den)
end

res = symbolic2tf(input)

```

@baggepinnen What do you think about this solution?

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [November 1, 2023, 5:25pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/14 "2023-11-01T17:25:26Z")

</div>

> [@ufechner7](#):
>
> `Symbolics.arguments`

The use of Symbolics.arguments is only correct if / is the top-level operator, you should probably check for that

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [November 1, 2023, 5:28pm UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/15 "2023-11-01T17:28:22Z")

</div>

That’s why I simplify the expression first…

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [November 2, 2023, 8:23am UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/16 "2023-11-02T08:23:46Z")

</div>

That’s not sufficient, your function produces the wrong result for this PID controller

```julia
@variables s
1 + s + 1/s

julia> symbolic2tf(1 + s + 1/s)
TransferFunction{Continuous, ControlSystemsBase.SisoRational{Num}}
1
--
1s

Continuous-time transfer function model

```

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [November 2, 2023, 8:34am UTC](https://discourse.julialang.org/t/converting-a-symbolic-transfer-function-to-a-transferfunction/103740/17 "2023-11-02T08:34:36Z")

</div>

Thanks for testing!
