Control systems, pid, and high-order transfer functions

romain-chiap
Fri, 18 Jul 2025 05:56:21 +0000
Modelling & Simulations

Hello,

It’s specific to control systems and this is my first post, so I still decided to post under “new to Julia” as I might be asking beginner questions.

I’m making a 1-dimension model of the PX4 cascaded control loops. PX4 is a controller for drones.

There are 4 cascaded loops. Let’s call then Gx (position closed loop), Gv (vel CL), Gout (angle CL), and Gin (rate CL). The closed loops obviously include the plant (i.e. the 1D model for the drone).

The rate loop is a PID, however as you can see, the D-term does not multiply the reference AND its signal is low pass filtered. We’ll omit the saturation as this is non-linear.

I derived the equations by hand and I obtained Gin (although it looks like ControlSystemsBase.pid_2dof() could have done exactly that)

TransferFunction{Continuous, ControlSystemsBase.SisoRational{Float64}}
                    1.7664s^3 + 8.8576s^2 + 5.120000000000001s
----------------------------------------------------------------------------------
0.00046575s^6 + 0.022725s^5 + 0.32s^4 + 2.8432s^3 + 8.8576s^2 + 5.120000000000001s

First question: how can I simplify this transfer function? I would like to divide the num and denominator by s.

I’m able to obtain the polynomial with Gin.matrix[1].num and Gin.matrix[1].den, then impossible to divide them.
Here is a code snippet so you can help me solve it

# transfer functions example in Julia - July 18, 2025 - Romain Chiappinelli
using Plots
using ControlSystemsBase, LinearAlgebra, ControlSystems
using RobustAndOptimalControl
plotly();

Gin=tf([1.7664, 8.8576, 5.120000000000001, 0],[0.00046575, 0.022725, 0.32, 2.8432, 8.8576, 5.120000000000001, 0])
if Gin.matrix[1].num(0)==0 && Gin.matrix[1].den(0)==0
   # what to do here ?
end

Then I close the loop with the P term. I obtain a 14 order polynomial at the denominator, which could be reduced to order 11 by answering question 1.

s=tf("s")
P=2.5
Gout = (P*Gin) / (s+P*Gin)

and I obtain the following warning.

Warning: High-order transfer functions are highly sensitive to numerical errors. The result may be inaccurate. Consider making use of statespace systems instead

At this point, I’m still able to do a step response that matches the real data. Spoiler alert: late on, Gv will have order 22 and the step response does not match the reality
Then, when I do

Gins=ss(Gin)
Gout = ss((P*Gins) / (s+P*Gins))

it tells me System is improper, a state-space representation is impossible. Any mathematical explanation cue?
Testing the code as I write this topic, I realized that this works

Gins=ss(Gin)
Gout = ss((P*Gins/s) / (1+P*Gins/s))

I think the topic is half resolved now. and by closing the loops properly I’ll be able to to have a proper system and have my step response.

Do you think the order 22 as a state space will give me accurate results?

8 posts - 3 participants