# Healthcare

A bedside monitor reports heart rate and oxygen saturation (SpO2) at 1 Hz, and here its sensor drops out for 20 s. While no data arrives, the monitor's clock advances the Detector every second with `advanceTo`, so the dropout is noticed while it lasts, not only once data resumes.

Parameters (in the page address as ?tachycardia=…):

- Tachycardia above (`tachycardia`): 85 to 115 bpm in steps of 5, default 100
- Tachycardia for (`tachycardiaSeconds`): 0 to 60 s in steps of 5, default 30
- Max gap (`maxGap`): 2 to 30 s in steps of 1, default 10
- Desaturation below (`desaturation`): 85 to 95 % in steps of 1, default 90
- Sensor lost after (`lost`): 1 to 20 s in steps of 1, default 5

The site cannot run the default parameters: (JavaScript) TypeError: Cannot read properties of undefined (reading 'length')

Java source at the default parameters:

```java
import static io.github.romanhaendler.rbed.Conditions.*;

import io.github.romanhaendler.rbed.*;
import java.time.Duration;
import java.util.Map;

Channel hr = Channel.named("hr");
Channel spo2 = Channel.named("spo2");

Rule tachycardia = Rule.named("Tachycardia")
    .when(hr.above(100)).forDuration(Duration.ofSeconds(30))
    .endWhen(hr.below(95)).forDuration(Duration.ofSeconds(30))
    .maxGap(Duration.ofSeconds(10));
Rule desaturation = Rule.named("Desaturation")
    .when(spo2.below(90)).forDuration(Duration.ofSeconds(10))
    .endWhen(spo2.below(92).not());
Rule hypoxicTachycardia = Rule.named("HypoxicTachycardia")
    .when(during(tachycardia).and(during(desaturation)));
Rule sensorLost = Rule.named("SensorLost")
    .when(hr.age().above(Duration.ofSeconds(5).toMillis()));
Detector detector = Detector.builder()
    .rules(tachycardia, desaturation, hypoxicTachycardia, sensorLost)
    .build();

for (long s = 0; s < 600; s++) {   // every second
  if (s >= 150 && s < 170) {
    detector.advanceTo(s * 1_000);   // the sensor drops out; the monitor's clock advances time
  } else {
    detector.push(s * 1_000, Map.of(
        hr, s < 60 ? 80.0 : s < 300 ? 120.0 : 85.0,
        spo2, s < 120 ? 97.0 : s < 200 ? 86.0 : 96.0));
  }
}
detector.close();
```

## The Rules

- **Tachycardia**: heart rate above 100 for 30 s, over below 95 for 30 s. A dropout longer than 10 s interrupts it: the Event Ends Truncated, and the one after the dropout starts Truncated because nobody knows what happened in between.
- **Desaturation**: SpO2 below 90 % for 10 s, over at 92 % or more.
- **HypoxicTachycardia**: both at the same time.
- **SensorLost**: no heart rate for more than 5 s, measured with `age()`.

At the defaults, the heart rate is 120 from 60 s, and `Tachycardia` is Confirmed at 90 s. The SpO2 is 86 % from 120 s to 200 s: `Desaturation` is Confirmed at 130 s, and `HypoxicTachycardia` with it.

The last Sample before the dropout is at 149 s. At the advance to 160 s, 11 s have passed since the last Sample, more than the `maxGap` of 10 s: `Tachycardia` Ends Truncated at 159 s, the last advance that still lay within 10 s of the last Sample. `HypoxicTachycardia`, which has no `maxGap` of its own, Ends at 160 s, the advance at which `during(tachycardia)` stops holding. `SensorLost` runs from 155 s, when the heart rate is 6 s old, until data resumes at 170 s, where a new `Tachycardia` starts Truncated. It is Confirmed at 200 s and Ends at 300 s, where the heart rate falls to 85.

### Things to try

- Raise *Max gap* to 30 s: the 20 s dropout no longer interrupts `Tachycardia`, which runs as one Event from 60 s to 300 s, and `HypoxicTachycardia` lasts until `Desaturation` Ends at 200 s.

## Reference

The example is [VitalSignsExample](https://github.com/romanhaendler/rbed/blob/main/src/test/java/io/github/romanhaendler/rbed/examples/VitalSignsExample.java), a test with its expected Events, listed in the README's [Examples](https://github.com/romanhaendler/rbed#examples).

Methods used: [`Channel.named`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Channel.html#named%28java.lang.String%29), [`Rule.named`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Rule.html#named%28java.lang.String%29), [`Rule.when`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Rule.html#when%28io.github.romanhaendler.rbed.Condition%29), [`Expression.above`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Expression.html#above%28double%29), [`Rule.forDuration`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Rule.html#forDuration%28java.time.Duration%29), [`Rule.endWhen`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Rule.html#endWhen%28io.github.romanhaendler.rbed.Condition%29), [`Expression.below`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Expression.html#below%28double%29), [`Rule.maxGap`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Rule.html#maxGap%28java.time.Duration%29), [`Condition.not`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Condition.html#not%28%29), [`Conditions.during`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Conditions.html#during%28io.github.romanhaendler.rbed.Rule%29), [`Condition.and`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Condition.html#and%28io.github.romanhaendler.rbed.Condition%29), [`ChannelExpression.age`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/ChannelExpression.html#age%28%29), [`Detector.builder`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.html#builder%28%29), [`Detector.Builder.rules`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.Builder.html#rules%28io.github.romanhaendler.rbed.Rule...%29), [`Detector.Builder.build`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.Builder.html#build%28%29), [`Detector.advanceTo`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.html#advanceTo%28long%29), [`Detector.push`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.html#push%28long,java.util.Map%29), [`Detector.close`](https://romanhaendler.github.io/rbed/api/io.github.romanhaendler.rbed/io/github/romanhaendler/rbed/Detector.html#close%28%29).

The concepts at work, each on a page of its own: [Silent sensors: advancing time](https://romanhaendler.github.io/rbed/silent-sensors/), [Data gaps](https://romanhaendler.github.io/rbed/data-gaps/), [During another Event](https://romanhaendler.github.io/rbed/during/), [End Conditions and hysteresis](https://romanhaendler.github.io/rbed/end-conditions/).
