Stream: implementers
Topic: Apple Watch ECGs and FHIR
Yannick Börner (Jan 24 2020 at 09:48):
I'm currently converting the ECG data provided by the Apple Watch into a FHIR Observation using Swift on iOS. Has anyone defined a proper structure for ECG observations made by the Apple Watch yet? I feel like the example given in the FHIR documentation (https://www.hl7.org/fhir/observation-example-sample-data.html) is not suitable.
Lloyd McKenzie (Jan 24 2020 at 12:54):
Can you expand on what you find unsuitable?
Pascal Pfiffner (Jan 24 2020 at 16:29):
Also, see here for a discussion around EKG (in PDF form): https://chat.fhir.org/#narrow/stream/179166-implementers/topic/PDF.20instance.20of.20Observation
Yannick Börner (Jan 25 2020 at 12:56):
@Lloyd McKenzie Yes, absolutely! The device used in the example has three components for instance, whereas the Apple Watch has only one component. In addition, I could not find a code for the Apple Watch (any input is greatly appreciated here).
Looking at the values themselves, the example provides variables such as 'system', 'code null', 'period' and 'factor'. My expertise with regards to medical devices is very limited to non-existent, so I don't really know if these variables are needed in the first place and if they are needed, how to substitute them coming from an Apple Watch.
I attached a CSV from an ECG made by the Apple Watch, hopefully that'll help understanding my troubles. ecg_2019-12-18_1.csv
My plan was to include the following information under device --> component --> value:
- Sample Rate
- Unit
- Every data point in the CSV's left column (Without time stamps)
Do you see any issues going forward like this?
Thank you for your reply!
Lloyd McKenzie (Jan 25 2020 at 17:31):
If you only have 1 lead, you'd only convey the data for one lead. The notion of "Apple Watch" would be conveyed as a device manufacturer and a device model number (presume the different apple watches have one of these, though I don't know off the top of my head what they would be). It may be that you can just convert Watch4,1 into that (there's a slot on Device to capture the software version too)
Within FHIR, whenever you have a code, you also need a system. The code '1' could mean all sorts of different things - in one code system it mean "yes", in another it might mean "diabetes" or "not applicable". So in FHIR we always identify the code system so that the combination of code + system is globally unique. Ideally, we try to use 'standard' code systems such as LOINC, SNOMED, one of the IEEE code systems, etc. I believe this example uses one of the latter. It's not clear from the spreadsheet what your origin value is. It might be 0 or it might be something else. (I'm not a clinical expert, so I can't say what's reasonable.)
In terms of there not being a unit code or system for the origin, that's actually something that's an issue with the example. It should have been specified, though it's not technically mandatory. For the first lead, we know that the origin is 2048. But we don't know 2048 "what". It's possible that the units can be inferred from the code for the observation - i.e. all components with code '131329' from code system 'urn:oid:2.16.840.1.113883.6.24' are always known to be millivolts. However, stating it explicitly is good practice. Feel free to submit a change request by clicking on the "propose a change" link at the bottom of any page in the spec. You'll need to register your first time. (That's free, but it may take a couple of days because we have a real human review your registration request to make sure you're not signing up to hawk Viagra or timeshares or something :>) In your case, it looks like the code should be "uV" and the system to be "http://units-of-measure.org" (which is a widely used code system for units that happens to have a code for micro-volts).
Period is the amount of time between samples in milliseconds. You can calculate that from the frequency. So 68 Hz would be one sample every 147ms
Factor allows for situations where the measured values aren't expressible as quantized integers. It looks like that's not an issue for your data so you can ignore it.
It looks like you've got values for two leads, even though it only says you've got 1. I don't know what the meaning is for the two columns, but presumably you'll want to have a component for each.
Yannick Börner (Jan 26 2020 at 14:09):
Thank you so much for the input! This definitely clears up a lot of things. I'll look into everything tomorrow and then get back to you.
Jose Costa Teixeira (Jan 26 2020 at 14:43):
My plan was to include the following information under device --> component --> value:
- Sample Rate
- Unit
- Every data point in the CSV's left column (Without time stamps)
Do you see any issues going forward like this?
I presume you mean observation.component.value,
not "device.component.value"
right?
Yannick Börner (Jan 27 2020 at 14:19):
@Jose Costa Teixeira Yes, you are absolutely right. I'll follow up with my results as soon as I am done.
Yannick Börner (Jan 31 2020 at 12:09):
@Jose Costa Teixeira @Lloyd McKenzie
First of all, thank you both for replying and helping me navigate this. I'm very grateful for your insights and really appreciate you doing this. This is what I came up with:
I created a JSON template for an ECG observation made on the Apple Watch. The template is loaded within my app and the corresponding data is filled into it programmatically. I attached the template as well as two printouts of an observation with data. Feel free to look it over and critique, though I don't want to hog your time.
My next steps are the following:
- Submit a new LOINC Code for ECG observations made on the Apple Watch
- Add the sample rate programmatically
- Submit @Lloyd McKenzie 's proposed change request for the ekg example
I hope other people can benefit from this then.
ECG-Observation-Apple-Watch-JSON-Template.rtf ECG-Observation-JSON-print.rtf ECG-Observation-Console-print.rtf
Lloyd McKenzie (Jan 31 2020 at 22:32):
"note" has a type of Annotation - which doesn't have an element called "symptoms". (Symptoms would typicallly be captured as additional Observations - which you could link to your ECG Observation. You might also use the workflow-reasonCode extension if the reason for capturing the 'symptoms' is a reason for the EKG. (Not sure what the meaning is for capturing they symptoms with the watch?)
code and display values are still strings - and must be delimited by quotes
The structure of the valueSampledData is incorrect. The actual data should be sent in 'data', not 'origin'.
You can't have empty strings for any element
Don't use 'display' for anything you expect to be computable - e.g. patient identity
Lloyd McKenzie (Jan 31 2020 at 22:34):
interpretation doesn't have an element called classification
status should be delimited by quotes
In general, try validating your instances against one of the test servers to make sure your JSON instance is legal
Yannick Börner (Feb 06 2020 at 13:33):
@Lloyd McKenzie Thank you so much yet again. I was busy writing a paper the past couple of days but I'll proceed with the implementation today.
To answer your question: After finishing an ECG on the Apple Watch you can manually add symptoms. They are not checked against anything and are written freely by the user. That's basically the reason why I opted to include them in 'notes' as they are nothing more than that. Great suggestion with the extension! I'll have a look into that tomorrow.
Lloyd McKenzie (Feb 06 2020 at 18:26):
The proper way would probably be to use Observation.component
Yannick Börner (Feb 07 2020 at 09:32):
Excellent, will do so!
Last updated: Apr 12 2022 at 19:14 UTC