Skip to content

MRD Model

The Magnetic Resonance Data (MRD) format is a vendor neutral standard for describing data from MR acquisitions and reconstructions.

MRD version 2 and above uses Yardl to generate stream-oriented SDKs implementing the standard. MRD streaming formats are described here.

The Model Definitions below are described using the Yardl language, and can be found in the model/ subdirectory of the MRD repository. Click to expand the full model file in each component section below.

MRD Protocol

The MRD Protocol describes an MRD stream or file, which contains:

  1. The MRD header containing general metadata describing the acquisition, including MR system details and k-space sampling.
  2. A sequence of MRD datatypes that may be one of:
    1. Raw k-space data, stored as individual readout acquisitions.
    2. Image data, stored as sets of 2D or 3D arrays.
    3. Waveforms, storing physiological data such as electrocardiograms, pulse oximetry, or external triggering sources.
    4. Intermediate data, commonly used in MR image reconstruction pipelines.
Click to view MRD Protocol definitions
yml
# Union of all primary types that can be streamed in the MRD Protocol
StreamItem:
  - Acquisition
  - WaveformUint32
  - ImageUint16
  - ImageInt16
  - ImageUint32
  - ImageInt32
  - ImageFloat
  - ImageDouble
  - ImageComplexFloat
  - ImageComplexDouble
  - AcquisitionBucket
  - ReconData
  - ArrayComplexFloat
  - ImageArray


# The MRD Protocol
Mrd: !protocol
  sequence:
    header: Header?
    data: !stream
      items: StreamItem


# Protocol for serializing a noise covariance matrix
MrdNoiseCovariance: !protocol
  sequence:
    noiseCovariance: NoiseCovariance

MRD Header

The MRD Header contains general metadata describing the acquisition, including MR system details and k-space sampling.

The header contains a small set of mandatory parameters common to all MR acquisitions, but is extensible to parameters for specialized acquisitions such as b-values, venc, magnetization preparation durations, etc.

The most critical elements for image reconstruction are contained in the encoding field of the header, which describes the encoded spaced as well as the target reconstructed space. This section allows reconstruction software to determine matrix sizes, oversampling factors, partial Fourier, etc. An experiment can have multiple encoding spaces and it is possible to indicate on each acquired data readout, which encoding space the data belongs to (see the encodingSpaceRef field in MRD Acquisition).

Click to view MRD Header definitions
yml
PatientGender: !enum
    values:
    - m
    - f
    - o

SubjectInformationType: !record
  fields:
    patientName: string?
    patientWeightKg: float?
    patientHeightM: float?
    patientID: string?
    patientBirthdate: date?
    patientGender: PatientGender?

StudyInformationType: !record
  fields:
    studyDate: date?
    studyTime: time?
    studyID: string?
    accessionNumber: long?
    referringPhysicianName: string?
    studyDescription: string?
    studyInstanceUID: string?
    bodyPartExamined: string?

PatientPosition: !enum
    values:
    - hFP
    - hFS
    - hFDR
    - hFDL
    - fFP
    - fFS
    - fFDR
    - fFDL

ThreeDimensionalFloat: !record
  fields:
    x: float
    y: float
    z: float

MeasurementDependencyType: !record
  fields:
    dependencyType: string
    measurementID: string

ReferencedImageSequenceType: !record
  fields:
    referencedSOPInstanceUID: string*

MeasurementInformationType: !record
  fields:
    measurementID: string?
    seriesDate: date?
    seriesTime: time?
    patientPosition: PatientPosition
    relativeTablePosition: ThreeDimensionalFloat?
    initialSeriesNumber: long?
    protocolName: string?
    sequenceName: string?
    seriesDescription: string?
    measurementDependency: MeasurementDependencyType*
    seriesInstanceUIDRoot: string?
    frameOfReferenceUID: string?
    referencedImageSequence: ReferencedImageSequenceType?

CoilLabelType: !record
  fields:
    coilNumber: uint
    coilName: string

AcquisitionSystemInformationType: !record
  fields:
    systemVendor: string?
    systemModel: string?
    systemFieldStrengthT: float?
    relativeReceiverNoiseBandwidth: float?
    receiverChannels: uint?
    coilLabel: CoilLabelType*
    institutionName: string?
    stationName: string?
    deviceID: string?
    deviceSerialNumber: string?

ExperimentalConditionsType: !record
  fields:
    h1resonanceFrequencyHz: long

MatrixSizeType: !record
  fields:
    x: uint
    y: uint
    z: uint

FieldOfViewMm: !record
  fields:
    x: float
    y: float
    z: float

EncodingSpaceType: !record
  fields:
    matrixSize: MatrixSizeType
    fieldOfViewMm: FieldOfViewMm

LimitType: !record
  fields:
    minimum: uint
    maximum: uint
    center: uint

EncodingLimitsType: !record
  fields:
    kspaceEncodingStep0: LimitType?
    kspaceEncodingStep1: LimitType?
    kspaceEncodingStep2: LimitType?
    average: LimitType?
    slice: LimitType?
    contrast: LimitType?
    phase: LimitType?
    repetition: LimitType?
    set: LimitType?
    segment: LimitType?
    user0: LimitType?
    user1: LimitType?
    user2: LimitType?
    user3: LimitType?
    user4: LimitType?
    user5: LimitType?
    user6: LimitType?
    user7: LimitType?

Trajectory: !enum
    values:
    - cartesian
    - epi
    - radial
    - goldenangle
    - spiral
    - other

UserParameterLongType: !record
  fields:
    name: string
    value: long

UserParameterDoubleType: !record
  fields:
    name: string
    value: double

UserParameterStringType: !record
  fields:
    name: string
    value: string

TrajectoryDescriptionType: !record
  fields:
    identifier: string
    userParameterLong: UserParameterLongType*
    userParameterDouble: UserParameterDoubleType*
    userParameterString: UserParameterStringType*
    comment: string?

AccelerationFactorType: !record
  fields:
    kspaceEncodingStep1: uint
    kspaceEncodingStep2: uint

CalibrationMode: !enum
    values:
    - noacceleration
    - embedded
    - interleaved
    - separate
    - external
    - other

InterleavingDimension: !enum
    values:
    - phase
    - repetition
    - contrast
    - average
    - other

MultibandSpacingType: !record
  fields:
    dZ: float*

Calibration: !enum
    values:
    - separable2D
    - full3D
    - other

MultibandType: !record
  fields:
    spacing: MultibandSpacingType*
    deltaKz: float
    multibandFactor: uint
    calibration: Calibration
    calibrationEncoding: uint64

ParallelImagingType: !record
  fields:
    accelerationFactor: AccelerationFactorType
    calibrationMode: CalibrationMode?
    interleavingDimension: InterleavingDimension?
    multiband: MultibandType?

EncodingType: !record
  fields:
    encodedSpace: EncodingSpaceType
    reconSpace: EncodingSpaceType
    encodingLimits: EncodingLimitsType
    trajectory: Trajectory
    trajectoryDescription: TrajectoryDescriptionType?
    parallelImaging: ParallelImagingType?
    echoTrainLength: long?

DiffusionDimension: !enum
    values:
    - average
    - contrast
    - phase
    - repetition
    - set
    - segment
    - user0
    - user1
    - user2
    - user3
    - user4
    - user5
    - user6
    - user7

GradientDirectionType: !record
  fields:
    rl: float
    ap: float
    fh: float

DiffusionType: !record
  fields:
    gradientDirection: GradientDirectionType
    bvalue: float

SequenceParametersType: !record
  fields:
    tR: float*
    tE: float*
    tI: float*
    flipAngleDeg: float*
    sequenceType: string?
    echoSpacing: float*
    diffusionDimension: DiffusionDimension?
    diffusion: DiffusionType*
    diffusionScheme: string?

UserParameterBase64Type: !record
  fields:
    name: string
    value: string

UserParametersType: !record
  fields:
    userParameterLong: UserParameterLongType*
    userParameterDouble: UserParameterDoubleType*
    userParameterString: UserParameterStringType*
    userParameterBase64: UserParameterBase64Type*

WaveformType: !enum
    values:
    - ecg
    - pulse
    - respiratory
    - trigger
    - gradientwaveform
    - other

WaveformInformationType: !record
  fields:
    waveformName: string
    waveformType: WaveformType
    userParameters: UserParametersType

Header: !record
  fields:
    version: long?
    subjectInformation: SubjectInformationType?
    studyInformation: StudyInformationType?
    measurementInformation: MeasurementInformationType?
    acquisitionSystemInformation: AcquisitionSystemInformationType?
    experimentalConditions: ExperimentalConditionsType
    encoding: EncodingType*
    sequenceParameters: SequenceParametersType?
    userParameters: UserParametersType?
    waveformInformation: WaveformInformationType*

MRD Acquisition

Raw k-space data is stored as individual readout Acquisitions. Each readout contains the complex raw data for all channels, a fixed header for metadata including encoding loop counters, and optionally corresponding k-space trajectory information.

Acquisition data is stored as a complex float array with dimensions [coils, samples].

k-space trajectory information is optionally included with each readout as a float array with dimensions [basis, samples].

Click to view MRD Acquisition definitions
yml
AcquisitionFlags: !flags
  base: uint64
  values:
    firstInEncodeStep1: 0x1
    lastInEncodeStep1: 0x2
    firstInEncodeStep2: 0x4
    lastInEncodeStep2: 0x8
    firstInAverage: 0x10
    lastInAverage: 0x20
    firstInSlice: 0x40
    lastInSlice: 0x80
    firstInContrast: 0x100
    lastInContrast: 0x200
    firstInPhase: 0x400
    lastInPhase: 0x800
    firstInRepetition: 0x1000
    lastInRepetition: 0x2000
    firstInSet: 0x4000
    lastInSet: 0x8000
    firstInSegment: 0x10000
    lastInSegment: 0x20000
    isNoiseMeasurement: 0x40000
    isParallelCalibration: 0x80000
    isParallelCalibrationAndImaging: 0x100000
    isReverse: 0x200000
    isNavigationData: 0x400000
    isPhasecorrData: 0x800000
    lastInMeasurement: 0x1000000
    isHpfeedbackData: 0x2000000
    isDummyscanData: 0x4000000
    isRtfeedbackData: 0x8000000
    isSurfacecoilcorrectionscanData: 0x10000000
    isPhaseStabilizationReference: 0x20000000
    isPhaseStabilization: 0x40000000

EncodingCounters: !record
  fields:
    # Phase encoding line
    kspaceEncodeStep1: uint?
    # Partition encoding
    kspaceEncodeStep2: uint?
    # Signal average
    average: uint?
    # Slice number (multi-slice 2D)
    slice: uint?
    # Echo number in multi-echo
    contrast: uint?
    # Cardiac phase
    phase: uint?
    # Counter in repeated/dynamic acquisitions
    repetition: uint?
    # Sets of different preparation, e.g. flow encoding, diffusion weighting
    set: uint?
    # Counter for segmented acquisitions
    segment: uint?
    # User-defined counters
    user: uint*

AcquisitionData: !array
  items: complexfloat
  dimensions:
    coils:
    samples:

TrajectoryData: !array
  items: float
  dimensions:
    basis:
    samples:

AcquisitionHeader: !record
  fields:
    # A bit mask of common attributes applicable to individual acquisition
    flags: AcquisitionFlags
    # Encoding loop counters
    idx: EncodingCounters
    # Unique ID corresponding to the readout
    measurementUid: uint
    # Zero-indexed incrementing counter for readouts
    scanCounter: uint?
    # Clock time stamp (e.g. milliseconds since midnight)
    acquisitionTimeStamp: uint?
    # Time stamps relative to physiological triggering
    physiologyTimeStamp: uint*
    # Channel numbers
    channelOrder: uint*
    # Number of readout samples to be discarded at the beginning
    #   (e.g. if the ADC is active during gradient events)
    discardPre: uint?
    # Number of readout samples to be discarded at the end
    #   (e.g. if the ADC is active during gradient events)
    discardPost: uint?
    # Index of the readout sample corresponing to k-space center (zero indexed)
    centerSample: uint?
    # Indexed reference to the encoding spaces enumerated in the MRD Header
    encodingSpaceRef: uint?
    # Readout bandwidth, as time between samples in microseconds
    sampleTimeUs: float?
    # Center of the excited volume, in LPS coordinates relative to isocenter in millimeters
    position: float[3]
    # Directional cosine of readout/frequency encoding
    readDir: float[3]
    # Directional cosine of phase encoding (2D)
    phaseDir: float[3]
    # Directional cosine of slice normal, i.e. cross-product of read_dir and phase_dir
    sliceDir: float[3]
    # Offset position of the patient table, in LPS coordinates
    patientTablePosition: float[3]
    # User-defined integer parameters
    userInt: int*
    # User-defined float parameters
    userFloat: float*

