Files
scim/docs/wiki/config/config.md

186 lines
11 KiB
Markdown

# 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 group and passed to it
* `truth`:`array` - array of ground truth values and their validity
* `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)