mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-09 12:40:43 +00:00
Migrate PRS1 F5 importer to PRS1Import::AddEvent.
The only change in functionality is that F5V2 sessions won't have empty channels for CA, VS, and LL, since they're not yet supported by the parser.
This commit is contained in:
parent
79b2af140c
commit
b80c5ef114
@ -1756,45 +1756,10 @@ void PRS1DataChunk::AddEvent(PRS1ParsedEvent* const event)
|
||||
|
||||
bool PRS1Import::ImportEventsF5V0123()
|
||||
{
|
||||
float GAIN = PRS1PressureEvent::GAIN;
|
||||
if (event->familyVersion == 2 || event->familyVersion == 3) {
|
||||
// F5V2 and F5V3 use a gain of 0.125 rather than 0.1 to allow for a maximum value of 30 cmH2O
|
||||
GAIN = 0.125; // TODO: this should be parameterized somewhere more logical
|
||||
if (!CreateEventChannels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Required channels
|
||||
EventList *CA = session->AddEventList(CPAP_ClearAirway, EVL_Event);
|
||||
EventList *OA = session->AddEventList(CPAP_Obstructive, EVL_Event);
|
||||
EventList *HY = session->AddEventList(CPAP_Hypopnea, EVL_Event);
|
||||
|
||||
EventList *FL = session->AddEventList(CPAP_FlowLimit, EVL_Event);
|
||||
EventList *SNORE = session->AddEventList(CPAP_Snore, EVL_Event); // snore count statistic
|
||||
EventList *VS = session->AddEventList(CPAP_VSnore, EVL_Event);
|
||||
EventList *VS2 = session->AddEventList(CPAP_VSnore2, EVL_Event); // flags nonzero snore-count intervals on overview
|
||||
// No RERA detection
|
||||
|
||||
EventList *PB = session->AddEventList(CPAP_PB, EVL_Event);
|
||||
EventList *LL = session->AddEventList(CPAP_LargeLeak, EVL_Event);
|
||||
EventList *TOTLEAK = session->AddEventList(CPAP_LeakTotal, EVL_Event);
|
||||
EventList *LEAK = session->AddEventList(CPAP_Leak, EVL_Event); // TODO: calculated for F5V0, reported by F5V1 and higher
|
||||
|
||||
EventList *RR = session->AddEventList(CPAP_RespRate, EVL_Event);
|
||||
EventList *TV = session->AddEventList(CPAP_TidalVolume, EVL_Event, 10.0F);
|
||||
EventList *MV = session->AddEventList(CPAP_MinuteVent, EVL_Event);
|
||||
EventList *PTB = session->AddEventList(CPAP_PTB, EVL_Event);
|
||||
|
||||
// TB could be on-demand
|
||||
EventList *TB = session->AddEventList(PRS1_TimedBreath, EVL_Event, 0.1F); // TODO: a gain of 0.1 should affect display, but it doesn't
|
||||
|
||||
EventList *IPAP = session->AddEventList(CPAP_IPAP, EVL_Event, GAIN);
|
||||
EventList *EPAP = session->AddEventList(CPAP_EPAP, EVL_Event, GAIN);
|
||||
EventList *PS = session->AddEventList(CPAP_PS, EVL_Event, GAIN);
|
||||
EventList *IPAPLo = session->AddEventList(CPAP_IPAPLo, EVL_Event, GAIN);
|
||||
EventList *IPAPHi = session->AddEventList(CPAP_IPAPHi, EVL_Event, GAIN);
|
||||
|
||||
// On-demand channels
|
||||
EventList *PP = nullptr;
|
||||
|
||||
EventDataType currentPressure=0;
|
||||
|
||||
// Unintentional leak calculation, see zMaskProfile:calcLeak in calcs.cpp for explanation
|
||||
@ -1815,24 +1780,31 @@ bool PRS1Import::ImportEventsF5V0123()
|
||||
for (int i=0; i < event->m_parsedData.count(); i++) {
|
||||
PRS1ParsedEvent* e = event->m_parsedData.at(i);
|
||||
t = qint64(event->timestamp + e->m_start) * 1000L;
|
||||
|
||||
QVector<ChannelID*> channels = PRS1ImportChannelMap[e->m_type];
|
||||
ChannelID channel = 0, PS, VS2;
|
||||
if (channels.count() > 0) {
|
||||
channel = *channels.at(0);
|
||||
}
|
||||
|
||||
switch (e->m_type) {
|
||||
case PRS1EPAPSetEvent::TYPE:
|
||||
// TODO: The below belong in average channels and then this should go into the EPAP adjustment channel.
|
||||
break;
|
||||
case PRS1IPAPAverageEvent::TYPE:
|
||||
IPAP->AddEvent(t, e->m_value); // TODO: This belongs in an average channel rather than setting channel.
|
||||
AddEvent(channel, t, e->m_value, e->m_gain); // TODO: This belongs in an average channel rather than setting channel.
|
||||
currentPressure = e->m_value;
|
||||
break;
|
||||
case PRS1IPAPLowEvent::TYPE:
|
||||
IPAPLo->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1IPAPHighEvent::TYPE:
|
||||
IPAPHi->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1EPAPAverageEvent::TYPE:
|
||||
EPAP->AddEvent(t, e->m_value); // TODO: This belongs in an average channel rather than setting channel.
|
||||
PS->AddEvent(t, currentPressure - e->m_value); // Pressure Support
|
||||
PS = *channels.at(1);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain); // TODO: This belongs in an average channel rather than setting channel.
|
||||
AddEvent(PS, t, currentPressure - e->m_value, e->m_gain); // Pressure Support
|
||||
break;
|
||||
case PRS1TimedBreathEvent::TYPE:
|
||||
// The duration appears to correspond to the length of the timed breath in seconds when multiplied by 0.1 (100ms)!
|
||||
@ -1840,33 +1812,33 @@ bool PRS1Import::ImportEventsF5V0123()
|
||||
// they can express durations less than 1 second.
|
||||
// TODO: consider allowing OSCAR to record millisecond durations so that the display will say "2.1" instead of "21" or "2".
|
||||
duration = e->m_duration * 100L; // for now do this here rather than in parser, since parser events don't use milliseconds
|
||||
TB->AddEvent(t - duration, e->m_duration * 0.1F); // TODO: a gain of 0.1 should render this unnecessary, but gain doesn't seem to work currently
|
||||
AddEvent(*channels.at(0), t - duration, e->m_duration * 0.1F, 0.1F); // TODO: a gain of 0.1 should render this unnecessary, but gain doesn't seem to work currently
|
||||
break;
|
||||
case PRS1ObstructiveApneaEvent::TYPE:
|
||||
OA->AddEvent(t, e->m_duration);
|
||||
AddEvent(channel, t, e->m_duration, e->m_gain);
|
||||
break;
|
||||
case PRS1ClearAirwayEvent::TYPE:
|
||||
CA->AddEvent(t, e->m_duration);
|
||||
AddEvent(channel, t, e->m_duration, e->m_gain);
|
||||
break;
|
||||
case PRS1HypopneaEvent::TYPE:
|
||||
HY->AddEvent(t, e->m_duration);
|
||||
AddEvent(channel, t, e->m_duration, e->m_gain);
|
||||
break;
|
||||
case PRS1FlowLimitationEvent::TYPE:
|
||||
FL->AddEvent(t, e->m_duration);
|
||||
AddEvent(channel, t, e->m_duration, e->m_gain);
|
||||
break;
|
||||
case PRS1PeriodicBreathingEvent::TYPE:
|
||||
// TODO: The graphs silently treat the timestamp of a span as an end time rather than start (see gFlagsLine::paint).
|
||||
// Decide whether to preserve that behavior or change it universally and update either this code or comment.
|
||||
duration = e->m_duration * 1000L;
|
||||
PB->AddEvent(t + duration, e->m_duration);
|
||||
AddEvent(channel, t + duration, e->m_duration, e->m_gain);
|
||||
break;
|
||||
case PRS1LargeLeakEvent::TYPE:
|
||||
// TODO: see PB comment above.
|
||||
duration = e->m_duration * 1000L;
|
||||
LL->AddEvent(t + duration, e->m_duration);
|
||||
AddEvent(channel, t + duration, e->m_duration, e->m_gain);
|
||||
break;
|
||||
case PRS1TotalLeakEvent::TYPE:
|
||||
TOTLEAK->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
// TODO: decide whether to keep this here, shouldn't keep it here just because it's "quicker".
|
||||
// TODO: compare this value for the reported value for F5V1 and higher?
|
||||
// TODO: Fix this for 0.125 gain: it assumes 0.1 (dividing by 10.0)...
|
||||
@ -1875,47 +1847,45 @@ bool PRS1Import::ImportEventsF5V0123()
|
||||
EventDataType leak = e->m_value;
|
||||
leak -= (((currentPressure/10.0f) - 4.0) * ppm + lpm4);
|
||||
if (leak < 0) leak = 0;
|
||||
LEAK->AddEvent(t, leak);
|
||||
AddEvent(CPAP_Leak, t, leak, 1); // TODO: should Leak be listed in channel map for TotalLeak and this refer to that?
|
||||
}
|
||||
break;
|
||||
case PRS1LeakEvent::TYPE:
|
||||
LEAK->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1SnoreEvent::TYPE: // snore count that shows up in flags but not waveform
|
||||
// TODO: The numeric snore graph is the right way to present this information,
|
||||
// but it needs to be shifted left 2 minutes, since it's not a starting value
|
||||
// but a past statistic.
|
||||
SNORE->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain); // Snore count
|
||||
if (e->m_value > 0) {
|
||||
// TODO: currently these get drawn on our waveforms, but they probably shouldn't,
|
||||
// since they don't have a precise timestamp. They should continue to be drawn
|
||||
// on the flags overview.
|
||||
VS2->AddEvent(t, 0);
|
||||
VS2 = *channels.at(1);
|
||||
AddEvent(VS2, t, 0, 1);
|
||||
}
|
||||
break;
|
||||
case PRS1VibratorySnoreEvent::TYPE: // real VS marker on waveform
|
||||
// TODO: These don't need to be drawn separately on the flag overview, since
|
||||
// they're presumably included in the overall snore count statistic. They should
|
||||
// continue to be drawn on the waveform, due to their precise timestamp.
|
||||
VS->AddEvent(t, 0);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1RespiratoryRateEvent::TYPE:
|
||||
RR->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1PatientTriggeredBreathsEvent::TYPE:
|
||||
PTB->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1MinuteVentilationEvent::TYPE:
|
||||
MV->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1TidalVolumeEvent::TYPE:
|
||||
TV->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1PressurePulseEvent::TYPE: // Only seen in F5V3, not F5V2 or earlier
|
||||
if (!PP) {
|
||||
if (!(PP = session->AddEventList(CPAP_PressurePulse, EVL_Event))) { return false; }
|
||||
}
|
||||
PP->AddEvent(t, e->m_value);
|
||||
AddEvent(channel, t, e->m_value, e->m_gain);
|
||||
break;
|
||||
case PRS1UnknownDataEvent::TYPE:
|
||||
// These will show up in chunk YAML and any user alerts will be driven
|
||||
@ -1944,6 +1914,30 @@ bool PRS1Import::ImportEventsF5V0123()
|
||||
}
|
||||
|
||||
|
||||
static const QVector<PRS1ParsedEventType> ParsedEventsF5V3 = {
|
||||
PRS1EPAPSetEvent::TYPE,
|
||||
PRS1TimedBreathEvent::TYPE,
|
||||
PRS1IPAPAverageEvent::TYPE,
|
||||
PRS1IPAPLowEvent::TYPE,
|
||||
PRS1IPAPHighEvent::TYPE,
|
||||
PRS1TotalLeakEvent::TYPE,
|
||||
PRS1RespiratoryRateEvent::TYPE,
|
||||
PRS1PatientTriggeredBreathsEvent::TYPE,
|
||||
PRS1MinuteVentilationEvent::TYPE,
|
||||
PRS1TidalVolumeEvent::TYPE,
|
||||
PRS1SnoreEvent::TYPE,
|
||||
PRS1EPAPAverageEvent::TYPE,
|
||||
PRS1LeakEvent::TYPE,
|
||||
PRS1PressurePulseEvent::TYPE,
|
||||
PRS1ObstructiveApneaEvent::TYPE,
|
||||
PRS1ClearAirwayEvent::TYPE,
|
||||
PRS1HypopneaEvent::TYPE,
|
||||
PRS1FlowLimitationEvent::TYPE,
|
||||
PRS1VibratorySnoreEvent::TYPE,
|
||||
PRS1PeriodicBreathingEvent::TYPE,
|
||||
PRS1LargeLeakEvent::TYPE,
|
||||
};
|
||||
|
||||
// Outer loop based on ParseSummaryF5V3 along with hint as to event codes from old ParseEventsF5V3,
|
||||
// except this actually does something with the data.
|
||||
bool PRS1DataChunk::ParseEventsF5V3(void)
|
||||
@ -2103,6 +2097,28 @@ bool PRS1DataChunk::ParseEventsF5V3(void)
|
||||
}
|
||||
|
||||
|
||||
static const QVector<PRS1ParsedEventType> ParsedEventsF5V0 = {
|
||||
PRS1EPAPSetEvent::TYPE,
|
||||
PRS1TimedBreathEvent::TYPE,
|
||||
PRS1ObstructiveApneaEvent::TYPE,
|
||||
PRS1ClearAirwayEvent::TYPE,
|
||||
PRS1HypopneaEvent::TYPE,
|
||||
PRS1FlowLimitationEvent::TYPE,
|
||||
PRS1VibratorySnoreEvent::TYPE,
|
||||
PRS1PeriodicBreathingEvent::TYPE,
|
||||
PRS1LargeLeakEvent::TYPE,
|
||||
PRS1IPAPAverageEvent::TYPE,
|
||||
PRS1IPAPLowEvent::TYPE,
|
||||
PRS1IPAPHighEvent::TYPE,
|
||||
PRS1TotalLeakEvent::TYPE,
|
||||
PRS1RespiratoryRateEvent::TYPE,
|
||||
PRS1PatientTriggeredBreathsEvent::TYPE,
|
||||
PRS1MinuteVentilationEvent::TYPE,
|
||||
PRS1TidalVolumeEvent::TYPE,
|
||||
PRS1SnoreEvent::TYPE,
|
||||
PRS1EPAPAverageEvent::TYPE,
|
||||
};
|
||||
|
||||
// 950P is F5V0
|
||||
bool PRS1DataChunk::ParseEventsF5V0(void)
|
||||
{
|
||||
@ -2246,6 +2262,29 @@ bool PRS1DataChunk::ParseEventsF5V0(void)
|
||||
}
|
||||
|
||||
|
||||
static const QVector<PRS1ParsedEventType> ParsedEventsF5V1 = {
|
||||
PRS1EPAPSetEvent::TYPE,
|
||||
PRS1TimedBreathEvent::TYPE,
|
||||
PRS1ObstructiveApneaEvent::TYPE,
|
||||
PRS1ClearAirwayEvent::TYPE,
|
||||
PRS1HypopneaEvent::TYPE,
|
||||
PRS1FlowLimitationEvent::TYPE,
|
||||
PRS1VibratorySnoreEvent::TYPE,
|
||||
PRS1PeriodicBreathingEvent::TYPE,
|
||||
PRS1LargeLeakEvent::TYPE,
|
||||
PRS1IPAPAverageEvent::TYPE,
|
||||
PRS1IPAPLowEvent::TYPE,
|
||||
PRS1IPAPHighEvent::TYPE,
|
||||
PRS1TotalLeakEvent::TYPE,
|
||||
PRS1RespiratoryRateEvent::TYPE,
|
||||
PRS1PatientTriggeredBreathsEvent::TYPE,
|
||||
PRS1MinuteVentilationEvent::TYPE,
|
||||
PRS1TidalVolumeEvent::TYPE,
|
||||
PRS1SnoreEvent::TYPE,
|
||||
PRS1EPAPAverageEvent::TYPE,
|
||||
PRS1LeakEvent::TYPE,
|
||||
};
|
||||
|
||||
// 960P and 961P are F5V1
|
||||
bool PRS1DataChunk::ParseEventsF5V1(void)
|
||||
{
|
||||
@ -2389,6 +2428,29 @@ bool PRS1DataChunk::ParseEventsF5V1(void)
|
||||
}
|
||||
|
||||
|
||||
static const QVector<PRS1ParsedEventType> ParsedEventsF5V2 = {
|
||||
PRS1EPAPSetEvent::TYPE,
|
||||
PRS1TimedBreathEvent::TYPE,
|
||||
PRS1ObstructiveApneaEvent::TYPE,
|
||||
//PRS1ClearAirwayEvent::TYPE, // not yet seen
|
||||
PRS1HypopneaEvent::TYPE,
|
||||
PRS1FlowLimitationEvent::TYPE,
|
||||
//PRS1VibratorySnoreEvent::TYPE, // not yet seen
|
||||
PRS1PeriodicBreathingEvent::TYPE,
|
||||
//PRS1LargeLeakEvent::TYPE, // not yet seen
|
||||
PRS1IPAPAverageEvent::TYPE,
|
||||
PRS1IPAPLowEvent::TYPE,
|
||||
PRS1IPAPHighEvent::TYPE,
|
||||
PRS1TotalLeakEvent::TYPE,
|
||||
PRS1RespiratoryRateEvent::TYPE,
|
||||
PRS1PatientTriggeredBreathsEvent::TYPE,
|
||||
PRS1MinuteVentilationEvent::TYPE,
|
||||
PRS1TidalVolumeEvent::TYPE,
|
||||
PRS1SnoreEvent::TYPE,
|
||||
PRS1EPAPAverageEvent::TYPE,
|
||||
PRS1LeakEvent::TYPE,
|
||||
};
|
||||
|
||||
// 960T is F5V2
|
||||
bool PRS1DataChunk::ParseEventsF5V2(void)
|
||||
{
|
||||
@ -3117,6 +3179,15 @@ const QVector<PRS1ParsedEventType> & GetSupportedEvents(const PRS1DataChunk* chu
|
||||
case 3: return ParsedEventsF3V3; break;
|
||||
case 6: return ParsedEventsF3V6; break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (chunk->familyVersion) {
|
||||
case 0: return ParsedEventsF5V0; break;
|
||||
case 1: return ParsedEventsF5V1; break;
|
||||
case 2: return ParsedEventsF5V2; break;
|
||||
case 3: return ParsedEventsF5V3; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return none;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user