Source code for pathsim.blocks.wrapper
#########################################################################################
##
## WRAPPER BLOCK
## (pathsim/blocks/wrapper.py)
##
#########################################################################################
# IMPORTS ===============================================================================
from ._block import Block
from ..events import Schedule
# BLOCK DEFINITIONS =====================================================================
[docs]
class Wrapper(Block):
"""Wrapper block for discrete implementation and external code integration.
The `Wrapper` class is designed to call the internal `func` at fixed intervals
using an internal `Schedule` event. This makes it particularly useful for wrapping
external code or implementing discrete-time systems.
Essentially this block does the same as `Function` with the difference that its
not evaluated continuously but periodically at discrete times.
Example
-------
There are two ways to setup the `Wrapper`, first and standard way is to define
a function to be wrapped and pass it to the block initializer:
.. code-block:: python
from pathsim.blocks import Wrapper
#function to be wrapped
def func(a, b, c):
return a * (b + c)
wrp = Wrapper(func, T=0.1)
Another option is to use the `dec` classmethod, which might be more convenient
in some situations:
.. code-block:: python
from pathsim.blocks import Wrapper
@Wrapper.dec(T=0.1)
def wrp(a, b, c):
return a * (b + c)
This way the internal function of the block `wrp` will be evaluated with a period
of `T=0.1` and its outputs updated accordingly.
Parameters
----------
func : callable
function that defines algebraic block IO behaviour
T : float
sampling period for the wrapped function
tau : float
delay time for the start time of the event
Attributes
----------
Evt : Schedule
internal event. Used for periodic sampling the wrapped method
"""
def __init__(self, func=None, T=1, tau=0):
super().__init__()
self._T = T
self._tau = tau
#assign func to wrap (direct initialization)
if callable(func):
self.func = func
def _sample(t):
#read current inputs
u = self.inputs.to_array()
#compute operator output
y = self.func(*u)
#update block outputs
self.outputs.update_from_array(y)
#internal scheduled events
self.Evt = Schedule(
t_start=tau,
t_period=T,
func_act=_sample
)
self.events = [self.Evt]
[docs]
def update(self, t):
"""Update system equation for fixed point loop.
Note
----
No direct passthrough, the `Wrapper` block doesnt
implement the `update` method. The behavior is
defined by the `func` arg.
Parameters
----------
t : float
evaluation time
"""
pass
@property
def tau(self):
"""Getter for tau
Returns
-------
tau : float
delay time for the Schedule event
"""
return self._tau
@tau.setter
def tau(self, value):
"""Setter for tau
Parameters
----------
value : float
delay time
"""
if value < 0:
raise ValueError("tau must be non-negative")
self._tau = value
self.Evt.t_start = value
@property
def T(self):
"""Get the sampling period of the block
Returns
-------
T: float
sampling period for the Schedule event
"""
return self._T
@T.setter
def T(self, value):
"""Set the sampling period of the block
Parameters
----------
value : float
sampling period
"""
if value <= 0:
raise ValueError("T must be positive")
self._T = value
self.Evt.t_period = value
[docs]
@classmethod
def dec(cls, T=1, tau=0):
"""decorator for direct instance construction from func
Example
-------
Decorate a function definition to directly make it
a `Wrapper` block instance:
.. code-block:: python
from pathsim.blocks import Wrapper
@Wrapper.dec(T=0.1)
def wrp(a, b, c):
return a * (b + c)
Parameters
----------
tau : float
delay time for the start time of the wrapper sampling
T : float
sampling period for calling the `wrapped` function
"""
def decorator(func):
return cls(func, T, tau)
return decorator