FHIR to CDISC Joint Mapping Implementation Guide, published by HL7 International - BR&R Work Group. This guide is not an authorized publication; it is the continuous build for version 1.0.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/fhir-cdisc-mapping/ and changes regularly. See the Directory of published versions
Like laboratory results, vital signs are also typically captured in Observations. FHIR actually defines specific profiles for common vital sign measures, significantly increasing the consistency of basic vital signs data. These profiles mandate the declaration of the vital-signs
category. This allows vital signs to be easily separated from other observations.
One consideration to be aware of is that Blood Pressure is typically captured as a single Observation with two components, however it is sometimes captured as two distinct resource instances. When converting, both approaches will need to be accounted for.
Guidance on interpreting the tables can be found here.
CDISC | FHIR map (or gap) | Comment | |||
---|---|---|---|---|---|
Label | CDASH | SDTM | Element | FHIRPath | |
Study Identifier |
STUDYID
Core: HR Type: Char |
STUDYID
Core: Req Type: Char |
ResearchStudy.identifier
0..* Identifier |
ResearchSubject.where(subject=Observation.subject).study.resolve().partOf.resolve().identifier Observation.extension(workflow-researchstudy).valueReference.resolve().partOf.resolve().identifier |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. ResearchStudy links to Patient. Observation links to Patient. If the patients are the same, that establishes the linkage. There's also an extension that allows direct linkage to a 'study' from any resource - if the source system has actually established such a linkage. |
Study Site Identifier |
SITEID
Core: HR Type: Char |
DM.SITEID
Core: Req Type: Char |
ResearchStudy.site
0..* Reference |
ResearchSubject.where(subject=Observation.subject).study.resolve().identifier Observation.extension(workflow-researchstudy).valueReference.resolve().identifier |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Subject Identifier for the Study |
SUBJID
Core: HR Type: Char |
DM.SUBJID
Core: Req Type: Char |
ResearchSubject.identifier
0..* Identifier |
ResearchSubject.where(individual=Observation.subject).identifier |
Study subject is found by finding the StudySubject that corresponds to the same Patient and ResearchStudy as the Observation. No standard way to decide which subject identifier to use |
Visit Name |
VISIT
Core: R/C Type: Char |
VISIT
Core: Perm Type: Char |
Encounter should have a standard instantiatesCanonical extension that would allow pointing to the ActivityDefinition. This would be the ActivityDefinition.name. Submit a change request to add the extension | ||
Visit Date |
VISDAT
Core: R/C Type: Char |
Encounter.period
0..1 Period |
Observation.encounter.resolve().period.start |
Linked via Observation.encounter | |
Vital Signs Performed |
VSPERF
Core: O Type: Char |
VSSTAT
Core: Perm Type: Char |
Observation.status
1..1 code Binding: ObservationStatus required |
Observation.status=('final' or 'cancelled') |
|
Vital Signs Date |
VSDAT
Core: R/C Type: Char |
VSDTC
Core: Exp Type: Char values: ISO 8601 |
Observation.effectiveDateTime
0..1 dateTime |
Observation.effectiveDateTime |
|
Vital Signs Time |
VSTIM
Core: R/C Type: Char |
VSDTC
Core: Exp Type: Char values: ISO 8601 |
Observation.effectiveDateTime
0..1 dateTime |
Observation.effectiveDateTime |
|
Category for Vital Signs |
VSCAT
Core: O Type: Char |
VSCAT
Core: Perm Type: Char |
Observation.category
0..* CodeableConcept Binding: ObservationCategory preferred |
Observation.category |
FHIR allows multiple categorizations at various levels of granularity. Observation.category.coding.system="http://terminology.hl7.org/CodeSystem/observation-category" + Observation.category.coding.code="vital-signs". This combination can be used to extract vital sign data points from EHR system and correctly assign them to the VS domain. |
Subcategory for Vital Signs |
VSSCAT
Core: O Type: Char |
VSSCAT
Core: Perm Type: Char |
Observation.category
0..* CodeableConcept Binding: ObservationCategory preferred |
Observation.category |
FHIR allows multiple categorizations at various levels of granularity. Observation.category.coding.system="http://terminology.hl7.org/CodeSystem/observation-category" + Observation.category.coding.code="vital-signs". This combination can be used to extract vital sign data points from EHR system and correctly assign them to the VS domain. |
Vital Signs Group ID | VSGRPID |
VSGRPID
Core: Perm Type: Char |
This would typically be done by having the related Observations being 'membersOf' a common parent Observation. | ||
Vital Signs Planned Time Point Name |
VSTPT
Core: R/C Type: Char |
VSTPT
Core: Perm Type: Char |
Observation.extension
0..* Extension |
Observation.extension('R5-Observation.instantiatesCanonical').resolve().title |
TimePoints will be represented in FHIR as PlanDefinition.activities. Referencing a PlanDefinition is supported in R5. Can use a standard extension to pre-adopt. |
Vital Signs Completion Status |
VSSTAT
Core: O Type: Char |
VSSTAT
Core: Perm Type: Char |
Observation.status
1..1 code Binding: ObservationStatus required |
Observation.status ServiceRequest.status IN {'cancelled'|'on-hold'|'revoked'| 'entered-in-error'} |
In some instances, VSSTAT="NOT DONE" records will come from FHIR Observation resources where Observation.status="cancelled". This is not an exact match and there could be observations which have been scheduled and did not happen so an observation may not exist. |
ServiceRequest.status
1..1 code Binding: ServiceRequestStatus required |
Observation.status ServiceRequest.status IN {'cancelled'|'on-hold'|'revoked'| 'entered-in-error'} |
||||
VS Result or Finding in Original Units |
VSORRES
Core: HR Type: Char |
VSORRES
Core: Exp Type: Char |
Observation.valueQuantity
0..1 Quantity obs-7 |
Observation.valueQuantity.value |
Ensure the value provided from the EHR is considered an actual value (result), an interpretation or range. |
VS Original Units |
VSORRESU
Core: R/C Type: Char |
VSORRESU
Core: Exp Type: Char |
Observation.valueQuantity
0..1 Quantity obs-7 |
Observation.valueQuantity.unit |
|
Vital Signs Clinical Significance |
VSCLSIG
Core: O Type: Char |
SUPPVS.QVAL |
Observation.interpretation
0..* CodeableConcept Binding: ObservationInterpretation extensible |
Observation.interpretation |
If clinical significance is a boolean, then the mapping is different from the existing http://hl7.org/fhir/ValueSet/observation-interpretation ValueSet. Meaning, the values of "normal", "high", :low", etc. can reside in the --NRIND variable. There are also cases where clinical significant outcome details can exist with corresponding details that don't fit into either of those mentioned buckets. |
Vital Signs Position of Subject |
VSPOS
Core: R/C Type: Char |
VSPOS
Core: Perm Type: Char |
Observation.code
1..1 CodeableConcept Binding: ObservationCode example |
Observation.code |
This is often pre-coordinated into the Observation.code, but can also be expressed in the method |
Observation.method
0..1 CodeableConcept Binding: ObservationMethod example |
Observation.method |
||||
Location of Vital Signs Measurement |
VSLOC
Core: O Type: Char |
VSLOC
Core: Perm Type: Char |
Observation.bodySite
0..1 CodeableConcept Binding: BodySite example |
Observation.bodySite |
Requires knowledge or review of data to ensure location, laterality and directionality are included in the code and can be parsed. |
Vital Signs Laterality |
VSLAT
Core: O Type: Char |
VSLAT
Core: Perm Type: Char |
Observation.bodySite
0..1 CodeableConcept Binding: BodySite example |
Observation.bodySite |
Requires knowledge or review of data to ensure location, laterality and directionality are included in the code and can be parsed. |
Vital Signs Directionality |
VSDIR
Core: O Type: Char |
VSDIR* |
Observation.bodySite
0..1 CodeableConcept Binding: BodySite example |
Observation.bodySite |
Requires knowledge or review of data to ensure location, laterality and directionality are included in the code and can be parsed. |
Vital Signs Test code | VSTESTCD |
VSTESTCD
Core: Req Type: Char |
Observation.code
1..1 CodeableConcept Binding: ObservationCode example |
Observation.code.coding.code |
May use one of the following:coding.display and coding.code (plus coding.system) |
Vital Signs Test Name |
VSTEST
Core: HR Type: Char |
VSTEST
Core: Req Type: Char |
Observation.code
1..1 CodeableConcept Binding: ObservationCode example |
Observation.code.coding.display |
May use one of the following:coding.display and coding.code (plus coding.system) |
Vital Signs Sponsor-Defined Identifier |
VSSPID
Core: O Type: Char |
VSSPID
Core: Perm Type: Char |
Observation.identifier
0..* Identifier |
Observation.identifier.where(assigner=[sponsor organization id]) |
The assigner of the identifier can be explicit or inferred by the Identifier.system. Example: "assigner=sponsor", the value of assigner can either be a simple name using "display" (e.g. "assigner.display=MyPharma" or a reference to an "Organization" |
Vital Signs Repetition Number |
VSREPNUM
Core: O Type: Char |
SUPPVS.QVAL | This could be captured as a specific ActivityDefinition where you'd have a distinct ActivityDefinition for each occurrence. However, it is more likely to be a single ActivityDefinition for the test and an extension would be added on Observation.instantiates to indicate which occurrence is the Observation. |
FHIR map (or gap) | CDISC | Comment | |||
---|---|---|---|---|---|
Label | Element | FHIRPath | CDASH | SDTM | |
Study Identifier |
ResearchStudy.identifier
0..* Identifier |
ResearchSubject.where(subject=Observation.subject).study.resolve().partOf.resolve().identifier Observation.extension(workflow-researchstudy).valueReference.resolve().partOf.resolve().identifier |
STUDYID
Core: HR Type: Char |
STUDYID
Core: Req Type: Char |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. ResearchStudy links to Patient. Observation links to Patient. If the patients are the same, that establishes the linkage. There's also an extension that allows direct linkage to a 'study' from any resource - if the source system has actually established such a linkage. |
Study Site Identifier |
ResearchStudy.site
0..* Reference |
ResearchSubject.where(subject=Observation.subject).study.resolve().identifier Observation.extension(workflow-researchstudy).valueReference.resolve().identifier |
SITEID
Core: HR Type: Char |
DM.SITEID
Core: Req Type: Char |
Mapping is based on presumption that research subject will be tied to site-specific ResearchStudy, which will then be part of overall ResearchStudy. The path using the extension will only exist if the system maintaining the Observation is aware of its relevance to the Study. |
Subject Identifier for the Study |
ResearchSubject.identifier
0..* Identifier |
ResearchSubject.where(individual=Observation.subject).identifier |
SUBJID
Core: HR Type: Char |
DM.SUBJID
Core: Req Type: Char |
Study subject is found by finding the StudySubject that corresponds to the same Patient and ResearchStudy as the Observation. No standard way to decide which subject identifier to use |
Visit Name | Encounter should have a standard instantiatesCanonical extension that would allow pointing to the ActivityDefinition. This would be the ActivityDefinition.name. Submit a change request to add the extension |
VISIT
Core: R/C Type: Char |
VISIT
Core: Perm Type: Char |
||
Visit Date |
Encounter.period
0..1 Period |
Observation.encounter.resolve().period.start |
VISDAT
Core: R/C Type: Char |
Linked via Observation.encounter | |
Vital Signs Performed |
Observation.status
1..1 code Binding: ObservationStatus required |
Observation.status=('final' or 'cancelled') |
VSPERF
Core: O Type: Char |
VSSTAT
Core: Perm Type: Char |
|
Vital Signs Date |
Observation.effectiveDateTime
0..1 dateTime |
Observation.effectiveDateTime |
VSDAT
Core: R/C Type: Char |
VSDTC
Core: Exp Type: Char values: ISO 8601 |
|
Vital Signs Time |
Observation.effectiveDateTime
0..1 dateTime |
Observation.effectiveDateTime |
VSTIM
Core: R/C Type: Char |
VSDTC
Core: Exp Type: Char values: ISO 8601 |
|
Category for Vital Signs |
Observation.category
0..* CodeableConcept Binding: ObservationCategory preferred |
Observation.category |
VSCAT
Core: O Type: Char |
VSCAT
Core: Perm Type: Char |
FHIR allows multiple categorizations at various levels of granularity. Observation.category.coding.system="http://terminology.hl7.org/CodeSystem/observation-category" + Observation.category.coding.code="vital-signs". This combination can be used to extract vital sign data points from EHR system and correctly assign them to the VS domain. |
Subcategory for Vital Signs |
Observation.category
0..* CodeableConcept Binding: ObservationCategory preferred |
Observation.category |
VSSCAT
Core: O Type: Char |
VSSCAT
Core: Perm Type: Char |
FHIR allows multiple categorizations at various levels of granularity. Observation.category.coding.system="http://terminology.hl7.org/CodeSystem/observation-category" + Observation.category.coding.code="vital-signs". This combination can be used to extract vital sign data points from EHR system and correctly assign them to the VS domain. |
Vital Signs Group ID | This would typically be done by having the related Observations being 'membersOf' a common parent Observation. | VSGRPID |
VSGRPID
Core: Perm Type: Char |
||
Vital Signs Planned Time Point Name |
Observation.extension
0..* Extension |
Observation.extension('R5-Observation.instantiatesCanonical').resolve().title |
VSTPT
Core: R/C Type: Char |
VSTPT
Core: Perm Type: Char |
TimePoints will be represented in FHIR as PlanDefinition.activities. Referencing a PlanDefinition is supported in R5. Can use a standard extension to pre-adopt. |
Vital Signs Completion Status |
Observation.status
1..1 code Binding: ObservationStatus required |
Observation.status ServiceRequest.status IN {'cancelled'|'on-hold'|'revoked'| 'entered-in-error'} |
VSSTAT
Core: O Type: Char |
VSSTAT
Core: Perm Type: Char |
In some instances, VSSTAT="NOT DONE" records will come from FHIR Observation resources where Observation.status="cancelled". This is not an exact match and there could be observations which have been scheduled and did not happen so an observation may not exist. |
ServiceRequest.status
1..1 code Binding: ServiceRequestStatus required |
Observation.status ServiceRequest.status IN {'cancelled'|'on-hold'|'revoked'| 'entered-in-error'} |
||||
VS Result or Finding in Original Units |
Observation.valueQuantity
0..1 Quantity obs-7 |
Observation.valueQuantity.value |
VSORRES
Core: HR Type: Char |
VSORRES
Core: Exp Type: Char |
Ensure the value provided from the EHR is considered an actual value (result), an interpretation or range. |
VS Original Units |
Observation.valueQuantity
0..1 Quantity obs-7 |
Observation.valueQuantity.unit |
VSORRESU
Core: R/C Type: Char |
VSORRESU
Core: Exp Type: Char |
|
Vital Signs Clinical Significance |
Observation.interpretation
0..* CodeableConcept Binding: ObservationInterpretation extensible |
Observation.interpretation |
VSCLSIG
Core: O Type: Char |
SUPPVS.QVAL | If clinical significance is a boolean, then the mapping is different from the existing http://hl7.org/fhir/ValueSet/observation-interpretation ValueSet. Meaning, the values of "normal", "high", :low", etc. can reside in the --NRIND variable. There are also cases where clinical significant outcome details can exist with corresponding details that don't fit into either of those mentioned buckets. |
Vital Signs Position of Subject |
Observation.code
1..1 CodeableConcept Binding: ObservationCode example |
Observation.code |
VSPOS
Core: R/C Type: Char |
VSPOS
Core: Perm Type: Char |
This is often pre-coordinated into the Observation.code, but can also be expressed in the method |
Observation.method
0..1 CodeableConcept Binding: ObservationMethod example |
Observation.method |
||||
Location of Vital Signs Measurement |
Observation.bodySite
0..1 CodeableConcept Binding: BodySite example |
Observation.bodySite |
VSLOC
Core: O Type: Char |
VSLOC
Core: Perm Type: Char |
Requires knowledge or review of data to ensure location, laterality and directionality are included in the code and can be parsed. |
Vital Signs Laterality |
Observation.bodySite
0..1 CodeableConcept Binding: BodySite example |
Observation.bodySite |
VSLAT
Core: O Type: Char |
VSLAT
Core: Perm Type: Char |
Requires knowledge or review of data to ensure location, laterality and directionality are included in the code and can be parsed. |
Vital Signs Directionality |
Observation.bodySite
0..1 CodeableConcept Binding: BodySite example |
Observation.bodySite |
VSDIR
Core: O Type: Char |
VSDIR* | Requires knowledge or review of data to ensure location, laterality and directionality are included in the code and can be parsed. |
Vital Signs Test code |
Observation.code
1..1 CodeableConcept Binding: ObservationCode example |
Observation.code.coding.code |
VSTESTCD |
VSTESTCD
Core: Req Type: Char |
May use one of the following:coding.display and coding.code (plus coding.system) |
Vital Signs Test Name |
Observation.code
1..1 CodeableConcept Binding: ObservationCode example |
Observation.code.coding.display |
VSTEST
Core: HR Type: Char |
VSTEST
Core: Req Type: Char |
May use one of the following:coding.display and coding.code (plus coding.system) |
Vital Signs Sponsor-Defined Identifier |
Observation.identifier
0..* Identifier |
Observation.identifier.where(assigner=[sponsor organization id]) |
VSSPID
Core: O Type: Char |
VSSPID
Core: Perm Type: Char |
The assigner of the identifier can be explicit or inferred by the Identifier.system. Example: "assigner=sponsor", the value of assigner can either be a simple name using "display" (e.g. "assigner.display=MyPharma" or a reference to an "Organization" |
Vital Signs Repetition Number | This could be captured as a specific ActivityDefinition where you'd have a distinct ActivityDefinition for each occurrence. However, it is more likely to be a single ActivityDefinition for the test and an extension would be added on Observation.instantiates to indicate which occurrence is the Observation. |
VSREPNUM
Core: O Type: Char |
SUPPVS.QVAL |