More on FHIR Observations (NEWS2, profiles and ObservationDefinition)

In my last post I proposed a couple of principles:

  • Only use the CareConnect-Observation-1 level 2 profile
  • Use SNOMED codes as much as possible
  • Use https://snomedbrowser.com/, other CareConnect profiles and/or openEHR archetypes to identify codes and units to use (if you have doubts on any codes/units speak to clinical coders). More on this at the end of this post though.

I say principles but at a technical level some of these are constraints. The Care Connect Reference Implementation was implemented using a database structure similar to many primary and acute care EPR’s.

This means the data internally looks like this.

select observation_id, effectivedatetime, code_concept_id, valuequantity, valueunitofmeasure_concept_id, 
c.code, c.display from Observation
join Concept c on c.concept_id = code_concept_id
where patient_id=2 and c.codesystem_id = 9

The Observations don’t know what profile they will be asked to become, it’s a table of codes, values, dates, etc. E.g. for heart rate these entries were created before the heart rate profile was created.

Observation Scores (NEWS2)

Before I start looking into NEWS2 I’ll run through a bit of background using how heart rate is used in cycling (surprise!). When you start to get a little serious about cycling, it’s likely you get a heart rate monitor and a cycling computer the reason for doing this is to start measuring your output. This tells you when you’re doing too much (or too little) and helps prevent the dreaded ‘bonk’ (that is running out of energy, being 20km away from home and unable to turn the pedals - also getting a series of ‘I told you so’ from the other half)

Cycling using a heart rate monitors is based on zones, to calculate these we first need to know your max heart rate. The crude version is to subtract your age from 220, which for me would give a figure above 170 but I’ve done a bit of testing and my actual figure is closer to 182. I’m not going to go into the zone calculations, if you want to velopress do a number of reasonably priced books on the subject (recommend: The Cyclists Training Bible and also Training and Racing with a power meter). However I’ve used the calculation within the strava app. The table below shows my results from the Tour De Yorkshire Sportive

Compare that to a ride from a few years ago when I ‘bonked’ (and had to sit at the side of the road eating to replace my energy so I could get to my car).

You may be able to work out how heart rate zones work, sticking to zone 1 means I can go for hours. Hitting Zone 5 means danger, I can do it for a short amount of time but too much and I’m risking burnout. I find them so useful I have my cycle computer configured to display the zones using it’s coloured LED’s (red - zone 1, amber zone 2, green zone 3, blue zone 4/5)

NEWS2 Heart Rate score has similarities and developer documentation can be found here National Early Warning Score (NEWS)2 | FHIR-NEWS2

From the chart below we can see the heart rate scoring system, a heart rate of 51-90 gives a zero score (which is good). Note this is a general (pragmatic) score, it doesn’t take into max heart rate or the patients resting heart rate. My resting heart rate is around 48-58 and could give me a score of 1.

NEWS2chart

It is a pretty easy system to follow, I covered how a FHIR Heart Observation would look like in a previous post and also Blood Pressure. Similarly for body temperature we can look at the profile and work out the SNOMED code is 276885007 and the units are Cel (celsius) and do similar for SpO2, respiration.

Air/Oxygen (Inspired Oxygen) and Conscious are different, they aren’t codes and a value.

Inspired Oxygen is just a code, no value with the code coming from this valueSet: HL7 UK FHIR Reference Server

Conscious has a code of 1104441000000107 and does have a value but it is a codedValue and this from this this valueSet HL7 UK FHIR Reference Server

To see examples use this url in postman https://data.developer.nhs.uk/ccri-fhir/STU3/Observation?code=1104441000000107

or using a browser use this url FHIR Explorer and then search for code 1104441000000107 note you can change the output format by clicking on the A in the menu bar.

Also note these individual scores can be combined to perform triggers or thresholds.

NEWS2thresholds

So we’ve seen more ways of recording observations but I’ve also followed the principles I mentioned earlier, stuck to the level 2 profile, used SNOMED and tried to stick to standard codes.

If you’ve followed some of the links you may have noticed I was only extracting parts of the NEWS2 profiles, these included:

  • code
  • units
  • valueSet
  • type of Observation

