Interconnect Tutorial
Sawyer B. Fuller 2023.04
Goal: Create a single dynamic system that implements a complicated interconnected (ie, realistic) system such as the following:
[1]:
import numpy as np # numerical library
import matplotlib.pyplot as plt # plotting library
import control as ct # control systems library
preliminaries
The representation of all systems in the interconnected system will be a linear, time-invariant system in state-space form given by
,
for continuous-time systems, and
for discrete-time systems. is the state,
is the input, and
is the output. All of which are possibly vector-valued.
auto-splitting
A signal is automatically routed into every system that has an input of the same name
u y1
u +--> sys1 --->
---|
+--> sys2 --->
u y2
[2]:
# arbitrary example systems
sys1 = ct.tf(1, [10, 1], inputs='u', outputs='y1')
sys2 = ct.tf(1, [1, 0], inputs='u', outputs='y2')
# create interconnected system
interconnected = ct.interconnect([sys1, sys2], inputs='u', outputs=['y1', 'y2'])
display(interconnected) # 1-input, 2-output system
For this system, the input has a single value , while the output is a two-element vector
.
auto-summing
Systems with output signals of the same name are automatically added.
u1 y
---> sys1 ---+
|
+ V y
O----->
+ ^
|
---> sys2 ---+
u1 y
[3]:
sys1 = ct.tf(1, [10, 1], inputs='u1', outputs='y')
sys2 = ct.tf(1, [1, 0], inputs='u2', outputs='y')
# create interconnected system
interconnected = ct.interconnect([sys1, sys2], inplist=['u1', 'u2'], outlist='y')
display(interconnected) # 2-input, 1-output system
summing junctions
Use a summing junction to interconnect signals of different names, or to change the sign of a signal.
u w
---> O --->
^
| -v
|
[4]:
summer = ct.summing_junction(['u', '-v'], 'w') # w = u - v
display(summer)
constructing the goal system depicted above
[5]:
# constants
K = 10
zc = 0.001 # controller zero location
pc = 2 # controller pole location
tau = 1
J = 100
b = 1
# systems
C = ct.tf([K, K*zc],[1, pc], inputs='e', outputs='u')
lopass = ct.tf(1, [tau, 1], inputs='u', outputs='v')
P = ct.tf(1, [J, b], inputs='w', outputs='thetadot')
integrator = ct.tf(1, [1, 0], inputs='thetadot', outputs='theta')
error = ct.summing_junction(['thetaref', '-theta'], 'e') # e = thetaref-theta
disturbance = ct.summing_junction(['d', 'v'], 'w') # w = d+v
# interconnect everything based on signal names
sys = ct.interconnect([C, lopass, P, integrator, error, disturbance],
inputs=['thetaref', 'd'], outputs='theta')
display(sys)
Finally, we can use the interconnected system just like we would use any other system object, such as computing step and frequency responses.
[6]:
# extract system input-output pairs
# index order is [output, input]
plt.figure(figsize=(7,3))
sys_thetaref_to_theta = sys[0, 0]
sys_d_to_theta = sys[0, 1]
t, y = ct.step_response(sys_thetaref_to_theta) # step response
plt.plot(t,y)
plt.figure(figsize=(7,3))
t, yd = ct.step_response(sys_d_to_theta) # disturbance response
plt.plot(t,yd);
plt.figure(figsize=(7,5))
ct.bode_plot(sys_thetaref_to_theta, plot=True);


