Consolidating EPI echo spacing and readout time for Philips scanner

Dear All,

I know that this has been previously discussed on various forums . However, I have noticed some discrepancy in the way EPI echo spacing and readout time are being calculated, specifically for Philips scanner. I will first attempt to summarize various methods that I have found and then through two cases show the discrepancies. I hope that this thread can be used for resolving these. The readout time is an important value that is required for “unwarping” using fieldmap; it is additionally used in diffusion tools like topup etc.

Abbreviations used
WFS: water-fat shift (per pixel)
ETL: echo train length


Calculating effective echo spacing (formulae edited for consistent abbreviations)

a) Using OSF formula [1]

effective echo spacing = (((1000 * WFS)/(434.215 * (ETL+1))/acceleration)

b) Using BrainVoyager formula [2]

echo spacing in msec = 1000 * (WFS/(water-fat shift (in Hz) * ETL))

where
ETL = EPI factor + 1
water-fat-shift (Hz) = fieldstrength (T) * water-fat difference (ppm) * resonance frequency (MHz/T)
water-fat difference (ppm) = 3.35 [2]
resonance frequency (MHz/T) = 42.576
effective echo spacing = echo spacing/acceleration

=> effective echo spacing = (1000*(WFS/427.888*ETL))/acceleration


Calculating total readout time (formulae edited for unit preservation and consistency)

a) Using FSL forum post [3]

total readout time = echo spacing * (EPI factor - 1)

b) Using topup FAQ formula [4]

total readout time = echo spacing * EPI factor

c) Using BIDS specification [5]

total readout time = effective echo spacing * (ReconMatrixPE - 1)

I am assuming that folks have interchangeably used echo spacing and effective echo spacing in the three formulae here.


Case1: sparse acquisition
Acquisition parameters (from ExamCard (console)):
EPI factor = 45
Act. WFS (pix) / BW (Hz) = 8.881 / 48.9
BW in EPI freq. dir. (Hz) = 3133.3
Min. WFS (pix) / Max. BW (Hz) = 8.859 / 49.0
Reconstruction matrix = 64
SENSE P reduction (AP) = 1.45000005
MB SENSE = no
Act. TR/TE (ms) = 4000 / 30
Min. TR/TE (ms) = 2053 / 12

Substituting above values into the formulae

effective echo spacing
a) OSF Method: = 0.3066
b) BrainVoyager Method: 0.3112 (echo spacing is 0.4512)

Using the BrainVoyager calculated value for readout calculation

a) Forum post formula: 13.6928
b) Topup FAQ formula: 14.0040
c) BIDS formula: 19.6056


Case2: regular acquisition
Acquisition parameters (from ExamCard (console)):
EPI factor = 45
Act. WFS (pix) / BW (Hz) = 8.885 / 48.9
BW in EPI freq. dir. (Hz) = 3131.4
Min. WFS (pix) / Max. BW (Hz) = 8.863 / 49.0
Reconstruction matrix = 64
SENSE P reduction (AP) = 1.45000005
MB SENSE = no
Act. TR/TE (ms) = 3000 / 30
Min. TR/TE (ms) = 2461 / 12

Substituting above values into the formulae

effective echo spacing
a) OSF Method: = 0.3068
b) BrainVoyager Method: 0.3113 (echo spacing is 0.4514)

Using the BrainVoyager calculated value for readout calculation

a) Forum post formula: 13.6972
b) Topup FAQ formula: 14.0085
c) BIDS formula: 19.6119


Questions:

  1. There is discrepancy in the definition of echo train length: dcm2niix reports theEPI factor as the echo train length in the JSON file while BrainVoyager mentions ETL = EPI factor + 1. The OSF document mentions that ETL=EPI factor

  2. The two formulae for calculating effective echo spacing are almost identical except for the constant term: OSF/Spinoza centre uses 434.215 while the calculation via BrainVoyager results in 427.888. How should we resolve this difference?

  3. Which method should be used for calculating total readout time?


Look forward to getting some advise on these. Of course, if there is an error in my interpretation, please feel free to point that out. Thank you


References
[1] Document on OSF: https://osf.io/hks7x/
[2] The BrainVoyager guide: https://support.brainvoyager.com/brainvoyager/functional-analysis-preparation/29-pre-processing/78-epi-distortion-correction-echo-spacing-and-bandwidth
[3] FSL forum post: https://www.jiscmail.ac.uk/cgi-bin/webadmin?A2=ind1308&L=FSL&D=0&P=112807
[4] FSL topup FAQ: https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/topup/Faq#How_do_I_know_what_phase-encode_vectors_to_put_into_my_--datain_text_file.3F

References (contd.)
[5] BIDS specification: https://bids-specification.readthedocs.io/en/latest/04-modality-specific-files/01-magnetic-resonance-imaging-data.html
[6] Spinoza Centre link: https://web.archive.org/web/20130420035502/www.spinozacentre.nl/wiki/index.php/NeuroWiki:Current_developments

I realize that if your readout time is identical for all acquisitions you don’t necessarily have to specify a valid value in this column (you can e.g. just set it to 1). But it would be nice to populate this BIDS field. However, it would be convenient for dcm2niix report some value, even if it is relative. I am ready to generate a new stable release of dcm2niix, and this is the last unresolved issue. One option is to just report base values (WFS, SENSE factor, WFS) in the BIDS header and let the user calculate effective readout time. However, if someone can provide good guidance on the preferred formula, I would be happy to use it.

Hi @Chris_Rorden,

I ran into this same issue when I was trying to write a BIDS conversion module for PAR REC and Philips DICOM files. I was not exactly sure how to approach this issue as well. I found about 4 different ways of calculating the effective echo spacing and total readout time. So far, the formulas that use WFS require PAR headers (as the WFS is a private tag in the Philips DICOM header).

