All Downloads are FREE. Search and download functionalities are using the official Maven repository.

protelis.state.time.pt Maven / Gradle / Ivy

There is a newer version: 17.6.0
Show newest version
module protelis:state:time
import java.lang.Math.min
import java.lang.Math.max
import protelis:lang:utils

/**
 * Apply a function while condition is true.
 *
 * @param event bool, event
 * @param f     () -> T, function to be applied
 * @param null  T, null value
 * @return      T, apply f if event occurs, return null otherwise
 */
public def applyWhile(event, f, null) {
    if (event) { f.apply() } else { null }
}

/**
 * @param length num, count down length
 * @return       num, remaining time
 */
public def countDown(length) {
    countDownWithDecay(length, self.getDeltaTime())
}

/**
 *
 * @param length num, count down length
 * @param dt     num, decay
 * @return       num, remaining time
 */
public def countDownWithDecay(length, dt) {
    T(length, 0, (t) -> {t - dt})
}

/**
 * Cyclic timer.
 *
 * @param length num, timeout
 * @return       bool, true if the timeout is expired, false otherwise
 */
public def cyclicTimer(length) {
    cyclicTimerWithDecay(length, self.getDeltaTime())
}

/**
 * Cyclic timer.
 *
 * @param length num, timeout
 * @param decay  num, decay rate
 * @return       bool, true if the timeout is expired, false otherwise
 */
public def cyclicTimerWithDecay(length, decay) {
    rep (left <- length) {
        if (left == 0) {
            length
        } else {
            countDownWithDecay(length, decay)
        }
    } == length
}

/**
 * Periodically invoke a function.
 *
 * @param length num, timeout
 * @param f      () -> T, function to be invoked
 * @param null   T, default value
 * @return       T, apply f if the timeout is expired, null otherwise
 */
public def cyclicFunction(length, f, null) {
    cyclicFunctionWithDecay(length, self.getDeltaTime(), f, null)
}

/**
 * Periodically invoke a function.
 *
 * @param length num, timeout
 * @param decay  num, decay rate
 * @param f      () -> T, function to be invoked
 * @param null   T, default value
 * @return       T, apply f if the timeout is expired, null otherwise
 */
public def cyclicFunctionWithDecay(length, decay, f, null) {
    if (cyclicTimerWithDecay(length, decay)) {
        f.apply()
    } else {
        null
    }
}

/**
 *
 * @param signal num, signal to be monitored
 * @return       num, variation between current and old values
 */
public def delta(signal) {
    rep (old <- [signal, 0]) {
        [signal, signal - old.get(0)]
    }.get(1)
}

/**
 * Evaporation pattern.
 * 
 * @param length num, duration
 * @param info   T, information
 * @param decay  num, decay rate
 * @return       [num, T]
 */
public def evaporation(length, info, decay) {
    T([length, info], [0, info], (t) -> { [t.get(0) - decay, t.get(1)] })
}

/**
 * Exponential back-off filter.
 *
 * @param signal num, signal to be filtered
 * @param a      num, alpha value
 * @return       num, filtered signal
 */
public def exponentialBackoffFilter(signal, a) {
    rep (old <- signal) {
        signal * a + old * (1 - a)
    }
}

/**
 * @param timeout num, timeout
 * @return        bool, false after timeout, true otherwise
 */

public def falseAfterTime(timeout) {
    falseAfterTimeWithDt(timeout, self.getDeltaTime())
}

/**
 * @param timeout num, timeout
 * @param dt      num, dt
 * @return        bool, false after timeout, true otherwise
 */
public def falseAfterTimeWithDt(timeout, dt) {
    !trueAfterTimeWithDt(timeout, dt)
}

/**
 * @param signal bool, binary signal to be monitored
 * @return       bool, true if the signal had a falling edge, false otherwise
 */
public def isFallingEdge(signal) {
    rep (old <- [signal, false]) {
        mux (old.get(0) && !signal) {
            [signal, true]
        } else {
            [signal, false]
        }
    }.get(1)
}

/**
 * @param event   bool, event
 * @param timeout num, timeout
 * @return        bool, true if the event occurred before timeout, false otherwise
 */
public def isRecentEvent(event, timeout) {
    if (rep(hasHappenedBefore <- false) { hasHappenedBefore || event } ) {
        if (event) {
            true
        } else {
            countDown(timeout) > 0
        }
    } else { false }
}

/**
 * @param signal bool, binary signal to be monitored
 * @return       bool, true if the signal had a rising edge, false otherwise
 */
public def isRisingEdge(signal) {
    rep (old <- [signal, false]) {
        mux (!old.get(0) && signal) {
            [signal, true]
        } else {
            [signal, false]
        }
    }.get(1)
}

/**
 * @param signal T, signal to be monitored
 * @param time   num, consider the signal stable after this time
 * @return       bool, true if the signal does not change for at least time
 */
public def isSignalStable(signal, time) {
    isSignalStableWithDt(signal, time, self.getDeltaTime())
}

/**
 * @param signal T, signal to be monitored
 * @param time   num, consider the signal stable after this time
 * @param dt     num, dt
 * @return       bool, true if the signal does not change for at least time
 */
public def isSignalStableWithDt(signal, time, dt) {
    let t =
        rep (old <- [signal, 0]) {
            mux (signal == old.get(0)) {
                [signal, old.get(1) + dt]
            } else {
                [signal, 0]
            }
        }.get(1);
    t >= time
}

/**
 * @param signal T, value to be monitored
 * @return       bool, whether v has changed given its previous state
 */
public def isValueChanged(signal) {
    rep (old <- [signal, true]) {
        [signal, !(signal == old.get(0))]
    }.get(1)
}

/**
 * Hold value until a specified timeout.
 *
 * TODO: reconsider this function. When do we trigger the recording?
 * @param value   T, value to be stored
 * @param null    T, default value
 * @param timeout num, hold the value for this amount of time
 * @param dt      num, increase the time of this value
 * @return        T, hold value if timeout is not expired, null otherwise
 */
public def limitedMemory(value, null, timeout, dt) {
    rep (v <- value) {
        if (waitWithDecay(timeout, dt)) {
            null
        } else {
            v
        }
    }
}

/*
 * Timer.
 *
 * @param initial num, initial value of the timer
 * @param zero    num, lower bound of the timer
 * @param decay   (num) -> num, decay rate
 * @return        num, current status of the timer
 */
public def T(initial, zero, decay) {
    rep (v <- initial) {
        min(initial, max(zero, decay.apply(v)))
    }
}

/**
 * @param timeout num, timeout
 * @return        bool, true after timeout, false otherwise
 */
public def trueAfterTime(timeout) {
    trueAfterTimeWithDt(timeout, self.getDeltaTime())
}

/**
 * @param timeout num, timeout
 * @param dt      num, dt
 * @return        bool, true after timeout, false otherwise
 */
public def trueAfterTimeWithDt(timeout, dt) {
    countDownWithDecay(timeout, dt) <= 0
}

/**
 * @param timeout num, count down length
 * @return        bool, whether the countdown is expired
 */
public def wait(timeout) {
    waitWithDecay(timeout, self.getDeltaTime())
}

/**
 * @param timeout num, count down length
 * @param dt      num, decay
 * @return        bool, whether the countdown is expired
 */
public def waitWithDecay(timeout, dt) {
    countDownWithDecay(timeout, dt) <= 0
}

/**
 * @param timeout num, timeut
 * @param f       () -> T, function to be applied
 * @param null    T, null value
 * @return        T, apply f after x, null otherwise
 */
public def waitAndApply(timeout, f, null) {
    if (wait(timeout)) { f.apply() } else { null }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy