SECOND_ORDER_SYSTEM
This block has a 2nd order exponential function and is designed to be used in a LOOP with an APPEND block. Inputs
------
default : Scalar
PID node output. Params: d1 : float The first time constant. d2 : float The second time constant. Returns: out : Scalar The most recent value of the second order function.
Python Code
from numpy import exp, ndarray, insert, zeros
from flojoy import flojoy, OrderedPair, DefaultParams, SmallMemory, Vector, Scalar
memory_key = "SECOND_ORDER_SYSTEM"
@flojoy(inject_node_metadata=True)
def SECOND_ORDER_SYSTEM(
default: OrderedPair | Vector | Scalar,
default_params: DefaultParams,
d1: float = 250,
d2: float = 100,
) -> OrderedPair:
"""This block has a 2nd order exponential function and is designed to be used in a LOOP with an APPEND block.
Inputs
------
default : Scalar
PID node output.
Parameters
----------
d1 : float
The first time constant.
d2 : float
The second time constant.
Returns
-------
Scalar
The most recent value of the second order function.
"""
# Let's first define things that won't change over
# each iteration: time constants, etc ...
def_key = default.c
node_id = default_params.node_id
# ... and now some helper functions
x1 = exp(-1.0 / d1) if d1 > 0 else 0.0
x2 = exp(-1.0 / d2) if d2 > 0 else 0.0
ac = (1.0 - x1) * (1.0 - x2)
bpd = x1 + x2
bd = x1 * x2
# Now we require memory. The only thing we need in memory is the last two
# values the system had in this basic example.
data = SmallMemory().read_memory(node_id, memory_key)
if data is None:
initialize = True
elif type(data) == ndarray:
initialize = False
else:
raise TypeError(f"Error loading object from REDIS. Type: {type(data)}")
# We're going to store and read the data in reverse order to
# how it is accessed here. We will write the functionality
# below to assume the most recent time step is the first
# index. However, for visualization and external access,
# it makes the most sense to have the first time step
# as the first index!
y_primes = zeros((2, 1)) if initialize else data[::-1]
# Using input from controller as v[0].y ...
response = ac * def_key + bpd * y_primes[0] - bd * y_primes[1]
y_primes[1] = y_primes[0]
# prepend the most recent result to the front of the histrory
y_primes = insert(y_primes, 0, response)
# We now write to memory, reversing the order ...
SmallMemory().write_to_memory(node_id, memory_key, y_primes[::-1])
# ... and return the result!
return Scalar(float(y_primes[0])) # returns input output pair
Example
Having problems with this example app? Join our Discord community and we will help you out!
This example demonstrates an active PID controller for a mock non-linear system to be driven to a given setpoint using SECOND_ORDER_SYSTEM
node.