Module openrtdynamics2.lang

Expand source code
from .lang import *

__pdoc__ = {}
__pdoc__['lang'] = False

# __all__ = ['show_required_inputs', 'run_batch_simulation', 'SystemInstance', 'CompiledCode']

__all__ = dir()

Sub-modules

openrtdynamics2.lang.block_interface
openrtdynamics2.lang.block_prototypes
openrtdynamics2.lang.block_prototypes_single_subsystem
openrtdynamics2.lang.block_prototypes_subsystems
openrtdynamics2.lang.block_prototypes_switched_subsystems
openrtdynamics2.lang.code_generation_templates
openrtdynamics2.lang.core_blocks
openrtdynamics2.lang.diagram_core
openrtdynamics2.lang.high_level_user_commands
openrtdynamics2.lang.libraries
openrtdynamics2.lang.signal_interface
openrtdynamics2.lang.standard_library
openrtdynamics2.lang.subsystems
openrtdynamics2.lang.system_context

Functions

def PID_controller(r, y, Ts, kp, ki=None, kd=None)

Discrete-time PID-controller

Parameters

r : SignalUserTemplate
the reference signal
y : SignalUserTemplate
the measured plant output
Ts : float
the sampleing time
kp : float
the parameter kp (proportional)
ki : float
the parameter ki (integral)
kd : float
the parameter kd (differential)

Returns

SignalUserTemplate
the control variable u
Expand source code
def PID_controller(r, y, Ts, kp, ki = None, kd = None):
    """Discrete-time PID-controller

    Parameters
    ----------
    r : SignalUserTemplate
        the reference signal
    y : SignalUserTemplate
        the measured plant output
    Ts : float
        the sampleing time
    kp : float
        the parameter kp (proportional)
    ki : float
        the parameter ki (integral)
    kd : float
        the parameter kd (differential)

    Returns
    -------
    SignalUserTemplate
        the control variable u

    """
    Ts = dy.float64(Ts)

    # control error
    e = r - y

    # P
    u = kp * e

    # D
    if kd is not None:
        u = u + dy.diff(e) * kd / Ts

    # I
    if ki is not None:
        u = u + dy.sum(e) * ki * Ts

    return u
def abs(u: SignalUserTemplate)

Absolute value

Computes the absolute value |u|.

Expand source code
def abs(u : SignalUserTemplate ):
    """
    Absolute value

    Computes the absolute value |u|.
    """
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'abs').outputs[0] )
def acos(u: SignalUserTemplate)
Expand source code
def acos(u : SignalUserTemplate ):
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'acos').outputs[0] )
def add(input_signals: List[SignalUserTemplate], factors: List[float])

Linear combination of the list of input signals with the list of factors

the output is given by

input_signals[0] * factors[0] + input_signals[1] * factors[1] + ...
Expand source code
def add(input_signals : List[SignalUserTemplate], factors : List[float]):
    """
    Linear combination of the list of input signals with the list of factors

    the output is given by

        input_signals[0] * factors[0] + input_signals[1] * factors[1] + ...
    """
    return wrap_signal( Add(dy.get_system_context(), unwrap_list( input_signals ), factors).outputs[0] )
def append_primay_ouput(output_signal, export_name: str = None)

add an output to the current system

Expand source code
def append_primay_ouput(output_signal, export_name : str = None):
    """
        add an output to the current system
    """

    if export_name is not None:
        output_signal.set_name_raw(export_name)

    get_system_context().append_primay_ouput(output_signal.unwrap)
def asin(u: SignalUserTemplate)
Expand source code
def asin(u : SignalUserTemplate ):
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'asin').outputs[0] )
def atan(u: SignalUserTemplate)
Expand source code
def atan(u : SignalUserTemplate ):
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'atan').outputs[0] )
def atan2(y: SignalUserTemplate, x: SignalUserTemplate)

atan2

This function returns atan2(x,y).

Parameters

x : SignalUserTemplate
x
y : SignalUserTemplate
y

Returns

SignalUserTemplate
the output signal

Details

returns atan2(x,y)

Expand source code
def atan2(y : SignalUserTemplate, x : SignalUserTemplate ):
    """
        atan2

        This function returns atan2(x,y).

        Parameters
        ----------
        x : SignalUserTemplate
            x
        y : SignalUserTemplate
            y

        Returns
        -------
        SignalUserTemplate
            the output signal

        Details
        -------
        returns 
            atan2(x,y)

    """
    return wrap_signal( StaticFnByName_2To1(dy.get_system_context(), y.unwrap, x.unwrap, 'atan2').outputs[0] )
def bitwise_and(u1: SignalUserTemplate, u2: SignalUserTemplate)

bitwise and

u1 & u2

Expand source code
def bitwise_and(u1 : SignalUserTemplate, u2 : SignalUserTemplate):
    """
        bitwise and

        u1 & u2
    """

    return wrap_signal( Operator1(dy.get_system_context(), inputSignals=unwrap_list([u1,u2]), operator=' & ').outputs[0] )
def bitwise_not(u: SignalUserTemplate)

Bitwise not operator

Parameters

u : SignalUserTemplate
the integer input signal

Returns

SignalUserTemplate
the integer output signal

Details

returns ~u

Expand source code
def bitwise_not(u : SignalUserTemplate ):
    """
    Bitwise not operator

    Parameters
    ----------
    u : SignalUserTemplate
        the integer input signal

    Returns
    -------
    SignalUserTemplate
        the integer output signal

    Details
    -------
    returns 
        ~u
    """
    return wrap_signal( Operator0(dy.get_system_context(), u.unwrap, '~').outputs[0] )
def bitwise_or(u1: SignalUserTemplate, u2: SignalUserTemplate)

bitwise or

u1 | u2

Expand source code
def bitwise_or(u1 : SignalUserTemplate, u2 : SignalUserTemplate):
    """
        bitwise or
    
        u1 | u2
    """

    return wrap_signal( Operator1(dy.get_system_context(), inputSignals=unwrap_list( [u1,u2] ), operator=' | ').outputs[0] )
def bitwise_shift_left(u: SignalUserTemplate, shift: SignalUserTemplate)

logical shift left

u << shift

Expand source code
def bitwise_shift_left(u : SignalUserTemplate, shift : SignalUserTemplate):
    """
        logical shift left
    
        u << shift
    """

    return wrap_signal( Operator1(dy.get_system_context(), inputSignals=unwrap_list( [u,shift] ), operator=' << ').outputs[0] )
def bitwise_shift_right(u: SignalUserTemplate, shift: SignalUserTemplate)

logical shift left

u >> shift

Expand source code
def bitwise_shift_right(u : SignalUserTemplate, shift : SignalUserTemplate):
    """
        logical shift left
    
        u >> shift
    """

    return wrap_signal( Operator1(dy.get_system_context(), inputSignals=unwrap_list( [u,shift] ), operator=' >> ').outputs[0] )
def boolean(value)

Cast anything to DataTypeBoolean

Convert the input value to a signal.

Parameters

value : SignalUserTemplate, int
the signal or a constant value to convert to a signal

Returns

SignalUserTemplate
the signal of type boolean
Expand source code
def boolean(value):
    """Cast anything to DataTypeBoolean

    Convert the input value to a signal.

    Parameters
    ----------
    value : SignalUserTemplate, int
        the signal or a constant value to convert to a signal

    Returns
    -------
    SignalUserTemplate
        the signal of type boolean

    """
    if isinstance(  value, SignalUserTemplate ):
        # already a singal
        return value
    else:
        # create a new constant
        return dy.const(value, dy.DataTypeBoolean(1) )
def clear()

clear the context

Expand source code
def clear():
    """
        clear the context
    """
    init_simulation_context()
def comparison(left: SignalUserTemplate, right: SignalUserTemplate, operator: str)
Expand source code
def comparison(left : SignalUserTemplate, right : SignalUserTemplate, operator : str ):
    return wrap_signal( ComparisionOperator(dy.get_system_context(), left.unwrap, right.unwrap, operator).outputs[0] )
def compile_system(system=None)
Expand source code
def compile_system(system = None):

    if system is None:
        system = get_system_context() 

    system.propagate_datatypes()

    #
    # compile the diagram: turn the blocks and signals into a tree-structure of commands to execute
    # at runtime.
    #

    compiler = dc.CompileDiagram()
    compile_results = compiler.compile( system )

    #
    return compile_results
def conditional_overwrite(signal: SignalUserTemplate, condition: SignalUserTemplate, new_value)

Overwrite the input signal by a given value in case a condition is true

The output is given by

signal     for condition==false
new_value  for condition==true

Parameters

signal : SignalUserTemplate
the input signal
condition : SignalUserTemplate
the boolean condition for when to overwrite signal
new_value : SignalUserTemplate, float, int
the value with is used to replace the input in case the condition is true

Returns

SignalUserTemplate
the output signal
Expand source code
def conditional_overwrite(signal : SignalUserTemplate, condition : SignalUserTemplate, new_value ):
    """
    Overwrite the input signal by a given value in case a condition is true

    The output is given by

        signal     for condition==false
        new_value  for condition==true

    Parameters
    ----------
    signal : SignalUserTemplate
        the input signal
    condition : SignalUserTemplate
        the boolean condition for when to overwrite signal
    new_value : SignalUserTemplate, float, int
        the value with is used to replace the input in case the condition is true

    Returns
    -------
    SignalUserTemplate
        the output signal
    """

    if isinstance(new_value, SignalUserTemplate):
        new_value = new_value.unwrap

    return wrap_signal( ConditionalOverwrite(dy.get_system_context(), signal.unwrap, condition.unwrap, new_value).outputs[0] )
def const(constant, datatype)
Expand source code
def const(constant, datatype ):
    return wrap_signal( Const(dy.get_system_context(), constant, datatype).outputs[0] )
def convert(u: SignalUserTemplate, target_type: DataType)

Datatype conversion

The input is converted to the given datatype

Parameters

u : SignalUserTemplate
the input signal
target_type
the datatype to convert the signal to

Returns

SignalUserTemplate
the output signal with the given type
Expand source code
def convert(u : SignalUserTemplate, target_type : dt.DataType ):
    """
    Datatype conversion

    The input is converted to the given datatype

    Parameters
    ----------
    u : SignalUserTemplate
        the input signal
    target_type
        the datatype to convert the signal to

    Returns
    -------
    SignalUserTemplate
        the output signal with the given type
    """
    return wrap_signal( ConvertDatatype(dy.get_system_context(), u.unwrap, target_type).outputs[0] )
def cos(u: SignalUserTemplate)
Expand source code
def cos(u : SignalUserTemplate ):
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'cos').outputs[0] )
def counter()

Basic counter - the sampling index k

The integer output is increasing with each sampling instant by 1. Counting starts at zero.

Returns

SignalUserTemplate
the integer output signal describing the sampling index k
Expand source code
def counter():
    """Basic counter - the sampling index k

    The integer output is increasing with each sampling instant by 1.
    Counting starts at zero.

    Returns
    -------
    SignalUserTemplate
        the integer output signal describing the sampling index k

    """

    if not 'counter' in dy.get_system_context().components:
        # no counter has been defined in this system so far. Hence, create one.

        increase = dy.const(1, dy.DataTypeInt32(1) )
        cnt = dy.signal()
        tmp = dy.delay(cnt + increase)
        cnt << tmp 

        tmp.set_name('shared_counter')

        # store the output signal of the counter as it might be used again. 
        dy.get_system_context().components['counter'] = __Counter(tmp)

    else:
        # use the output of an already created counter
        tmp = dy.get_system_context().components['counter'].output

    return tmp
def counter_triggered(upper_limit, stepwidth=None, initial_state=0, reset=None, reset_on_limit: bool = False, start_trigger=None, pause_trigger=None, auto_start: bool = True, no_delay: bool = False)

A generic counter

Features: - upper limit - triggerable start/pause - resetable - dynamic adjustable step-size

Parameters

upper_limit : int
the upper limit of the counter
initial_state : int
the state after reset
reset : SignalUserTemplate
reset the counter
reset_on_limit : bool
reset counter once the upper limit is reached
start_trigger : SignalUserTemplate
event to start counting
pause_trigger : SignalUserTemplate
event to pause counting
auto_start : bool
start counting automatically
no_delay : bool
when True the new value of the counter is returned without delay

Returns

SignalUserTemplate
the boolean output signal
SignalUserTemplate
event that fires when the upper limit of the counter is reached
Expand source code
def counter_triggered( upper_limit, stepwidth=None, initial_state = 0, reset=None, reset_on_limit:bool=False, start_trigger=None, pause_trigger=None, auto_start:bool=True, no_delay:bool=False ):
    """A generic counter

    Features:
    - upper limit
    - triggerable start/pause
    - resetable
    - dynamic adjustable step-size

    Parameters
    ----------

    upper_limit : int
        the upper limit of the counter
    initial_state : int
        the state after reset
    reset : SignalUserTemplate
        reset the counter
    reset_on_limit : bool
        reset counter once the upper limit is reached
    start_trigger : SignalUserTemplate
        event to start counting
    pause_trigger : SignalUserTemplate
        event to pause counting
    auto_start : bool
        start counting automatically
    no_delay : bool
        when True the new value of the counter is returned without delay 

    Returns
    -------
    SignalUserTemplate
        the boolean output signal 
    SignalUserTemplate
        event that fires when the upper limit of the counter is reached 
        
    """

    if stepwidth is None:
        stepwidth = dy.int32(1)

    counter = dy.signal()

    reached_upper_limit = counter >= dy.int32(upper_limit)

    if start_trigger is None:
        start_trigger = dy.boolean(0)

    # 
    if pause_trigger is not None: 
        activate_trigger = dy.logic_or(reached_upper_limit, pause_trigger)
    else:
        if not auto_start:
            activate_trigger = reached_upper_limit
        else:
            # when auto_start is active, continue counting after reset on reached_upper_limit
            activate_trigger = dy.boolean(0)


    # state for pause/counting
    paused =  dy.flipflop(activate_trigger=activate_trigger, disable_trigger=start_trigger, initial_state = not auto_start, no_delay=True).set_name('paused')

    # prevent counter increase
    stepwidth = dy.conditional_overwrite(stepwidth, paused, 0).set_name('stepwidth')

    # increase the counter until the end is reached
    new_counter = counter + dy.conditional_overwrite(stepwidth, reached_upper_limit, 0)

    if reset is not None:
        # reset in case this is requested
        new_counter = dy.conditional_overwrite(new_counter, reset, initial_state)

    if reset_on_limit:
        new_counter = dy.conditional_overwrite(new_counter, reached_upper_limit, initial_state)

    # introduce a state variable for the counter
    counter << dy.delay( new_counter, initial_state=initial_state )

    if not no_delay:
        return counter, reached_upper_limit
    else:
        return new_counter, reached_upper_limit
def cpp_allocate_class(datatype, code_constructor_call)

Return a pointer signal pointing to a class instance initialized by code_constructor_call

Parameters

ptr_signal : DataTypePointer
the datatype of the pointer to use
code_constructor_call : str
the code to initialize the class instance
Expand source code
def cpp_allocate_class(datatype, code_constructor_call):
    """
        Return a pointer signal pointing to a class instance initialized by code_constructor_call

        Parameters
        ----------
        ptr_signal : DataTypePointer
            the datatype of the pointer to use
        code_constructor_call : str
            the code to initialize the class instance

    """
    return wrap_signal( AllocateClass(dy.get_system_context(), datatype, code_constructor_call).outputs[0] )
def cpp_call_class_member_function(ptr_signal: SignalUserTemplate, input_signals: List[SignalUserTemplate], input_types, output_types, member_function_name_to_calc_outputs: str = None, member_function_name_to_update_states: str = None, member_function_name_to_reset_states: str = None)

Call member functions of a c++ class

This function calls member functions of a class instance given by a pointer to an instance. In- and outputs are passed as parameters to the member function given by 'member_function_name_to_calc_outputs'. Herein, the output signals are the first parameters and the input signals then follow.

On an optional state update call, the member function 'member_function_name_to_update_states' is called and the parameters are the input signals.

Parameters

ptr_signal : SignalUserTemplate
the pointer to the class instance as generated by cpp_allocate_class()
input_signals : SignalUserTemplate
a list of input signals that are passed to the called member functions via the parameters
input_types : List[ Datatype ]
the datatypes of the inputs
output_types : List[ Datatype ]
the datatypes of the outputs
member_function_name_to_calc_outputs : str
the name of the member function to call to compute the output signals
member_function_name_to_update_states : str
optional: the name of the member function to call to update the states

Returns

List[SignalUserTemplate|
the output signals
Expand source code
def cpp_call_class_member_function(
    ptr_signal : SignalUserTemplate, 
        
    input_signals : List[SignalUserTemplate], input_types, 
    output_types,

    member_function_name_to_calc_outputs : str = None,
    member_function_name_to_update_states : str = None,
    member_function_name_to_reset_states : str = None

):
    """
        Call member functions of a c++ class

        This function calls member functions of a class instance given by a pointer to an instance.
        In- and outputs are passed as parameters to the member function given by
        'member_function_name_to_calc_outputs'. Herein, the output signals are the first parameters
        and the input signals then follow.

        On an optional state update call, the member function 'member_function_name_to_update_states'
        is called and the parameters are the input signals.

        Parameters
        ----------
        ptr_signal : SignalUserTemplate
            the pointer to the class instance as generated by cpp_allocate_class()
        input_signals : SignalUserTemplate
            a list of input signals that are passed to the called member functions via the parameters
        input_types : List[ Datatype ]
            the datatypes of the inputs
        output_types : List[ Datatype ]
            the datatypes of the outputs
        member_function_name_to_calc_outputs : str
            the name of the member function to call to compute the output signals
        member_function_name_to_update_states : str
            optional: the name of the member function to call to update the states

        Returns
        -------
        List[SignalUserTemplate|
            the output signals

    """
    bp = CallClassMemberFunction(
        dy.get_system_context(), 
        unwrap_list(input_signals), 
        input_types, 
        output_types, 
        ptr_signal = ptr_signal.unwrap,

        member_function_name_to_calc_outputs  = member_function_name_to_calc_outputs,
        member_function_name_to_update_states = member_function_name_to_update_states,
        member_function_name_to_reset_states  = member_function_name_to_reset_states
    )
    return wrap_signal_list( bp.outputs )
def delay(u, initial_state=None)

Unit delay

Delay the input u by one sampling instant:

y[k+1] = u[k], y[0] = initial_state

Parameters

u : SignalUserTemplate
the input signal to delay
initial_state : SignalUserTemplate
the initial state (signal or constant value)

Returns

SignalUserTemplate
the one-step delayed input
Expand source code
def delay(u , initial_state = None):
    """Unit delay

    Delay the input u by one sampling instant:

        y[k+1] = u[k], y[0] = initial_state

    Parameters
    ----------
    u : SignalUserTemplate
        the input signal to delay
    initial_state : SignalUserTemplate
        the initial state (signal or constant value)

    Returns
    -------
    SignalUserTemplate
        the one-step delayed input   

    """

    if not isinstance( initial_state, SignalUserTemplate ):
        return dy.delay__( u, initial_state )

    else:

        event_on_first_sample = initial_event()

        delayed_input = dy.delay__( u, None )
        delayed_input = dy.conditional_overwrite( delayed_input, event_on_first_sample, initial_state )

        return delayed_input
def delay__(u: SignalUserTemplate, initial_state=None)
Expand source code
def delay__(u : SignalUserTemplate, initial_state = None):
    return wrap_signal( Delay(dy.get_system_context(), u.unwrap, initial_state ).outputs[0] )
def diff(u: SignalUserTemplate, initial_state=None)

Discrete difference

Parameters

u : SignalUserTemplate
the input signal
initial_state : float, SignalUserTemplate
the initial state

Returns

SignalUserTemplate
the output signal of the filter

Details:

y = u[k] - u[k-1]

initial state

u[0] = initial_state in case initial_state is not None u[0] = 0 otherwise

Expand source code
def diff(u : SignalUserTemplate, initial_state = None):
    """Discrete difference

    Parameters
    ----------

    u : SignalUserTemplate
        the input signal
    initial_state : float, SignalUserTemplate
        the initial state

    Returns
    -------
    SignalUserTemplate
        the output signal of the filter

    Details:
    --------

    y = u[k] - u[k-1] 

    initial state

    u[0] = initial_state   in case initial_state is not None
    u[0] = 0               otherwise
    """

    i = dy.delay( u, initial_state )
    y = dy.add( [ i, u ], [ -1, 1 ] )

    return y
def dtf_lowpass_1_order(u: SignalUserTemplate, z_infinity)

First-order discrete-time low pass filter

Parameters

u : SignalUserTemplate
the input signal

Returns

SignalUserTemplate
the output signal of the filter

Details:

            1 - z_infinity
    H (z) =  --------------
            z - z_infinity
Expand source code
def dtf_lowpass_1_order(u : SignalUserTemplate, z_infinity):
    """First-order discrete-time low pass filter

    Parameters
    ----------

    u : SignalUserTemplate
        the input signal

    Returns
    -------
    SignalUserTemplate
        the output signal of the filter

    Details:
    --------

                    1 - z_infinity
            H (z) =  --------------
                    z - z_infinity
    """

    zinf = dy.float64( z_infinity )
    zinf_ = dy.float64( 1 ) - zinf

    y_delayed = dy.signal()
    y =  zinf * y_delayed + zinf_ * u

    y_delayed << dy.delay(y)
    
    return y
def enter_system(name: str = 'simulation', upper_level_system=None)

create a new system and activate it in the context

Expand source code
def enter_system(name : str = 'simulation', upper_level_system = None):
    """
        create a new system and activate it in the context
    """
    # new simulation
    system = System(upper_level_system, name)

    # register this subsystem to the parent system
    if get_system_context() is not None:
        get_system_context().append_subsystem( system )

    push_simulation_context(system)

    return system
def euler_integrator(u: SignalUserTemplate, Ts, initial_state=0.0)

Euler (forward) integrator

Parameters

u : SignalUserTemplate
the input signal
Ts : float
the sampling time
initial_state : float, SignalUserTemplate
the initial state of the integrator

Returns

SignalUserTemplate
the output signal of the filter

Details:

y[k+1] = y[k] + Ts * u[k]
Expand source code
def euler_integrator( u : SignalUserTemplate, Ts, initial_state = 0.0):
    """Euler (forward) integrator

    Parameters
    ----------

    u : SignalUserTemplate
        the input signal
    Ts : float
        the sampling time
    initial_state : float, SignalUserTemplate
        the initial state of the integrator

    Returns
    -------
    SignalUserTemplate
        the output signal of the filter

    Details:
    --------

        y[k+1] = y[k] + Ts * u[k]
    """

    yFb = dy.signal()

    if not isinstance( Ts, SignalUserTemplate ): 
        i = dy.add( [ yFb, u ], [ 1, Ts ] )
    else:
        i = yFb + Ts * u

    y = dy.delay( i, initial_state )

    yFb << y

    return y
def export_graph(filename, system=None)
Expand source code
def export_graph(filename, system = None):

    if system is None:
        system = get_system_context() 

    graph = system.exportGraph()

    with open( os.path.join(  filename ), 'w') as outfile:  
        json.dump(graph, outfile)
def flipflop(activate_trigger: SignalUserTemplate, disable_trigger: SignalUserTemplate, initial_state=False, no_delay=False)

Flipflop logic element

The block has a state that can be activated or deactivated by the external boolean events 'activate_trigger' and 'disable_trigger', respectively.

Parameters

activate_trigger : SignalUserTemplate
the event to activate the state
disable_trigger : SignalUserTemplate
the event to deactivate the state
initial_state : bool
the initial state
no_delay : bool
return the state change without a delay

Returns

SignalUserTemplate
the state
Expand source code
def flipflop(activate_trigger : SignalUserTemplate, disable_trigger : SignalUserTemplate, initial_state = False, no_delay = False):
    """Flipflop logic element

    The block has a state that can be activated or deactivated by the external boolean events 'activate_trigger'
    and 'disable_trigger', respectively.

    Parameters
    ----------
    activate_trigger : SignalUserTemplate       
        the event to activate the state
    disable_trigger : SignalUserTemplate       
        the event to deactivate the state
    initial_state : bool       
        the initial state
    no_delay : bool
        return the state change without a delay 

    Returns
    -------
    SignalUserTemplate
        the state

    """
    
    return wrap_signal( Flipflop(dy.get_system_context(), activate_trigger.unwrap, disable_trigger.unwrap, initial_state = initial_state, no_delay=no_delay ).outputs[0] )
def float64(value)

Cast anything to DataTypeFloat64

Convert the input value to a signal.

Parameters

value : SignalUserTemplate, float
the signal or a constant value to convert to a signal

Returns

SignalUserTemplate
the signal of type float64
Expand source code
def float64(value):
    """Cast anything to DataTypeFloat64

    Convert the input value to a signal.

    Parameters
    ----------
    value : SignalUserTemplate, float
        the signal or a constant value to convert to a signal

    Returns
    -------
    SignalUserTemplate
        the signal of type float64

    """
    if isinstance(  value, SignalUserTemplate ):
        # already a singal
        return value
    else:
        # create a new constant
        return dy.const(value, dy.DataTypeFloat64(1) )
def fmod(x: SignalUserTemplate, y: SignalUserTemplate)

Modulo function for floating point values

This function returns the remainder of dividing x/y.

Parameters

x : SignalUserTemplate
x
y : SignalUserTemplate
y

Returns

SignalUserTemplate
the output signal

Details

returns fmod(x,y)
Expand source code
def fmod(x : SignalUserTemplate, y : SignalUserTemplate ):
    """
        Modulo function for floating point values

        This function returns the remainder of dividing x/y.

        Parameters
        ----------
        x : SignalUserTemplate
            x
        y : SignalUserTemplate
            y

        Returns
        -------
        SignalUserTemplate
            the output signal

        Details
        -------
            returns fmod(x,y)

    """
    return wrap_signal( StaticFnByName_2To1(dy.get_system_context(), x.unwrap, y.unwrap, 'fmod').outputs[0] )
def gain(u: SignalUserTemplate, gain: float)
Expand source code
def gain(u : SignalUserTemplate, gain : float ):
    return wrap_signal( Gain(dy.get_system_context(), u.unwrap, gain).outputs[0] )
def generate_code(template: TargetGenericCpp, folder=None, build=False, include_code_list: List[str] = [])
Expand source code
def generate_code(template : TargetGenericCpp, folder=None, build=False, include_code_list : t.List[str] = [] ):

    template.add_code_to_include(include_code_list)

    # Compile system (propagate datatypes)
    compile_results = compile_system()

    # Build an executable based on a template
    template.set_compile_results( compile_results )
    code_gen_results = template.code_gen()

    if folder is not None:

        # check of path exists - in case no, create it
        pl.Path(folder).mkdir(parents=True, exist_ok=True)

        print("Generated code will be written to " + str(folder) + ' .')

        # write generated code into a folder and build
        template.write_code(folder)

        if build:
            template.build()


    return code_gen_results
def generic_cpp_static(input_signals: List[SignalUserTemplate], input_names: List[str], input_types, output_names, output_types, cpp_source_code: str)

Embed C/C++ source code (stateless code only)

Parameters

input_signals : List[SignalUserTemplate]
the list of input signals
input_names : List[str]
the list of the names of the input signals to be used as variable names for the c++ code
input_types : List[Datatype]
the list of the datatypes of the input signals (must be fixed)
output_types : List[Datatype]
the list of the datatypes of the output signals (must be fixed)
output_names : List[str]
the list of the names of the output signals to be used as variable names for the c++ code
cpp_source_code : str
the code to embed

Returns

List[SignalUserTemplate]
the output signals

Example

source_code = """

    // This is c++ code
    output1 = value;
    if (someinput > value) {
        output2 = value;
    } else {
        output2 = someinput;
    }
    output3 = 0.0;

"""

outputs = dy.generic_cpp_static(
    input_signals=[ someinput, value ], input_names=[ 'someinput', 'value' ], 
    input_types=[ dy.DataTypeFloat64(1), dy.DataTypeFloat64(1) ], 
    output_names=['output1', 'output2', 'output3'],
    output_types=[ dy.DataTypeFloat64(1), dy.DataTypeFloat64(1), dy.DataTypeFloat64(1) ],
    cpp_source_code = source_code
)

output1 = outputs[0]
output2 = outputs[1]
output3 = outputs[2]
Expand source code
def generic_cpp_static(
    input_signals : List[SignalUserTemplate], input_names : List [str], input_types, 
    output_names, output_types, 
    cpp_source_code : str
):
    """
    Embed C/C++ source code (stateless code only)

    Parameters
    ----------
    input_signals : List[SignalUserTemplate]
        the list of input signals
    input_names : List[str]
        the list of the names of the input signals to be used as variable names for the c++ code
    input_types : List[Datatype]
        the list of the datatypes of the input signals (must be fixed)
    output_types : List[Datatype]
        the list of the datatypes of the output signals (must be fixed)
    output_names : List[str]
        the list of the names of the output signals to be used as variable names for the c++ code
    cpp_source_code : str
        the code to embed

    Returns
    -------
    List[SignalUserTemplate]
        the output signals

    Example
    -------

        source_code = \"\"\"

            // This is c++ code
            output1 = value;
            if (someinput > value) {
                output2 = value;
            } else {
                output2 = someinput;
            }
            output3 = 0.0;

        \"\"\"

        outputs = dy.generic_cpp_static(
            input_signals=[ someinput, value ], input_names=[ 'someinput', 'value' ], 
            input_types=[ dy.DataTypeFloat64(1), dy.DataTypeFloat64(1) ], 
            output_names=['output1', 'output2', 'output3'],
            output_types=[ dy.DataTypeFloat64(1), dy.DataTypeFloat64(1), dy.DataTypeFloat64(1) ],
            cpp_source_code = source_code
        )

        output1 = outputs[0]
        output2 = outputs[1]
        output3 = outputs[2]
    """
    return wrap_signal_list( GenericCppStatic(dy.get_system_context(), unwrap_list(input_signals), input_names, input_types, output_names, output_types, cpp_source_code  ).outputs )
def generic_subsystem(manifest, inputSignals: List[SignalUserTemplate])
Expand source code
def generic_subsystem( manifest, inputSignals : List[SignalUserTemplate] ):
    return wrap_signal_list( GenericSubsystem(dy.get_system_context(), manifest, unwrap_hash(inputSignals) ).outputSignals )
def get_system_context()
Expand source code
def get_system_context():
    global current_simulation_context
    return current_simulation_context
def init(autoreset=False, convert=None, strip=None, wrap=True)
Expand source code
def init(autoreset=False, convert=None, strip=None, wrap=True):

    if not wrap and any([autoreset, convert, strip]):
        raise ValueError('wrap=False conflicts with any other arg=True')

    global wrapped_stdout, wrapped_stderr
    global orig_stdout, orig_stderr

    orig_stdout = sys.stdout
    orig_stderr = sys.stderr

    if sys.stdout is None:
        wrapped_stdout = None
    else:
        sys.stdout = wrapped_stdout = \
            wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
    if sys.stderr is None:
        wrapped_stderr = None
    else:
        sys.stderr = wrapped_stderr = \
            wrap_stream(orig_stderr, convert, strip, autoreset, wrap)

    global atexit_done
    if not atexit_done:
        atexit.register(reset_all)
        atexit_done = True
def init_simulation_context()
Expand source code
def init_simulation_context():
    global simulation_stack
    global current_simulation_context
    global counter_of_created_systems

    current_simulation_context = None
    simulation_stack = []
    counter_of_created_systems = 1000
def initial_event()

Emits an event on the first sampling instant after the reset of the system

Returns

SignalUserTemplate
the signal of type boolean containing the event
Expand source code
def initial_event():
    """Emits an event on the first sampling instant after the reset of the system

    Returns
    -------
    SignalUserTemplate
        the signal of type boolean containing the event
    """

    # TODO: introduce caching like done for counter()

    return dy.counter() == int32(0)
def int32(value)

Cast anything to DataTypeInt32

Convert the input value to a signal.

Parameters

value : SignalUserTemplate, int
the signal or a constant value to convert to a signal

Returns

SignalUserTemplate
the signal of type int32
Expand source code
def int32(value):
    """Cast anything to DataTypeInt32

    Convert the input value to a signal.

    Parameters
    ----------
    value : SignalUserTemplate, int
        the signal or a constant value to convert to a signal

    Returns
    -------
    SignalUserTemplate
        the signal of type int32

    """

    if isinstance(  value, SignalUserTemplate ):
        # already a singal
        return value
    else:
        # create a new constant
        return dy.const(value, dy.DataTypeInt32(1) )
def leave_system()
Expand source code
def leave_system():
    return pop_simulation_context()
def logic_and(u1: SignalUserTemplate, u2: SignalUserTemplate)

logical and

u1 && u2

Expand source code
def logic_and(u1 : SignalUserTemplate, u2 : SignalUserTemplate):
    """
        logical and

        u1 && u2
    """

    return wrap_signal( Operator1(dy.get_system_context(), inputSignals=unwrap_list([u1,u2]), operator=' && ').outputs[0] )
def logic_not(u: SignalUserTemplate)

Logic negation

Parameters

u : SignalUserTemplate
the boolean input signal

Returns

SignalUserTemplate
the boolean output signal

Details

returns !u

Expand source code
def logic_not(u : SignalUserTemplate ):
    """
    Logic negation

    Parameters
    ----------
    u : SignalUserTemplate
        the boolean input signal

    Returns
    -------
    SignalUserTemplate
        the boolean output signal

    Details
    -------
    returns 
        !u
    """
    return wrap_signal( Operator0(dy.get_system_context(), u.unwrap, '!').outputs[0] )
def logic_or(u1: SignalUserTemplate, u2: SignalUserTemplate)

logical or

u1 || u2

Expand source code
def logic_or(u1 : SignalUserTemplate, u2 : SignalUserTemplate):
    """
        logical or
    
        u1 || u2
    """

    return wrap_signal( Operator1(dy.get_system_context(), inputSignals=unwrap_list( [u1,u2] ), operator=' || ').outputs[0] )
def logic_xor(u1: SignalUserTemplate, u2: SignalUserTemplate)

exclusive logical or (xor)

u1 ^ u2

Expand source code
def logic_xor(u1 : SignalUserTemplate, u2 : SignalUserTemplate):
    """
        exclusive logical or (xor)
    
        u1 ^ u2
    """

    return wrap_signal( Operator1(dy.get_system_context(), inputSignals=unwrap_list( [u1,u2] ), operator=' ^ ').outputs[0] )
def memory(datatype, constant_array, write_index: SignalUserTemplate = None, value: SignalUserTemplate = None)

Define an array for storing and reading values

Allocates static memory for an array of elements given a datatype. During each sampling instant, one element can be (over)written.

Parameters

datatype : Datatype
the datatype of the array elements
constant_array : List[float], List[int]
list of constants that contain the data to initialize the array
write_index : SignalUserTemplate
the array index (integer signal) of the element to replace by value (optional)
value : SignalUserTemplate
the value to write into the array at write_index (optional)

returns a reference to the memory segment which is accessible by memory_read()

Returns

List[SignalUserTemplate]
a reference to the memory segment which is accessible by memory_read()

Limitations

currently the memory is not reset on subsystem reset. This will change.

Expand source code
def memory(datatype, constant_array, write_index : SignalUserTemplate = None, value : SignalUserTemplate = None):
    """
    Define an array for storing and reading values

    Allocates static memory for an array of elements given a datatype.
    During each sampling instant, one element can be (over)written. 

    Parameters
    ----------
    datatype : Datatype       
        the datatype of the array elements
    constant_array : List[float], List[int]
        list of constants that contain the data to initialize the array
    write_index : SignalUserTemplate
        the array index (integer signal) of the element to replace by value (optional)
    value : SignalUserTemplate
        the value to write into the array at write_index (optional)

    returns a reference to the memory segment which is accessible by memory_read()

    Returns
    -------
    List[SignalUserTemplate]
        a reference to the memory segment which is accessible by memory_read()


    Limitations
    -----------
    currently the memory is not reset on subsystem reset. This will change.
    """

    if write_index is not None and value is not None:
        return wrap_signal( Memory(dy.get_system_context(), datatype, constant_array, write_index.unwrap, value.unwrap).outputs[0] )
    elif write_index is None and value is None:
        return wrap_signal( Memory(dy.get_system_context(), datatype, constant_array).outputs[0] )
    else:
        raise BaseException('memory: write_index and value were not properly defined')
def memory_read(memory: SignalUserTemplate, index: SignalUserTemplate)

Read an element from an array defined by memory()

Parameters

memory : SignalUserTemplate
the memory as returned by memory()
index : SignalUserTemplate
the index indicating the element to read

Returns

List[SignalUserTemplate]
returns the value of the element
Expand source code
def memory_read( memory : SignalUserTemplate, index : SignalUserTemplate ):
    """
    Read an element from an array defined by memory()

    Parameters
    ----------
    memory : SignalUserTemplate
        the memory as returned by memory()
    index : SignalUserTemplate
        the index indicating the element to read

    Returns
    -------
    List[SignalUserTemplate]
        returns the value of the element
    """
    return wrap_signal( MemoryRead(dy.get_system_context(), memory.unwrap, index.unwrap ).outputs[0] )
def operator1(inputSignals: List[SignalUserTemplate], operator: str)
Expand source code
def operator1(inputSignals : List[SignalUserTemplate], operator : str ):
    return wrap_signal( Operator1(dy.get_system_context(), unwrap_list( inputSignals ), operator).outputs[0] )
def play(sequence_array, stepwidth=None, initial_state=0, reset=None, reset_on_end: bool = False, start_trigger=None, pause_trigger=None, auto_start: bool = True, no_delay: bool = False)

Play a given sequence of samples

Parameters

sequence_array : list[float]
the sequence given as a list of values
reset : SignalUserTemplate
reset playback and start from the beginning
reset_on_end : SignalUserTemplate
reset playback once the end is reached (repetitive playback)
start_trigger : SignalUserTemplate
event to start playback
pause_trigger : SignalUserTemplate
event to pause playback
auto_start : bool
start playback automatically

Returns

SignalUserTemplate
the value obtained from sequence_array
SignalUserTemplate
the current position of playback (index of the currently issued sequence element)
Expand source code
def play( sequence_array,  stepwidth=None, initial_state = 0, reset=None, reset_on_end:bool=False, start_trigger=None, pause_trigger=None, auto_start:bool=True, no_delay:bool=False ):
    """Play a given sequence of samples

    Parameters
    ----------

    sequence_array : list[float]
        the sequence given as a list of values
    reset : SignalUserTemplate
        reset playback and start from the beginning
    reset_on_end : SignalUserTemplate
        reset playback once the end is reached (repetitive playback)
    start_trigger : SignalUserTemplate
        event to start playback
    pause_trigger : SignalUserTemplate
        event to pause playback
    auto_start : bool
        start playback automatically 


    Returns
    -------
    SignalUserTemplate
        the value obtained from sequence_array
    SignalUserTemplate
        the current position of playback (index of the currently issued sequence element)


    """

    sequence_array_storage = dy.memory(datatype=dy.DataTypeFloat64(1), constant_array=sequence_array )

    # if prevent_initial_playback:
    #     initial_counter_state = np.size(sequence_array)
    # else:
        

    playback_index, _ = counter_triggered(
        upper_limit=np.size(sequence_array)-1, 
        stepwidth=stepwidth, initial_state=initial_state, 
        reset=reset, reset_on_limit=reset_on_end, 
        start_trigger=start_trigger, pause_trigger=pause_trigger, 
        auto_start=auto_start,
        no_delay=no_delay
    )

    # sample the given data
    sample = dy.memory_read(sequence_array_storage, playback_index)

    return sample, playback_index
def pow(x: SignalUserTemplate, y: SignalUserTemplate)

Power function for floating point values

This function returns the x to the power of y (x^y).

Parameters

x : SignalUserTemplate
x
y : SignalUserTemplate
y

Returns

SignalUserTemplate
the output signal

Details

returns pow(x,y)
Expand source code
def pow(x : SignalUserTemplate, y : SignalUserTemplate ):
    """
        Power function for floating point values

        This function returns the x to the power of y (x^y).

        Parameters
        ----------
        x : SignalUserTemplate
            x
        y : SignalUserTemplate
            y

        Returns
        -------
        SignalUserTemplate
            the output signal

        Details
        -------
            returns pow(x,y)

    """
    return wrap_signal( StaticFnByName_2To1(dy.get_system_context(), x.unwrap, y.unwrap, 'pow').outputs[0] )
def rate_limit(u, Ts, lower_limit, upper_limit, initial_state=0)

Rate limiter

Parameters

Ts : SignalUserTemplate
sampling time (constant)
lower_limit : SignalUserTemplate
lower rate limit
upper_limit : SignalUserTemplate
upper rate limit

Returns

SignalUserTemplate
the output signal
Expand source code
def rate_limit( u, Ts, lower_limit, upper_limit, initial_state = 0 ):
    """Rate limiter

    Parameters
    ----------

    Ts : SignalUserTemplate
        sampling time (constant)
    lower_limit : SignalUserTemplate
        lower rate limit
    upper_limit : SignalUserTemplate
        upper rate limit

    Returns
    -------
    SignalUserTemplate
        the output signal    

    """

    Ts_ = float64(Ts)

    y = dy.signal()

    omega = u - y
    omega_sat = saturate(omega, float64(lower_limit) * Ts_, float64(upper_limit) * Ts_)
    y << euler_integrator( omega_sat, 1, initial_state=initial_state)

    return y
def sample_and_hold(u, event, initial_state=None)

Sample & hold

Samples the input when event is true and hold this value for the proceeding time instants.

Parameters

u : SignalUserTemplate
the input to sample
event : SignalUserTemplate
the event on which sampling of the input is performed
initial_state : SignalUserTemplate
the initial output

Returns

SignalUserTemplate
the sampled input
Expand source code
def sample_and_hold(u, event, initial_state = None):
    """Sample & hold

    Samples the input when event is true and hold this value for the proceeding time instants. 

    Parameters
    ----------
    u : SignalUserTemplate
        the input to sample
    event : SignalUserTemplate
        the event on which sampling of the input is performed
    initial_state : SignalUserTemplate
        the initial output

    Returns
    -------
    SignalUserTemplate
        the sampled input   

    """

    # NOTE: this could be implemented in a more comp. efficient way directly in C in block_prototypes.py

    y = dy.signal()

    delayed_y = delay( y, initial_state )
    y << dy.conditional_overwrite( delayed_y, event, u )

    return y
def saturate(u, lower_limit=None, upper_limit=None)

Saturation

The output is the saturated input

Parameters

lower_limit : SignalUserTemplate
lower bound for the output
upper_limit : SignalUserTemplate
upper bound for the output

Returns

SignalUserTemplate
the integer output signal

Details

    { lower_limit   for u < lower_limit
y = { u             otherwise
    { upper_limit  for u > upper_limit
Expand source code
def saturate(u, lower_limit = None, upper_limit = None):
    """Saturation

    The output is the saturated input

    Parameters
    ----------

    lower_limit : SignalUserTemplate
        lower bound for the output 
    upper_limit : SignalUserTemplate
        upper bound for the output

    Returns
    -------
    SignalUserTemplate
        the integer output signal 

    Details
    -------
            { lower_limit   for u < lower_limit
        y = { u             otherwise
            { upper_limit  for u > upper_limit
    """

    y = u

    if lower_limit is not None:
        y = dy.conditional_overwrite( y, y < float64(lower_limit), lower_limit )
    
    if upper_limit is not None:
        y = dy.conditional_overwrite( y, y > float64(upper_limit), upper_limit )

    return y
def set_primary_outputs(output_signals, names=None)
Expand source code
def set_primary_outputs(output_signals, names = None):

    if names is not None:
        for i in range(0,len(names)):
            output_signals[i].set_name_raw( names[i] )

    get_system_context().set_primary_outputs( si.unwrap_list( output_signals ) )
def show_blocks(system=None)

List all blocks in the current or given system

Expand source code
def show_blocks(system = None):
    """
        List all blocks in the current or given system
    """

    if system is None:
        system = get_system_context() 

    print()
    print(Style.BRIGHT + "-------- list of blocks --------")
    print()

    system.ShowBlocks()
def show_execution_lines(compile_results)
Expand source code
def show_execution_lines(compile_results):

    print()
    print(Style.BRIGHT + "-------- List all execution lines and commands  --------")
    print()

    compile_results.command_to_execute.print_execution()
def signal()

Create a new signal for defining a closed-loop

Expand source code
def signal():
    """
        Create a new signal for defining a closed-loop
    """

    # return an anonymous signal
    return si.SignalUser(get_system_context())
def signal_impulse(k_event)

Pulse signal generator

Generates a unique pulse at the sampling index k_event.

Parameters

k_event : SignalUserTemplate
the sampling index at which the pulse appears

Returns

SignalUserTemplate
the output signal
Expand source code
def signal_impulse(k_event):
    """Pulse signal generator

    Generates a unique pulse at the sampling index k_event.

    Parameters
    ----------
    k_event : SignalUserTemplate
        the sampling index at which the pulse appears


    Returns
    -------
    SignalUserTemplate
        the output signal
    """

    if k_event < 0:
        raise BaseException('The sampling index for the event is invalid (k_event < 0)')

    k = dy.counter()
    pulse_signal = dy.int32(k_event) == k

    return pulse_signal
def signal_periodic_impulse(period, phase)

Signal generator for periodic pulses

Parameters

period : SignalUserTemplate
singal or constant describing the period in samples at which the pulses are generated
phase : SignalUserTemplate
singal or constant describing the phase in samples at which the pulses are generated

Returns

SignalUserTemplate
the output signal
Expand source code
def signal_periodic_impulse(period, phase):
    """Signal generator for periodic pulses

    Parameters
    ----------

    period : SignalUserTemplate
        singal or constant describing the period in samples at which the pulses are generated
    phase : SignalUserTemplate
        singal or constant describing the phase in samples at which the pulses are generated

    Returns
    -------
    SignalUserTemplate
        the output signal

    """

    k, trigger = counter_triggered( upper_limit=dy.int32(period) - dy.int32(1), reset_on_limit=True )
    pulse_signal = dy.int32(phase) == k

    return pulse_signal
def signal_ramp(k_start)

Signal generator for a ramp signal

Parameters

k_start : SignalUserTemplate
the sampling index as returned by counter() at which the ramp starts increasing.

Returns

SignalUserTemplate
the output signal

Details

y[k] = { 0           for k <  k_start
       { k-k_start   for k >= k_start
Expand source code
def signal_ramp(k_start):
    """Signal generator for a ramp signal

    Parameters
    ----------
    k_start : SignalUserTemplate
        the sampling index as returned by counter() at which the ramp starts increasing.

    Returns
    -------
    SignalUserTemplate
        the output signal

    Details
    -------

        y[k] = { 0           for k <  k_start
               { k-k_start   for k >= k_start
    """
    k = dy.counter()
    active = dy.int32(k_start) <= k

    linearRise = dy.convert( (k - dy.int32(k_start) ), dy.DataTypeFloat64(1) )
    activation = dy.convert( active, dy.DataTypeFloat64(1) )

    return activation * linearRise
def signal_sinus(N_period: int = 100, phi=None)

Sine wave generator

Parameters

N_period : SignalUserTemplate
period in sampling instants (type: constant integer)
phi : SignalUserTemplate
phase shift (signal)

Returns

SignalUserTemplate
the output signal

Details

The output is computed as follows:

y = sin( k * (1 / N_period * 2 * pi) + phi )

k - is the sampling index

Expand source code
def signal_sinus(N_period : int = 100, phi = None):
    """Sine wave generator

    Parameters
    ----------
    N_period : SignalUserTemplate
        period in sampling instants (type: constant integer)
    phi : SignalUserTemplate
        phase shift (signal)

    Returns
    -------
    SignalUserTemplate
        the output signal

    Details
    -------
    The output is computed as follows:

    y = sin( k * (1 / N_period * 2 * pi) + phi )

    k - is the sampling index

    """

    if N_period <= 0:
        raise BaseException('N_period <= 0')

    if phi is None:
        phi = dy.float64(0.0)

    i, _ = dy.counter_triggered( upper_limit=N_period-1, reset_on_limit=True )
    y = dy.sin( i * dy.float64(1/N_period * 2*math.pi) + phi )

    return y
def signal_square(period, phase)

Square wave signal generator

Parameters

period : SignalUserTemplate
singal or constant describing the period in samples at which the edges of the square are placed
phase : SignalUserTemplate
singal or constant describing the phase in samples at which the edges of the square are placed

Returns

SignalUserTemplate
the output signal
Expand source code
def signal_square(period, phase):
    """Square wave signal generator

    Parameters
    ----------

    period : SignalUserTemplate
        singal or constant describing the period in samples at which the edges of the square are placed
    phase : SignalUserTemplate
        singal or constant describing the phase in samples at which the edges of the square are placed

    Returns
    -------
    SignalUserTemplate
        the output signal

    """
    trigger = signal_periodic_impulse(period, phase)


    # k, trigger = counter_triggered( upper_limit=dy.int32(period) - dy.int32(1), reset_on_limit=True )

    state, activate, deactivate = toggle(trigger, no_delay=True)

    return state, activate, deactivate
def signal_step(k_step)

Signal generator for a step signal

Parameters

k_step : SignalUserTemplate
the sampling index as returned by counter() at which the step appears.

Returns

SignalUserTemplate
the output signal
Expand source code
def signal_step(k_step):
    """Signal generator for a step signal

    Parameters
    ----------
    k_step : SignalUserTemplate
        the sampling index as returned by counter() at which the step appears.

    Returns
    -------
    SignalUserTemplate
        the output signal
    """
    k = dy.counter()
    y = dy.int32(k_step) <= k

    return y
def signal_step_wise_sequence(time_instance_indices, values, time_scale=None, counter=None, reset=None)

Signal generator for a step-wise changeing signal

Parameters

time_instance_indices : List[int]
an array of sampling instants at which the signal changes its values
values : List[float]
an array of values; must have one more element than time_instance_indices
time_scale : SignalUserTemplate
multiplies all elements of time_instance_indices by the given factor (optional)
counter : SignalUserTemplate
an alternative sample counter (optional), default: counter=dy.counter()
reset : SignalUserTemplate
boolean signal to reset the sequence (optional)

Returns

SignalUserTemplate
the output signal

Example

time_instance_indices = [      50, 100, 150, 250, 300, 350, 400,  450, 500  ]
values                = [ 0, -1.0,   0, 1.0,  0, -1.0, 0,   0.2, -0.2, 0   ]

v = step_wise_sequence( time_instance_indices, values )
Expand source code
def signal_step_wise_sequence( time_instance_indices, values, time_scale=None, counter=None, reset=None ):
    """Signal generator for a step-wise changeing signal

    Parameters
    ----------

    time_instance_indices : List[int]
        an array of sampling instants at which the signal changes its values
    values : List[float]
        an array of values; must have one more element than time_instance_indices
    time_scale : SignalUserTemplate
        multiplies all elements of time_instance_indices by the given factor (optional)
    counter : SignalUserTemplate
        an alternative sample counter (optional), default: counter=dy.counter()
    reset : SignalUserTemplate
        boolean signal to reset the sequence (optional)

    Returns
    -------
    SignalUserTemplate
        the output signal

    Example
    -------

        time_instance_indices = [      50, 100, 150, 250, 300, 350, 400,  450, 500  ]
        values                = [ 0, -1.0,   0, 1.0,  0, -1.0, 0,   0.2, -0.2, 0   ]

        v = step_wise_sequence( time_instance_indices, values )
    """
    
    if len(values) - 1 != len(time_instance_indices):
        raise BaseException( "len(values) - 1 != len(time_instance_indices)" )

    if counter is None:
        counter = dy.counter()

    indices_mem = dy.memory(datatype=dy.DataTypeInt32(1),   constant_array=time_instance_indices )
    values_mem  = dy.memory(datatype=dy.DataTypeFloat64(1), constant_array=values )

    current_index = dy.signal()

    current_time_index_to_check = dy.memory_read( indices_mem, current_index )

    # scale time
    if time_scale is not None:
        index_to_check = time_scale * current_time_index_to_check
    else:
        index_to_check = current_time_index_to_check

    # check wether to step to the next sample
    increase_index = dy.int32(0)
    increase_index = dy.conditional_overwrite(increase_index, counter >= index_to_check, dy.int32(1) )

    cnt_, _ = dy.counter_triggered(upper_limit=len(time_instance_indices), stepwidth=increase_index, reset=reset )
    current_index << cnt_
    val = dy.memory_read(values_mem, current_index)

    return val
def sin(u: SignalUserTemplate)
Expand source code
def sin(u : SignalUserTemplate ):
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'sin').outputs[0] )
def sqrt(u: SignalUserTemplate)

Square root

Expand source code
def sqrt(u : SignalUserTemplate ):
    """
    Square root
    """
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'sqrt').outputs[0] )
def sum(u: SignalUserTemplate, initial_state=0, no_delay=False)

Accumulative sum

Parameters

u : SignalUserTemplate
the input signal
initial_state : float, SignalUserTemplate
the initial state
no_delay : bool
when true the output is not delayed

Returns

SignalUserTemplate
the output signal of the filter

Details:

The difference equation

y[k+1] = y[k] + u[k]

is evaluated. The return value is either

y[k]   by default or when no_delay == False

or

y[k+1] in case no_delay == True .
Expand source code
def sum(u : SignalUserTemplate, initial_state=0, no_delay=False):
    """Accumulative sum

    Parameters
    ----------

    u : SignalUserTemplate
        the input signal
    initial_state : float, SignalUserTemplate
        the initial state
    no_delay : bool
        when true the output is not delayed

    Returns
    -------
    SignalUserTemplate
        the output signal of the filter

    Details:
    --------

    The difference equation

        y[k+1] = y[k] + u[k]

    is evaluated. The return value is either

        y[k]   by default or when no_delay == False
    or

        y[k+1] in case no_delay == True .
    """

    y_k = dy.signal()
    
    y_kp1 = y_k + u

    y_k << dy.delay(y_kp1, initial_state=initial_state)

    if no_delay:
        return y_kp1
    else:
        return y_k
def sum2(u: SignalUserTemplate, initial_state=0)

Accumulative sum

Parameters

u : SignalUserTemplate
the input signal
initial_state : float, SignalUserTemplate
the initial state

Returns

SignalUserTemplate
the output signal of the filter

Details:

The difference equation

y[k+1] = y[k] + u[k]

is evaluated. The return values are

y[k], y[k+1]
Expand source code
def sum2(u : SignalUserTemplate, initial_state=0):
    """Accumulative sum

    Parameters
    ----------

    u : SignalUserTemplate
        the input signal
    initial_state : float, SignalUserTemplate
        the initial state

    Returns
    -------
    SignalUserTemplate
        the output signal of the filter

    Details:
    --------

    The difference equation

        y[k+1] = y[k] + u[k]

    is evaluated. The return values are

        y[k], y[k+1]
    """

    y_k = dy.signal()
    
    y_kp1 = y_k + u

    y_k << dy.delay(y_kp1, initial_state=initial_state)

    return y_k, y_kp1
def switchNto1(state: SignalUserTemplate, inputs: List[SignalUserTemplate])

N to one signal switch

returns

inputs[0]  for state == 1
inputs[1]  for state == 2
inputs[2]  for state == 3
   ...

Parameters

state : SignalUserTemplate
the state of the switch
inputs : List[SignalUserTemplate]
the input signals among which to switch

Returns

SignalUserTemplate
the output signal of the switch
Expand source code
def switchNto1( state : SignalUserTemplate, inputs : List[SignalUserTemplate] ):
    """N to one signal switch

    returns 

        inputs[0]  for state == 1
        inputs[1]  for state == 2
        inputs[2]  for state == 3
           ...

    Parameters
    ----------
    state : SignalUserTemplate
        the state of the switch  
    inputs : List[SignalUserTemplate]
        the input signals among which to switch

    Returns
    -------
    SignalUserTemplate
        the output signal of the switch
    """
    return wrap_signal( SwitchNto1(dy.get_system_context(), state.unwrap, unwrap_list(inputs) ).outputs[0] )
def system_input(datatype, name: str = None, default_value=None, value_range=None, title: str = '')

Introduce a new system input signal

datatype - the datatype of the signal name - the name of the signal default_value - the default value the will be applied to the system input by default value_range - the available numeric range for the signal the form [min, max]
title - the description of the signal

Expand source code
def system_input(datatype, name : str = None, default_value=None, value_range=None, title : str = ""):
    """
        Introduce a new system input signal

        datatype      - the datatype of the signal
        name          - the name of the signal
        default_value - the default value the will be applied to the system input by default
        value_range   - the available numeric range for the signal the form [min, max]  
        title         - the description of the signal
    """

    signal = si.SimulationInputSignalUser(get_system_context(), datatype)

    if name is not None:
        signal.set_name(name)

    properties = {}

    if default_value is not None:
        properties['default_value'] = default_value

    if value_range is not None:
        properties['range'] = value_range

    if title is not None:
        properties['title'] = title

    signal.set_properties(properties)

    return signal 
def tan(u: SignalUserTemplate)
Expand source code
def tan(u : SignalUserTemplate ):
    return wrap_signal( StaticFnByName_1To1(dy.get_system_context(), u.unwrap, 'tan').outputs[0] )
def toggle(trigger, initial_state=False, no_delay=False)

Toggle a state based on an event

Parameters

period : SignalUserTemplate
the signal to trigger a state change
initial_state : int
the initial state
no_delay : bool
when true the toggle immediately reacts to a trigger (default: false)

Returns

SignalUserTemplate
the boolean state signal
SignalUserTemplate
the event for activation
SignalUserTemplate
the event for deactivation
Expand source code
def toggle(trigger, initial_state=False, no_delay=False):
    """Toggle a state based on an event

    Parameters
    ----------

    period : SignalUserTemplate
        the signal to trigger a state change
    initial_state : int
        the initial state
    no_delay : bool
        when true the toggle immediately reacts to a trigger (default: false)

    Returns
    -------
    SignalUserTemplate
        the boolean state signal

    SignalUserTemplate
        the event for activation
    SignalUserTemplate
        the event for deactivation

    

    """

    state = dy.signal()

    activate   = dy.logic_and( dy.logic_not( state ), trigger )
    deactivate = dy.logic_and( trigger , state)

    state_ = dy.flipflop( activate, deactivate, 
                            initial_state = 0, 
                            no_delay=no_delay )

    if not no_delay:
        state << state_
    else:
        state << dy.delay(state_)


    return state_, activate, deactivate
def transfer_function_discrete(u: SignalUserTemplate, num_coeff: List[float], den_coeff: List[float])

Discrete time transfer function

Parameters

u : SignalUserTemplate
the input signal
num_coeff : List[float]
a list of numerator coefficients of the transfer function
den_coeff : List[float]
a list of denominator coefficients of the transfer function

Returns

SignalUserTemplate
the output signal of the filter

Details:

This filter realizes a discrete-time transfer function by using 'direct form II' c.f. https://en.wikipedia.org/wiki/Digital_filter .

        b0 + b1 z^-1 + b2 z^-2 + ... + bN z^-N
H(z) = ----------------------------------------
        1 + a1 z^-1 + a2 z^-2 + ... + aM z^-M

The coefficient vectors num_coeff and den_coeff describe the numerator and denominator polynomials, respectively, and are defined as follows:

num_coeff = [b0, b1, .., bN]
den_coeff = [a1, a2, ... aM] .
Expand source code
def transfer_function_discrete(u : SignalUserTemplate, num_coeff : t.List[float], den_coeff : t.List[float] ):

    """Discrete time transfer function

    Parameters
    ----------
    u : SignalUserTemplate
        the input signal
    num_coeff : List[float]
        a list of numerator coefficients of the transfer function
    den_coeff : List[float]
        a list of denominator coefficients of the transfer function

    Returns
    -------
    SignalUserTemplate
        the output signal of the filter

    Details:
    --------

    This filter realizes a discrete-time transfer function by using 'direct form II'
    c.f. https://en.wikipedia.org/wiki/Digital_filter .

                b0 + b1 z^-1 + b2 z^-2 + ... + bN z^-N
        H(z) = ----------------------------------------
                1 + a1 z^-1 + a2 z^-2 + ... + aM z^-M

    The coefficient vectors num_coeff and den_coeff describe the numerator and 
    denominator polynomials, respectively, and are defined as follows:

        num_coeff = [b0, b1, .., bN]
        den_coeff = [a1, a2, ... aM] .
        
    """


    # get filter order
    N = len(num_coeff)-1

    # feedback start signal
    z_pre = dy.signal()

    # array to store state signals
    z_ = []

    # create delay chain
    z_iterate = z_pre
    for i in range(0,N):

        z_iterate = dy.delay( z_iterate ) .extend_name('_z' + str(i) )
        z_.append( z_iterate ) 


    # build feedback path
    #
    # a1 = den_coeff[0]
    # a2 = den_coeff[1]
    # a3 = den_coeff[2]
    #        ...
    sum_feedback = u
    for i in range(0,N):

        a_ip1 = dy.float64( den_coeff[i] ).extend_name('_a' + str(i+1) )

        sum_feedback = sum_feedback - a_ip1 * z_[i]

    sum_feedback.extend_name('_i')


    # close the feedback loop
    z_pre << sum_feedback

    # build output path
    #
    # b0 = num_coeff[0]
    # b1 = num_coeff[1]
    # b2 = num_coeff[2]
    #        ...    
    for i in range(0,N+1):
        
        b_i = dy.float64( num_coeff[i] ).extend_name('_b' + str(i) )

        if i==0:
            y = b_i * sum_feedback
        else:
            y = y + b_i * z_[i-1]

    # y is the filter output   
    return y
def unwrap_angle(angle, normalize_around_zero=False)

Unwrap an angle

Unwrap and normalize the input angle to the range

   [0, 2*pi[     in case normalize_around_zero == false
or [-pi, pi]     in case normalize_around_zero == true

Parameters

angle : SignalUserTemplate
the input signal (angle in radians)

Returns

SignalUserTemplate
the output signal
Expand source code
def unwrap_angle(angle, normalize_around_zero = False):
    """Unwrap an angle

    Unwrap and normalize the input angle to the range 

           [0, 2*pi[     in case normalize_around_zero == false
        or [-pi, pi]     in case normalize_around_zero == true


    Parameters
    ----------

    angle : SignalUserTemplate
        the input signal (angle in radians)

    Returns
    -------
    SignalUserTemplate
        the output signal   

    """

    def normalize_around_zero(angle):
        """
            Normalize an angle

            Normalize an angle to a range [-pi, pi]

            Important: the assumed range for the input is - 2*pi <= angle <= 2*p
        """

        tmp = angle            + dy.conditional_overwrite( dy.float64(0), angle <= float64(-math.pi), 2*math.pi )
        normalized_angle = tmp + dy.conditional_overwrite( dy.float64(0), angle > float64(math.pi), -2*math.pi )

        return normalized_angle

    #
    #
    angle_ = dy.fmod(angle, dy.float64(2*math.pi) )

    unwrapped_angle = angle_ + dy.conditional_overwrite( dy.float64(0), angle_ < float64(0), 2*math.pi )

    if normalize_around_zero:
        return normalize_around_zero(unwrapped_angle)
    else:
        return unwrapped_angle

Classes

class DataTypeArray (length: int, datatype: DataType)
Expand source code
class DataTypeArray(DataType):

    def __init__(self, length : int, datatype : DataType ):
        DataType.__init__(self, type_id=None, size=1)

        self._array_element_datatype = datatype
        self._length    = length

    @property
    def cpp_datatype_string(self):
        return self._array_element_datatype.cpp_datatype_string + ' [' + str(self._length) + ']'
    
    @property
    def datatype_of_elements(self):
        return self._array_element_datatype

    def cpp_define_variable(self, variable_name, make_a_reference = False):

        if make_a_reference:
            variable_name_ = ' (&' + variable_name + ')'
        else:
            variable_name_ = variable_name

        return self._array_element_datatype.cpp_datatype_string + ' ' + variable_name_ + '[' + str(self._length) + ']'

Ancestors

Instance variables

var cpp_datatype_string
Expand source code
@property
def cpp_datatype_string(self):
    return self._array_element_datatype.cpp_datatype_string + ' [' + str(self._length) + ']'
var datatype_of_elements
Expand source code
@property
def datatype_of_elements(self):
    return self._array_element_datatype

Methods

def cpp_define_variable(self, variable_name, make_a_reference=False)
Expand source code
def cpp_define_variable(self, variable_name, make_a_reference = False):

    if make_a_reference:
        variable_name_ = ' (&' + variable_name + ')'
    else:
        variable_name_ = variable_name

    return self._array_element_datatype.cpp_datatype_string + ' ' + variable_name_ + '[' + str(self._length) + ']'
class DataTypeBoolean (size: int)
Expand source code
class DataTypeBoolean(DataType):

    def __init__(self, size : int):
        DataType.__init__(self, type_id=ORTD_DATATYPE_BOOLEAN, size=size)

    @property
    def cpp_datatype_string(self):
        return 'bool'

    @property
    def cpp_printf_pattern(self):
        return '%d'

    @property
    def cpp_zero_element(self):
        return 'false'

Ancestors

Instance variables

var cpp_datatype_string
Expand source code
@property
def cpp_datatype_string(self):
    return 'bool'
var cpp_printf_pattern
Expand source code
@property
def cpp_printf_pattern(self):
    return '%d'
var cpp_zero_element
Expand source code
@property
def cpp_zero_element(self):
    return 'false'
class DataTypeFloat64 (size: int)
Expand source code
class DataTypeFloat64(DataTypeNumeric):

    def __init__(self, size : int):
        DataType.__init__(self, type_id=ORTD_DATATYPE_FLOAT, size=size)

    @property
    def cpp_datatype_string(self):
        return 'double'

    @property
    def cpp_printf_pattern(self):
        return '%f'

    @property
    def cpp_zero_element(self):
        return '0.0'

Ancestors

Instance variables

var cpp_datatype_string
Expand source code
@property
def cpp_datatype_string(self):
    return 'double'
var cpp_printf_pattern
Expand source code
@property
def cpp_printf_pattern(self):
    return '%f'
var cpp_zero_element
Expand source code
@property
def cpp_zero_element(self):
    return '0.0'
class DataTypeInt32 (size: int)
Expand source code
class DataTypeInt32(DataTypeNumeric):

    def __init__(self, size : int):

        DataType.__init__(self, type_id=ORTD_DATATYPE_INT32, size=size)

    @property
    def cpp_datatype_string(self):
        return 'int32_t'

    @property
    def cpp_printf_pattern(self):
        return '%d'

    @property
    def cpp_zero_element(self):
        return '0'

Ancestors

Instance variables

var cpp_datatype_string
Expand source code
@property
def cpp_datatype_string(self):
    return 'int32_t'
var cpp_printf_pattern
Expand source code
@property
def cpp_printf_pattern(self):
    return '%d'
var cpp_zero_element
Expand source code
@property
def cpp_zero_element(self):
    return '0'
class DataTypeNumeric (size: int)
Expand source code
class DataTypeNumeric(DataType):
    def __init__(self, size : int):
        DataType.__init__(self, type_id=ORTD_DATATYPE_FLOAT, size=size)

Ancestors

Subclasses

class DataTypePointer (cpp_type_name_class: str)

Create a pointer pointing to an instance of a given class

Example:

cpp_type_name_class = 'SomeClass'

In the source code of the class, the following definition is required

typedef SomeClass *SomeClassPtr
Expand source code
class DataTypePointer(DataType):
    """
    Create a pointer pointing to an instance of a given class

    Example:
    --------

        cpp_type_name_class = 'SomeClass' 

    In the source code of the class, the following definition is required

        typedef SomeClass *SomeClassPtr

    """

    def __init__(self, cpp_type_name_class : str ):
        DataType.__init__(self, type_id=None, size=1)

        self._cpp_ptr_type_name   = cpp_type_name_class + 'Ptr' # cpp_ptr_type_name
        self._cpp_type_name_class = cpp_type_name_class

    @property
    def cpp_datatype_string(self):
        """
        return the c++ datatype string of the pointer to the class instance 
        """
        return self._cpp_ptr_type_name

    @property
    def cpp_datatype_string_class(self):
        """
        return the c++ datatype string of the class
        """
        return self._cpp_type_name_class

    def is_equal_to(self, other_type):

        result = DataType.is_equal_to(self, other_type)

        if result == 1:
            if self._cpp_ptr_type_name == other_type._cpp_ptr_type_name:
                return 1
        else:
            return result

Ancestors

Instance variables

var cpp_datatype_string

return the c++ datatype string of the pointer to the class instance

Expand source code
@property
def cpp_datatype_string(self):
    """
    return the c++ datatype string of the pointer to the class instance 
    """
    return self._cpp_ptr_type_name
var cpp_datatype_string_class

return the c++ datatype string of the class

Expand source code
@property
def cpp_datatype_string_class(self):
    """
    return the c++ datatype string of the class
    """
    return self._cpp_type_name_class

Methods

def is_equal_to(self, other_type)
Expand source code
def is_equal_to(self, other_type):

    result = DataType.is_equal_to(self, other_type)

    if result == 1:
        if self._cpp_ptr_type_name == other_type._cpp_ptr_type_name:
            return 1
    else:
        return result
class SignalUserTemplate (system, wrapped_signal: Signal)
Expand source code
class SignalUserTemplate(object):
    def __init__(self, system, wrapped_signal : Signal):

        self._system = system
        self._wrapped_signal = wrapped_signal

    def __hash__(self):
        return id(self)

    @property
    def unwrap(self):
        """
        Get the library-internal representation of a signal (internal use only)
        """
        return self._wrapped_signal

    @property
    def name(self):
        """
        the identifier of the signal
        """
        return self._wrapped_signal.name

    @property
    def properties(self):
        """
        A hash array of properties
        """
        return self._wrapped_signal.properties

    def set_properties(self, p):
        """
        Set the properties of the signal
        """
        self._wrapped_signal.set_properties(p)
        return self

    def set_datatype(self, datatype):
        # call setDatatype_nonotitication to prevent the (untested) automatic update of the datatypes
        self._wrapped_signal.setDatatype_nonotitication(datatype)
        return self

    def set_name(self, name):
        """
        Set the signals identifier. Must be a string without spaces and alphanumerical characters only. 
        """
        self._wrapped_signal.set_name(name)
        return self

    def set_name_raw(self, name):
        self._wrapped_signal.set_name_raw(name)
        return self


    def extend_name(self, name):
        """
        Extand the current signal identifier by appending characters at the end of the string
        """
        self._wrapped_signal.set_name( self._wrapped_signal.name + name )
        return self

    def set_blockname(self, name):
        """
        Set the name of the block that has the signal as one of its outputs
        """
        self._wrapped_signal.set_blockname(name)
        return self

    # ...

    #
    # operator overloads
    #

    def __add__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ self.unwrap, other.unwrap ], operator='+').outputs[0] )

    def __radd__(self, other): 
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ self.unwrap, other.unwrap ], operator='+').outputs[0] )


    def __sub__(self, other): 
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ self.unwrap, other.unwrap ], operator='-').outputs[0] )

    def __rsub__(self, other): 
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ other.unwrap, self.unwrap ], operator='-').outputs[0] )


    def __mul__(self, other): 
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ self.unwrap, other.unwrap ], operator='*').outputs[0] )

    def __rmul__(self, other): 
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ self.unwrap, other.unwrap ], operator='*').outputs[0] )


    def __truediv__(self, other): 
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ self.unwrap, other.unwrap ], operator='/').outputs[0] )

    def __rtruediv__(self, other): 
        other = convert_python_constant_val_to_const_signal(other)
        return wrap_signal( block_prototypes.Operator1( dy.get_system_context(), inputSignals=[ other.unwrap, self.unwrap ], operator='/').outputs[0] )



    # _comparison operators
    def __le__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '<=' ) )

    def __rle__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = other, right = self, operator = '<=' ) )



    def __ge__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '>=' ) )

    def __rge__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = other, right = self, operator = '>=' ) )



    def __lt__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '<' ) )

    def __rlt__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = other, right = self, operator = '<' ) )



    def __gt__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '>' ) )

    def __rgt__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = other, right = self, operator = '>' ) )



    def __eq__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '==' ) )

    def __req__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '==' ) )

    def __ne__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '!=' ) )

    def __rne__(self, other):
        other = convert_python_constant_val_to_const_signal(other)
        return ( _comparison(left = self, right = other, operator = '!=' ) )

