def firstOrder( u, z_inf, name : str = ''):

    yFb = dy.signal()

    i = dy.add( [ yFb, u ], [ z_inf, 1 ] ).set_name(name + '_i')
    y = dy.delay( i).set_name(name + '_y')

    yFb << y

    return y
def dInt( u , name : str = ''):

    yFb = dy.signal()

    i = dy.add( [ yFb, u ], [ 1, 1 ] ).set_name(name + '_i')
    y = dy.delay( i).set_name(name + '_y')

    yFb << y

    return y
def euler_integrator(u: dy.Signal, sampling_rate: float, initial_state=0.0):

    yFb = dy.signal()

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

    yFb << y

    return y
def euler_integrator( u : dy.Signal, Ts : float, name : str, initial_state = None):

    yFb = dy.signal()

    i = dy.add( [ yFb, u ], [ 1, Ts ] ).set_name(name + '_i')
    y = dy.delay( i, initial_state ).set_name(name + '_y')

    yFb << y

    return y
def firstOrderAndGain( u, z_inf, gain, name : str = ''):

    dFb = dy.signal()

    s = dy.add( [ dFb, u ], [ z_inf, 1 ] ).set_name('s'+name+'')
    d = dy.delay( s).set_name('d'+name+'')

    dFb << d

    y = dy.gain( d, gain).set_name('y'+name+'')

    return y
def diff( u , name : str):

    i = dy.delay( u ).set_name(name + '_i')
    y = dy.add( [ i, u ], [ -1, 1 ] ).set_name(name + '_y')

    return y

if testname == 'test1':

    baseDatatype = dy.DataTypeFloat64(1) 

    U = dy.system_input( baseDatatype ).set_name('extU')

    y1 = firstOrderAndGain( U, 0.2, gain=0.8, name="1")
    y2 = firstOrderAndGain( y1, 0.2, gain=0.8, name="2")
    y3 = firstOrderAndGain( y2, 0.2, gain=0.8, name="3")

    E1 = dy.system_input( baseDatatype ).set_name('extE1')
    E2 = dy.system_input( baseDatatype ).set_name('extE2')

    y = dy.add( [ y3, E1, E2 ], [ 0.1, 0.2, 0.3] ).set_blockname('y (add)').set_name('y')

    # define the outputs of the simulation
    output_signals = [ y, y2 ]

    # specify what the input signals shall be in the runtime
    input_signals_mapping = {}
    input_signals_mapping[ U ] = 1.0
    input_signals_mapping[ E1 ] = 2.0
    input_signals_mapping[ E2 ] = 3.0



if testname == 'test_integrator':

    baseDatatype = dy.DataTypeFloat64(1) 
        timeout = ( counter > number_of_samples_to_stay_in_A ).set_name('timeout')
        next_state = dy.conditional_overwrite(signal=dy.int32(-1), condition=timeout, new_value=1 ).set_name('next_state')

        system.set_switched_outputs([ x, v, counter ], next_state)


    with switch.new_subsystem('state_B') as system:

        # implement a simple spring-mass oscillator: 
        # x is the position, v is the velocity, acc is the acceleration

        # create placeholder symbols for x and v (as they are used before being defined)
        x = dy.signal()
        v = dy.signal()

        acc = dy.add( [ U, v, x ], [ 1, -0.1, -0.1 ] ).set_blockname('acc').set_name('acc')

        # close the feedback loops for x and v
        v << euler_integrator( acc, Ts=0.1, name="intV", initial_state=-1.0 )
        x << euler_integrator( v,   Ts=0.1, name="intX" )

        leave_this_state = (x > threshold_for_x_to_leave_B).set_name("leave_this_state")
        next_state = dy.conditional_overwrite(signal=dy.int32(-1), condition=leave_this_state, new_value=0 ).set_name('next_state')

        counter = dy.counter().set_name('counter')

        system.set_switched_outputs([ x, v, counter ], next_state)


# define the outputs
output_x      = switch.outputs[0].set_name("ox")