Events, intervals and breaths#
M3Resp has three objects for things that happen at a time, beside the continuous signals. All modalities use the same three objects.
Object |
What it is |
Example |
|---|---|---|
|
Something at a single instant: |
An R peak, a blood gas sample |
|
Something that lasts for a period, from |
An occlusion manoeuvre, a noisy period, an intervention |
|
A breath found in EIT, EMG or ventilator data |
All times are in seconds.
Make an event and an interval#
from m3resp import Event, Interval
sample = Event("arterial_blood_gas_draw", "ventilator", 125.0, label="before PEEP step 2")
occlusion = Interval("ventilator", 10.0, 12.5, name="occlusion")
print(occlusion.duration) # 2.5
namesays what kind of event or interval it is.labelis a note of your own that tells two events of the same kind apart. M3Resp does not uselabel.For an
Interval, givemodality,start_timeandend_timein this order, and all other fields by name. An interval that ends before it starts raisesValueError.An interval with equal start and end times is allowed. It means that only one time point is known.
Breaths#
A BreathEvent has all fields of an Interval. Its name is always "breath". It also has extremum_time (in seconds) and extremum_index (the sample number):
from m3resp import BreathEvent, Interval
breath = BreathEvent("eit", 1.0, 2.0, extremum_time=1.5)
print(breath.duration) # 1.0
print(isinstance(breath, Interval)) # True
The extremum is the highest or the lowest point of the breath in the signal. Its meaning depends on the signal:
Signal |
Extremum |
|---|---|
EIT impedance |
The highest impedance: the end of inspiration |
EMG envelope |
The highest muscle activity |
Ventilator volume |
The highest volume |
Airway pressure of an occlusion |
The lowest pressure |
EIT, EMG and ventilator breath detection all give BreathEvent objects. So you can compare the breaths of different modalities (see Synchronization and breath timing).
The default EMG breath detection finds only the highest point of the envelope. So the start time, the end time and the extremum time of an EMG breath are equal, and metadata["boundaries_measured"] is False. The step emg.onoffpeak_baseline_crossing measures the start and the end of each EMG breath, and keeps them in its own result.
An occlusion (Pocc) is also a BreathEvent, with metadata["event_type"] == "pocc": it is a breath effort against a closed airway, with the lowest pressure as its extremum.
Sample numbers#
The fields sample_index (for an event), start_index, end_index and extremum_index give positions in a signal. Each recording can have signals with different sampling rates, so signal_name and sample_frequency say which signal the positions belong to. When an event does not come from a signal, the three fields are None.
The identifier of an event#
Each event, interval and breath gets a random id when M3Resp makes it. The id stays the same when M3Resp shifts the event to the shared clock, and when it writes the event to a file and reads it back. When you run the breath detection two times on the same data, the breaths of the two runs have the same times but different ids. M3Resp ignores the id when it compares two events, so the breaths of both runs count as equal.
A result can point to one event with its id, for example with ParameterResult.event_id. The results per breath of M3Resp still point to a breath by its position in the list.
Convert other objects#
coerce_interval and coerce_breath_event make an M3Resp object from a dictionary, from a (start_time, end_time) pair, or from an object with start_time and end_time, for example an eitprocessing interval. Give name= and modality= if the input does not have them.
from m3resp import coerce_interval
interval = coerce_interval((10.0, 12.5), name="occlusion", modality="ventilator")
An input with the name
"breath", or with an extremum, becomes aBreathEvent.An input with an extremum and another name raises
ValueError, because anIntervalhas no extremum.coerce_breath_eventraisesValueErrorfor an input with another name than"breath". So an occlusion or a noisy period never becomes a breath by mistake.coerce_breath_eventreads the extremum fromextremum_timeandextremum_index, then from the older namespeak_timeandpeak_index(with aUserWarning), then from themiddle_timeofeitprocessing.
Values per interval or event#
Some results have one value per breath or per event, for example the TIV of each breath or the amplitude of each R peak. IntervalData and EventData keep each value next to its interval or event:
from m3resp import IntervalData
tiv = IntervalData(
name="tidal_impedance_variation",
modality="eit",
intervals=session.get_events("eit_breaths"),
values=[1.5, 1.7, 1.6],
unit="a.u.",
)
Field |
Contents |
|---|---|
|
What the values are |
|
The device of the values. This can be another device than the device of the intervals: EIT values can belong to breaths from the ventilator data. |
|
The intervals or events, in order |
|
One value per interval or event, in the same order: a number, an array (for example a pixel map) or an M3Resp object. |
|
The physical quantity and the unit, as on a parameter |
|
The calculation and other details |
If the number of values is not equal to the number of intervals, M3Resp raises ValueError. A NaN value stays next to its breath. to_dict() gives the content as lists and dictionaries for a JSON file.
The EIT steps store their values per breath in session.interval_data:
Step |
Name |
One value per breath |
|---|---|---|
|
|
TIV |
|
|
EELI |
|
|
A pixel map of TIV |
|
|
The start, middle and end time of the breath in each pixel |
preprocess_eit also stores continuous_tivs, continuous_eelis and pixel_tivs. The breaths of these values have the times of the EIT recording. A breath with the same start and end time as a breath in session.events["eit_breaths"] is the same object.
Where the breaths are stored#
The session stores each list of breaths or events in session.events, under a name:
Name |
Filled by |
|---|---|
|
|
|
|
|
The |
|
|
|
The step |
To store or read a list yourself:
session.add_events("interventions", [occlusion])
print(session.get_events("interventions"))
ventilator.detect_breaths finds breaths as the highest points of the volume. An occlusion moves no air, so it is only in "pocc_breaths". ventilator.detect_pressure_breaths finds breaths as the lowest points of the airway pressure, so with that step an occlusion can be in both lists.
Continue with Parameters.