Acquisition: !record
  fields:
    # Acquisition header
    head: AcquisitionHeader
    # Raw k-space samples array
    data: AcquisitionData
    # Trajectory array
    trajectory: TrajectoryData
  computedFields:
    coils: size(data, "coils")
    samples: size(data, "samples")
    activeChannels: size(head.channelOrder)
    trajectoryDimensions: size(trajectory, "basis")
    trajectorySamples: size(trajectory, "samples")

MRD Image

Image data is stored as either sets of 2D or 3D arrays with a fixed Image header of common properties and metadata. Images can be organized into series of common types and multi-channel data is supported for non-coil-combined images.

Image data is organized as a 4-D array of the chosen image data type with dimensions [channel, z, y, x].

Click to view MRD Image definitions
yml
ImageFlags: !flags
  base: uint64
  values:
    isNavigationData: 0x1
    firstInAverage: 0x10
    lastInAverage: 0x20
    firstInSlice: 0x40
    lastInSlice: 0x80
    firstInContrast: 0x100
    lastInContrast: 0x200
    firstInPhase: 0x400
    lastInPhase: 0x800
    firstInRepetition: 0x1000
    lastInRepetition: 0x2000
    firstInSet: 0x4000
    lastInSet: 0x8000

ImageType: !enum
  values:
    magnitude: 1
    phase: 2
    real: 3
    imag: 4
    complex: 5

ImageData<Y>: !array
  items: Y
  dimensions:
    channel:
    z:
    y:
    x:

ImageHeader: !record
  fields:
    # A bit mask of common attributes applicable to individual images
    flags: ImageFlags
    # Unique ID corresponding to the image
    measurementUid: uint
    # Physical size (in mm) in each of the 3 dimensions in the image
    fieldOfView: float[3]
    # Center of the excited volume, in LPS coordinates relative to isocenter in millimeters
    position: float[3]
    # Directional cosine of readout/frequency encoding
    colDir: float[3]
    # Directional cosine of phase encoding (2D)
    lineDir: float[3]
    # Directional cosine of 3D phase encoding direction
    sliceDir: float[3]
    # Offset position of the patient table, in LPS coordinates
    patientTablePosition: float[3]
    # Signal average
    average: uint?
    # Slice number (multi-slice 2D)
    slice: uint?
    # Echo number in multi-echo
    contrast: uint?
    # Cardiac phase
    phase: uint?
    # Counter in repeated/dynamic acquisitions
    repetition: uint?
    # Sets of different preparation, e.g. flow encoding, diffusion weighting
    set: uint?
    # Clock time stamp (e.g. milliseconds since midnight)
    acquisitionTimeStamp: uint?
    # Time stamps relative to physiological triggering, e.g. ECG, pulse oximetry, respiratory
    physiologyTimeStamp: uint*
    # Interpretation type of the image
    imageType: ImageType
    # Image index number within a series of images, corresponding to DICOM InstanceNumber (0020,0013)
    imageIndex: uint?
    # Series index, used to separate images into different series, corresponding to DICOM SeriesNumber (0020,0011)
    imageSeriesIndex: uint?
    # User-defined int parameters
    userInt: int*
    # User-defined float parameters
    userFloat: float*


ImageMetaValue: [string, long, double]

ImageMeta: string->ImageMetaValue*

Image<T>: !record
  fields:
    # Image header
    head: ImageHeader
    # Image data array
    data: ImageData<T>
    # Meta attributes
    meta: ImageMeta
  computedFields:
    channels: size(data, "channel")
    slices: size(data, "z")
    rows: size(data, "y")
    cols: size(data, "x")

ImageUint16: Image<uint16>
ImageInt16: Image<int16>
ImageUint32: Image<uint>
ImageInt32: Image<int>
ImageFloat: Image<float>
ImageDouble: Image<double>
ImageComplexFloat: Image<complexfloat>
ImageComplexDouble: Image<complexdouble>

# Union of all MRD Image types
AnyImage:
  - ImageUint16
  - ImageInt16
  - ImageUint32
  - ImageInt32
  - ImageFloat
  - ImageDouble
  - ImageComplexFloat
  - ImageComplexDouble

MRD Waveform

Physiological data such as electrocardiograms, pulse oximetry, or external triggering sources are stored as individual waveforms along with a fixed Waveform header for metadata.

The waveformId field in the Waveform record describes the type of physiological data stored. For custom Waveform IDs, corresponding WaveformInformation entries should be added to the MRD header to describe the data interpretation.

Waveform data is streamed as an uint32 array with dimensions [channels, samples].

Click to view MRD Waveform definitions
yml
WaveformSamples<T>: !array
  items: T
  dimensions:
    - channels
    - samples

Waveform<T>: !record
  fields:
    # Bit field of flags. Currently unused
    flags: uint64
    # Unique ID for this measurement
    measurementUid: uint
    # Number of the acquisition after this waveform
    scanCounter: uint
    # Starting timestamp of this waveform
    timeStamp: uint
    # Time between samples in microseconds
    sampleTimeUs: float
    # ID matching the waveform in the MRD header
    waveformId: uint
    # Waveform sample array
    data: WaveformSamples<T>
  computedFields:
    channels: size(data, "channels")
    numberOfSamples: size(data, "samples")


WaveformUint32: Waveform<uint32>

MRD Intermediate Types

MRD includes definitions for intermediate data types commonly used in MR image reconstruction, including Acquisitions "bucketed" by encoding parameters, buffered k-space data, arrays of Images, and dynamic multi-dimensional arrays.

Click to view MRD Intermediate definitions
yml
NoiseCovariance: !record
  fields:
    # Comes from Header.acquisitionSystemInformation.coilLabel
    coilLabels: CoilLabelType*
    # Comes from Header.acquisitionSystemInformation.relativeReceiverNoiseBandwidth
    receiverNoiseBandwidth: float
    # Comes from Acquisition.sampleTimeUs
    noiseDwellTimeUs: float
    # Number of samples used to compute matrix
    sampleCount: size
    # Noise covariance matrix with dimensions [coil, coil]
    matrix: complexfloat[,]

AcquisitionBucket: !record
  fields:
    data: Acquisition*
    ref: Acquisition*
    datastats: EncodingLimitsType*
    refstats: EncodingLimitsType*
    waveforms: WaveformUint32*

# Sampled range along E0, E1, E2 (for asymmetric echo and partial fourier)
SamplingLimits: !record
  fields:
    kspaceEncodingStep0: LimitType
    kspaceEncodingStep1: LimitType
    kspaceEncodingStep2: LimitType

SamplingDescription: !record
  fields:
    encodedFOV: FieldOfViewMm
    reconFOV: FieldOfViewMm
    encodedMatrix: MatrixSizeType
    reconMatrix: MatrixSizeType
    samplingLimits: SamplingLimits

ReconBuffer: !record
  fields:
    # Buffered Acquisition data
    data: complexfloat[loc, s, n, chan, e2, e1, e0]
    # Buffered Trajectory data
    trajectory: float[loc, s, n, e2, e1, basis, samples]
    # Buffered Density weights
    density: float[loc, s, n, e2, e1, e0]?
    # Buffered AcquisitionHeaders
    headers: AcquisitionHeader[loc, s, n, e2, e1]
    # Sampling details for these Acquisitions
    sampling: SamplingDescription

ReconAssembly: !record
  fields:
    data: ReconBuffer
    ref: ReconBuffer?

ReconData: !record
  fields:
    buffers: ReconAssembly*


ImageArray: !record
  fields:
    data: complexfloat[loc, s, n, channel, z, y, x]
    headers: ImageHeader[loc, s, n]
    meta: ImageMeta[loc, s, n]
    waveforms: WaveformUint32*


Array<T>: !array
  items: T

ArrayComplexFloat: Array<complexfloat>