From a50b386cadd7d45623ad320d17a784133c44014e Mon Sep 17 00:00:00 2001 From: Pascal Date: Wed, 29 Jan 2020 01:19:10 -0600 Subject: [PATCH] [add] added initial configuration wiki entry --- README.md | 5 + docs/wiki/config/config.md | 185 ++++++++++++++++++++++++++++++++++++ docs/wiki/config/config.yml | 70 ++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 README.md create mode 100644 docs/wiki/config/config.md create mode 100644 docs/wiki/config/config.yml diff --git a/README.md b/README.md new file mode 100644 index 0000000..d30017e --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# untitled + +## Wiki + +[Configuration File](docs/wiki/config/config.md) - [Example](docs/wiki/config/config.yml) diff --git a/docs/wiki/config/config.md b/docs/wiki/config/config.md new file mode 100644 index 0000000..c99173b --- /dev/null +++ b/docs/wiki/config/config.md @@ -0,0 +1,185 @@ +# Configuration File + +## Simulation + +* `duration`:`int` - number of simulation ticks, after which everything will be reset to the initial configuration +* `tickfactor`:`int` - used to artificially add ticks by repeating the result of a simulation tick by the given value +* `loop`:`bool` - loop the simulation +* `loopcount`:`int` - amount of loops, `0` for infinite + +## Sensors + +Elements: + +* `group`:`String` - used to assign ground truth and behaviour to the sensors. Any String can be used, internally assigned an `int`, by adding all groups to an array and using their index +* `cells`:`array` _[optional]_ - holds the x-/y-coordinates and count of the sensors in the group, only optional if `blocks` is present + * `x`:`int` - x-coordinate + * `y`:`int` - y-coordinate + * `count`:`int` - count of the sensors in this cell + Alternative condensed notation as `array`: `[x, y, count]` +* `blocks`:`array` _[optional]_ - holds start-/end-coordinates and count of sensors in the group, only optional if `cells` is present + * `start`:`[int, int]` - start coordinates `[x, y]` of a block + * `end`:`[int, int]` - end coordinates `[x, y]` of a block, can be equal to `start` (but not desirable) + * `count`:`int` - count of the sensors in this block + +_Notes:_ Overlaps of `cells` and/or `blocks` within a `group` are possible (but not desirable). The result will be the sum of all `count` values. +The distribution in `blocks` goes from left to right (`x`-axis), bottom to top (`y`-axis): + +Examples: +2x2 block with 3 sensors (labeled 1 to n): + +| | | +|:---:|:---:| +| 3 | | +| 1 | 2 | + +If the `count` of sensors is greater than the amount of `cells` in a `block`, they get evenly distributed with any leftovers being distributed like the example above: + +2x2 block with 11 sensors (labeled 1 to n): +* amount of cells: 4 +* `count`: 11 +* evenly distributed: 2 per cell +* leftovers: 3 (marked with `()`) + +| | | +|:---:|:---:| +| 7, 8, (9) | 10, 11 | +| 1, 2, (3) | 4, 5, (6) | + +## Ground Truth + +Elements: + +* `group`:`String` - sensor group assignment +* `parent`:`String` _[optional]_ - parent group assignment. The parents group ground truth for the current simulation tick is calculated before this grout and passed to it +* `value`:`double` - ground truth value + * `timeline`:`array` - sets simulation tick when this ground truth is active and turns inactive. + * `start`:`int` - simulation tick when this function is active + * `end`:`int` _[optional]_ - last simulation tick before this function is inactive + Alternative condensed of `timeline` notation as `array`: `[start, end]` + Alternative condensed of `value` notation as `array`: `[start, value or None, ...]` +* `delta`:`array` _[optional]_ - function to calculate `value` of the next simulation tick, only called if no value is defined for the next tick. Result is saved as new `value` and passed again to the function for the next tick. If no function is given, the `value` remains + * `name`:`String` - name of the function. Needs to exist at compile time in a map: `["name" -> (value: double, parentValue: double, args: ...) => double]` + * `args`:`array` - arguments passed to the function in addition to the `value` + * `timeline`:`array` - sets simulation tick when this function is active and turns inactive. + * `start`:`int` - simulation tick when this function is active + * `end`:`int` _[optional]_ - last simulation tick before this function is inactive + Alternative condensed of `timeline` notation as `array`: `[start, end]` + Alternative condensed of `delta` notation as `array`: `[start, name or None, [args] or []]` +* `cells`:`array` _[optional]_ - holds the x-/y-coordinates and count of assigned sensors in the group, only optional if `blocks` is present + * `x`:`int` - x-coordinate + * `y`:`int` - y-coordinate + * `count`:`int` _[optional]_ - count of assigned sensors in this cell, only optional if `percent` is present + * `percent`:`double` _[optional]_ - percent of assigned sensors (rounded) in this cell, only optional if `count` is present + Alternative condensed notation as `array`: `[x, y, count]` +* `blocks`:`array` _[optional]_ - holds start-/end-coordinates and count of assigned sensors in the group, only optional if `cells` is present + * `start`:`[int, int]` - start coordinates `[x, y]` of a block + * `end`:`[int, int]` - end coordinates `[x, y]` of a block, can be equal to `start` (but not desirable) + * `count`:`int` _[optional]_ - count of assigned sensors in this block, only optional if `percent` is present + * `percent`:`double` _[optional]_ - percent of assigned sensors (rounded) in this block, only optional if `count` is present + +_Notes:_ Overlaps of `cells` and/or `blocks` within a `group` are possible (but not desirable). The result will be the sum of all `count`, `percent` values. +The distribution in `blocks` goes from left to right (`x`-axis), bottom to top (`y`-axis) (see above) + +## Behaviour + +Elements: + +* `group`:`String` - sensor group assignment + * `sharedObject`:`String` _[optional]_ _[experimental idea]_ - an object shared between sensor `behaviours`, can be waited up and synchronized. Use case example: cascading failure of sensors of different groups. + _More of an idea, as this might be complex to implement in an asynchronous environment._ +* `functions`:`array` _[optional]_ - function to calculate the output of a sensor on a given simulation tick. Function receives `ground truth` which can be `None`. Function returns `double` or `None`. If no function is given, `None` is returned as result for the tick + * `name`:`String` - name of the function. Needs to exist at compile time in a map: `["name" -> (groundTruth: double, args: ...) => double]` + * `args`:`array` - arguments passed to the function in addition to the `value` + * `timeline`:`array` - sets simulation tick when this function is active and turns inactive. + * `start`:`int` - simulation tick when this function is active + * `end`:`int` _[optional]_ - last simulation tick before this function is inactive + Alternative condensed of `timeline` notation as `array`: `[start, end]` + Alternative condensed of `functions` notation as `array`: `[start, name or None, [args] or []]` +* `cells`:`array` _[optional]_ - holds the x-/y-coordinates and count of assigned sensors in the group, only optional if `blocks` is present + * `x`:`int` - x-coordinate + * `y`:`int` - y-coordinate + * `count`:`int` _[optional]_ - count of assigned sensors in this cell, only optional if `percent` is present + * `percent`:`double` _[optional]_ - percent of assigned sensors (rounded) in this cell, only optional if `count` is present + Alternative condensed notation as `array`: `[x, y, count]` +* `blocks`:`array` _[optional]_ - holds start-/end-coordinates and count of assigned sensors in the group, only optional if `cells` is present + * `start`:`[int, int]` - start coordinates `[x, y]` of a block + * `end`:`[int, int]` - end coordinates `[x, y]` of a block, can be equal to `start` (but not desirable) + * `count`:`int` _[optional]_ - count of assigned sensors in this block, only optional if `percent` is present + * `percent`:`double` _[optional]_ - percent of assigned sensors (rounded) in this block, only optional if `count` is present + +_Notes:_ Overlaps of `cells` and/or `blocks` within a `group` are possible (but not desirable). The result will be the sum of all `count`, `percent` values. +The distribution in `blocks` goes from left to right (`x`-axis), bottom to top (`y`-axis) (see above) + +## Implementation Ideas + +### general + +* the result `None` from a sensor `behaviour` is treated as if the sensor did not output any data +* as `group` entries are not _[unique]_ it is possible to have multiple definitions of the same `group`. If any element of the group conflicts with another definition, the last declaration takes precedence +* configuring failing sensors in a type of sensor can be achieved by creating two groups (working, failing), assigning the working group as parent of the failing und using a `delta` function that just returns the parent `ground truth` + +### storing function<->timeline relations + +All timeline dependend elements (e.g. `groundtruth`, `delta`, `behaviour`) are held in an array of their respective group. The array is initialized with an `Option[T]` that is set to `None`. All elements get inserted with their corresponding `timeline: start` value and the `None` gets inserted with the `timeline: end+1` value. A modified binary search (that will return either the value if found or the next lower value) is then used to get the element at any given simulation tick: +`[0:None, 30:factor, 61:None, 120:factor]` would correspond to: +```yml +delta: + - name: factor + args: + - 1.1 + timeline: + - start: 30 + end: 60 + - start: 120 +``` +a lookup of `delta` at tick 20 would result in `None`, at tick 42 in `factor`, at tick 110 in `None`, anytime after 119 in `factor`. +For the `groundtruth` and `behaviour` a `None` results in no output of the effected sensors. A `None` in the `delta` would result in no change of the `value`, but normal sensor output. + +Alternatively a `None` in `behaviour` could result in a default `behaviour`of the sensor. This default would have to be added to `sensor`. + +### adding a sensor block from config + +1. get the smallest `x` and `y` from `start` and `end` from a `blocks` element, save as `bottomleft` +2. save other `x` and `y` as `topright` +3. calculate the amount of cells in the block by multiplying the distance of the `x` and `y` pairs: +```scala +// no abs() necessary as topright is always greater than or equal to topleft +cellCount = (topright.x - bottomleft.x + 1) * (topright.x - bottomleft.x + 1) +``` +4. set amount of sensors per cell in `sensorsPerCell` +```pseudo +if cellCount < count: + sensorsPerCell = roundDown(count/cellCount) + extraSensors = count - (sensorsPerCell*cellCount) +else: + sensorsPerCell = 1 +``` + +```scala +for { + y <- bottomleft.y to topright.y + x <- bottomleft.x to topright.x + } { + // exit condition for count < cellCount + if (count <= 0) break else count -= 1 + + var sensors: Int = sensorsPerCell + if (extraSensors > 0) + { + sensors += 1 + extraSensors -= 1 + } + + addSensors((x, y), sensors, ...) + } +``` + +_TODO:_ Decide which structure to use: `Array.ofDim` vs `Array(Array())` vs `map` + + ### applying ground truth/behaviour to block + + fast: uneven distribution, start left to right, top to bottom and grab all sensors in each cell until done assigning required sensors + slow: even distribution, iterate over block left to right, top to bottom and assign a single sensor (if available) in each cell, continue until done + (possible optimisation: get all counts of sensors per cell, sort by size, delete smallest and assign that count on all available cells, subtract from remaining counts, repeat until done) + \ No newline at end of file diff --git a/docs/wiki/config/config.yml b/docs/wiki/config/config.yml new file mode 100644 index 0000000..19e85d0 --- /dev/null +++ b/docs/wiki/config/config.yml @@ -0,0 +1,70 @@ +simulation: + duration: 500 + tickfactor: 10 + loop: true + loopcount: 20 + +sensors: + - group: temperature + cells: + - x: 0 + y: 2 + count: 10 + - [2, 3, 50] + blocks: + - start: [8, 1] + end: [3, 3] + count: 30 + +groundtruth: + - group: temperature + truth: + - value: 11 + timeline: + - start: 0 + end: 120 + - [240, 360] + delta: + - name: factor + args: + - 1.1 + timeline: + - start: 60 + end: 120 + cells: + - [0, 2, 10] + blocks: + - start: [8, 1] + end: [3, 3] + count: 50 + - group: humidity + parent: temperature + truth: + - [0, None] + - [30, 0.6] + - [50, None] + delta: + - [10, None, []] + - [30, addValuePercent, [0.03, 0.8]] + - [50, humidFromTemp, []] + blocks: + - start: [15, 15] + end: [17, 17] + percent: 0.8 + +behaviour: + - group: temperature + sharedObject: objectTemp + functions: + - name: randomValue + args: + - 40 + - 80 + duration: + - start: 60 + - [100, normalValue, [2]] + - [120, None, []] + blocks: + - start: [5,6] + end: [8,9] + percent: 1.0 \ No newline at end of file