Most of this is just summed up in a function here (https://github.com/AdebayoBraimah/convert_source/blob/master/convert_source/utils.py#L45) under calc_read_time(file, json_file="")

Best,

@AdebayoBraimah the upcoming release of dcm2niix will populate BIDS tags WaterFatShift (2001,1022) EchoTrainLength (0018,0091 or 2001,1013+1), ParallelReductionFactorInPlane (0018,9069), AcquisitionMatrixPE (0018,9231) MagneticFieldStrength (0018, 0087). This should allow the user to derive PartialFourier, EffectiveEchoSpacing and TotalReadoutTime. Since I am unsure of the preferred formula, and have no validation datasets, I will not generate those tags.

Are you convinced that your Python code generates the desired values when partial Fourier, pixel interpolation, phase oversampling and SENSE are applied? Do you have a validation dataset similar to Siemens? If not, can you acquire one? It would be nice to compute this reliably and automatically for users, but I am not sure if any of these solutions are robust. I am not criticizing your work, just want to have a solution that works for all scenarios.

  • This topic is related to sdcflows issue 5
  • Echoing @drmclem, I would discourage the use of Philips PAR/REC and stick with DICOM. As noted, it was designed for simpler times, and there are known issues with some implementations that can not be resolved. I would not consider it archival quality.

@Chris_Rorden that’s excellent news about the upcoming release. Additionally, no worries and I understand.

Are you convinced that your Python code generates the desired values when partial Fourier, pixel interpolation, phase oversampling and SENSE are applied?

In the case when SENSE is applied - yes. However, in the other scenarios in which partial Fourier, pixel interpolation, and/or phase oversampling is applied - I do not know, as these values are not explicitly used in the calculation of the EffectiveEchoSpacing.

Do you have a validation dataset similar to Siemens? If not, can you acquire one?

No, I do not unfortunately. As far as acquiring a validation dataset - I will need to check and get back to you on that. Is there any documentation that I can refer to for acquiring a validation dataset?

@Chris_Rorden very happy to hear about the upcoming release! I will check and see if I can generate some validation data that would be useful for working out these information reliably. Which factors would you like to see varied systematically in the validation data? I am guessing SENSE factor, with and without partial Fourier, and with and without phase oversampling should be enough, but please let me know if you would like to see any other factors being varied too. As a side note, the actual WFS (px) field can be retrieved from the Private DICOM tag (2001,1022) but I have not checked whether the information is present in all cases.

@parekhpravesh this would be a great help to the community to resolve this once and for all. Please see the Excel worksheet included with the Siemens validation data. The ideal validation datasets are low resolution (as we want to share these and process them with each new software commit to detect regressions). So a 64x64 matrix EPI scan with a few slices. As you can see by reviewing @mharms Siemens Excel spreadsheet, he modulated the following parameters:

  • Partial Fourier
  • Interpolation
  • In plane acceleration (SENSE)
  • Phase resolution
  • Phase oversampling

Hello. Quick update: I have setup the protocol for acquiring validation set. Hope to acquire them on Wednesday. I will share these asap. Thanks!

Terrific. I will hold off on a new dcm2niix release until we get these.

Also, it would be great if this was a dataset we can share publicly like dcm_qa. This means you should scan a phantom or a scientist who does not mind having their image shared. This will allow us to regression test each build of dcm2niix to ensure good results. It will also allow developers of alternative converters to leverage your dataset.

@AdebayoBraimah I would appreciate any comments you have on the Excel spreadsheet provided with issue 377. My goal is that future versions of dcm2niix will populate the TotalReadOutTime field in the BIDS file without requiring scripts like yours. However, your Python script is still useful for legacy datasets. Looking at your formula, it seems to assume a 3T MRI and images without interpolation or SENSE. Assuming your BIDS json files were acquired with previous versions of my software, you could use ImagingFrequency to determine field strength and ReconMatrixPE to determine reconstructed pixel dimensions in the phase encoding direction.

@Chris_Rorden thanks! I agree that having dcm2niix populate the TotalReadOutTime field would be convenient for all end users.

Additionally, I plan to implement the formula you used to calculate the TotalReadOutTime in the Excel spreadsheet for legacy datasets within my python script moving forward.

Thanks @Chris_Rorden and @parekhpravesh for making so much headway on this issue.

1 Like

@AdebayoBraimah and any other Phillips users interested in this topic: @parekhpravesh and Paul Morgan have kindly provided open source validation datasets. I have created a Open Science Framework resource named Calculating TotalReadoutTime for Philips MRI that includes the DICOM datasets, Python scripts, generated field maps (in Hz) and a brief overview of the problem.

Based on this, my current working hypothesis is that a robust formula is:

EffectiveEchoSpacing = WaterFatShift/(ImagingFrequency*(EPI_Factor+1)*3.4))
TotalReadOutTime = EffectiveEchoSpacing * (ReconMatrixPE - 1)
WaterFatShift = (2001,1022)
ImagingFrequency = (0018,0084)
EPI_Factor =  (2001,1013)
ReconMatrixPE = Reconstructed Matrix Pixels in Phase Encoding Direction 

However, I would be grateful if others could either validate my formula or describe a better formula.

1 Like

Here is a link for those who are not members of OSF Institutions

1 Like

Hi,

many thanks for looking into and posting on this! Is this still the most reasonable formula in your opinion or any new input that have changed it?

Se dcm2niix issue 377 for my current understanding of the issue.

Hi Dr.@Chris_Rorden, in issue 377 you discussed the possibility of using bogus/estimated values for EffectiveEchoSpacing and TotalReadoutTime. I’ve run some par/recs through the latest version dcm2niix but don’t see these values. Did you ever decide to include them in BIDS jsons? I would calculate myself by hand, but can’t find a few of the DICOM values (e.g. imaging frequency) in the .pars.
Many thanks.

See also dcm2niix issue 431. This value usually does not matter, you can usually estimate it if you make a few assumptions about your data. With dcm2niix, I do not like to make assumptions, so I do not populate this tag.

1 Like

Thanks. For now I’ve just put a value of 1 for TotalReadoutTime on the fieldmaps.