[add] added SimulationBehaviour functions
- this allows to simulate the new config file
This commit is contained in:
@@ -21,7 +21,7 @@ object Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def startSimulation(): Unit = {
|
def startSimulation(): Unit = {
|
||||||
val config = new Parser().parse("docs/wiki/config/config.yml", simBehavirous)
|
val config = new Parser().parse("docs/wiki/config/config_preview.yml", scim.components.behaviour.behaviours)
|
||||||
val sharedMemory = config.sharedMemory
|
val sharedMemory = config.sharedMemory
|
||||||
val output = new Output(sharedMemory)
|
val output = new Output(sharedMemory)
|
||||||
val simulator = new Simulation(config)
|
val simulator = new Simulation(config)
|
||||||
|
|||||||
126
src/main/scala/scim/components/Behaviour.scala
Normal file
126
src/main/scala/scim/components/Behaviour.scala
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
package scim.components
|
||||||
|
|
||||||
|
import scim.datastruct.{Cell, FunctionArgs, SimulationBehaviours, Time}
|
||||||
|
import scim.lib.numberUtil._
|
||||||
|
import scim.lib.behaviourUtil._
|
||||||
|
import scim.lib.simInterfaces.SimulationBehaviour
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
|
package object behaviour {
|
||||||
|
|
||||||
|
val behaviours = SimulationBehaviours(Map[String, SimulationBehaviour](
|
||||||
|
"measureTemp" -> measureTemp,
|
||||||
|
"measureHumid" -> measureHumid,
|
||||||
|
"noOutput" -> noOutput,
|
||||||
|
"fluctuate" -> fluctuate,
|
||||||
|
"change" -> change,
|
||||||
|
"humidFromTemp" -> humidFromTemp
|
||||||
|
))
|
||||||
|
|
||||||
|
def measureTemp: SimulationBehaviour = {
|
||||||
|
sensorFactory(Vector(-50, 150), 0.1, 1.0, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
def measureHumid: SimulationBehaviour = {
|
||||||
|
sensorFactory(Vector(0, 100), 1.0, 2.0, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
def noOutput: SimulationBehaviour = {
|
||||||
|
(_: Cell, _: Time, _: Option[Double], _: Option[FunctionArgs]) => { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
def sensorFactory(defaultRange: Vector[Double], defaultResolution: Double, defaultAccuracy: Double, defaultOffset: Double,
|
||||||
|
preFunction: Option[SimulationBehaviour] = None,
|
||||||
|
postFunction: Option[SimulationBehaviour] = None,
|
||||||
|
altFunction: Option[SimulationBehaviour] = None): SimulationBehaviour = {
|
||||||
|
|
||||||
|
val genericSensor: SimulationBehaviour = (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]) => {
|
||||||
|
// can use altFunction to entirely disable normal behaviour (including pre/postFunction)
|
||||||
|
// useful when trying to use different params based on cell/time
|
||||||
|
val altResult = if (!altFunction.isEmpty) altFunction.get(cell, time, inTruth, args) else None
|
||||||
|
if (!altResult.isEmpty) {
|
||||||
|
altResult
|
||||||
|
} else {
|
||||||
|
// preFunction can modify ground truth
|
||||||
|
// can e.g. be used to return None or modify truth based on cell/time
|
||||||
|
val preResult = if (!preFunction.isEmpty) preFunction.get(cell, time, inTruth, args) else inTruth
|
||||||
|
if (preResult.isEmpty) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
val truth = preResult.get
|
||||||
|
val range: Vector[Double] = args.getParam("range", defaultRange) // using a vector to match yml parsing
|
||||||
|
val resolution: Double = args.getParam("resolution", defaultResolution)
|
||||||
|
val accuracy: Double = args.getParam("accuracy", defaultAccuracy)
|
||||||
|
val offset: Double = args.getParam("offset", defaultOffset)
|
||||||
|
val rng = new Random()
|
||||||
|
val rngAcc = rng.nextDouble() * accuracy * (if (rng.nextBoolean()) -1 else 1)
|
||||||
|
val result: Option[Double] = Some((truth + rngAcc + offset).resolution(resolution).range(range(0), range(1)))
|
||||||
|
// postFunction can modify result
|
||||||
|
// can e.g. be used to modify result based on cell, time and result itself
|
||||||
|
// (e.g. return garbage when result is above threshold to simulate failure above threshold)
|
||||||
|
if (!postFunction.isEmpty) postFunction.get(cell, time, result, args) else result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
genericSensor
|
||||||
|
}
|
||||||
|
|
||||||
|
def fluctuate (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
||||||
|
if(inTruth.isEmpty) return None
|
||||||
|
val range: Double = args.getParam("range", 1.0)
|
||||||
|
val center: Vector[Int] = args.getParam("center", Vector(0, 0))
|
||||||
|
val distOffset: Double = args.getParam("distOffset", 0)
|
||||||
|
val offsetTimes: Vector[Int] = args.getParam("time", Vector(-1))
|
||||||
|
val offset = if(distOffset != 0 && offsetTimes.contains(time.time)) {
|
||||||
|
val centerCell = Cell(center(0), center(1))
|
||||||
|
centerCell.distance(cell) * distOffset
|
||||||
|
} else { 0 }
|
||||||
|
|
||||||
|
val rng = new Random()
|
||||||
|
val rngRange = rng.nextDouble() * range * (if (rng.nextBoolean()) -1 else 1)
|
||||||
|
|
||||||
|
//if(time.time == 0 || time.time == 11) println("\nXXX: " + cell + " :: " + inTruth.get + " :OFF: " + offset + " :RES: " + (inTruth.get + rngRange + offset))
|
||||||
|
|
||||||
|
Some(inTruth.get + rngRange + offset)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def change (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
||||||
|
if(inTruth.isEmpty) return None
|
||||||
|
val range: Double = args.getParam("range", 1.0)
|
||||||
|
val target: Double = args.getParam("target", inTruth.get + 5)
|
||||||
|
val targetTime: Int = args.getParam("targetTime", time.time + 1)
|
||||||
|
val center: Vector[Int] = args.getParam("center", Vector(0, 0))
|
||||||
|
val distOffset: Double = args.getParam("distOffset", 0)
|
||||||
|
val offsetTimes: Vector[Int] = args.getParam("time", Vector(-1))
|
||||||
|
// always calculate offset for target
|
||||||
|
val offset = if(distOffset != 0) {
|
||||||
|
val centerCell = Cell(center(0), center(1))
|
||||||
|
centerCell.distance(cell) * distOffset
|
||||||
|
} else { 0 }
|
||||||
|
|
||||||
|
// only change truth on offsetTimes
|
||||||
|
val truth = if(offsetTimes.contains(time.time)) inTruth.get + offset else inTruth.get
|
||||||
|
|
||||||
|
val rng = new Random()
|
||||||
|
val rngRange = rng.nextDouble() * range * (if (rng.nextBoolean()) -1 else 1)
|
||||||
|
val step: Double = if(time.time < targetTime) {
|
||||||
|
(target + offset - truth) / (targetTime - time.time).toDouble
|
||||||
|
} else { 0 }
|
||||||
|
|
||||||
|
Some(inTruth.get + rngRange + step)
|
||||||
|
}
|
||||||
|
|
||||||
|
def humidFromTemp (cell: Cell, time: Time, inTruth: Option[Double], args: Option[FunctionArgs]): Option[Double] = {
|
||||||
|
if(inTruth.isEmpty) return None
|
||||||
|
val dewpoint: Double = args.getParam("dewpoint", 12.0)
|
||||||
|
val temp: Double = inTruth.get
|
||||||
|
|
||||||
|
// source: https://bmcnoldy.rsmas.miami.edu/Humidity.html
|
||||||
|
val rh = 100*(Math.exp((17.625*dewpoint)/(243.04+dewpoint))/Math.exp((17.625*temp)/(243.04+temp)))
|
||||||
|
Some(rh)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user