Ok I only briefly mentioned type, most of the Observations we talked about were Quantity observations, the others were CodeableConcepts (I’m not sure if the inspired oxygen is but I’m tempted to think it should be… )

A full list can be found here Valueset-permitted-data-type - FHIR v5.0.0

If you know your FHIR standards you will have noticed I’ve just gone from the current UK FHIR STU3 version to International R4. Part of the reason was to introduce FHIR R4 OperationDefinition

FHIR R4 OperationDefinition

Why have I started talking about R4? If you look at this example:

{
"resourceType": "ObservationDefinition",
"id": "3",
"category": [
    {
        "coding": [
            {
                "system": "http://hl7.org/fhir/observation-category",
                "code": "vital-signs",
                "display": "Vital Signs"
            }
        ]
    }
],
"code": {
    "coding": [
        {
            "system": "http://snomed.info/sct",
            "code": "364075005",
            "display": "Heart rate"
        }
    ]
},
"permittedDataType": [
    "Quantity"
],
"quantitativeDetails": {
    "unit": {
        "coding": [
            {
                "system": "http://unitsofmeasure.org",
                "code": " /min",
                "display": "per minute"
            }
        ]
    }
}
}

It tells us all the key information we need to build a Observation. Does it matter it’s a R4 resource, we would have easily extracted this information into a spreadsheet - so I think not. It’s defining information we need to build a resource and is not intended to be sent anywhere. Similar in some ways to a profile BUT a lot smaller and so easier to follow. Likewise I can build a ObservationDefinition for ACPVU

{
"resourceType": "ObservationDefinition",
"id": "4",
"code": {
    "coding": [
        {
            "system": "http://snomed.info/sct",
            "code": "1104441000000107",
            "display": "ACVPU (Alert Confusion Voice Pain Unresponsive) scale score"
        }
    ]
},
"permittedDataType": [
    "CodeableConcept"
],
"validCodedValueSet": {
    "reference": "https://fhir.hl7.org.uk/STU3/ValueSet/CareConnect-ACVPU-1",
    "display": "Care Connect ACVPU"
}
}

This time I’ve dropped the category section, it wasn’t specified in the profile, type is set as CodeableConcept and the last set of elements state the valueSet to use.

I mentioned some issues with inspired oxygen. I’m thinking this could be profiled wrong or more specifically it could have been done differently. Modifying the ACVPU example, this gives for Inspired Oxygen:

{
"resourceType": "ObservationDefinition",
"id": "5",
"code": {
    "coding": [
        {
            "system": "http://snomed.info/sct",
            "code": "106048009",
            "display": "Respiratory finding"
        }
    ]
},
"permittedDataType": [
    "CodeableConcept"
],
"validCodedValueSet": {
    "reference": "https://fhir.hl7.org.uk/STU3/ValueSet/CareConnect-InspiredOxygen-1",
    "display": "Care Connect Inspired Oxygen"
}
}

The main reason I’m thinking this should be done differently is how do I search for inspired oxygen. The way it has been profiled is to suggest:

https://data.developer.nhs.uk/ccri-fhir/STU3/Observation?code=722742002,371825009

So I would search on all the codes in the valueSet. That’s not going to be practical especially for larger valueSets. The equivalent for ACVPU is

https://data.developer.nhs.uk/ccri-fhir/STU3/Observation?code=1104441000000107

Far more simpler. So the modification I’ve done the code allows search on a singular code, so I search for respiratory finding (also that seems more like a real question) i.e.

https://data.developer.nhs.uk/ccri-fhir/STU3/Observation?code=106048009 (this doesn’t work on the CCRI, the examples follow the published profile).

Note: I’m not sure the code for Patient on oxygen is correct, it seems to be in a different section of SNOMED to Breathing room air (finding) should the code for on oxygen be something like this code Dependence on supplemental oxygen?

I’m not sure what the correct answer is here but I think we need to be careful not to specify patterns for specific use cases. Codes such as heart rate, on oxygen are likely to be reused and this is good.