Subclasses

Instance variables

var name

the identifier of the signal

Expand source code
@property
def name(self):
    """
    the identifier of the signal
    """
    return self._wrapped_signal.name
var properties

A hash array of properties

Expand source code
@property
def properties(self):
    """
    A hash array of properties
    """
    return self._wrapped_signal.properties
var unwrap

Get the library-internal representation of a signal (internal use only)

Expand source code
@property
def unwrap(self):
    """
    Get the library-internal representation of a signal (internal use only)
    """
    return self._wrapped_signal

Methods

def extend_name(self, name)

Extand the current signal identifier by appending characters at the end of the string

Expand source code
def extend_name(self, name):
    """
    Extand the current signal identifier by appending characters at the end of the string
    """
    self._wrapped_signal.set_name( self._wrapped_signal.name + name )
    return self
def set_blockname(self, name)

Set the name of the block that has the signal as one of its outputs

Expand source code
def set_blockname(self, name):
    """
    Set the name of the block that has the signal as one of its outputs
    """
    self._wrapped_signal.set_blockname(name)
    return self
def set_datatype(self, datatype)
Expand source code
def set_datatype(self, datatype):
    # call setDatatype_nonotitication to prevent the (untested) automatic update of the datatypes
    self._wrapped_signal.setDatatype_nonotitication(datatype)
    return self
