m3resp.M3Session#
- class m3resp.M3Session(eit_adapter=None, emg_adapter=None, metadata=None, allow_overwrite=False, ventilator_adapter=None)[source]#
Recordings, processing results and provenance for a multimodal study session.
Methods
Store a named event list while keeping session.events as backing data.
Deprecated alias for synchronize_multimodal_breaths - kept for backward compatibility with existing calling code.
Compute and store breath timing measures from linked_breaths.
Detect EIT breaths and store them as
BreathEventobjects.Detect EMG breaths and store normalized events.
Detect ventilator breaths from the volume channel.
Compute the moving baseline of the EMG envelope (Grasshoff et al. 2021).
Compute the slope-sum baseline of the EMG envelope (ReSurfEMG).
Write session tables, JSON summaries and array archives.
Return a named event list from session.events.
A loaded ventilator recording by name, or the primary one.
Link breaths across modalities into LinkedBreath objects (Milestone 2.5).
Load EIT data and store it under raw["eit"].
Load EMG data and store it under raw["emg"].
Load ventilator data and store it under raw["ventilator"].
Run EMG postprocessing through the adapter.
Preprocess the loaded EIT recording and store the results.
Run EMG preprocessing through the adapter.
Extract ventilator channels and optionally apply a low-pass filter.
The name of the recording session.ventilator points at.
Run a registered preset on this session.
Use the loaded recordings as they are, without synchronizing them.
Keep only the part of the loaded EIT recording between two times.
Keep only the part of the loaded EMG recording between two times.
Keep only the part of standalone ventilator recordings between two times.
Apply basic Stage 1 alignment to stored breath event lists.
Set when each loaded recording started, on one shared clock.
- Parameters:
- add_events(name, events)[source]#
Store a named event list while keeping session.events as backing data.
- align_modalities(method='manual_offset', offset_seconds=0.0, reference_modality=None)[source]#
Deprecated alias for synchronize_multimodal_breaths - kept for backward compatibility with existing calling code.
- compute_breath_timing_parameters(*, delay_pairs=None, duration_pairs=None, anchor='start')[source]#
Compute and store breath timing measures from linked_breaths.
Call link_breaths after aligning the recordings’ time axes. Each successful call replaces all stored multimodal breath-timing results, including those from earlier pairs or anchors, and records provenance. Other parameter results are retained. Empty linked breaths clear the previous timing results and return an empty list.
- Parameters:
delay_pairs (Sequence[tuple[str, str]] | None) – Ordered pairs (from, to) for delays and event agreement. Positive delays mean the second modality occurs later. None selects every unordered pair of observed modalities in alphabetical order; [] selects none.
duration_pairs (Sequence[tuple[str, str]] | None) – Ordered pairs (a, b) for duration(a) minus duration(b). None uses every observed pair in alphabetical order; [] selects none.
anchor (str) – Breath point for delays: “start” (default), “extremum”, or “end”.
- Returns:
- Stored results: per-breath delays and duration
differences in seconds, and aggregate agreement fractions per delay pair. Agreement counts links holding either modality and measures the fraction holding both. Per-breath results require both breaths; delays also require both selected anchors.
- Return type:
- Raises:
ValueError – If the anchor name is invalid, including for empty inputs. Existing parameter results are retained when validation fails.
- detect_eit_breaths(*, variant=None, **kwargs)[source]#
Detect EIT breaths and store them as
BreathEventobjects.Breaths matching an existing per-breath EIT result by modality and exact start and end time reuse that result’s breath object, including its identifier. Detection is recorded in the session’s history.
- Parameters:
variant (str | None) – Detect breaths in the
preprocess_eit(..., variant=<name>)result. Events are stored undersession.events['eit_breaths:<name>'].Noneuses the default processed result, falling back to the raw recording, and stores events under'eit_breaths'.**kwargs (Any) – Passed on to EITProcessingAdapter.detect_breaths.
detector=replaces the detection with a function of your own.
- Returns:
- Detected breaths in detector order, also stored
in
session.events. Times use the input recording’s clock.
- Return type:
- Raises:
MissingModalityDataError – If the named preprocessing variant is unavailable, or default processed EIT data and a raw recording are both unavailable.
- detect_emg_breaths(*, variant=None, **kwargs)[source]#
Detect EMG breaths and store normalized events.
- Parameters:
variant (str | None) – Detect breaths in the preprocess_emg result with this name, stored under session.events[“emg_breaths:<name>”]. See detect_eit_breaths.
**kwargs (Any) – Passed on to ReSurfEMGAdapter.detect_breaths (for example
baseline=).detector=replaces the detection with a function of your own.
- Returns:
The detected breaths, a list of BreathEvent.
- Return type:
Any
- detect_ventilator_breaths(*, variant=None, **kwargs)[source]#
Detect ventilator breaths from the volume channel.
This promotes what used to be a side effect of postprocess_emg into a method of its own, so ventilator breaths can be detected without running EMG postprocessing first. postprocess_emg still populates session.events[“ventilator_breaths”] as before.
- Parameters:
variant (str | None) – Detect breaths in the preprocess_ventilator result with this name, stored under session.events[“ventilator_breaths:<name>”]. See detect_eit_breaths. When None and the ventilator has not been preprocessed, it is preprocessed here with the default settings.
**kwargs (Any) – Passed on to VentilatorAdapter.detect_breaths (for example
breath_width_seconds).detector=replaces the detection with a function of your own.
- Returns:
The detected breaths, a list of BreathEvent.
- Return type:
Any
- emg_moving_baseline(*, window_seconds=7.5, step_seconds=0.2, percentile=33.0, variant=None)[source]#
Compute the moving baseline of the EMG envelope (Grasshoff et al. 2021).
The baseline is the quiet level of the envelope: a percentile of the envelope in a moving window. Breath detection measures its threshold above this level, so compute it before detect_emg_breaths and pass it on, with the same
variant:baseline = session.emg_moving_baseline() session.detect_emg_breaths(baseline=baseline)
The baseline is added to session.signals as
<channel>_moving_baseline(<channel>_moving_baseline:<variant>for a variant), replacing the one from an earlier call, and the call is recorded in session.provenance.- Parameters:
- Returns:
- One baseline value per envelope sample, in the
units of the envelope.
- Return type:
- Raises:
MissingModalityDataError – If there is no processed EMG (or no such variant).
ValueError – If the processed EMG has no envelope, or a setting is out of range.
- emg_slopesum_baseline(*, window_seconds=7.5, step_seconds=0.2, percentile=33.0, augmented_percentile=25.0, moving_average_seconds=0.5, percentile_window_seconds=1.0, variant=None)[source]#
Compute the slope-sum baseline of the EMG envelope (ReSurfEMG).
The slope-sum baseline is the quiet level of the envelope with its slope added: in each window it is 1.2 times a percentile of the envelope plus its absolute, smoothed slope. The calculation is the same as in the
emg.slopesum_baselinestep. Breath detection measures its threshold above this level, so pass it on, with the samevariant:baseline = session.emg_slopesum_baseline() session.detect_emg_breaths(baseline=baseline)
Three signals are added to session.signals:
<channel>_slopesum_baseline, and the running mean and running standard deviation of the moving baseline,<channel>_slopesum_baseline_running_meanand..._running_std(each with:<variant>at the end for a variant). They replace the ones from an earlier call. The call is recorded in session.provenance.- Parameters:
window_seconds (float) – Window length in seconds.
step_seconds (float) – Time between updates of the moving baseline, in seconds.
percentile (float) – Percentile of the envelope in each window for the moving baseline, 0 to 100.
augmented_percentile (float) – Percentile of the envelope plus its slope in each window, 0 to 100.
moving_average_seconds (float) – Smoothing window of the envelope slope, in seconds.
percentile_window_seconds (float) – Time between updates of the slope-sum baseline, in seconds.
variant (str | None) – Use the preprocess_emg result with this name; None uses the current processed EMG.
- Returns:
- One baseline value per envelope sample, in the
units of the envelope.
- Return type:
- Raises:
MissingModalityDataError – If there is no processed EMG (or no such variant).
ValueError – If the processed EMG has no envelope, or a setting is out of range.
- export_summary(output_dir, *, processing_run_id=None)[source]#
Write session tables, JSON summaries and array archives.
Creates the destination directory and records the export in the session’s provenance after writing. See export_session_summary for file contents.
- Parameters:
- Returns:
Directory containing the exported files.
- Return type:
Path
- Raises:
OSError – If the directory or an export file cannot be written.
- get_events(name, default=None)[source]#
Return a named event list from session.events.
- Parameters:
name (str) – The name the events were stored under, for example
"emg_breaths".default (Any) – What to return when no events have this name.
- Returns:
The stored events, or default.
- Return type:
Any
- get_ventilator(name=None)[source]#
A loaded ventilator recording by name, or the primary one.
- Parameters:
name (str | None) – The name the recording was loaded under (see load_ventilator). None gives the primary recording.
- Returns:
The loaded recording.
- Return type:
VentilatorRecording
- link_breaths(*, time_tolerance=0.5)[source]#
Link breaths across modalities into LinkedBreath objects (Milestone 2.5).
Prefers the aligned breath lists produced by synchronize_multimodal_breaths (
self.processed["synchronized"]) over the per-modality event lists inself.events. A list that was not aligned there is moved onto the shared clock here, using the start times from synchronize_raw_modalities, so breaths are always matched on one time axis.Warns (UnsynchronizedDataWarning) when the breaths come from recordings on different clocks and one of them was never synchronized; see skip_synchronization.
- Parameters:
time_tolerance (float) – Largest time difference, in seconds, at which two breaths from different modalities are still linked. The closest match wins; a breath with no match gets a LinkedBreath of its own.
- Returns:
- The linked breaths. Also stored in
session.linked_breaths.
- Return type:
- load_eit(path, vendor=None, *, loader='auto', **kwargs)[source]#
Load EIT data and store it under raw[“eit”].
A newly loaded recording has not been synchronized yet: any EIT start time and synchronization record from before are cleared.
- Parameters:
path (str | Path | list) – The EIT file to read, or a list of files recorded one after the other, read as one recording. The files are joined in the given order; a pause between two files stays in the time axis and gives a warning. With eitprocessing,
first_frame/max_framescannot be used with several files.vendor (str | None) – The EIT device maker, passed to eitprocessing (for example
"draeger").loader (str) –
"eitprocessing"reads a Draeger, Sentec or Timpel file and needsvendor;"custom"uses the loader given to session.eit_adapter (EITProcessingAdapter( loader=...));"auto"uses that custom loader when there is one, else eitprocessing.**kwargs (Any) – Passed on to the EIT file reader.
- Returns:
The loaded eitprocessing Sequence (session.eit.data).
- Return type:
Any
- load_emg(path, **kwargs)[source]#
Load EMG data and store it under raw[“emg”].
A newly loaded recording has not been synchronized yet: any EMG start time and synchronization record from before are cleared.
- Parameters:
path (str | Path) – The EMG file to read.
**kwargs (Any) – Passed on to the EMG file reader.
- Returns:
- The loaded EMG data (session.emg.data), a dictionary with
the samples under
"array"and the file details under"metadata".
- Return type:
Any
- load_ventilator(path, *, name=None, **kwargs)[source]#
Load ventilator data and store it under raw[“ventilator”].
Mirrors load_eit/load_emg. The recording is additionally stored under the legacy raw[“vent”] key, pointing at the same object.
A newly loaded standalone recording has not been synchronized yet: its own start time and synchronization record from before are cleared. Ventilator data from the EIT or EMG file follows that file’s clock.
- Parameters:
path (str | Path) – The file the ventilator data arrives in: the multi-channel export shared with the sEMG, or an EIT
*.bincarrying ventilator waveforms beside its impedance frames. VentilatorAdapter picks by file suffix.name (str | None) – Files this recording alongside any already loaded, for a study where more than one instrument recorded ventilator data - a ventilator export and the EIT file’s own Medibus channels, say, each with its own airway pressure. Without a name the recording is the primary one, which is what session.ventilator and raw[“ventilator”] point at. Preprocess a named recording with preprocess_ventilator(name=…), which qualifies its channel keys so the two airway pressures stay distinct in session.signals.
**kwargs (Any) – Passed on to the ventilator file reader. Use
source="eit"/"emg"/"ventilator"to choose the file type, andventilator_channels=to select which channels to read from a*.bin(see m3resp.adapters.ventilator_adapter).
- Returns:
- The loaded ventilator data (VentilatorRecording.data), a
dictionary with the samples under
"array"and the file details under"metadata".
- Return type:
Any
- postprocess_emg(**kwargs)[source]#
Run EMG postprocessing through the adapter.
Uses the default EMG preprocessing result and the breaths in session.events[“emg_breaths”]. Any ventilator breaths found during postprocessing are stored in session.events[“ventilator_breaths”].
- Parameters:
**kwargs (Any) – Passed on to ReSurfEMGAdapter.postprocess, for example
ventilator,ventilator_fs(Hz) andventilator_breath_width_seconds.- Returns:
- The postprocessing result, a dictionary with the values
computed (
"computed"), those skipped ("skipped") and the settings used ("settings"). Also stored in session.parameters[“emg_postprocessing”].
- Return type:
Any
- preprocess_eit(*, variant=None, overwrite=False, **kwargs)[source]#
Preprocess the loaded EIT recording and store the results.
Results are stored in
session.processed_variants['eit']under the variant name, or'default'when omitted. The default result is also stored insession.processed['eit']. Upstream preprocessing adds signals, rate parameters, values per breath and quality flags to the session’s collections. Per-breath results reuse breaths stored under the matching variant’s event key.- Parameters:
variant (str | None) – Name to store this result under. None stores it as
"default".overwrite (bool) – Replace a result already stored under the same name.
session.allow_overwritealso permits replacement.**kwargs (Any) – Passed on to EITProcessingAdapter.preprocess (for example
filter_mode).preprocess=replaces the whole step with a function of your own; its output is stored directly in the processed-result dictionaries.
- Returns:
- The preprocessing result, also stored in
session.processed_variants[“eit”].
- Return type:
Any
- Raises:
MissingModalityDataError – If an EIT recording has yet to be loaded.
VariantAlreadyExistsError – If the variant already exists and replacement is disabled.
- preprocess_emg(*, variant=None, overwrite=False, **kwargs)[source]#
Run EMG preprocessing through the adapter.
See preprocess_eit for what variant/overwrite/allow_overwrite do - it persists this result under session.processed_variants[“emg”][name], raising VariantAlreadyExistsError if name is already populated, and mirrors it onto session.processed[“emg”] only when name is “default”.
- Parameters:
- Returns:
- The preprocessing result. The default step gives a
dictionary that includes the
"filtered"and"envelope"signals, the"channel"used and the sampling rate"fs"in Hz.
- Return type:
Any
- preprocess_ventilator(*, name=None, variant=None, overwrite=False, **kwargs)[source]#
Extract ventilator channels and optionally apply a low-pass filter.
Stores the result in processed_variants[“ventilator”], adds signals, parameters and quality flags from the adapter, and records provenance. Updates the recording’s airway_pressure, flow, volume and fs fields. The default and primary-recording variants also update processed[“ventilator”].
- Parameters:
name (str | None) – Loaded recording to preprocess. None selects the primary recording. Other recordings get channel keys ending in their name, such as “airway_pressure__pod”.
variant (str | None) – Name for the stored result. Defaults to the recording name supplied in name, or “default” when name is None.
overwrite (bool) – Allow replacement of an existing variant. The session’s allow_overwrite setting also allows replacement.
**kwargs (Any) – Options for VentilatorAdapter.preprocess, including channels, explicit channel indices, fs in Hz, lowpass_hz in Hz, and filter_order. The default selection is airway_pressure, flow and volume. With lowpass_hz=None, values retain their recorded units and are copied into the channel arrays. preprocess may supply a custom function.
- Returns:
- Adapter result. The default result contains channel arrays,
raw and filtered channel mappings, per-channel units, and fs in Hz. Filtering is applied when lowpass_hz is supplied.
- Return type:
Any
- Raises:
MissingModalityDataError – If the selected recording is unavailable.
VariantAlreadyExistsError – If the variant exists and overwriting is disabled.
UnresolvedChannelError – If a requested channel cannot be found.
- primary_ventilator_name()[source]#
The name of the recording session.ventilator points at.
- Returns:
- The name, or None when no ventilator recording is
loaded.
- Return type:
str | None
- run_preset(name, *, config=None)[source]#
Run a registered preset on this session.
The built-in presets are eit, emg and multimodal. Each runs a fixed sequence of session methods or registered steps using the supplied settings. Load the required recordings first; the multimodal preset uses previously detected breaths to store aligned events.
- Parameters:
- Returns:
- This session with results and provenance added by the preset’s
operations. Changes made before an operation fails remain available.
- Return type:
- Raises:
UnknownPresetError – If name is unregistered.
MissingModalityDataError – If an operation needs an unavailable recording.
- skip_synchronization()[source]#
Use the loaded recordings as they are, without synchronizing them.
For recordings that really did start at the same moment - for example when one trigger started every device. Each loaded recording that has not been synchronized is recorded as
"none"in session.sync_methods, so steps that compare recordings skip their missing-synchronization warning, while the choice stays visible in the provenance log and the exported summary. Recordings already synchronized keep their record. Breath lists added directly with add_events, without a loaded recording, are covered too. Recordings loaded later are not.
- slice_eit(start_seconds, end_seconds=None)[source]#
Keep only the part of the loaded EIT recording between two times.
Times are in seconds from the first frame of the recording as it is now (after any earlier slicing), not the time of day stored in the file.
end_seconds=Nonekeeps everything up to the end. The kept part runs from the first frame at or after start_seconds up to, but not including, the first frame at or after end_seconds.The cutting itself is done by eitprocessing (EITProcessingAdapter.slice_sequence): pixel data, global impedance, the pressure/flow channels and the vendor’s markers are all cut to the same frames. A ventilator recording loaded from the same EIT file is cut at exactly those frames too, so it stays lined up with the EIT. EIT frame times keep their original values; the EIT start time in session.start_times moves later by the part cut off the front, so the EIT stays lined up with the other recordings.
Run this before preprocess_eit. The removed frames are gone from the loaded recording; reload the file to get them back.
- Parameters:
- Returns:
- The times used, the number of frames removed from
the start and the end and kept, and how many ventilator recordings were cut with the EIT. Also stored in session.parameters[“eit_slice”].
- Return type:
- slice_emg(start_seconds, end_seconds=None)[source]#
Keep only the part of the loaded EMG recording between two times.
Times are in seconds from the start of the recording as it is now (after any earlier slicing).
end_seconds=Nonekeeps everything up to the end. Ventilator channels recorded in the same file (for example airway pressure on a Biopac export) are cut the same way, so they stay lined up with the EMG. After slicing, EMG times count from the new start, and the EMG start time in session.start_times moves later by start_seconds, so the EMG stays lined up with the other modalities.Run this before preprocess_emg. The removed samples are gone from the loaded recording; reload the file to get them back.
- Parameters:
- Returns:
- The times used and the number of samples removed
from the start and the end and kept. Also stored in session.parameters[“emg_slice”].
- Return type:
- slice_ventilator(start_seconds, end_seconds=None, *, name=None)[source]#
Keep only the part of standalone ventilator recordings between two times.
“Standalone” means a ventilator or monitor export with a clock of its own, loaded with
load_ventilator(path, source="ventilator"). Ventilator data that came inside the EIT or EMG file is on that file’s clock and is cut with it by slice_eit or slice_emg; asking to cut it here raises an error, since cutting it alone would move it out of line with its host recording.Times are in seconds from the start of the recording as it is now (after any earlier slicing).
end_seconds=Nonekeeps everything up to the end. After slicing, the recording’s times count from the new start, and its start time moves later by start_seconds: it is stored under its own"ventilator:<name>"entry in session.start_times, so the recording stays lined up with the other modalities and no other recording moves.Run this before preprocess_ventilator. The removed samples are gone from the loaded recording; reload the file to get them back.
- Parameters:
- Returns:
- The times used and, under
"recordings", the number of samples removed from the start and the end and kept for each recording that was cut. Also stored in session.parameters[“ventilator_slice”].
- The times used and, under
- Return type:
- synchronize_multimodal_breaths(method='manual_offset', offset_seconds=0.0, reference_modality=None)[source]#
Apply basic Stage 1 alignment to stored breath event lists.
Named to mirror synchronize_raw_modalities: that one shifts raw signals in time before processing, this one shifts already-detected breath events (ALIGNMENT_EVENT_LISTS) in time after detection. Previously named align_modalities, kept below as an alias.
Offsets are resolved relative to reference_modality (or the auto-detected one - see m3resp.synchronization.alignment.breath_reference_modality) before being applied, so the reference modality’s own events are shifted by zero and every other modality moves by its offset relative to the reference, matching synchronize_raw_modalities. self.parameters[“alignment”] keeps both: offset_seconds (relative, what was actually applied) and configured_offset_seconds (the raw per-modality values passed in).
The start times set by synchronize_raw_modalities are added on top, so the shifted breaths are on the shared clock. The two add up: offset_seconds is only for a further correction after detection. start_time_shift_seconds records what was added for each modality.
- Parameters:
method (str) – How the breaths are shifted. Only
"manual_offset"is supported.offset_seconds (float | Mapping[str, float]) – Extra shift of each modality’s breaths in seconds, on top of the start times, for example
{"emg": 0.2}. A single number is the EMG shift.reference_modality (str | None) – The modality whose breaths are not shifted by an extra offset. When None: the ventilator if there are ventilator breaths, otherwise EIT.
- Returns:
- The shifted breath lists, keyed by list name (for
example
"emg_breaths"). Also stored in session.processed[“synchronized”].
- Return type:
- synchronize_raw_modalities(method='manual_offset', offset_seconds=0.0, reference_modality=None)[source]#
Set when each loaded recording started, on one shared clock.
No samples are removed: every recording keeps its full length. The start times are stored in session.start_times and are added to breath times only when modalities are compared (synchronize_multimodal_breaths, link_breaths), so each modality’s own results stay on its own clock. Calling this again replaces the start times rather than adding to them. See m3resp.synchronization.start_times.
- Parameters:
method (str) – How the start times are found. Only
"manual_offset"is supported.offset_seconds (float | Mapping[str, float]) – Start time of each modality in seconds, for example
{"emg": 5.0}for “EMG started 5 s after EIT”, or{"emg": -5.0}for “EMG started 5 s before EIT”. A single number is the EMG start time."ventilator"is the start time of the standalone ventilator recordings (those loaded withsource="ventilator"). When two of them started at different moments, give one its own start time with"ventilator:<name>", the name it was loaded under, e.g.{"ventilator": 0.0, "ventilator:monitor": 12.5}. Ventilator data that came inside the EIT or EMG file always uses that file’s start time.reference_modality (str | None) – The recording that start times are counted from, so its own start time is always 0. A modality name or
"ventilator:<name>". When None: the ventilator if one is loaded, otherwise EIT, otherwise EMG.
- Returns:
{modality: {"start_time_seconds": ...}}forevery loaded modality, plus a
"ventilator:<name>"entry for each standalone ventilator recording given its own start time.
- Return type: