Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional waveform signal to IOD definitions #53

Closed
briangow opened this issue May 6, 2024 · 7 comments
Closed

Add additional waveform signal to IOD definitions #53

briangow opened this issue May 6, 2024 · 7 comments

Comments

@briangow
Copy link
Collaborator

briangow commented May 6, 2024

We need to add additional mappings between a waveform signal type and a DICOM IOD. In some cases we need to add the code for the IOD to the dcm_waveform_writer.py file:

  • HemodynamicWaveform
  • whatever we use for CO2

I've attempted to create a complete list of the signal type to IOD mappings for all signal types in our benchmarking waveform suite ( #11 (comment) ) :

CHANNEL_TO_DICOM_IOD = {
    "I":  dcm_writer.GeneralECGWaveform,
    "II":  dcm_writer.GeneralECGWaveform,
    "III":  dcm_writer.GeneralECGWaveform,
    "V":  dcm_writer.GeneralECGWaveform,
    "V2": dcm_writer.GeneralECGWaveform,
    "V5": dcm_writer.GeneralECGWaveform,
    "aVR":  dcm_writer.GeneralECGWaveform,
    "ECG": dcm_writer.GeneralECGWaveform,
    "Pleth":  dcm_writer.ArterialPulseWaveform,
    "Resp":  dcm_writer.RespiratoryWaveform,
    "CO2": ,
    "CVP": dcm_writer.HemodynamicWaveform,
    "PAP": dcm_writer.HemodynamicWaveform,
    "ABP": dcm_writer.HemodynamicWaveform,
    "Ao": dcm_writer.HemodynamicWaveform,
    "MCL": dcm_writer.GeneralECGWaveform,
    "ICP": dcm_writer.HemodynamicWaveform,
    "F3-M2": dcm_writer.SleepEEGWaveform,
    "F4-M1": dcm_writer.SleepEEGWaveform,
    "C3-M2": dcm_writer.SleepEEGWaveform,
    "C4-M1": dcm_writer.SleepEEGWaveform,
    "O1-M2": dcm_writer.SleepEEGWaveform,
    "O2-M1": dcm_writer.SleepEEGWaveform,
    "E1-M2": dcm_writer.SleepEEGWaveform,
    "Chin1-Chin2": dcm_writer.ElectromyogramWaveform,
    "ABD": dcm_writer.RespiratoryWaveform,
    "CHEST": dcm_writer.RespiratoryWaveform,
    "AIRFLOW": dcm_writer.RespiratoryWaveform,
    "SaO2": dcm_writer.ArterialPulseWaveform,
}

I guess the CO2 object should map to some kind of "Exhaled Gas IOD"

@briangow briangow mentioned this issue May 6, 2024
@tcpan
Copy link
Collaborator

tcpan commented May 7, 2024

Thanks, Brian, for getting this started. I've added these to the code, untested, however.

A few questions:

  1. is ECG just a generic ECG channel?
  2. I've put MCL with GeneralECGWaveform, but I am not sure if there is a group of ECG leads it best go with?
  3. is ECG just a generic lead?
  4. Are there specific groupings for the hemodynamic, sleepEEG, and Respiratory waveforms (i.e. which are commonly collected together and with same frequency?
  5. I put the CO2 waveform with respiratoryWaveform IOD. I did not see another waveform IOD that would make sense.

We also need to update units:

UCUM_ENCODING = {
"mV": "millivolt",
"bpm": "beats per minute",
"mmHg": "millimeter of mercury",
"uV": "microvolt",
"NU": "number",
"Ohm": "ohm"
}

Ultimately, I need to cite the source vocabulary for the waveform names and the units. But for now, I've just filled in some values if i didn't know them.

Finally, the code currently does not enforce the limits on number of multiplex groups, number of channels in each group, maximum number of samples and frequency ranges. ( the test case did not hit the limits) Let's see if the rest of the test data creates problems.

Updates (untested) checked in.

@tcpan
Copy link
Collaborator

tcpan commented May 7, 2024

Also, i have some Emory GE data in WFDB format.

Spot checking them shows the following channel names:
I, II, III, V, AR1, AR2, PA2, SPO2, RR, CVP1, CVP2, CO2 in the "***_layout.hea" file.

I assume CVP1 is same as CVP. Not sure about CVP2, AR1, AR2, and PA2.

@briangow
Copy link
Collaborator Author

briangow commented May 7, 2024

is ECG just a generic ECG channel?

Yes.

I've put MCL with GeneralECGWaveform, but I am not sure if there is a group of ECG leads it best go with?

From what I read online, the MCL lead is independent and isn't usually grouped with other leads.

is ECG just a generic lead?

I don't see information regarding which lead this comes from in the project descriptions.

Are there specific groupings for the hemodynamic, sleepEEG, and Respiratory waveforms (i.e. which are commonly collected together and with same frequency?

Based on the result from #11 (comment) :

hemodynamic:
ABP, Ao, and CVP seem to share the same fs and bit resolution
PAP seems to have the same fs as ABP but a different bit resolution
ICP seems to ahve the samfe fs as ABP but a slightly different bit resolution

sleepEEG:
these all group together with the same fs, and bit resolution

Respiratory:
ADB, CHEST, AIRFLOW seem to share the same fs and bit resolution
SaO2 has the same fs as the above but a different bit resolution

I put the CO2 waveform with respiratoryWaveform IOD. I did not see another waveform IOD that would make sense.

Ok, thanks

We also need to update units

This is what I see for units for the new signal types:

    "ECG": mV,
    "Pleth":  NU - "nadir upstroke",
    "Resp":  Ohm,
    "CO2": mmHg,
    "CVP": mmHg,
    "PAP": mmHg,
    "ABP": mmHg,
    "Ao": mmHg,
    "MCL": mV,
    "ICP":  mmHg,
    "F3-M2": uV,
    "F4-M1": uV,
    "C3-M2": uV,
    "C4-M1": uV,
    "O1-M2": uV,
    "O2-M1": uV,
    "E1-M2": uV,
    "Chin1-Chin2": uV,
    "ABD": uV,
    "CHEST": uV,
    "AIRFLOW": uV,
    "SaO2": %

Updates (untested) checked in.

Where were your untested updates checked in?

@briangow
Copy link
Collaborator Author

briangow commented May 7, 2024

I assume CVP1 is same as CVP. Not sure about CVP2, AR1, AR2, and PA2

I also can't tell from searching online what the difference between CVP (Central Venous Pressure), CVP1, and CVP2 are. Similarly for AR1 and AR2 which are arterial waveforms. PA2 is a pulmonary artery waveform.

@tcpan
Copy link
Collaborator

tcpan commented May 9, 2024

My engineer did a scan through our existing WFDB files for channel names. Below is the aggregated list. I am checking internally also for meaning of the names. I have not checked in these as the inclusion of canonical name is going to require code change.

'0 IC1': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'0 IC2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ABD': { 'iod': dcm_writer.RespiratoryWaveform, 'canonical_name': 'ABD'},  # tentative
'ABP': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'ABP'},
'AI': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'AIRFLOW': { 'iod': dcm_writer.RespiratoryWaveform, 'canonical_name': 'AIRFLOW'},
'Ao': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'Ao'},
'AR1': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'AR2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'AR3': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'AR4': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'AR5': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'AR6': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'AR7': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ART': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'ART'},  # tentative
'AS': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'AS'}, # tentative
'AVF': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'aVF'},
'aVF': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'aVF'},
'AVL': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'aVL'},
'aVL': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'aVL'},
'aVR': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'aVR'},
'AVR': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'aVR'},
'C3-M2': { 'iod': dcm_writer.SleepEEGWaveform, 'canonical_name': 'C3-M2'},
'C4-M1': { 'iod': dcm_writer.SleepEEGWaveform, 'canonical_name': 'C4-M1'},
'CHEST': { 'iod': dcm_writer.RespiratoryWaveform, 'canonical_name': 'CHEST'},
'Chin1-Chin2': { 'iod': dcm_writer.ElectromyogramWaveform, 'canonical_name': 'Chin1-Chin2'},
'CO': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'CO2': { 'iod': dcm_writer.RespiratoryWaveform, 'canonical_name': 'CO2'},
'CVP': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'TBD'},
'CVP1': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'CVP2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'CVP3': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'CVP4': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'CVP5': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'CVP6': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'CVP8': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'E1-M2': { 'iod': dcm_writer.SleepEEGWaveform, 'canonical_name': 'E1-M2'},
'ECG': { 'iod': dcm_writer.AmbulatoryECGWavaform, 'canonical_name': 'ECG'},
'EMPTY': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ES': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'F3-M2': { 'iod': dcm_writer.SleepEEGWaveform, 'canonical_name': 'F3-M2'},
'F4-M1': { 'iod': dcm_writer.SleepEEGWaveform, 'canonical_name': 'F4-M1'},
'FAP': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'I': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'I'},
'ICG': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'ICG'},
'ICP': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'ICP'},
'ICP1': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ICP2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ICP3': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ICP4': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ICP5': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ICP6': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ICP7': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'ICP8': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'II': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'II'},
'III': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'III'},
'LA1': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'LA1'},
'LA2': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'LA2'},
'LA3': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'LA3'},
'LA4': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'LA4'},
'LA6': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'LA6'},
'LAP': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'LAP'},
'MCL': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'MCL'},
'0 MCL': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'MCL'},
'O1-M2': { 'iod': dcm_writer.SleepEEGWaveform, 'canonical_name': 'O1-M2'},
'O2-M1': { 'iod': dcm_writer.SleepEEGWaveform, 'canonical_name': 'O2-M1'},
'P': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'PA1': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'PA1'},
'PA2': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'PA2'},
'PA3': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'PA3'},
'PA4': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'PA4'},
'PA6': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'PA6'},
'PAP': { 'iod': dcm_writer.HemodynamicWavaform, 'canonical_name': 'PAP'},
'Pleth': { 'iod': dcm_writer.ArterialPulseWaveform, 'canonical_name': 'Pleth'},
'PLETHl': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'PlethT': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'PLTHpo': { 'iod': dcm_writer.ArterialPulseWaveform, 'canonical_name': 'Pleth'}, # tentative.  primary plethysmograph
'PLTHpr': { 'iod': dcm_writer.ArterialPulseWaveform, 'canonical_name': 'PlethPR'}, # refelected
'RA1': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'RA1'},
'RA2': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'RA2'},
'RA3': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'RA3'},
'RA4': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'RA4'},
'RAP': { 'iod': dcm_writer.HemodynamicWaveform, 'canonical_name': 'RAP'},
'Resp': { 'iod': dcm_writer.RespiratoryWaveform, 'canonical_name': 'RR'},
'RESP': { 'iod': dcm_writer.RespiratoryWaveform, 'canonical_name': 'RR'},
'RM_FLOW': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'RM_VOL': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'RR': { 'iod': dcm_writer.RespiratoryWaveform, 'canonical_name': 'RR'},
'SaO2': { 'iod': dcm_writer.ArterialPulseWaveform, 'canonical_name': 'SaO2'},
'SP1': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'SP2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'SP3': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'SP4': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'SP5': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'SP6': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'SP8': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'SPO2': { 'iod': dcm_writer.ArterialPulseWaveform, 'canonical_name': 'SpO2'},
'SvO2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},  # venous oxygen saturation
'UAC1': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},  # audio?
'UAC2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UAC3': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UAC4': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UAP': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UNKNOWN': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UVC1': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UVC2': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UVC3': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UVC4': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'UVP': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'V': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'V'},
'V1': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'V1'},
'V2': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'V2'},
'V3': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'V3'},
'V4': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'V4'},
'V5': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'V5'},
'V6': { 'iod': dcm_writer.GeneralECGWaveform, 'canonical_name': 'V6'},
'VNT_FLOW': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},
'VNT_PRES': { 'iod': dcm_writer.TBD, 'canonical_name': 'TBD'},

@briangow
Copy link
Collaborator Author

briangow commented May 9, 2024

@tcpan , thanks for generating a comprehensive list. My thought is that we should focus on the signal types that you and I noted further above that came from the waveform suite of files we are using for benchmarking. These signal types come from the 40 files here ( #11 (comment) ) and 10 of the files you've provided. That will enable me to run the official benchmarking on the DICOM format.

We could continue to update your code after the benchmarking is done to add additional signal type to IOD mappings.

What do you think?

@tcpan
Copy link
Collaborator

tcpan commented May 9, 2024

Agree with the plan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants