I would need to plot the step responses of a MIMO system with the python control package.
I've tried so far by using the function step_response
, that however converts the system into a SISO before computing the step response, so that only one set of output is computed.
I then tried using the function forced_response
with different setup for the input (i.e. constant unity value, numpy
array of ones etc..., just for the sake of trying).
I get different step responses, so related to other output, but not all the responses (i.e. number of input x number of output).
Here is a minimum sample code that implements a simple 2nd order model with 2 input and 4 output and dummy data. In attachment a plot of the responses I get.
In my test I first run the step_response
function, yout
results to be of size 4 x size_time
(so only the first 4 output are excited).
Then I run the forced_response
function, and youtForced
still results of size 4 x size_time
, instead of size 4 x size_time x 2
(or similar) as I expected (in the hypothesis forced_response
treats the system as a MIMO).
Is there a way to have full control of the step response via the forced_response
function (similarly to what the MATLAB step function does)?
Unfortunately there is poor documentation and very few practical examples about this.
Many thanks to who can help.
from control import ss, step_response, forced_response
import numpy as np
import matplotlib.pyplot as plt
sz = 2
f1 = 1*2*np.pi
f2 = 1.5*2*np.pi
OM2 = [-f1**2, -f2**2]
ZI = [-2*f1*0.01, -2*f2*0.01]
A11 = np.zeros((sz, sz))
A12 = np.eye(sz)
A21 = np.diag(OM2)
A22 = np.diag(ZI)
A = np.vstack((np.concatenate((A11, A12), axis=1), np.concatenate((A21, A22), axis=1)))
B1 = np.zeros((sz, sz))
B2 = [[1e-6, 1e-7],[2e-6, 2e-7]]
B = np.vstack((B1, B2))
C1 = np.zeros((sz, sz*2))
C1[0] = [1e-4, 2*1e-4, 3*1e-4, 5*1e-5]
C1[1] = [2e-4, 3.5*1e-4, 1.5*1e-4, 2*1e-5]
C2 = np.zeros((sz*2, sz))
C = np.concatenate((C1.T, C2), axis=1)
D = np.zeros((sz*2, sz))
sys = ss(A, B, C, D)
tEnd = 1
time = np.arange(0, tEnd, 1e-3)
tout, youtStep = step_response(sys, T=time)
tout, youtForced, xout = forced_response(sys, T=time, U=1.0)
plt.figure()
for k, y in enumerate(youtStep):
plt.subplot(4,1,k+1)
plt.grid(True)
plt.plot(tout, y,label='step')
plt.plot(tout, youtForced[k], '--r',label='forced')
if k == 0:
plt.legend()
plt.xlabel('Time [s]')
OK the step response is easily manageable via the function control.matlab.step
which actually allows the selection of the different input of the MIMO system, something I initially ignored, but was well reported in the official documentation:
https://python-control.readthedocs.io/en/0.8.1/generated/control.matlab.step.html
Here's the output [MIMO step response output]
Luckily it was an easy fix :)
from control import ss
import control.matlab as ctl
import numpy as np
import matplotlib.pyplot as plt
sz = 2
f1 = 1*2*np.pi
f2 = 1.5*2*np.pi
OM2 = [-f1**2, -f2**2]
ZI = [-2*f1*0.01, -2*f2*0.01]
A11 = np.zeros((sz, sz))
A12 = np.eye(sz)
A21 = np.diag(OM2)
A22 = np.diag(ZI)
A = np.vstack((np.concatenate((A11, A12), axis=1), np.concatenate((A21, A22), axis=1)))
B1 = np.zeros((sz, sz))
B2 = [[1e-6, 1e-7],[2e-6, 2e-7]]
B = np.vstack((B1, B2))
C1 = np.zeros((sz, sz*2))
C1[0] = [1e-4, 2*1e-4, 3*1e-4, 5*1e-5]
C1[1] = [2e-4, 3.5*1e-4, 1.5*1e-4, 2*1e-5]
C2 = np.zeros((sz*2, sz))
C = np.concatenate((C1.T, C2), axis=1)
D = np.zeros((sz*2, sz))
sys = ss(A, B, C, D)
tEnd = 100
time = np.arange(0, tEnd, 1e-3)
yy1, tt1 = ctl.step(sys, T=time, input=0)
yy2, tt2 = ctl.step(sys, T=time, input=1)
plt.figure()
for k in range(0, len(yy1[1,:])):
plt.subplot(4,1,k+1)
plt.grid(True)
plt.plot(tt1, yy1[:,k], label='input=0')
plt.plot(tt2, yy2[:,k], label='input=1')
if k == 0:
plt.legend()
plt.xlabel('Time [s]')