Element Factories

ControlSBML provides factories for making elements of closed loops. Elements constructed from these factories are control.NonlinearIOSystem objects. Elements are classified as signal generators that produce a signal or system elements that transform signals.

  • Signal generators
    • Step

    • Sine

    • Arbitrary signal

  • Systems
    • PID controller

    • Filter

    • Adder

    • Multiplier

    • Passthru

All factory methods have a single positional argument: the name of the element, and they return an NonlinearIOSystem with the specified names and names for its inputs and outputs.

Signal generators

All signal generator factories have the keyword arguments start_time (which defaults to 0) and end_time (which defaults to None). Signal generator factories also have keyword arguments that specify specifics of the signal. The factory returns an NonlinearIOSystem that has no input and a single output named out.

Step

makeStep is a factory that creates step signals. It has the signal specific keyword argument step_size that specifies the magnitude of the step. The code below illustrates the creation of a step signal generator for a step of size 3 that starts at time 1 and ends at time 3.

factory = ctl.IOSystemFactory()
step = factory.makeStep("step", 2, start_time=1, end_time=3)

Below is an example of creating an control.InterconnectedSystem that consists only of a step function. Then, we plot the result.

1# Create an InterconnectedSystem
2connected_system = control.interconnect(
3[step],       # systems
4outlist=["step.out"],
5)
6# Simulate the system and plot the result.
7ts = ctl.simulateSystem(connected_system, output_names=["step.out"], end_time=end_time)
8ctl.plotOneTS(ts, figsize=(5,5))
_images/step_simulation.png

Sinusoid

makeSinusoid is a factory that creates sinusoid signals and has the keyword arguments amplitude, frequency, phase, and dc_offset (cosntant addition to the sinusoid). Below is an example of creating a cosine.

factory = ctl.IOSystemFactory()
cosine = factory.makeSinusoid("cosine", amp=2, frequency=2, phase=np.pi/2)

Below is an example of creating an control.InterconnectedSystem that consists only of a step function. Then, we plot the result.

1# Create an InterconnectedSystem
2connected_system = control.interconnect(
3[cosine],       # systems
4outlist=["cosine.out"],
5)
6# Simulate the system and plot the result.
7ts = ctl.simulateSystem(connected_system, output_names=["cosine.out"])
8ctl.plotOneTS(ts, figsize=(5,5))
_images/cosine_simulation.png

Arbitrary Signal

makeArbitrarySignal is a factory that creates a signal specified in a user provided function. It has the keyword argument signal_function that specifies the function that defines the signal.

We illustrate this factory by creating an NonlinearIOSystem object that generates a ramp. The signal_function is

# Make a unit ramp
def rampFunction(time):
    return time

Creating the ramp generator is illustrated below.

factory = ctl.IOSystemFactory()
ramp = factory.makeArbitrarySignal("ramp", signal_function=rampFunction)

Here’s an example of constructing a system with ramp and simulating the system.

1# Create an InterconnectedSystem
2connected_system = control.interconnect(
3[ramp],       # systems
4outlist=["ramp.out"],
5)
6# Simulate the system and plot the result.
7ts = ctl.simulateSystem(connected_system, output_names=["ramp.out"])
8ctl.plotOneTS(ts, figsize=(5,5))
_images/ramp_simulation.png

System generators

Systems are elements that transform signals. NonlinearIOSystem objects constructed by system factories have one or more input and one or more output. Elements with a single input and a single output use the names in and out.

PID controller

Proportional, integral, and differential (PID) control is widely used in control systems. The factory makePIDController has the keyword arguments kp, ki, and kd that correspond to the parameters of a PID controller. The default value of these arguments is 0 to facilitate making various combinations of proportional, integral, and differential control. Below is an example of construcing a proportional controller with a gain of 2. A controller as the input in and the output out.

factory = ctl.IOSystemFactory()
controller = factory.makePIDController("controller", kp=2)

