KSFoundation  [April-2021]
A platform for simpler EPIC programming on GE MR systems
Phase encoding plans (KS_PHASEENCODING_PLAN)


ksgre.e, ksfse.e and ksepi.e now have basic support for 2D and 3D (3D/4D if we count multiphase). To keep the scan loop structure fixed regardless of 2D/3D or e.g. random undersampling (Compressed Sensing), a new KS_PHASEENCODING_PLAN is now used to control the looping structure. All top-level sequence structures (KSGRE_SEQUENCE, KSFSE_SEQUENCE, KSEPI_SEQUENCE) now holds one (or more) KS_PHASEENCODING_PLAN.
Moreover, the KS_PHASEENCODING_PLAN is now also used to generate on-HOST psd plots in the new HTML format, where now also the k-space trajectory can be visualized. See the new Plotting section for more details.

How the scan loop is organized

Here is how e.g. ksgre.e's scan loop structure looks like (similar for ksfse.e and ksepi.e):

ksgre_scan_scanloop() // Data for the entire scan
ksgre_scan_acqloop() // All data for one set of slices that fit within one TR (one acquisition)
ksgre_scan_sliceloop() // One set of slices that fit within one TR played out for one shot
ksgre_scan_coreslice() // One slice playout, with optional other sequence modules
ksgre_scan_seqstate() // Update gradient amplitudes and RF/receive freq/phase

New is that there is a single shot-loop in ksgre_scan_acqloop(), where the shot counter spans all ky-kz shots in the 3D case. The number of shots is determined by KS_PHASEENCODING_PLAN, which has been set up by one of ks_phaseencoding_generate_simple(), ks_phaseencoding_generate_simple_ellipse(), ks_phaseencoding_generate_2Dfse(), or ks_phaseencoding_generate_epi() for now...or by your own. Note that the ks_phaseencoding_generate_*** functions must be called in (ksgre_pg()) so it is executed both on HOST and TGT.

Workflow: Setup KS_PHASER first, then pass it/them to a ks_phaseencoding_generate*** function

Setup KS_PHASER first, then pass them to a ks_phaseencoding_generate*** function to build a KS_PHASEENCODING_PLAN. For 2D, there is only one phase encoding (ksgre.phaseenc), but for 3D we have two: ksgre.phaseenc and ksgre.zphaseenc. These are set up in ksgre_eval_setupobjects() as before, but are not used in the scan loop directly anymore. Each KS_PHASER contains the .linetoacq[] field determining the span in ky and kz. But, within this 1D (ky) or 2D span (ky-kz), an appropriate ks_phaseencoding_generate*** function creates a phase encoding plan, with arbitrary encoding within the span (but guided by acceleration .R etc from KS_PHASER). This allows also 3D FSE sequences to collect any ky-kz point in any order, if the plan is set up correctly, without any need to modify the scan loop further. Also, it is possible to use multiple KS_PHASEENCODING_PLANs to vary the k-space sampling between e.g. volumes.

Summary (3D ksgre case)

In ksgre_setupobjects() (and similarly for the other psds):

ksgre.phaseenc.fov = opfov;
ksgre.zphaseenc.fov = opslquant * opslthick;
ksgre.zphaseenc.res = opslquant;

In ksgre_pg() (run on both HOST and TGT):

/* KS_3D_SELECTED is a C-macro in KSFoundation.h that checks for 3D menu being selected in the UI.
Since ksgre.e does not have multiple echoes that change phase encoding from echo to echo, ks_phaseencoding_generate_simple()
is sufficient.
ks_phaseencoding_generate_simple(&ksgre.phaseenc_plan, "ksgreplan", &ksgre.phaseenc, (KS_3D_SELECTED) ? &ksgre.zphaseenc : NULL);

Please contribute to new KS_PHASEENCODING_PLANs

The following cases would be good to create a ks_phaseencoding_generate_*** function for in the future:

  1. T2-CUBE, to allow ksfse.e to run as GE's 3D CUBE FSE sequence
  2. Compressed Sensing with single-echo (ksgre.e), based on ks_phaseencoding_generate_simple()
  3. Compressed Sensing for FSE trains, subsampling a T2-CUBE k-space
  4. 4D: T1/T2-shuffling or T2-shuffling using one KS_PHASEENCODING_PLAN per volume.
  5. Your own!