This is the Repository for the M-Lab Course project VentCore. This Course was held during the WS 2021/2022 by the MAST Team of University of Hamburg.
Table of Contents
This is the repository for the UKE M-Lab prototype of VentCore: A Mock-Up for a possible 3-in-1 Medical device which combines a patient Monitoring, Defibrillation and Ventilation.
The App in this repository demonstrates the User-Interface and Alarm-Management for such a device in a Tablet-Application. This Tablet-Application was designed for a 10" Inch Screen with the Flutter SDK to run on both, Android and iOS.
The prototype is build with simulation data designed to mimic real emergency scenarios that where provided by emergency doctors of the UKE and the friendly help of WEINMANN.
The following sections will guide you through the installation process, documentation and functionalities of the code, the design and Style Guide used as well as the data used an how it was processed.
As mentioned, this is a Flutter Tablet application written in dart. For the Data Processing and creation we used Python.
To start the Application and Simulate the Scenarios follow the upcoming steps.
Please make sure, that you've installed a stable Version of the Flutter SDK. Please consider this link.
-
Verify your working Installation with:
flutter doctor
Depending on your operating system make sure to have the simulator(macOS) or Android Emulator(Windows) installed and working.
Since this App was designed with a requirement of a 10" Inch tablet screen with a resolution of 1920x1200 pixels, we recommend to use one of the following emulation devices:
- macOS
iPad Pro (3rd generation)
iOS Version 15.2
- Windows
Pixel C
Android Version 11.0 x86
-
Clone the repository.
git clone https://git.informatik.uni-hamburg.de/mast/teaching/mlab/wt202122/uke
-
Start the emulator you want to use. Device Recommendations
-
Run Application with terminal in the location on your disk:
flutter run lib/main.dart
This prototype works as showcase for demonstrating and evaluating of a future 3-in-1 interface with simulated data.
Choose Presets | Explore Patient Scenarios |
Switch between Modes via Buttons | Set Limits directly and add Graph |
Ventilation | Defibrillator |
High Alarms | Overview of All Alarmlimits |
For more examples, please refer to the Documentation
For the design created in Figma please follow this link:
Also have a look at our StyleGuide for the colors used in the prototype.
For a complete overview, please refer to our AlarmLogic.md
The system is able to play the highest alarm sounds for active alarms and to play only one alarm at time. It also changes the visualisation of the current alarm state with colors on the screen. Furthermore it can evaluate the alarm type wether it is coming from monitoring or ventilation sensors. All alarm sounds are selfmaed to convey a new feeling for the application and because the old sound files were not reachable for the M-Lab project. The user is able to confirm single alarms or all alarms at once. In defibrillation mode all alarms are muted. Switching back to montioring or ventilation enables active alarms again. Upcoming alarms can be confirmed and stay confirmed for a defined time. When the alarm is raising in its priority, the confirm state ends to inform the user about the worse condition that occured. In addition to that, the user gets the offer from the system to "smart adjust boundaries" when a middle alert is occuring three times in a row without being interrupted by a higher alarm or an alarm with another alarm message. If the user accepts this offer, the system adjust the triggered boundary by predefined percentages. This aims to reduce the sensory overload and to support.
With the updated values, the system checks for the priority of the value update and if it’s a middle or high alert or a warning. To check the priority, every sensor has a predefined SensorDeviation
. The SensorDeviation
describes the range of allowed values above or below a limit before an alarm is classified as high.
Sensor: Heartfrequency
Upper Boundary: 120
Lower Boundaray: 50
SensorDeviation: 0.1 (10%)
middle alert upper boundary: if (newValue < 120 * 1.1)
high alert upper boundary: if (newValue >= 120 * 1.1)
middle alert lower boundary: if (newValue > 50 * 0.9)
high alert upper boundary: if (newValue <= 50 * 0.9)
Sensor | Lower Boundary | Upper Boundary | sensorDeviation |
high alarm lower | high alarm upper |
---|---|---|---|---|---|
Heartfrequency | 50 | 120 | 10% | 45 | 132 |
SpO2 | 90 | - | 10% | 81 | - |
Temperature | 36.0 | 37.9 | 1% | 35.6 | 38.2 |
CO2 | 30 | 45 | 10% | 27 | 49 |
If a value update is whether a high or a middle alert, the system still checks for warnings. Those can occur, when the ValueDeviation
, the value difference from the current value and the new updated value, is higher than allowed. This can for example also happen when the updated value is in the boundaries of the sensor. The ValueDeviation
is different for every sensor but calculated with the following formular:
Sensor: Heartfrequency
Upper Boundary: 120
Lower Boundary: 50
valueDifference = [upperBoundary – lowerBoundary] / 2 = 35
The system also needs to check for Zero-Values. This can be an indicator of disconnection of the physical sensor or for high alert at the same time.
For a complete overview, please refer to our AlarmLogic.md
Files to consider:
Mr. Neuhaus from Weinmann provided us with with data twice, once actual recorded ventilation and ECG data and the second time generated simulation data.
As the patient scenarios are very complex finding data that fits our needs is near impossible. Even just finding a healthy ECG wave is a very hard task. Thats why we are building our datasets ourselfs.
The first time we received an "edf" file containing recorded ventilation and ECG data. since this was a raw recording and not filtered or treated in any way we had to process the data which we did in Notebook 1.
We used a python library called mne to read the "edf" file and extract relevant information.
Since we immediately wanted to visualize the provided data within our application, we did not bother constructing a complex json file. Thus we built a simple list holding dictionaries for each graph (ECG, paw, pleth, etc.).
Since the data is raw and unfiltered a lot of noise was present, to filter out the noise Mr. Neuhaus recomended us to use a algorithm called simple moving average. Our implementation of the simple moving average can be found in this Notebook 1 under the section "Simple Moving Average". This provided us with a clean ECG wave we could use to display the ECG channel in our application. After finishing up the data for our graphs we realized that this is only half the data our application needs to be realistic enough for our customer.
Thankfully Mr.Neuhaus provided us with clean simulated data. Using this data we redesinged our json datastructure.
We were now able to display an ECG wave as a graph. However for a realistic representation of the associated heartfrequency we would have to analyze the number of pqrst complexes in one minute. Which would have taken to much time to implement correctly, we decided against analyzing our graphs. We still lacked a datasource to realisticly display a heartfrequency.
Our most basic approach was generating semi random numbers and just display those. The problem that arrises with random generated numbers is that a random datapoint is not depended on its predecessor. In the realm of medical data this leads to serious inconsistencies. Since the heartfrequency might be 120 at time x and 75 the next timestep this does not mimic a realistic trend for a heartfrequency (even in the most dramatic cases hf would not drop by that much).
To tackle this issue we decided to generate our heartfrequency with an algorithm called random walk. A random walk generates a list of values each based on the last value to allow for a more realistic trend . Our implementation of a random walk can be found under the section "Random Walk" in the notebook. The relationship between ECG and heartfrequency is not unique and almost every graph brings its associated value (i.e. pleth -> spo2, co2 -> co2Absolute). With our strategy we were able to generate all the datastreams necessary.
Every scenario and our standard scenario have a dedicated json file. On the top level one can find a list containing all the (sensor)channels needed, and general information for the scenario such as the duration. A channel can contain data for either a graph or one of the absolute values that are associated to the graphs and channel information. The data just holds a list of all the datapoints. Channel information provides useful descriptions and important parameters such as the enum identifier and the resolution. The resolution is stated in Hz.
With a combination of the random walk and the clean, easily loopable data we recieved, we had the tools to construct any scenario we wanted. Now that we had all the basic components needed we tried to replicate the given patient scenarios as close as possible.
-
Please refer to our Code Documentation
-
Application Styleguide
-
Approaches and Logic for Alarmmangement
-
UseCases for Testing
1. Sound Problems with MacOS and Simulator
If you are using a Mac and you are simulating an iPad over XCode and the Simulator, please make sure, that you have enabled the sound in settings. Also playing sounds with the Mac speakers can lead to sound issues. Please consider using headphones.
RAM filled with 4.3 GB after running application for extended time period (about 15 minutes). Tested on iPad Pro, 12.9inches, 2nd generation.
3. Add-Button ValueTiles for the right side missing
Adding an absolute sensor on the right side of the screen is currently missing.
Alarms sound don't start right away. This seems to be a problem of Audioplayer and Timer. Initial start should be directly.
Alarmsound should be alternating, when at least two alarms from monitoring and ventilation occur at the same time with the same priority.
6. Alarms disappear too quickly
Alarms should be visualized at least 10 seconds before it can update to a lower alarm.
7. Server Issues with Pipeline
The pipeline for the project couldn't be started due to server issues.
Tim Puhlfürß - [email protected]
- Corvin Biebach - [email protected]
- Maximilian Brosius - [email protected]
- Fynn Menk - [email protected]
- Anni Reinert - [email protected]
- Noah Scheld - [email protected]
- Arne Struck - [email protected]
- Mudassar Zahid - [email protected]
Project Link: UHH Informatics GitLab Repository
Special Thanks for the friendly help for the Requirements Elicitation and medical questions to:
- Dr. Mahler - Emergency Doctor @ UKE Hamburg
- Dr. Reip - Emergency Doctor @ UKE Hamburg
- Dr. Sasu - Emergency Doctor @ UKE Hamburg
And also for providing simulation / real patient data and helping with DataGeneration for the showcase.
- Christian Neuhaus - WEINMANN Emergency