4

When I create a system using the python-control package:

import control
H = control.tf([1], [1])

And then want to iteratively simulate that system, how do I do it?

I know I can do this:

T = np.arange(0, 10, 0.01)
u = np.sin(T)
y, t, x = control.lsim(H, u, T)

But what I want to do is this:

Tstart = get_current_time()   # returns a scalar
T = get_current_time()
x = None
while T - Tstart < 100:
    u = get_next_input()      # returns a scalar
    T = get_current_time()
    y, x = control.step_system(H, u, T, x)
    do_something_with_output(y)

Is there some way I can do this? How else are you supposed to use a system developed with the control package to, you know, control something?

Tom
  • 7,269
  • 1
  • 42
  • 69
  • Requiring a discretised system is fine, BTW. – Tom Apr 14 '16 at 15:23
  • 1
    The best I've come up with is to convert to state space, discretise it and step it manually myself. It works, but why isn't there something built in to do this? – Tom Apr 14 '16 at 15:46

1 Answers1

2

This is a great question. I am interested in this myself and asked a similar question on the Mathworks forum a while ago and it's not currently possible in MATLAB.

The good news is, you can now do it in Python Control using the iosys module and the input_output_response function.

For a linear system as in your example you use the LinearIOSystem class

Here is my simulation example:

import time
import numpy as np
import matplotlib.pyplot as plt
import control
from control import input_output_response
from control.iosys import LinearIOSystem

# Define system
# Continuous-time transfer function
G = control.tf([1], [2, 1])

# Convert to state-space representation
Gss = control.ss(G)

# Construct IO system
sys = LinearIOSystem(Gss, inputs='u', outputs='y')

def get_next_input(u, avg_time=0.5):
    """Function to simulate data acquisition"""
    t0 = time.time()
    wait_time = avg_time*(0.5 + np.random.rand())
    while time.time() - t0 < wait_time:
        pass
    if np.random.rand() > 0.8:
        u = u + np.random.randn()
    return u

# Simulate system in response to irregular inputs
t0 = time.time()
t = 0
y0 = 0
u = 0
x = np.zeros(sys.nstates)
np.random.seed(1)
sim_results = [[0, u, y0]]
print(sim_results[-1])
while t < 10:
    u_new, t_new  = get_next_input(u), time.time() - t0
    # Simulation of system up to current time
    T_sim = [t, t_new]
    T_sim, Y_sim, X_sim = input_output_response(sys, T_sim, u, X0=x,
                                                return_x=True)
    sim_results.append([T_sim[-1], u_new, Y_sim[-1]])
    print(sim_results[-1])
    # Set current state and outputs to end of simulation period
    x = X_sim[0, -1]
    u = u_new
    t = t_new

sim_results = np.array(sim_results)
t = sim_results[:, 0]
u = sim_results[:, 1]
y = sim_results[:, 2]

# Plot inputs and outputs
plt.subplot(2, 1, 1)
plt.plot(t, y, 'o-')
plt.xlabel('t')
plt.ylabel('y(t)')
plt.grid()
plt.subplot(2, 1, 2)
plt.step(t, u, where='post')
plt.xlabel('t')
plt.ylabel('u(t)')
plt.grid()
plt.show()

input-output time response of simulated system

In answer to your final question:

How else are you supposed to use a system developed with the control package to, you know, control something?"

I think tools like the MATLAB control module and python-control are intended to be used for the analysis, design and simulation of control systems, not necessarily for their implementation. Depending on your application, usually the final control system implementation is done on specialized hardware and/or software or might be hand-coded in a low-level language like C for example. High-level languages like MATLAB and Python are arguably too unreliable and difficult to maintain/upgrade for them to be attractive solutions in any serious process control or real-world robotics application. But for hobbyists and laboratory experiments they are ideal and so I agree this kind of functionality is useful.

Bill
  • 10,323
  • 10
  • 62
  • 85
  • 2
    Thanks for the answer and it's terrific that you can now do this. TBH I forget what I even wanted it for. I've spent most of my career writing real-time control systems & I'm perfectly familiar with why control systems in Python are a bad idea; I think I wanted to smooth a discrete-time input or something and so wasn't all that interested in the real-timeness of it all. It just seemed crazy that you would design a discrete-time filter... and then had to re-implement it for yourself if you actually wanted to use it. – Tom Aug 09 '21 at 08:28