def set_name(self, name)

Set the signals identifier. Must be a string without spaces and alphanumerical characters only.

Expand source code
def set_name(self, name):
    """
    Set the signals identifier. Must be a string without spaces and alphanumerical characters only. 
    """
    self._wrapped_signal.set_name(name)
    return self
def set_name_raw(self, name)
Expand source code
def set_name_raw(self, name):
    self._wrapped_signal.set_name_raw(name)
    return self
def set_properties(self, p)

Set the properties of the signal

Expand source code
def set_properties(self, p):
    """
    Set the properties of the signal
    """
    self._wrapped_signal.set_properties(p)
    return self
class TargetBasicExecutable (i_max: int, input_signals_mapping={})

generates code for the runtime environment

Expand source code
class TargetBasicExecutable(TargetGenericCpp):
    """
        generates code for the runtime environment
    """

    def __init__(self, i_max : int, input_signals_mapping = {} ):

        self._i_max = i_max

        TargetGenericCpp.__init__(self)

        self.input_signals_mapping = input_signals_mapping
        self.initCodeTemplate()

        
    def code_gen(self):

        # call helper to fill in some generic elements into the template
        code_gen_results = TargetGenericCpp.code_gen(self)

        #
        # make strings 
        # 

        # constant inputs
        inputConstAssignments = []
        for signal, value in self.input_signals_mapping.items():
            inputConstAssignments.append( signal.name + ' = ' + str(value) )

        inputConstAssignment = '; '.join( inputConstAssignments ) + ';'

        self.sourceCode = Template(self.template).safe_substitute( iMax=self._i_max,
                                                                 inputConstAssignment=inputConstAssignment    ) 

        code_gen_results['sourcecode'] = self.sourceCode
        return code_gen_results

    def write_code(self, folder):
        TargetGenericCpp.writeFiles(self, folder)

        self.codeFolder = folder

        f = open(os.path.join( folder + "main.cpp"), "w")
        f.write( self.sourceCode )
        f.close()


    def build(self):
        os.system("c++ " + self.codeFolder + "main.cpp -o " + self.codeFolder + "main")


    def run(self):
        # run the generated executable
        p = subprocess.Popen(self.codeFolder + 'main', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        retval = p.wait()

        # parse csv data
        data = [ ]
        outputs = range(0, len(self.main_command.command_to_put_main_system.outputCommand.outputSignals) )

        for o in outputs:
            data.append( [] )

        for line in p.stdout.readlines():
            sample = line.decode("utf-8").split(' ')

            for o in outputs:
                data[ o ].append( float( sample[o] ) )

        # put data into a key-array
        dataStruct = { }
        o = 0
        for s in self.main_command.command_to_put_main_system.outputCommand.outputSignals:
            dataStruct[ s.name ] = data[o]

            o = o + 1

        return dataStruct


    def initCodeTemplate(self):

        #
        # template for main function in c++
        #

        self.template = """
            
#include <math.h>
#include <stdio.h>

//
// implementation of $mainSimulationName
//

$algorithmCode

//
// main
//

int main () {

    // create an instance of the simulation
    $mainSimulationName simulation;

    // input signals
    $inputAll_NamesVarDef

    // output signals
    $outputNamesVarDef

    // const assignments of the input signals
    $inputConstAssignment

    // reset the simulation
    simulation.resetStates();

    // simulate
    int i;

    for (i=0; i< $iMax; ++i) {
        simulation.calcResults_1( $calcOutputsArgs );
        simulation.updateStates(  $input2_NamesCSVList );

        printf("$outputPrinfPattern\\n", $outputNamesCSVList);
    }

}

            
        """        

Ancestors

Methods

def build(self)
Expand source code
def build(self):
    os.system("c++ " + self.codeFolder + "main.cpp -o " + self.codeFolder + "main")
def code_gen(self)
Expand source code
def code_gen(self):

    # call helper to fill in some generic elements into the template
    code_gen_results = TargetGenericCpp.code_gen(self)

    #
    # make strings 
    # 

    # constant inputs
    inputConstAssignments = []
    for signal, value in self.input_signals_mapping.items():
        inputConstAssignments.append( signal.name + ' = ' + str(value) )

    inputConstAssignment = '; '.join( inputConstAssignments ) + ';'

    self.sourceCode = Template(self.template).safe_substitute( iMax=self._i_max,
                                                             inputConstAssignment=inputConstAssignment    ) 

    code_gen_results['sourcecode'] = self.sourceCode
    return code_gen_results
def initCodeTemplate(self)
Expand source code
    def initCodeTemplate(self):

        #
        # template for main function in c++
        #

        self.template = """
            
#include <math.h>
#include <stdio.h>

//
// implementation of $mainSimulationName
//

$algorithmCode

//
// main
//

int main () {

    // create an instance of the simulation
    $mainSimulationName simulation;

    // input signals
    $inputAll_NamesVarDef

    // output signals
    $outputNamesVarDef

    // const assignments of the input signals
    $inputConstAssignment

    // reset the simulation
    simulation.resetStates();

    // simulate
    int i;

    for (i=0; i< $iMax; ++i) {
        simulation.calcResults_1( $calcOutputsArgs );
        simulation.updateStates(  $input2_NamesCSVList );

        printf("$outputPrinfPattern\\n", $outputNamesCSVList);
    }

}

            
        """        
def run(self)
Expand source code
def run(self):
    # run the generated executable
    p = subprocess.Popen(self.codeFolder + 'main', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    retval = p.wait()

    # parse csv data
    data = [ ]
    outputs = range(0, len(self.main_command.command_to_put_main_system.outputCommand.outputSignals) )

    for o in outputs:
        data.append( [] )

    for line in p.stdout.readlines():
        sample = line.decode("utf-8").split(' ')

        for o in outputs:
            data[ o ].append( float( sample[o] ) )

    # put data into a key-array
    dataStruct = { }
    o = 0
    for s in self.main_command.command_to_put_main_system.outputCommand.outputSignals:
        dataStruct[ s.name ] = data[o]

        o = o + 1

    return dataStruct
def write_code(self, folder)
Expand source code
def write_code(self, folder):
    TargetGenericCpp.writeFiles(self, folder)

    self.codeFolder = folder

    f = open(os.path.join( folder + "main.cpp"), "w")
    f.write( self.sourceCode )
    f.close()

Inherited members

class TargetGenericCpp (enable_tracing=False)

generates code for the runtime environment

Expand source code
class TargetGenericCpp:
    """
        generates code for the runtime environment
    """

    def __init__(self, enable_tracing=False ):
        ExecutionCommand.__init__(self)  # TODO: what is this?

        # if compile_results is not None:
        #     self.compileResults = compile_results
        #     self.main_command = compile_results.command_to_execute

        # else:

        # those are set via set_compile_results after a system is compiled
        self.compileResults = None
        self.main_command = None
        self._include_code_list = None

        #
        self._algorithm_code = None

        # list of systems to include
        self._includedSystems = []

        self._enable_tracing = enable_tracing

    def set_compile_results(self, compile_results : CompileResults ):
        self.compileResults = compile_results
        self.main_command = compile_results.command_to_execute

    def include_systems(self, system : SystemLibraryEntry):
        self._includedSystems = system

    def add_code_to_include(self, include_code_list : List[str] = []):
        self._include_code_list = include_code_list

    def get_algorithm_code(self):
        """
            Return only the code that implement the system and all sub systems
        """
        return self._algorithm_code



    def code_gen(self):

        # generate code for the algorithm
        self.manifest, self._algorithm_code = _generate_algorithm_code(
            self.compileResults, 
            self._enable_tracing, 
            self._includedSystems, 
            self._include_code_list
        )

        
        # TODO: iterate over all functions present in the API of the system
        # NOTE: Currently only the main functions are used: output, update, and reset
        #
        API_functions = self.main_command.command_to_put_main_system.API_functions

        #
        # make strings 
        # 

        def makeStrings(signals):
            names_CSV_list = cgh.signal_list_to_names_string(signals)
            names_var_def = cgh.define_variable_list_string(signals)
            printf_pattern = cgh.signalListHelper_printfPattern_string(signals)

            return names_CSV_list, names_var_def, printf_pattern


        # for the output signals
        # input1_NamesCSVList; list of output signals. e.g. 'y1, y2, y3' 
        outputNamesCSVList, outputNamesVarDef, outputPrinfPattern = makeStrings( self.main_command.command_to_put_main_system.outputCommand.outputSignals )

        # the inputs to the output command
        # input1_NamesCSVList: list of output signals. e.g. 'y1, y2, y3' 
        input1_NamesCSVList, input1_NamesVarDef, input1PrinfPattern = makeStrings( self.main_command.command_to_put_main_system.outputCommand.inputSignals )

        # the inputs to the update command
        # input2_NamesCSVList list of output signals. e.g. 'u1, u2, u3' 
        input2_NamesCSVList, input2_NamesVarDef, input2_PrinfPattern = makeStrings( self.main_command.command_to_put_main_system.updateCommand.inputSignals )

        # all inputs
        # merge the list of inputs for the calcoutput and stateupdate function
        allInputs = list(set(self.main_command.command_to_put_main_system.outputCommand.inputSignals + self.main_command.command_to_put_main_system.updateCommand.inputSignals))
        inputAll_NamesCSVList, inputAll_NamesVarDef, inputAll_PrinfPattern = makeStrings( allInputs )

        # the names of input and output signals of the outputCommand combined
        calcOutputsArgs = cgh.signal_list_to_name_list( self.main_command.command_to_put_main_system.outputCommand.outputSignals + self.main_command.command_to_put_main_system.outputCommand.inputSignals )

        # fill in template
        self.template = Template(self.template).safe_substitute(  
                                                    mainSimulationName = self.main_command.command_to_put_main_system.API_name,
                                                    algorithmCode=self._algorithm_code,

                                                    input1_NamesVarDef=input1_NamesVarDef,
                                                    input1_NamesCSVList=input1_NamesCSVList,

                                                    input2_NamesVarDef=input2_NamesVarDef,
                                                    input2_NamesCSVList=input2_NamesCSVList,

                                                    inputAll_NamesVarDef=inputAll_NamesVarDef,
                                                    inputAll_NamesCSVList=inputAll_NamesCSVList,

                                                    outputNamesCSVList=outputNamesCSVList, 
                                                    outputNamesVarDef=outputNamesVarDef,
                                                    outputPrinfPattern=outputPrinfPattern,
                                                    
                                                    calcOutputsArgs=calcOutputsArgs )


        return {'sourcecode' : self.template, 'manifest' : self.manifest, 'algorithm_sourcecode' : self._algorithm_code }

    def writeFiles(self, folder):

        with open( os.path.join( folder + '//simulation_manifest.json' ), 'w') as outfile:  
            json.dump(self.manifest, outfile)

    def build(self):
        pass

    def run(self):
        pass

Subclasses

Methods

def add_code_to_include(self, include_code_list: List[str] = [])
Expand source code
def add_code_to_include(self, include_code_list : List[str] = []):
    self._include_code_list = include_code_list
def build(self)
Expand source code
def build(self):
    pass
def code_gen(self)
Expand source code
def code_gen(self):

    # generate code for the algorithm
    self.manifest, self._algorithm_code = _generate_algorithm_code(
        self.compileResults, 
        self._enable_tracing, 
        self._includedSystems, 
        self._include_code_list
    )

    
    # TODO: iterate over all functions present in the API of the system
    # NOTE: Currently only the main functions are used: output, update, and reset
    #
    API_functions = self.main_command.command_to_put_main_system.API_functions

    #
    # make strings 
    # 

    def makeStrings(signals):
        names_CSV_list = cgh.signal_list_to_names_string(signals)
        names_var_def = cgh.define_variable_list_string(signals)
        printf_pattern = cgh.signalListHelper_printfPattern_string(signals)

        return names_CSV_list, names_var_def, printf_pattern


    # for the output signals
    # input1_NamesCSVList; list of output signals. e.g. 'y1, y2, y3' 
    outputNamesCSVList, outputNamesVarDef, outputPrinfPattern = makeStrings( self.main_command.command_to_put_main_system.outputCommand.outputSignals )

    # the inputs to the output command
    # input1_NamesCSVList: list of output signals. e.g. 'y1, y2, y3' 
    input1_NamesCSVList, input1_NamesVarDef, input1PrinfPattern = makeStrings( self.main_command.command_to_put_main_system.outputCommand.inputSignals )

    # the inputs to the update command
    # input2_NamesCSVList list of output signals. e.g. 'u1, u2, u3' 
    input2_NamesCSVList, input2_NamesVarDef, input2_PrinfPattern = makeStrings( self.main_command.command_to_put_main_system.updateCommand.inputSignals )

    # all inputs
    # merge the list of inputs for the calcoutput and stateupdate function
    allInputs = list(set(self.main_command.command_to_put_main_system.outputCommand.inputSignals + self.main_command.command_to_put_main_system.updateCommand.inputSignals))
    inputAll_NamesCSVList, inputAll_NamesVarDef, inputAll_PrinfPattern = makeStrings( allInputs )

    # the names of input and output signals of the outputCommand combined
    calcOutputsArgs = cgh.signal_list_to_name_list( self.main_command.command_to_put_main_system.outputCommand.outputSignals + self.main_command.command_to_put_main_system.outputCommand.inputSignals )

    # fill in template
    self.template = Template(self.template).safe_substitute(  
                                                mainSimulationName = self.main_command.command_to_put_main_system.API_name,
                                                algorithmCode=self._algorithm_code,

                                                input1_NamesVarDef=input1_NamesVarDef,
                                                input1_NamesCSVList=input1_NamesCSVList,

                                                input2_NamesVarDef=input2_NamesVarDef,
                                                input2_NamesCSVList=input2_NamesCSVList,

                                                inputAll_NamesVarDef=inputAll_NamesVarDef,
                                                inputAll_NamesCSVList=inputAll_NamesCSVList,

                                                outputNamesCSVList=outputNamesCSVList, 
                                                outputNamesVarDef=outputNamesVarDef,
                                                outputPrinfPattern=outputPrinfPattern,
                                                
                                                calcOutputsArgs=calcOutputsArgs )


    return {'sourcecode' : self.template, 'manifest' : self.manifest, 'algorithm_sourcecode' : self._algorithm_code }
def get_algorithm_code(self)

Return only the code that implement the system and all sub systems

Expand source code
def get_algorithm_code(self):
    """
        Return only the code that implement the system and all sub systems
    """
    return self._algorithm_code
def include_systems(self, system: SystemLibraryEntry)
Expand source code
def include_systems(self, system : SystemLibraryEntry):
    self._includedSystems = system
def run(self)
Expand source code
def run(self):
    pass
def set_compile_results(self, compile_results: CompileResults)
Expand source code
def set_compile_results(self, compile_results : CompileResults ):
    self.compileResults = compile_results
    self.main_command = compile_results.command_to_execute
def writeFiles(self, folder)
Expand source code
def writeFiles(self, folder):

    with open( os.path.join( folder + '//simulation_manifest.json' ), 'w') as outfile:  
        json.dump(self.manifest, outfile)
class TargetWasm (enable_tracing=False)

generates code for the Webassemble runtime environment

https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html

Expand source code
class TargetWasm(TargetGenericCpp):
    """
        generates code for the Webassemble runtime environment

        https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html

    """

    def __init__(self, enable_tracing = False ):

        TargetGenericCpp.__init__(self, enable_tracing=enable_tracing)

        self.initCodeTemplate()

        
    def code_gen(self):

        # build I/O structs
        ioExport = self.generate_code_writeIO(self.main_command.command_to_put_main_system.outputCommand)
        ioExport += self.generate_code_writeIO(self.main_command.command_to_put_main_system.updateCommand)

        ioExport += self.generate_code_writeIO(self.main_command.command_to_put_main_system.resetCommand)

        self.template = Template(self.template).safe_substitute( ioExport=ioExport,
                                                                 inputConstAssignment=''    ) 

        # call helper to fill in some generic elements into the template
        code_gen_results = TargetGenericCpp.code_gen(self)

        self.sourceCode = self.template

        code_gen_results['sourcecode'] = self.sourceCode
        return code_gen_results



    def generate_code_writeIO__(self, command_API, inputOutput : int):

        if inputOutput == 1:
            structPrefix = 'Inputs_'
            signals = command_API.inputSignals

        elif inputOutput == 2:
            structPrefix = 'Outputs_'
            signals = command_API.outputSignals

        mainSimulationName = self.main_command.command_to_put_main_system.API_name

        lines = ''

        # Inputs
        structname = structPrefix + command_API.API_name 

        lines += 'value_object<' + mainSimulationName + '::' + structname + '>("' + mainSimulationName + '__' + structname + '")\n'

        for s in signals:
            fieldName = s.name

            lines += '.field("' + fieldName + '", &' + mainSimulationName + '::' + structname + '::' + fieldName + ')\n'

        lines += ';\n\n'


        return lines

    def generate_code_writeIO(self, command_API):
        return self.generate_code_writeIO__(command_API, 1) + self.generate_code_writeIO__(command_API, 2)


    def write_code(self, folder):

        TargetGenericCpp.writeFiles(self, folder)

        self.codeFolder = folder

        f = open( Path( folder ) / "main.cpp", "w")
        f.write( self.sourceCode )
        f.close()


    def build(self):

        buildCommand = 'emcc --bind -s MODULARIZE=1 -s EXPORT_NAME="ORTD_simulator" '  + os.path.join(self.codeFolder , "main.cpp") + " -g4 -s -o " + os.path.join( self.codeFolder , "main.js" )
        print("Running compiler: " + buildCommand)

        returnCode = os.system(buildCommand)

        print( "Compilation result: ", returnCode )


    def initCodeTemplate(self):

        #
        # template for main function in c++
        #

        self.template = """
            
#include <math.h>
#include <stdio.h>
#include <emscripten/bind.h>

using namespace emscripten;

//
// implementation of $mainSimulationName
//

$algorithmCode

// Binding code
EMSCRIPTEN_BINDINGS(my_class_example) {
  class_<$mainSimulationName>("$mainSimulationName")
    .constructor<>()
    .function("resetStates", &$mainSimulationName::resetStates__)
    .function("calcResults_1", &$mainSimulationName::calcResults_1__)
    .function("updateStates", &$mainSimulationName::updateStates__)
    ;


// --------------------------------

$ioExport


}
            
        """        

Ancestors

Methods

def build(self)
Expand source code
def build(self):

    buildCommand = 'emcc --bind -s MODULARIZE=1 -s EXPORT_NAME="ORTD_simulator" '  + os.path.join(self.codeFolder , "main.cpp") + " -g4 -s -o " + os.path.join( self.codeFolder , "main.js" )
    print("Running compiler: " + buildCommand)

    returnCode = os.system(buildCommand)

    print( "Compilation result: ", returnCode )
def code_gen(self)
Expand source code
def code_gen(self):

    # build I/O structs
    ioExport = self.generate_code_writeIO(self.main_command.command_to_put_main_system.outputCommand)
    ioExport += self.generate_code_writeIO(self.main_command.command_to_put_main_system.updateCommand)

    ioExport += self.generate_code_writeIO(self.main_command.command_to_put_main_system.resetCommand)

    self.template = Template(self.template).safe_substitute( ioExport=ioExport,
                                                             inputConstAssignment=''    ) 

    # call helper to fill in some generic elements into the template
    code_gen_results = TargetGenericCpp.code_gen(self)

    self.sourceCode = self.template

    code_gen_results['sourcecode'] = self.sourceCode
    return code_gen_results
def generate_code_writeIO(self, command_API)
Expand source code
def generate_code_writeIO(self, command_API):
    return self.generate_code_writeIO__(command_API, 1) + self.generate_code_writeIO__(command_API, 2)
def generate_code_writeIO__(self, command_API, inputOutput: int)
Expand source code
def generate_code_writeIO__(self, command_API, inputOutput : int):

    if inputOutput == 1:
        structPrefix = 'Inputs_'
        signals = command_API.inputSignals

    elif inputOutput == 2:
        structPrefix = 'Outputs_'
        signals = command_API.outputSignals

    mainSimulationName = self.main_command.command_to_put_main_system.API_name

    lines = ''

    # Inputs
    structname = structPrefix + command_API.API_name 

    lines += 'value_object<' + mainSimulationName + '::' + structname + '>("' + mainSimulationName + '__' + structname + '")\n'

    for s in signals:
        fieldName = s.name

        lines += '.field("' + fieldName + '", &' + mainSimulationName + '::' + structname + '::' + fieldName + ')\n'

    lines += ';\n\n'


    return lines
def initCodeTemplate(self)
Expand source code
    def initCodeTemplate(self):

        #
        # template for main function in c++
        #

        self.template = """
            
#include <math.h>
#include <stdio.h>
#include <emscripten/bind.h>

using namespace emscripten;

//
// implementation of $mainSimulationName
//

$algorithmCode

// Binding code
EMSCRIPTEN_BINDINGS(my_class_example) {
  class_<$mainSimulationName>("$mainSimulationName")
    .constructor<>()
    .function("resetStates", &$mainSimulationName::resetStates__)
    .function("calcResults_1", &$mainSimulationName::calcResults_1__)
    .function("updateStates", &$mainSimulationName::updateStates__)
    ;


// --------------------------------

$ioExport


}
            
        """        
def write_code(self, folder)
Expand source code
def write_code(self, folder):

    TargetGenericCpp.writeFiles(self, folder)

    self.codeFolder = folder

    f = open( Path( folder ) / "main.cpp", "w")
    f.write( self.sourceCode )
    f.close()

Inherited members

class state_sub (subsystem_name=None)

A single subsystem as part of a state machine (implemented by sub_statemachine)

  • methods to called by the user -

set_switched_outputs(signals, state_signal) - connect a list of signals to the output of the state machine

Expand source code
class state_sub(SwitchedSubsystemPrototype):
    """
        A single subsystem as part of a state machine (implemented by sub_statemachine)

        - methods to called by the user -

        set_switched_outputs(signals, state_signal)  - connect a list of signals to the output of the state machine
    """

    def __init__(self, subsystem_name = None ):
        SwitchedSubsystemPrototype.__init__(self, subsystem_name)

        self._output_signals = None
        self._state_signal = None


    def set_switched_outputs(self, signals, state_signal):
        """
            set the output signals of a subsystem embedded into the state machine

            - signals      - normal system output that are forwarded using a switch
            - state_signal - control signal indicating the next state the state machine enters
        """
        self._output_signals = signals
        self._state_signal = state_signal

        self.set_switched_outputs_prototype( signals +  [state_signal] )

    @property
    def state_control_output(self):
         return self._state_signal

    @property
    def subsystem_outputs(self):
        return self._output_signals

Ancestors

Instance variables

var state_control_output
Expand source code
@property
def state_control_output(self):
     return self._state_signal
var subsystem_outputs
Expand source code
@property
def subsystem_outputs(self):
    return self._output_signals

Methods

def set_switched_outputs(self, signals, state_signal)

set the output signals of a subsystem embedded into the state machine

  • signals - normal system output that are forwarded using a switch
  • state_signal - control signal indicating the next state the state machine enters
Expand source code
def set_switched_outputs(self, signals, state_signal):
    """
        set the output signals of a subsystem embedded into the state machine

        - signals      - normal system output that are forwarded using a switch
        - state_signal - control signal indicating the next state the state machine enters
    """
    self._output_signals = signals
    self._state_signal = state_signal

    self.set_switched_outputs_prototype( signals +  [state_signal] )

Inherited members

class sub_if (condition_signal: SignalUserTemplate, subsystem_name=None, prevent_output_computation=False)

NOTE: in case the if condition is false, the outputs are hold. Eventally uninitialized.

Expand source code
class sub_if:
    """

        NOTE: in case the if condition is false, the outputs are hold. Eventally uninitialized.
    """


    def __init__(self, condition_signal : dy.SignalUserTemplate, subsystem_name = None, prevent_output_computation = False ):

        if subsystem_name is not None:
            self._subsystem_name = subsystem_name
        else:
            self._subsystem_name = generate_subsystem_name()

        self._condition_signal = condition_signal
        self._prevent_output_computation = prevent_output_computation

        # 
        self._outputs_of_embeded_subsystem = []

        # outputs (links to the subsystem outputs) to be used by the user
        self._output_links = None


    def set_outputs(self, signals):
        self._outputs_of_embeded_subsystem = signals.copy()

    def __enter__(self):
        self._system = enter_subsystem(self._subsystem_name )

        return self


    def __exit__(self, type, value, traceback):

        embedded_subsystem = dy.get_system_context()

        # set the outputs of the system
        embedded_subsystem.set_primary_outputs( si.unwrap_list( self._outputs_of_embeded_subsystem ) )

        # create generic subsystem block prototype
        self._subsystem_block_prototype = bp.GenericSubsystem( sim=embedded_subsystem.upper_level_system, 
                                                    manifest=None, inputSignals=None, 
                                                    embedded_subsystem=embedded_subsystem,
                                                    N_outputs=len(self._outputs_of_embeded_subsystem) )

        # leave the context of the subsystem
        dy.leave_system()

        #
        # now in the system in which the embeder block (including the logic) shall be placed.
        #

        # create the embedder prototype
        embeddedingBlockPrototype = bp.TruggeredSubsystem( sim=dy.get_system_context(), 
                control_input=si.unwrap( self._condition_signal ), 
                subsystem_prototype=self._subsystem_block_prototype,
                prevent_output_computation = self._prevent_output_computation)


        # connect the normal outputs via links
        self._output_links = si.wrap_signal_list( embeddedingBlockPrototype.outputs )

        # connect the additional (control) outputs
        # self._state_output = si.wrap_signal( embeddedingBlockPrototype.state_output )

    @property
    def outputs(self):

        if self._output_links is None:
            BaseException("Please close the subsystem before querying its outputs")
        
        return self._output_links

Instance variables

var outputs
Expand source code
@property
def outputs(self):

    if self._output_links is None:
        BaseException("Please close the subsystem before querying its outputs")
    
    return self._output_links

Methods

def set_outputs(self, signals)
Expand source code
def set_outputs(self, signals):
    self._outputs_of_embeded_subsystem = signals.copy()
class sub_loop (max_iterations: int, subsystem_name=None)
Expand source code
class sub_loop:
    """

    """


    def __init__(self, max_iterations : int, subsystem_name = None ):

        if subsystem_name is not None:
            self._subsystem_name = subsystem_name
        else:
            self._subsystem_name = generate_subsystem_name()

        self._max_iterations = max_iterations

        # control outputs of the embedded subsystem
        self._until_signal = None
        self._yield_signal = None

        # 
        self._outputs_of_embeded_subsystem = []

        # outputs (links to the subsystem outputs) to be used by the user
        self._output_links = None


    def set_outputs(self, signals):
        self._outputs_of_embeded_subsystem = si.unwrap_list( signals.copy() )

    def loop_until(self, condition_signal):
        self._until_signal = condition_signal.unwrap

    def loop_yield(self, condition_signal):
        self._yield_signal = condition_signal.unwrap

    def __enter__(self):

        self._system = enter_subsystem(self._subsystem_name )

        return self


    def __exit__(self, type, value, traceback):

        embedded_subsystem = dy.get_system_context()

        # collect all outputs
        all_output_signals = []
        all_output_signals.extend(self._outputs_of_embeded_subsystem)
        if self._until_signal is not None:
            all_output_signals.append(self._until_signal)
        if self._yield_signal is not None:
            all_output_signals.append(self._yield_signal)

        # set the outputs of the system
        embedded_subsystem.set_primary_outputs(  all_output_signals  )

        # create generic subsystem block prototype
        self._subsystem_block_prototype = bp.GenericSubsystem( sim=embedded_subsystem.upper_level_system, 
                                                    manifest=None, inputSignals=None, 
                                                    embedded_subsystem=embedded_subsystem,
                                                    N_outputs=len(all_output_signals) )

        # leave the context of the subsystem
        dy.leave_system()

        #
        # now in the system in which the embeder block (including the logic) shall be placed.
        #

        # create the embeeder prototype
        embeddedingBlockPrototype = bp.LoopUntilSubsystem( sim=dy.get_system_context(), 
                max_iterations=self._max_iterations, 
                subsystem_prototype=self._subsystem_block_prototype,
                until_signal=self._until_signal,
                yield_signal=self._yield_signal)


                # subsystem_prototypes=subsystem_prototypes, 
                # reference_outputs=  si.unwrap_list( self._reference_outputs ) )

        # connect the normal outputs via links
        self._output_links = si.wrap_signal_list( embeddedingBlockPrototype.outputs )

        # connect the additional (control) outputs
        # self._state_output = si.wrap_signal( embeddedingBlockPrototype.state_output )

    @property
    def outputs(self):

        if self._output_links is None:
            BaseException("Please close the subsystem before querying its outputs")
        
        return self._output_links

Instance variables

var outputs
Expand source code
@property
def outputs(self):

    if self._output_links is None:
        BaseException("Please close the subsystem before querying its outputs")
    
    return self._output_links

Methods

def loop_until(self, condition_signal)
Expand source code
def loop_until(self, condition_signal):
    self._until_signal = condition_signal.unwrap
def loop_yield(self, condition_signal)
Expand source code
def loop_yield(self, condition_signal):
    self._yield_signal = condition_signal.unwrap
def set_outputs(self, signals)
Expand source code
def set_outputs(self, signals):
    self._outputs_of_embeded_subsystem = si.unwrap_list( signals.copy() )
class sub_statemachine (switch_subsystem_name)

A state machine subsystem

  • properties -

self.state - status signal of the state machine (available after 'with sub_statemachine' has findished)

Expand source code
class sub_statemachine(SwitchPrototype):
    """
        A state machine subsystem

        - properties -

        self.state - status signal of the state machine (available after 'with sub_statemachine' has findished)
    """
    def __init__(self, switch_subsystem_name):
        number_of_control_outputs = 1 # add one control output to inform about the current state

        SwitchPrototype.__init__(self, switch_subsystem_name, number_of_control_outputs )

        # state output signal undefined until defined by on_exit() 
        self._state_output = None

    @property
    def state(self):
        """
            get the signal describing the current state
        """
        return self._state_output

    def new_subsystem(self, subsystem_name = None):

        system = state_sub(subsystem_name=subsystem_name)
        self._subsystem_list.append(system)

        return system

    def on_exit(self, subsystem_prototypes):

        # create the embeeder prototype
        embeddedingBlockPrototype = bp.StatemachineSwitchSubsystems( sim=dy.get_system_context(), 
                subsystem_prototypes=subsystem_prototypes, 
                reference_outputs=  si.unwrap_list( self._reference_outputs ) )

        # connect the normal outputs via links
        self._switch_output_links = si.wrap_signal_list( embeddedingBlockPrototype.switched_normal_outputs )

        # connect the additional (control) outputs
        self._state_output = si.wrap_signal( embeddedingBlockPrototype.state_output )

Ancestors

Instance variables

var state

get the signal describing the current state

Expand source code
@property
def state(self):
    """
        get the signal describing the current state
    """
    return self._state_output

Methods

def new_subsystem(self, subsystem_name=None)
Expand source code
def new_subsystem(self, subsystem_name = None):

    system = state_sub(subsystem_name=subsystem_name)
    self._subsystem_list.append(system)

    return system

Inherited members

class sub_switch (switch_subsystem_name, select_signal: SignalUserTemplate)

a switch for subsystems that are implemented by SwitchedSubsystemPrototype (class to be derived)

switch_subsystem_name - the name of the switch number_of_control_outputs - the number of system outputs in addition to the embedded systems outputs i.e. control outputs of a switch/statemaching/…

  • member variables -

self._switch_output_links - overwrite by derived class when calling on_exit() self.outputs - a list of output signals as defined by self._switch_output_links

  • methods to be defined -

on_exit(subsystem_prototypes) - callback once all subsystems were defined during this callback self._switch_output_links must be defined

Expand source code
class sub_switch(SwitchPrototype):
    def __init__(self, switch_subsystem_name, select_signal : dy.SignalUserTemplate ):

        self._select_signal = select_signal
        SwitchPrototype.__init__(self, switch_subsystem_name, number_of_control_outputs=0)

    def new_subsystem(self, subsystem_name = None):

        system = SwitchedSubsystem(subsystem_name=subsystem_name)
        self._subsystem_list.append(system)

        return system


    def on_exit(self, subsystem_prototypes):

        # create the  embeeder prototype
        embeddedingBlockPrototype = bp.SwitchSubsystems( sim=dy.get_system_context(), 
                control_input=self._select_signal.unwrap, 
                subsystem_prototypes=subsystem_prototypes, 
                reference_outputs=  si.unwrap_list( self._reference_outputs ) )

        # connect the normal outputs via links
        self._switch_output_links = si.wrap_signal_list( embeddedingBlockPrototype.switched_normal_outputs )

Ancestors

Methods

def new_subsystem(self, subsystem_name=None)
Expand source code
def new_subsystem(self, subsystem_name = None):

    system = SwitchedSubsystem(subsystem_name=subsystem_name)
    self._subsystem_list.append(system)

    return system

Inherited members