Below, we simulate this system and plot the results.

 1# Create a ramp signal in the same factory
 2ramp = factory.makeArbitrarySignal("ramp", signal_function=rampFunction)
 3# Create an InterconnectedSystem
 4connected_system = control.interconnect(
 5[ramp, controller],       # systems
 6    connections=[
 7    ['controller.in', 'ramp.out'],
 8],
 9outlist=["controller.out"],
10)
11# Simulate the system and plot the result.
12ts = ctl.simulateSystem(connected_system, output_names=["controller.out"])
13ctl.plotOneTS(ts, figsize=(5,5))
_images/controller_simulation.png

Filters

Filters are elements that remove undesirable charaacteristics of signals. The factory method makeFilter returns a NonlinearIOSystem that implements a first order low pass filter, a filter function likes a moving average. Let the input to the filter is \(u(t)\) and the output be \(y(t)\). The filter is defined by the differential equation:

\[\dot{y}(t) = - a y(t) + a u(t)\]

The filter has a DC gain of 1 so that it produces a correct average value. The constant \(-a\) is the time constant of the filter. Below is an example of filtering a sinusoidal input. A filter has the input in and the output out.

factory = ctl.IOSystemFactory()
filter = factory.makeFilter("filter", 0.1)
 1# Create a ramp signal in the same factory
 2sine = factory.makeSinusoid("sine", amplitude=1, frequency= 10, dc_offset=5)
 3# Create an InterconnectedSystem
 4connected_system = control.interconnect(
 5[sine, filter],       # systems
 6    connections=[
 7    ['filter.in', 'sine.out'],
 8],
 9outlist=["filter.out", "sine.out"],
10)
11# Simulate the system and plot the result.
12ts = ctl.simulateSystem(connected_system, output_names=["filter.out", "sine.out"], end_time=10)
13ctl.plotOneTS(ts, figsize=(5,5), )
_images/filter_simulation.png

Adder

An adder inputs one or more signals and outputs their sum. A signal is subtracted if its name begins with a minus (-).

The example below shows an adder that inputs a step, a sine, and the negative of a ramp.

1# Create a sum of a step and a sine minus a ramp
2step = factory.makeStep("step", step_size=1)
3sine = factory.makeSinusoid("sine", amplitude=1, frequency= 10)
4ramp = factory.makeArbitrarySignal("ramp", signal_function=lambda t: t)  # Define Ramp with a lambda function
5#
6factory = ctl.IOSystemFactory()
7adder = factory.makeAdder("adder", input_names=["step_in", "sine_in", "-ramp_in"])

Below shows how the adder is used in an InterconnectedSystem``system and the simulation of that ``InterconnectedSystem.

 1# Create an InterconnectedSystem
 2connected_system = control.interconnect(
 3[step, sine, ramp, adder],       # systems
 4    connections=[
 5        ['adder.step_in', 'step.out'],
 6        ['adder.sine_in', 'sine.out'],
 7        ['adder.ramp_in', 'ramp.out'],
 8],
 9outlist=["adder.out", "step.out", "sine.out", "ramp.out"],
10)
11# Simulate the system and plot the result.
12ts = ctl.simulateSystem(connected_system, output_names=["adder.out", "step.out", "sine.out", "ramp.out"], end_time=10)
13ctl.plotOneTS(ts, figsize=(5,5), )
_images/adder_simulation.png

Multiplier

A multiplier inputs one signal and outputs the product of this signal with a constant factor. This is illustrated below.

# Create a multiplier
factory = ctl.IOSystemFactory()
multiplier = factory.makeMultiplier("multiplier", factor=3)

Below shows how the multiplier is used in an InterconnectedSystem``system and the simulation of that ``InterconnectedSystem.

 1ramp = factory.makeArbitrarySignal("ramp", signal_function=lambda t: t)  # Define Ramp with a lambda function
 2# Create an InterconnectedSystem
 3connected_system = control.interconnect(
 4[ramp, multiplier],       # systems
 5    connections=[
 6        ['multiplier.in', 'ramp.out'],
 7],
 8outlist=["multiplier.out", "ramp.out"],
 9)
10# Simulate the system and plot the result.
11ts = ctl.simulateSystem(connected_system, output_names=["multiplier.out", "ramp.out"])
12ctl.plotOneTS(ts, figsize=(5,5), )
_images/multiplier_simulation.png

Passthru

Example (FINISH)

This section illustrates how to use the factory constructed elements. An important part of this is knowing the inputs and outputs defined for each.