KSFoundation  [October2024]
A platform for structured EPIC programming on GE MR systems
KSFoundation_common.c File Reference

Data Structures

struct  _phaseencoding_coord_pool_s
 

Macros

#define ABORT_ON_KSERROR   0
 
#define _INIT_PHASEENCODING_COORD_POOL   {0, 0, NULL, 0, 0};
 
#define PHASEENCODING_PLAN_FILENAME   "ks_phaseencodingtable.host.txt"
 

Functions

STATUS acqq_longdab (WF_PULSE_ADDR pulse, LONG pos_ref, LONG dab_ref, LONG xtr_ref, LONG fslot_value)
 
int isNaN (float a)
 
STATUS ks_error (const char *format,...)
 
void ks_dbg_reset ()
 
STATUS ks_dbg (const char *format,...)
 
STATUS existfile (const char *fname)
 
int ks_syslimits_hasICEhardware ()
 
float ks_syslimits_ampmax_phys ()
 
float ks_syslimits_ampmax (LOG_GRAD loggrd)
 
float ks_syslimits_ampmax2 (LOG_GRAD loggrd)
 
float ks_syslimits_ampmax1 (LOG_GRAD loggrd)
 
float ks_syslimits_ampmax1p (LOG_GRAD loggrd)
 
float ks_syslimits_gradtarget (LOG_GRAD loggrd, int board)
 
int ks_syslimits_ramptimemax (LOG_GRAD loggrd)
 
int ks_syslimits_ramptimemax_phys ()
 
float ks_syslimits_slewrate_phys ()
 
float ks_syslimits_slewrate (LOG_GRAD loggrd)
 
float ks_syslimits_slewrate2 (LOG_GRAD loggrd)
 
float ks_syslimits_slewrate1 (LOG_GRAD loggrd)
 
float ks_syslimits_slewrate1p (LOG_GRAD loggrd)
 
unsigned short ks_cycles_to_iphase (double cycles)
 
unsigned short ks_degrees_to_iphase (double degrees)
 
unsigned short ks_radians_to_iphase (double radians)
 
void ks_polyder (const double *coeffs, const int order, double *der_coeffs)
 
void ks_polyval (const double *coeffs, const int order, const double *x, const int numx, double *values)
 
void ks_polyval_f (const double *coeffs, const int order, const float *x, const int numx, float *values)
 
double ks_Newtons_method (const double *coeffs, const int order, const double x0, const int num_iter)
 
float ks_calc_selgradamp (float rfbw, float slthick)
 
float ks_calc_minfov (float ampmax, int tsp)
 
float ks_calc_minslthick (float bw)
 
int ks_calc_mintsp (float ampmax, float fov)
 
float ks_calc_fov2gradareapixel (float fov)
 
void ks_init_dynamic (KS_DYNAMIC_STATE *dynamic)
 
float ks_calc_caipi_scale (const int ky, const int R, const int caipi_factor)
 
float ks_calc_caipi_phase (const float sms_slice_gap, const int sms_multiband_factor, const SCAN_INFO *slice_info, const float caipi_blip_area, const int slice_encode_dir)
 
float ks_calc_caipi_offset_phase (const float sms_slice_gap, const int sms_multiband_factor, const SCAN_INFO *slice_info, const int caipi_factor, const float caipi_blip_area, const int ky, const int R, const int slice_encode_dir)
 
STATUS ks_phaseencoding_memorypool_init (KS_PHASEENCODING_COORD *entries, uint64_t size)
 
KS_PHASEENCODING_COORD ks_phaseencoding_get (const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int encode, int shot)
 
KS_PHASEENCODING_SHOTCOORDS ks_phaseencoding_get_shot (const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int shot)
 
void ks_phaseencoding_set (KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int encode, int shot, int ky, int kz)
 
void ks_create_suffixed_description (char *const out, const char *const prefix, const char *const suffix,...)
 
void ks_phaseencoding_print (const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr)
 
STATUS ks_phaseencoding_alloc (KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int etl, int num_shots)
 
int ks_phaseencoding_isvalid (const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr)
 
STATUS ks_fse_calcecho (double *bestecho, double *optecho, int *nacqlines_to_kspacecenter, const KS_PHASER *const pe, KS_PF_EARLYLATE pf_direction, int TE, int etl, int esp)
 
STATUS ks_phaseencoding_generate_simple (KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, const char *const desc, KS_PHASER *phaser, KS_PHASER *zphaser, int encodes_per_shot)
 
STATUS ks_phaseencoding_generate_simple_ellipse (KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, const char *const desc, KS_PHASER *phaser, KS_PHASER *zphaser)
 
STATUS ks_phaseencoding_generate_epi (KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, const char *const desc, const KS_EPI *epitrain, const ks_enum_epiblipsign blipsign, const KS_PF_EARLYLATE pf_direction, const int numileavestoacq, ks_enum_sweep_order sweep_order, int numsegments, const int caipi_delta)
 
void ks_wave_compute_params (KS_WAVE *const wave)
 
int ks_wave_res (const KS_WAVE *wave)
 
int ks_echotrain_get_max_kspace_index (KS_ECHOTRAIN *echotrain)
 
STATUS ks_pg_echotrain_readout (KS_ECHOTRAIN *echotrain, int readout_index, int echo_time, KS_ECHOTRAIN_READOUT_TIMING *timing, KS_SEQ_CONTROL *ctrl)
 
float ks_waveform_max (const KS_WAVEFORM waveform, int res)
 
float ks_wave_max (const KS_WAVE *wave)
 
float ks_waveform_min (const KS_WAVEFORM waveform, int res)
 
float ks_wave_min (const KS_WAVE *wave)
 
short ks_iwave_absmax (const KS_IWAVE waveform, int res)
 
float ks_waveform_absmax (const KS_WAVEFORM waveform, int res)
 
float ks_wave_absmax (const KS_WAVE *wave)
 
float ks_waveform_maxslew (const KS_WAVEFORM waveform, int res, int duration, int *index)
 
float ks_wave_maxslew (const KS_WAVE *wave)
 
int ks_wave_time2area (const KS_WAVE *wave, float area_in)
 
float ks_waveform_area (const KS_WAVEFORM waveform, int start, int end, int dwelltime)
 
long ks_iwave_area (const KS_IWAVE iwave, int start, int end, int dwelltime)
 
float ks_wave_area (const KS_WAVE *wave, int start, int end)
 
float ks_wave_full_area (const KS_WAVE *wave)
 
float ks_waveform_sum (const KS_WAVEFORM waveform, int res)
 
float ks_wave_sum (const KS_WAVE *wave)
 
float ks_waveform_norm (const KS_WAVEFORM waveform, int res)
 
float ks_wave_norm (const KS_WAVE *wave)
 
void ks_waveform_cumsum (KS_WAVEFORM cumsumwaveform, const KS_WAVEFORM waveform, int res)
 
void ks_wave_cumsum (KS_WAVE *cumsumwave, const KS_WAVE *wave)
 
void ks_waveform_multiply (KS_WAVEFORM waveform_mod, const KS_WAVEFORM waveform, int res)
 
void ks_wave_multiply (KS_WAVE *wave_mod, const KS_WAVE *wave)
 
void ks_waveform_add (KS_WAVEFORM waveform_mod, const KS_WAVEFORM waveform, int res)
 
void ks_wave_add (KS_WAVE *wave_mod, const KS_WAVE *wave)
 
void ks_waveform_multiplyval (KS_WAVEFORM waveform, float val, int res)
 
void ks_wave_multiplyval (KS_WAVE *wave, float val)
 
void ks_waveform_addval (KS_WAVEFORM waveform, float val, int res)
 
void ks_wave_addval (KS_WAVE *wave, float val)
 
STATUS ks_waveform2iwave (KS_IWAVE iwave, const KS_WAVEFORM waveform, int res, int board, float max, float fs_factor)
 
STATUS ks_wave2iwave (KS_IWAVE iwave, const KS_WAVE *wave, int board)
 
WF_PULSE * ks_pg_echossp (WF_PULSE *echo, const char *suffix)
 
void ks_pg_trap_make_symramps (KS_TRAP *trap, float min_fs_factor, KS_IWAVE attack, KS_IWAVE decay)
 
STATUS ks_pg_trap (KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_phaser (KS_PHASER *phaser, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_read (KS_READ *read, int pos, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_readtrap (KS_READTRAP *readtrap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_readwave (KS_READWAVE *readwave, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_wave (KS_WAVE *wave, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_addwaveformstate (KS_WAVE *wave, KS_WAVEFORM waveform, int state_index)
 
STATUS ks_pg_rf (KS_RF *rf, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_selrf (KS_SELRF *selrf, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_wait (KS_WAIT *wait, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_isirot (KS_ISIROT *isirot, SCAN_INFO scan_info, int pos, void(*rotfun)(), KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_epi_dephasers (KS_EPI *epi, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_epi_rephasers (KS_EPI *epi, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_epi_echo (KS_EPI *epi, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
STATUS ks_pg_epi (KS_EPI *epi, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
 
void ks_pg_mod_fse_rfpulse_structs (KS_SELRF *rf1, KS_SELRF *rf2, KS_SELRF *rf3, const double *flip_angles, const int etl)
 
STATUS ks_pg_fse_flip_angle_taperoff (double *flip_angles, int etl, double flip1, double flip2, double flip3, double target_flip, int start_middle)
 
KS_SEQLOC ks_pg_get_trap_loc (KS_TRAP *trap, int instance)
 
KS_SEQLOC ks_pg_get_wave_loc (KS_WAVE *wave, int instance)
 
void ks_init_rtscalelog (KS_RT_SCALE_LOG *const rtscale)
 
void ks_instancereset_trap (KS_TRAP *trap)
 
void ks_instancereset_wave (KS_WAVE *wave)
 
void ks_instancereset_wait (KS_WAIT *wait)
 
void ks_instancereset_phaser (KS_PHASER *phaser)
 
void ks_instancereset_readtrap (KS_READTRAP *read)
 
void ks_instancereset_rf (KS_RF *rf)
 
void ks_instancereset_selrf (KS_SELRF *selrf)
 
void ks_instancereset_epi (KS_EPI *epi)
 
void ks_mat4_zero (KS_MAT4x4 m)
 
void ks_mat4_identity (KS_MAT4x4 m)
 
void ks_mat4_print (const KS_MAT4x4 m)
 
void ks_mat4_multiply (KS_MAT4x4 lhs, const KS_MAT4x4 rhs_left, const KS_MAT4x4 rhs_right)
 
void ks_mat4_invert (KS_MAT4x4 lhs, const KS_MAT4x4 rhs)
 
void ks_mat4_double_to_float (KS_MAT4x4f out, const KS_MAT4x4 in)
 
void ks_mat4_float_to_double (KS_MAT4x4 out, const KS_MAT4x4f in)
 
void ks_mat4_setgeometry (KS_MAT4x4 lhs, float x, float y, float z, float xr, float yr, float zr)
 
void ks_mat4f_setgeometry (KS_MAT4x4f lhs, float x, float y, float z, float xr, float yr, float zr)
 
void ks_mat4_setrotation1axis (KS_MAT4x4 rhs, float rot, char axis)
 
void ks_mat4_extractrotation (KS_MAT3x3 R, const KS_MAT4x4 M)
 
void ks_mat4_extracttranslation (double *T, const KS_MAT4x4 M)
 
void ks_mat3_identity (KS_MAT3x3 m)
 
void ks_mat3_multiply (KS_MAT3x3 lhs, const KS_MAT3x3 rhs_left, const KS_MAT3x3 rhs_right)
 
void ks_mat3_print (const KS_MAT3x3 m)
 
void ks_mat3_apply (double *w, const KS_MAT3x3 R, const double *v)
 
void ks_mat3_invapply (double *w, const KS_MAT3x3 R, const double *v)
 
void ks_mat3f_apply (float *w, const KS_MAT3x3f R, const float *v)
 
void ks_mat3f_invapply (float *w, const KS_MAT3x3f R, const float *v)
 
void ks_scan_update_slice_location (SCAN_INFO *new_loc, const SCAN_INFO orig_loc, const KS_MAT4x4 M_physical, const KS_MAT4x4 M_logical)
 
void ks_scan_update_slice_location_float (SCAN_INFO *new_loc, const SCAN_INFO orig_loc, const KS_MAT4x4f M_physical, const KS_MAT4x4f M_logical)
 
int ks_compare_loc_by_timeboard (const KS_SEQLOC *a, const KS_SEQLOC *b)
 
int ks_compare_wfi_by_timeboard (const KS_WFINSTANCE *a, const KS_WFINSTANCE *b)
 
int ks_compare_wfi_by_boardtime (const KS_WFINSTANCE *a, const KS_WFINSTANCE *b)
 
int ks_compare_wfp_by_time (const WF_PULSE *a, const WF_PULSE *b)
 
void ks_sort_wfi_by_timeboard (KS_WFINSTANCE *a, int nitems)
 
void ks_sort_loc_by_timeboard (KS_SEQLOC *a, int nitems)
 
void ks_sort_wfi_by_boardtime (KS_WFINSTANCE *a, int nitems)
 
void ks_sort_wfp_by_time (WF_PULSE *a, int nitems)
 
int ks_compare_pshort (const void *v1, const void *v2)
 
int ks_compare_pint (const void *v1, const void *v2)
 
int ks_compare_pfloat (const void *v1, const void *v2)
 
int ks_compare_short (const void *v1, const void *v2)
 
int ks_compare_int (const void *v1, const void *v2)
 
int ks_compare_float (const void *v1, const void *v2)
 
void ks_sort_getsortedindx (int *sortedindx, int *array, int n)
 
void ks_sort_getsortedindx_s (int *sortedindx, short *array, int n)
 
void ks_sort_getsortedindx_f (int *sortedindx, float *array, int n)
 
void ks_plot_slicetime_begin ()
 
void ks_plot_slicetime (const KS_SEQ_CONTROL *ctrl, int nslices, float *slicepos_mm, float slthick_mm, KS_PLOT_EXCITATION_MODE excmode)
 
void ks_plot_slicetime_endofpass (KS_PLOT_PASS_MODE pass_mode)
 
void ks_plot_slicetime_endofslicegroup_tagged (const char *desc, const KS_PLOT_SLICEGROUP_MODE tag)
 
void ks_plot_slicetime_endofslicegroup (const char *desc)
 
void ks_plot_slicetime_end ()
 
void ks_plot_tgt_reset (KS_SEQ_CONTROL *ctrl)
 
void ks_plot_tgt_addframe (KS_SEQ_CONTROL *ctrl)
 
STATUS ks_eval_addtraptogradrfctrl (KS_GRADRFCTRL *gradrfctrl, KS_TRAP *trap)
 
STATUS ks_eval_addwaittogradrfctrl (KS_GRADRFCTRL *gradrfctrl, KS_WAIT *wait)
 
FILE * ks_open_file_in_embed (const char *fname, const char *write_mode)
 
STATUS ks_eval_addwavetogradrfctrl (KS_GRADRFCTRL *gradrfctrl, KS_WAVE *wave)
 
STATUS ks_eval_addrftogradrfctrl (KS_GRADRFCTRL *gradrfctrl, KS_RF *rf)
 
STATUS ks_eval_addreadtogradrfctrl (KS_GRADRFCTRL *gradrfctrl, KS_READ *read)
 
float ks_scan_rf_phase_spoiling (int counter)
 
int ks_numplaced (KS_BASE *base)
 
int ks_scan_gettherightshot (const KS_DYNAMIC_STATE *dynamic)
 
float ks_get_trapamp_instance (const KS_TRAP *trap, int instance)
 
const KS_READks_get_read_in_echotrain (const KS_ECHOTRAIN *echotrain, const int readout_index)
 
void ks_rt_scale_log_set (KS_RT_SCALE_LOG *log, int instance_idx, float ampscale)
 
void ks_rt_scale_log_set_state (KS_RT_SCALE_LOG *log, int instance_idx, int state)
 
void ks_rt_scale_log_next (KS_RT_SCALE_LOG *log)
 
float ks_rt_scale_log_get (const KS_RT_SCALE_LOG *log, int instance_idx, int playout_idx)
 
int ks_rt_scale_log_get_state (const KS_RT_SCALE_LOG *log, int instance_idx, int playout_idx)
 

Variables

int maxGradRes
 
int psd_rf_wait
 
int psd_grd_wait
 
int cfssctype
 
float opfov
 
int opxres
 
int opyres
 
float opslthick
 
int rhkacq_uid
 
int ks_plot_filefmt
 
char ks_psdname [256]
 
int abort_on_kserror = ABORT_ON_KSERROR
 
int ks_rhoboard = TYPRHO1
 
struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool = _INIT_PHASEENCODING_COORD_POOL
 

Detailed Description

This file contains functions accessible on both HOST and TGT

Macro Definition Documentation

◆ ABORT_ON_KSERROR

#define ABORT_ON_KSERROR   0

◆ _INIT_PHASEENCODING_COORD_POOL

#define _INIT_PHASEENCODING_COORD_POOL   {0, 0, NULL, 0, 0};

◆ PHASEENCODING_PLAN_FILENAME

#define PHASEENCODING_PLAN_FILENAME   "ks_phaseencodingtable.host.txt"

Function Documentation

◆ acqq_longdab()

STATUS acqq_longdab ( WF_PULSE_ADDR  pulse,
LONG  pos_ref,
LONG  dab_ref,
LONG  xtr_ref,
LONG  fslot_value 
)
1841 {
1842  static const CHAR *routine = "acqq_longdab";
1843  CHAR *basename = NULL;
1844  INT start; /* Start of the pulse */
1845  WF_PULSE_ADDR newpulse; /* Pointer to new pulse */
1846  INT pack_ix = 0; /* CERD change */
1847  INT LONG_DAB_length = 31; /* Maximum is 31, hardware limitation */
1848  SHORT LONG_DAB_bits[31]; /* Maximum is 31, hardware limitation */
1849 #ifdef PGEN_TIMING
1850  extern INT time_pgen;
1851  if (time_pgen == 1) {
1852  start_timer(&_PGEN_start_time);
1853  }
1854 #endif
1855 
1856  pack_ix = PSD_XCVR2;
1857 
1858 #ifdef SIM_IO
1859  if (psdtrace3)
1860  {
1861  CHAR tmpname[50];
1862  if (pulse->pulsename == NULL)
1863  strcpy(tmpname,"");
1864  else
1865  strcpy(tmpname,pulse->pulsename);
1866 
1867  fprintf(stderr,"%s pulse: %s posref %d xtrref %d dabref %d fslot %d\n",
1868  routine,
1869  tmpname,
1870  pos_ref,
1871  xtr_ref,
1872  dab_ref,
1873  fslot_value);
1874  fflush(stderr);
1875  }
1876 #endif
1877  LONG_DAB_bits[0] = SSPDS + DABDC; /* CAPM , CERD change: new opcode */
1878  LONG_DAB_bits[1] = SSPOC + DXCT; /* Excitation , CERD change: ew opcode */
1879  LONG_DAB_bits[2] = SSPD;
1880  LONG_DAB_bits[3] = SSPD;
1881  LONG_DAB_bits[4] = SSPD;
1882  LONG_DAB_bits[5] = SSPD;
1883  LONG_DAB_bits[6] = SSPD;
1884  LONG_DAB_bits[7] = SSPD + DABIS; /* if DABIS is really needed is unclear, we leave it for the moment */
1885  LONG_DAB_bits[8] = SSPD;
1886  LONG_DAB_bits[9] = SSPD;
1887  LONG_DAB_bits[10] = SSPD;
1888  LONG_DAB_bits[11] = SSPD;
1889  LONG_DAB_bits[12] = SSPD;
1890  LONG_DAB_bits[13] = SSPD;
1891  LONG_DAB_bits[14] = SSPD;
1892  LONG_DAB_bits[15] = SSPD;
1893  LONG_DAB_bits[16] = SSPD;
1894  LONG_DAB_bits[17] = SSPD;
1895  LONG_DAB_bits[18] = SSPD;
1896  LONG_DAB_bits[19] = SSPD;
1897  LONG_DAB_bits[20] = SSPD;
1898  LONG_DAB_bits[21] = SSPD;
1899  LONG_DAB_bits[22] = SSPD;
1900  LONG_DAB_bits[23] = SSPD;
1901  LONG_DAB_bits[24] = SSPD;
1902  LONG_DAB_bits[25] = SSPD;
1903  LONG_DAB_bits[26] = SSPD;
1904  LONG_DAB_bits[27] = SSPD;
1905  LONG_DAB_bits[28] = SSPD;
1906  LONG_DAB_bits[29] = SSPD;
1907  LONG_DAB_bits[30] = SSPDS; /* Last field must be SSPDS, max number of fields = 31 */
1908 
1909  /* Make sure packets are ordered properly (dab->xtr->rba) and that
1910  the dab packet doesn't collide with xtr packet. */
1911  if ((dab_ref != DEFAULTPOS) && (xtr_ref != DEFAULTPOS) &&
1912  (dab_ref + LONG_DAB_length > xtr_ref))
1913  MsgHndlr(routine,
1914  MSG_PULSE, pulse,
1915  MSG_FORMAT,
1916  CODING_PBM,
1917  EMT_INVLD_INSTR_START,
1918  dab_ref);
1919 
1920  /* Make sure there is enough room for xtr packet */
1921  if ((xtr_ref != DEFAULTPOS) &&
1922  (pos_ref - xtr_ref < (XTR_length[pack_ix] + RBA_length[pack_ix])))
1923  MsgHndlr(routine,
1924  MSG_PULSE, pulse,
1925  MSG_FORMAT,
1926  CODING_PBM,
1927  EMT_INVLD_INSTR_START,
1928  xtr_ref);
1929 
1930  if ((xtr_ref == DEFAULTPOS) && (RBA_length[pack_ix] > XTRSETLNG))
1931  MsgHndlr(routine,
1932  MSG_PULSE, pulse,
1933  MSG_FORMAT,
1934  CODING_PBM,
1935  EMT_INVLD_INSTR_START,
1936  pos_ref);
1937 
1938  /* This routine assumes that the user has created the
1939  * the pulse passed into this routine with the pre-processor
1940  */
1941 
1942  /***** The bits will be created first ****/
1943  /* The first thing this routine will do will be to verify if
1944  * any bits have been created or no.
1945  */
1946 
1947  if (pulse-> ninsts == 0)
1948  {
1949 
1950  /***************************************/
1951  /**** Create DAB 'bits' Pulse **********/
1952  /***************************************/
1953 
1954  if (!(basename = (CHAR *)AllocNode(strlen(pulse-> pulsename)+1)))
1955  {
1956  MsgHndlr(routine, MSG_FORMAT, HARDWARE_PBM,
1957  EMT_ALLOC, pulse-> pulsename);
1958  }
1959  strcpy(basename, pulse-> pulsename);
1960 
1961  char* dabname = (char *)AllocNode(strlen(basename)+4);
1962  /* Create Name For Pulse */
1963  if (!dabname)
1964  {
1965  MsgHndlr(routine, MSG_PULSE, pulse,
1966  MSG_FORMAT, HARDWARE_PBM,
1967  EMT_ALLOC, "DAB Bits Pulse Name");
1968  }
1969 
1970  /* Append "dab" suffix for loaddab... routines */
1971  sprintf(dabname,"%sdab",basename);
1972  pulse-> pulsename = dabname;
1973 
1974  createbits(pulse, (WF_PROCESSOR)TYPSSP,
1975  LONG_DAB_length,
1976  LONG_DAB_bits);
1977 
1978  /***************************************/
1979  /**** Create XTR 'bits' Pulse **********/
1980  /***************************************/
1981 
1982  if (!(newpulse = (WF_PULSE *)AllocNode(sizeof(WF_PULSE))))
1983  {
1984 
1985  MsgHndlr(routine, MSG_FORMAT,
1986  HARDWARE_PBM, EMT_ALLOC, "Receive Bits");
1987 
1988  }
1989 
1990  char* xtrname = (char *)AllocNode(strlen(basename)+4);
1991  /* Create Name For Pulse */
1992  if (!xtrname)
1993  {
1994  MsgHndlr(routine, MSG_PULSE, pulse,
1995  MSG_FORMAT,
1996  HARDWARE_PBM,
1997  EMT_ALLOC,
1998  "Xtr Bits Pulse Name");
1999  }
2000 
2001  /* Attach to dab pulse */
2002  pulse-> assoc_pulse = newpulse;
2003 
2004  /* Append xtr for use by other routines */
2005  sprintf(xtrname,"%sxtr",basename);
2006  newpulse-> pulsename = xtrname;
2007 
2008  /* Verify the parameters for the pulse */
2009 
2010  /* Begin LxMGD - RJF 12/6/00 */
2011 
2012  /* For MGD, there is a maximum of 8 filters with slot numbers 0 thru 7.
2013  The filter block is terminated with a slot number of -1.
2014  So the valid filter slots are from 0 to 7 - RJF */
2015 
2016  if ((fslot_value < MIN_FILTER_SLOT) || (fslot_value > MAX_FILTER_SLOT) )
2017  {
2018  MsgHndlr(routine,
2019  MSG_PULSE, newpulse,
2020  MSG_FORMAT,
2021  CODING_PBM,
2022  EMT_DAB_SLOT_NO,
2023  fslot_value);
2024  }
2025 
2026  /* Begin LxMGD - RJF, 12/6/00 */
2027  /* The way XTR bits was set up for CERD was wrong
2028  (see sspinit.c, which initializes the
2029  packet.) The receiver values should have been at offset 10
2030  and the filter slot value should be at offset 11. */
2031 
2032  XTR_bits[pack_ix][10] = SSPOC + RFLTRS;
2033  XTR_bits[pack_ix][11] = SSPD + fslot_value;
2034 
2035  /* End CERD change */
2036 
2037  /* Insert EOS */
2038  XTR_bits[pack_ix][XTR_length[pack_ix]-1] = SSPDS;
2039 
2040  createbits(newpulse,
2041  (WF_PROCESSOR)TYPSSP,
2042  XTR_length[pack_ix],
2043  XTR_bits[pack_ix]);
2044 
2045 
2046  /*************************************/
2047  /**** Create Receive 'bits' Pulse ****/
2048  /*************************************/
2049 
2050  if (!(newpulse = (WF_PULSE *)AllocNode(sizeof(WF_PULSE))))
2051  {
2052 
2053  MsgHndlr(routine, MSG_FORMAT,
2054  HARDWARE_PBM, EMT_ALLOC, "Receive Bits");
2055 
2056  }
2057 
2058  char* rbaname = (char *)AllocNode(strlen(basename)+4);
2059  /* Create Name For Pulse */
2060  if (!rbaname)
2061  {
2062  MsgHndlr(routine, MSG_PULSE, pulse,
2063  MSG_FORMAT,
2064  HARDWARE_PBM,
2065  EMT_ALLOC,
2066  "Receive Bits Pulse Name");
2067  }
2068  sprintf(rbaname,"%srba",basename);
2069  newpulse-> pulsename = rbaname;
2070 
2071  /* Attach to exciter pulse */
2072  pulse-> assoc_pulse -> assoc_pulse = newpulse;
2073 
2074 
2075  createbits(newpulse,
2076  (WF_PROCESSOR)TYPSSP,
2077  RBA_length[pack_ix],
2078  RBA_bits[pack_ix]);
2079  /* End CERD change */
2080 
2081  }
2082 
2083  /********** End of creating bits *******************/
2084 
2085  /***************************************/
2086  /**** Create XTR Instruction ***********/
2087  /***************************************/
2088 
2089  /* Back off for settling time of exciter */
2090  if (xtr_ref == DEFAULTPOS) {
2091  start = pos_ref - (XTRSETLNG + XTR_length[pack_ix]);
2092  } else {
2093  start = xtr_ref;
2094  }
2095  createinstr(pulse -> assoc_pulse,
2096  start,
2097  XTR_length[pack_ix],
2098  0);
2099 
2100  pulse->assoc_pulse-> tag = SSPXTR;
2101 
2102  /***************************************/
2103  /**** Create DAB Instruction ***********/
2104  /***************************************/
2105  /* The DAB needs at least DABSETUP set-up time. */
2106  if (dab_ref == DEFAULTPOS) {
2107  if (xtr_ref == DEFAULTPOS) {
2108  start = pos_ref - IMax(2, DABSETUP,
2109  XTRSETLNG + XTR_length[pack_ix] + LONG_DAB_length);
2110  } else {
2111  start = IMin(2, pos_ref-DABSETUP,xtr_ref-LONG_DAB_length);
2112  }
2113 
2114  } else {
2115  start = dab_ref;
2116  }
2117 
2118  /* For DAB packet */
2119  createinstr(pulse, start, LONG_DAB_length, 0);
2120 
2121  pulse->tag = SSPDAB;
2122 
2123  /***************************************/
2124  /**** Create RBA Instruction ***********/
2125  /***************************************/
2126  /* Back off by length of RBA packet */
2127 
2128  start = pos_ref - RBA_length[pack_ix];
2129 
2130  createinstr(pulse -> assoc_pulse -> assoc_pulse,
2131  start + RBA_start,
2132  RBA_length[pack_ix],
2133  0);
2134 
2135  pulse-> assoc_pulse-> assoc_pulse-> tag = SSPRBA;
2136  /* End of CERD change */
2137  FreeNode(basename); /* Arg must be a LONG : pradeep */
2138 #ifdef PGEN_TIMING
2139  if (time_pgen == 1) {
2140 
2141  end_timer(_PGEN_start_time,acqq_ix,"acqq");
2142 
2143  }
2144 #endif
2145 
2146  return SUCCESS;
2147 }

◆ isNaN()

int isNaN ( float  a)
58  {
59  return a != a;
60 }

◆ ks_error()

STATUS ks_error ( const char *  format,
  ... 
)
78  {
79  char errstring[1000];
80  FILE *fp;
81  time_t mytime;
82  char mydatestr[100];
83 
84  va_list args;
85  va_start(args, format);
86  vsprintf(errstring, format, args);
87  va_end(args);
88  mytime = time(NULL);
89  sprintf(mydatestr, "%s", ctime(&mytime));
90  mydatestr[strcspn(mydatestr, "\n")] = 0; /* remove newline character */
91 
92 #ifdef PSD_HW
93  /* Report the error in the debug file also so that "stack traces"
94  from KS_RAISE are completed. */
95  ks_dbg("HOST ERROR - %s", errstring);
96 
97  /* if on MR scanner (HOST and TGT/IPG, HW=hardware=MRscanner) */
98  fp = fopen("/usr/g/mrraw/ks_errors.txt", "a+");
99 #else
100  /* in WTools (simulation) (HOST and TGT/IPG) */
101  fp = stdout;
102 #endif
103 
104 #ifdef IPG
105  char side[] = "TGT";
106 #else
107  char side[] = "HOST";
108 #endif
109 
110 #ifdef REV
111  fprintf(fp, "%s ERROR %s@%s [%s] - %s\n", side, ks_psdname, REV, mydatestr, errstring);
112 #else
113  fprintf(fp, "%s ERROR %s [%s] - %s\n", side, ks_psdname, mydatestr, errstring);
114 #endif
115 
116  fflush(fp);
117 
118 #ifdef PSD_HW
119  /* if on MR scanner */
120  fclose(fp);
121 #endif
122 
123 #if defined(HOST_TGT)
124  /* HOST_TGT: HOST for either WTools or MR scanner */
125 
126  char *err_tail = strrchr(errstring, ':');
127  epic_error( 0, err_tail ? err_tail + 1 : errstring, 0, EE_ARGS(0));
128 #endif
129 
130  if (abort_on_kserror) {
131  abort();
132  }
133 
134  return ADVISORY_FAILURE;
135 }
STATUS ks_dbg(const char *format,...)
Definition: KSFoundation_common.c:157
int abort_on_kserror
Definition: KSFoundation_common.c:40
char ks_psdname[256]
Definition: GERequired.e:245

◆ ks_dbg_reset()

void ks_dbg_reset ( )

Clear debug file content

140  {
141  FILE *fp;
142 
143 /* if on MR scanner (HOST and TGT/IPG, HW=hardware=MRscanner) */
144 #ifdef PSD_HW
145  fp = fopen("/usr/g/mrraw/ks_debug.txt", "w");
146 #else
147  fp = fopen("./ks_debug.txt", "w");
148 #endif
149 
150 fclose(fp);
151 
152 }

◆ ks_dbg()

STATUS ks_dbg ( const char *  format,
  ... 
)
157  {
158  char fname[1000];
159  char string[1000];
160  FILE *fp;
161  time_t mytime;
162  char mydatestr[100];
163 
164  va_list args;
165  va_start(args, format);
166  vsprintf(string, format, args);
167  va_end(args);
168 
169 
170 #ifdef PSD_HW
171 #ifdef IPG
172  return SUCCESS; /* Don't run ks_dbg() on MR scanner TGT to avoid potential real-time issues writing to disk */
173 #endif
174  /* MR scanner */
175  sprintf(fname, "/usr/g/mrraw/ks_debug.txt");
176 #else
177  /* Simulation (WTools) */
178  sprintf(fname, "./ks_debug.txt");
179 #endif
180 
181  mytime = time(NULL);
182  sprintf(mydatestr, "%s", ctime(&mytime));
183  mydatestr[strcspn(mydatestr, "\n")] = 0; /* remove newline character */
184 
185  fp = fopen(fname, "a+");
186 
187 #ifdef REV
188  fprintf(fp, "%s@%s [%s] - %s\n", ks_psdname, REV, mydatestr, string);
189 #else
190  fprintf(fp, "%s [%s] - %s\n", ks_psdname, mydatestr, string);
191 #endif
192 
193  fflush(fp);
194  fclose(fp);
195 
196  return SUCCESS;
197 
198 }
char ks_psdname[256]
Definition: GERequired.e:245

◆ existfile()

STATUS existfile ( const char *  fname)

ADDTITLEHERE

ADDDESCHERE

Parameters
fnameADDTEXTHERE
Return values
STATUSADDTEXTHERE
203  {
204  FILE *file;
205  if ((file = fopen(fname, "r"))) {
206  fclose(file);
207  return SUCCESS;
208  }
209  return FAILURE;
210 }

◆ ks_syslimits_hasICEhardware()

int ks_syslimits_hasICEhardware ( )

Check for ICE Hardware (e.g. RX27+ on SIGNA Premier)

Return values
int1: ICE 0: MGD
215  {
216  int isice = FALSE;
217 #if EPIC_RELEASE >= 27
218  isice = cfssctype;
219 #endif
220 
221  return isice;
222 
223 }
int cfssctype

◆ ks_syslimits_ampmax_phys()

float ks_syslimits_ampmax_phys ( )

ADDTITLEHERE

228  {
229  return FMin(3, phygrd.xfs, phygrd.yfs, phygrd.zfs);
230 }
PHYS_GRAD phygrd

◆ ks_syslimits_ampmax()

float ks_syslimits_ampmax ( LOG_GRAD  loggrd)

Returns the maximum gradient amplitude that can be used on all gradient boards simultaneously

Since the waveform design (using ks_eval_***() functions) is separated from the placement of waveforms (using ks_pg_***() functions), the maximum gradient limit to use for gradient design must account for the least capable gradient board given the current slice angulation. ks_syslimits_ampmax() assumes that all gradients may be on simultaneously

The return value from this function can be passed in as ampmax to all ks_eval***_constrained() functions

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
gradmaxMaximum gradient amplitude ([G/cm]) that can be used on all boards simultaneously
235  {
236  return (FMin(3, loggrd.tx_xyz, loggrd.ty_xyz, loggrd.tz_xyz));
237 }
LOG_GRAD loggrd

◆ ks_syslimits_ampmax2()

float ks_syslimits_ampmax2 ( LOG_GRAD  loggrd)

Returns the maximum gradient amplitude that can be used on two gradient boards simultaneously

Since the waveform design (using ks_eval_***() functions) is separated from the placement of waveforms (using ks_pg_***() functions), the maximum gradient limit to use for gradient design must account for the least capable gradient board given the current slice angulation. ks_syslimits_ampmax2() assumes that gradients are played out on at most one more board at the same time as the current trapezoid

The return value from this function can be passed in as ampmax to all ks_eval***_constrained() functions

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
gradmaxMaximum gradient amplitude ([G/cm]) that can be used on 2 boards simultaneously
242  {
243  return (FMin(6, loggrd.tx_xy, loggrd.tx_xz, loggrd.ty_xy, loggrd.ty_yz, loggrd.tz_xz, loggrd.tz_yz));
244 }
LOG_GRAD loggrd

◆ ks_syslimits_ampmax1()

float ks_syslimits_ampmax1 ( LOG_GRAD  loggrd)

Returns the maximum gradient amplitude that can be used on one gradient board at a time

Since the waveform design (using ks_eval_***() functions) is separated from the placement of waveforms (using ks_pg_***() functions), the maximum gradient limit to use for gradient design must account for the least capable gradient board given the current slice angulation. ks_syslimits_ampmax1() assumes that no other gradient is played out on another board at the same time as the current trapezoid

The return value from this function can be passed in as ampmax to all ks_eval***_constrained() functions

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
gradmaxMaximum gradient amplitude ([G/cm]) that can be used on one board at a time
249  {
250  return (FMin(3, loggrd.tx, loggrd.ty, loggrd.tz));
251 }
LOG_GRAD loggrd

◆ ks_syslimits_ampmax1p()

float ks_syslimits_ampmax1p ( LOG_GRAD  loggrd)

Returns the maximum gradient amplitude on the physical gradient axes

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
gradmaxMaximum gradient amplitude ([G/cm]) as defined by the physical gradients (lowest of physical X, Y, Z)
257  {
258  return (FMin(3, loggrd.xfs, loggrd.yfs, loggrd.zfs));
259 }
LOG_GRAD loggrd

◆ ks_syslimits_gradtarget()

float ks_syslimits_gradtarget ( LOG_GRAD  loggrd,
int  board 
)

Returns the maximum target amplitude for a board (internal use)

For gradient boards, the field .tx, .ty or .tz is returned. For non-gradient boards, 1.0 is returned. This function is used internally by ks_pg_***() functions and there should be no need to call it directly.

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
[in]boardThe board on which the current trapezoid or waveform is to be played out on
Return values
gradampMaximum target amplitude for a board
264  {
265  switch (board) {
266  case XGRAD:
267  return loggrd.tx;
268  case YGRAD:
269  return loggrd.ty;
270  case ZGRAD:
271  return loggrd.tz;
272  case OMEGA:
273  return 5e6;
274  default:
275  return 1.0;
276  }
277 }
LOG_GRAD loggrd

◆ ks_syslimits_ramptimemax()

int ks_syslimits_ramptimemax ( LOG_GRAD  loggrd)

Returns the minimum ramp time to get from zero to full gradient scale

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
ramptimeRamptime in [us] to get from zero to full gradient scale
282  {
283  /* ramptime at full gradient scale */
284  return IMax(3, loggrd.xrt, loggrd.yrt, loggrd.zrt);
285 }
LOG_GRAD loggrd

◆ ks_syslimits_ramptimemax_phys()

int ks_syslimits_ramptimemax_phys ( )

ADDTITLEHERE

290  {
291  /* ramptime at full gradient scale */
292  return IMax(3, phygrd.xrt, phygrd.yrt, phygrd.zrt);
293 }
PHYS_GRAD phygrd

◆ ks_syslimits_slewrate_phys()

float ks_syslimits_slewrate_phys ( )

ADDTITLEHERE

298  {
300 }
int ks_syslimits_ramptimemax_phys()
ADDTITLEHERE
Definition: KSFoundation_common.c:290
float ks_syslimits_ampmax_phys()
ADDTITLEHERE
Definition: KSFoundation_common.c:228

◆ ks_syslimits_slewrate()

float ks_syslimits_slewrate ( LOG_GRAD  loggrd)

Returns the maximum slewrate that can be used on all gradient boards simultaneously

The return value from this function is the ratio of ks_syslimits_ampmax() and ks_syslimits_ramptimemax() and can be passed in as slewrate to all ks_eval***_constrained() functions

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
slewrateMaximum slewrate ([(G/cm) / us]) that can be used on all boards simultaneously
305  {
306  extern float ks_srfact, ks_qfact;
307  if (ks_srfact / ks_qfact < 1/sqrt(3)){
308  return(ks_syslimits_slewrate_phys());
309  }
310 #if EPIC_RELEASE >= 27
311  return (ks_syslimits_ampmax(loggrd) / ((float)ks_syslimits_ramptimemax(loggrd) * loggrd.scale_3axis_risetime));
312 #else
314 #endif
315 }
float ks_syslimits_slewrate_phys()
ADDTITLEHERE
Definition: KSFoundation_common.c:298
float ks_qfact
Definition: GERequired.e:271
LOG_GRAD loggrd
float ks_syslimits_ampmax(LOG_GRAD loggrd)
Returns the maximum gradient amplitude that can be used on all gradient boards simultaneously
Definition: KSFoundation_common.c:235
int ks_syslimits_ramptimemax(LOG_GRAD loggrd)
Returns the minimum ramp time to get from zero to full gradient scale
Definition: KSFoundation_common.c:282
float ks_srfact
Definition: GERequired.e:270

◆ ks_syslimits_slewrate2()

float ks_syslimits_slewrate2 ( LOG_GRAD  loggrd)

Returns the maximum slewrate that can be used on two gradient boards simultaneously

The return value from this function is the ratio of ks_syslimits_ampmax2() and ks_syslimits_ramptimemax() and can be passed in as slewrate to all ks_eval***_constrained() functions

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
slewrateMaximum slewrate ([(G/cm) / us]) that can be used on all boards simultaneously
320  {
321  extern float ks_srfact, ks_qfact;
322  if (ks_srfact / ks_qfact < 1/sqrt(3)){
323  return(ks_syslimits_slewrate_phys());
324  }
325 #if EPIC_RELEASE >= 27
326  return (ks_syslimits_ampmax2(loggrd) / ((float)ks_syslimits_ramptimemax(loggrd) * loggrd.scale_2axis_risetime));
327 #else
329 #endif
330 }
float ks_syslimits_slewrate_phys()
ADDTITLEHERE
Definition: KSFoundation_common.c:298
float ks_syslimits_ampmax2(LOG_GRAD loggrd)
Returns the maximum gradient amplitude that can be used on two gradient boards simultaneously
Definition: KSFoundation_common.c:242
float ks_qfact
Definition: GERequired.e:271
LOG_GRAD loggrd
int ks_syslimits_ramptimemax(LOG_GRAD loggrd)
Returns the minimum ramp time to get from zero to full gradient scale
Definition: KSFoundation_common.c:282
float ks_srfact
Definition: GERequired.e:270

◆ ks_syslimits_slewrate1()

float ks_syslimits_slewrate1 ( LOG_GRAD  loggrd)

Returns the maximum slewrate that can be used on one gradient board at a time

The return value from this function is the ratio of ks_syslimits_ampmax1() and ks_syslimits_ramptimemax() and can be passed in as slewrate to all ks_eval***_constrained() functions

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
slewrateMaximum slewrate ([(G/cm) / us]) that can be used on one board at at time
335  {
336  extern float ks_srfact, ks_qfact;
337  if (ks_srfact / ks_qfact < 1/sqrt(3)){
338  return(ks_syslimits_slewrate_phys());
339  }
340 #if EPIC_RELEASE >= 27
341  return (ks_syslimits_ampmax1(loggrd) / ((float)ks_syslimits_ramptimemax(loggrd) * loggrd.scale_1axis_risetime));
342 #else
344 #endif
345 
346 }
float ks_syslimits_ampmax1(LOG_GRAD loggrd)
Returns the maximum gradient amplitude that can be used on one gradient board at a time...
Definition: KSFoundation_common.c:249
float ks_syslimits_slewrate_phys()
ADDTITLEHERE
Definition: KSFoundation_common.c:298
float ks_qfact
Definition: GERequired.e:271
LOG_GRAD loggrd
int ks_syslimits_ramptimemax(LOG_GRAD loggrd)
Returns the minimum ramp time to get from zero to full gradient scale
Definition: KSFoundation_common.c:282
float ks_srfact
Definition: GERequired.e:270

◆ ks_syslimits_slewrate1p()

float ks_syslimits_slewrate1p ( LOG_GRAD  loggrd)

Returns the maximum gradient amplitude on the physical gradient axes

Parameters
[in]loggrdGE's LOG_GRAD struct, dependent on the gradient system and current slice angulation
Return values
gradmaxMaximum slewrate ([(G/cm) / us]) that can be used on one board at at time as defined by the physical gradients (lowest of physical X, Y, Z)
352  {
354 }
LOG_GRAD loggrd
float ks_syslimits_ampmax1p(LOG_GRAD loggrd)
Returns the maximum gradient amplitude on the physical gradient axes
Definition: KSFoundation_common.c:257
int ks_syslimits_ramptimemax(LOG_GRAD loggrd)
Returns the minimum ramp time to get from zero to full gradient scale
Definition: KSFoundation_common.c:282

◆ ks_cycles_to_iphase()

unsigned short ks_cycles_to_iphase ( double  cycles)

Returns the integer phase (internal use)

All phase values in KSFoundation are in [degrees], including flip angles, RF/receive phases and THETA waveforms. This function is used internally by another internal function ks_wave2iwave(), which is in turn called by ks_pg_wave()

Parameters
[in]cyclesperiods
Return values
unsignediphase to use on THETA board on hardwarewrapper of ks_cycles_to_iphase for degrees
367  {
368  /* Actual period for u14 */
369  static const unsigned short FS_2PI_u14 = (1<<14);
370  /* Want the fractional part */
371  cycles -= (long)cycles;
372  /* Force positive */
373  cycles++;
374  /* Scale to u14 domain then shift two bits to the
375  left for compatibility with FS_2PI [u16] period. */
376  return (unsigned short)(cycles * (double)FS_2PI_u14 + 0.5) % FS_2PI_u14 << 2;
377 } /* ks_cycles_to_iphase */

◆ ks_degrees_to_iphase()

unsigned short ks_degrees_to_iphase ( double  degrees)

wrapper of ks_cycles_to_iphase for radians

379  {
380  return ks_cycles_to_iphase(degrees / 360.0);
381 } /* wrapper for ks_cycles_to_iphase */
unsigned short ks_cycles_to_iphase(double cycles)
Returns the integer phase (internal use)
Definition: KSFoundation_common.c:367

◆ ks_radians_to_iphase()

unsigned short ks_radians_to_iphase ( double  radians)
383  {
384  return ks_cycles_to_iphase(radians / (2.0 * PI));
385 } /* wrapper for ks_cycles_to_iphase */
unsigned short ks_cycles_to_iphase(double cycles)
Returns the integer phase (internal use)
Definition: KSFoundation_common.c:367

◆ ks_polyder()

void ks_polyder ( const double *  coeffs,
const int  order,
double *  der_coeffs 
)

get derivative coeffs of polynomial of order

388  {
389  int ido;
390  for (ido = 0; ido < order; ido++) {
391  der_coeffs[ido] = coeffs[ido] * (order - ido);
392  }
393 }

◆ ks_polyval()

void ks_polyval ( const double *  coeffs,
const int  order,
const double *  x,
const int  numx,
double *  values 
)

eval polynomial

398  {
399  int idx, ido;
400  for (idx = 0; idx < numx; idx++) {
401  values[idx] = 0.0;
402  for (ido = 0; ido <= order; ido++) {
403  values[idx] = values[idx] * x[idx] + coeffs[ido];
404  }
405  }
406 }

◆ ks_polyval_f()

void ks_polyval_f ( const double *  coeffs,
const int  order,
const float *  x,
const int  numx,
float *  values 
)

eval polynomial with float values

411  {
412  double xd[numx];
413  double vald[numx];
414  int i;
415 
416  for (i = 0; i < numx; i++) {
417  xd[i] = (double) x[i];
418  }
419 
420  ks_polyval(coeffs, order, xd, numx, vald);
421 
422  for (i = 0; i < numx; i++) {
423  values[i] = (float) vald[i];
424  }
425 }
void ks_polyval(const double *coeffs, const int order, const double *x, const int numx, double *values)
eval polynomial
Definition: KSFoundation_common.c:398
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_Newtons_method()

double ks_Newtons_method ( const double *  coeffs,
const int  order,
const double  x0,
const int  num_iter 
)

find real polynomial root near x0 using Newton's method

430  {
431  double x = x0;
432  double der_coeffs[order];
433  ks_polyder(coeffs, order, der_coeffs); /* get derivative */
434 
435  int iter;
436  for (iter = 0; iter < num_iter; iter++) {
437  double f, fp; /* polynomial and its derivative at x */
438  ks_polyval(coeffs, order, &x, 1, &f);
439  ks_polyval(der_coeffs, order-1, &x, 1, &fp);
440  x -= f / fp;
441  }
442  return x;
443 }
void ks_polyval(const double *coeffs, const int order, const double *x, const int numx, double *values)
eval polynomial
Definition: KSFoundation_common.c:398
void ks_polyder(const double *coeffs, const int order, double *der_coeffs)
get derivative coeffs of polynomial of order
Definition: KSFoundation_common.c:388

◆ ks_calc_selgradamp()

float ks_calc_selgradamp ( float  rfbw,
float  slthick 
)

Returns the gradient amplitude in [G/cm] necessary for slice selection (internal use)

Given an RF bandwidth in [Hz] and a slice thickness in [mm], this function calculates the gradient strength in [G/cm] necessary to produce a slice with the given slice thickness

This function is used by ks_eval_seltrap(), ks_eval_selrf_constrained() and ks_scan_selrf_setfreqphase()

Parameters
[in]rfbwThe bandwidth of the RF pulse to use with the gradient
[in]slthickThe desired slice thickness in [mm]
Return values
gradampGradient amplitude to use [G/cm]
448  {
449 
450  if (slthick > 0 && rfbw > 0)
451  return (rfbw / (GAM * slthick / 10.0));
452  else
453  return 0.0; /* return zero amp if requested slice thickness is <= 0 */
454 }

◆ ks_calc_minfov()

float ks_calc_minfov ( float  ampmax,
int  tsp 
)

Calculates the minimum readout FOV

Given a maximum allowed gradient amplitude in [G/cm] and a dwell time in [us] (see ks_calc_bw2tsp()), the minimum possible readout FOV in [mm] is calculated. This function is called internally by ks_eval_readtrap_constrained() when rampsampling is not used (.rampsampling = 0)

Parameters
[in]ampmaxThe maximum allowed gradient amplitude ([G/cm])
[in]tspDuration in [us] for each data sample in the acquisition window. Minimum: 2 [us]
Return values
minFOVMinimum FOV in the readout direction
459  {
460  float minfov;
461 
462  minfov = ((float) (2 * (1.0e3 / (tsp * 2.0)) * 1000 / GAM) * (10.0 / ampmax));
463 
464  return minfov;
465 }

◆ ks_calc_minslthick()

float ks_calc_minslthick ( float  bw)

Calculates the minimum slice thickness [mm]

Given an RF bandwidth in [kHz], this function returns the minimum slice thickness possible given the gradient max amplitude.

Parameters
[in]bwRF bandwidth in [kHz]
Return values
minSliceThicknessMinimum slice thickness in [mm]
470  {
471  return (bw / (ks_syslimits_ampmax(loggrd) * (0.1) * GAM));
472 }
LOG_GRAD loggrd
float ks_syslimits_ampmax(LOG_GRAD loggrd)
Returns the maximum gradient amplitude that can be used on all gradient boards simultaneously
Definition: KSFoundation_common.c:235

◆ ks_calc_mintsp()

int ks_calc_mintsp ( float  ampmax,
float  fov 
)

Calculates the minimum dwell time

Given a maximum allowed gradient amplitude in [G/cm] and a readout FOV in [mm], the smallest dwell time (i.e. largest rBW) in [us] is calculated.

Parameters
[in]ampmaxThe maximum allowed gradient amplitude ([G/cm])
[in]fovFOV in the readout direction
Return values
tspDuration in [us] for each data sample in the acquisition window
477  {
478  int mintsp;
479  int sysmintsp = 2;
480 
481  mintsp = (int) ceil(1.0e3 / (fov / ((float) (2 * 1000 / GAM) * (10.0 / ampmax)) * 2.0));
482 
483  if (mintsp < sysmintsp)
484  mintsp = mintsp;
485 
486  return mintsp;
487 }

◆ ks_calc_fov2gradareapixel()

float ks_calc_fov2gradareapixel ( float  fov)

Calculates the gradient area needed to move one pixel in k-space

Given a readout FOV in [mm], the gradient area needed to move one pixel in a fully sampled k-space is calculated

Parameters
[in]fovFOV in the readout direction
Return values
areaGradient area in [(G/cm) * us]
492  {
493  if (fov > 0) {
494  /* G/cm * us. Area needed to move one pixel in k-space corresponding to the input FOV */
495  return (1.0e6 / (fov / 10.0 * GAM));
496  } else {
497  return (0.0);
498  }
499 }

◆ ks_init_dynamic()

void ks_init_dynamic ( KS_DYNAMIC_STATE *  dynamic)

Initialise the dynamic structure

It is important to have dynamic in a known state at the start of any scan function.

Parameters
dynamicThe current state of the scan (used by ksscan)
Returns
void
504  {
505  KS_MAT4x4 physical;
506  memcpy(physical, dynamic->Mphysical, sizeof(KS_MAT4x4));
507  KS_DYNAMIC_STATE defdynamic = KS_INIT_DYNAMIC_STATE;
508  *dynamic = defdynamic;
509  memcpy(dynamic->Mphysical, physical, sizeof(KS_MAT4x4));
510 }
double KS_MAT4x4[16]
Definition: KSFoundation.h:356
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829

◆ ks_calc_caipi_scale()

float ks_calc_caipi_scale ( const int  ky,
const int  R,
const int  caipi_factor 
)

ADDTITLEHERE

520  {
521  float caipi_scale = 0;
522 
523  /* Get target caipi-phase with pattern linspace(-1.0, 1.0, sms_caipi_factor) */
524  if (ky != KS_NOTSET && caipi_factor > 1) {
525  caipi_scale = ( (double) ((ky / R) % caipi_factor) / (caipi_factor - 1.0) ) * 2.0 - 1.0;
526  }
527 
528  return caipi_scale;
529 }
#define KS_NOTSET
Definition: KSFoundation.h:115

◆ ks_calc_caipi_phase()

float ks_calc_caipi_phase ( const float  sms_slice_gap,
const int  sms_multiband_factor,
const SCAN_INFO *  slice_info,
const float  caipi_blip_area,
const int  slice_encode_dir 
)

ADDTITLEHERE

534  {
535 
536  int sign = slice_encode_dir == 0 ? -1 : 1;
537  float offset = (sms_slice_gap / 2) * (sms_multiband_factor - 1) * sign; /* bottom slice's distance from RF-scan_info slice position (optloc) [mm] */
538  float A_blip = (caipi_blip_area / 10.0) * 1e-6 ; /* [(G/cm) * us] -> [(G/mm) * s] */
539  float gamma = (2.0*PI*GAM); /* [Hz/G] */
540 
541  float caipi_phase = (slice_info->optloc + offset) * A_blip * gamma; /* radians */
542 
543  return caipi_phase * (180.0/PI); /* convert to degrees and return */
544 }

◆ ks_calc_caipi_offset_phase()

float ks_calc_caipi_offset_phase ( const float  sms_slice_gap,
const int  sms_multiband_factor,
const SCAN_INFO *  slice_info,
const int  caipi_factor,
const float  caipi_blip_area,
const int  ky,
const int  R,
const int  slice_encode_dir 
)

ADDTITLEHERE

550  {
551 
552  float caipi_phase = ks_calc_caipi_phase(sms_slice_gap, sms_multiband_factor, slice_info, caipi_blip_area, slice_encode_dir);
553 
554  float caipi_scale = ks_calc_caipi_scale(ky, R, caipi_factor);
555 
556  return caipi_phase *= caipi_scale;
557 
558 }
float ks_calc_caipi_phase(const float sms_slice_gap, const int sms_multiband_factor, const SCAN_INFO *slice_info, const float caipi_blip_area, const int slice_encode_dir)
ADDTITLEHERE
Definition: KSFoundation_common.c:534
float ks_calc_caipi_scale(const int ky, const int R, const int caipi_factor)
ADDTITLEHERE
Definition: KSFoundation_common.c:520

◆ ks_phaseencoding_memorypool_init()

STATUS ks_phaseencoding_memorypool_init ( KS_PHASEENCODING_COORD entries,
uint64_t  size 
)

Internal use for correct migration of KS_PHASEENCODING_PLAN from HOST to TGT (IPG)

Parameters
[in]entriesPointer to KS_PHASEENCODING_COORD array with phase encoding coordinates
[in]sizeSize of memory pool
Returns
void
580  {
581 #ifdef IPG
585 #else
590 #endif
591  return SUCCESS;
592 }
int is_cleared_on_tgt
Definition: KSFoundation_common.c:573
struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool
Definition: KSFoundation_common.c:577
uint64_t size
Definition: KSFoundation_common.c:569
KS_PHASEENCODING_COORD * entries
Definition: KSFoundation_common.c:571
uint64_t used_size
Definition: KSFoundation_common.c:570
uint32_t epoch
Definition: KSFoundation_common.c:572

◆ ks_phaseencoding_get()

KS_PHASEENCODING_COORD ks_phaseencoding_get ( const KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
int  encode,
int  shot 
)

Get [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given encode and shot

If the .ky and .kz values returned by this function is = KS_NOTSET (-1), it indicates that this encode/shot combination should have zero phase encoding and should be ignored. For 2D, .kz will always be KS_NOTSET

Parameters
[in]phaseenc_plan_ptrPointer to KS_PHASEENCODING_PLAN
[in]encodePhase encoding index in the sequence echo train in range [0,encodes_per_shot-1]
[in]shotShot index (i.e. how many times the sequence is played out per slice). For 3D, this is the combined number of shots over ky and kz
Return values
<tt>KS_PHASEENCODING_COORD</tt>
597  {
598 
599 #ifdef IPG
600  int oktoget = (phaseenc_plan_ptr != NULL) && _phaseencoding_coord_pool.is_cleared_on_tgt;
601 #else
602  int oktoget = (phaseenc_plan_ptr != NULL) && phaseenc_plan_ptr->epoch == _phaseencoding_coord_pool.epoch;
603 #endif
604 
605  if (!oktoget ||
606  phaseenc_plan_ptr->encodes_per_shot == KS_NOTSET ||
607  !(phaseenc_plan_ptr->entries_offset) ||
608  shot >= phaseenc_plan_ptr->num_shots ||
609  encode < 0 || encode >= phaseenc_plan_ptr->encodes_per_shot) {
610 
612  return fake_coords;
613  }
614 
615  const int shot_start_index = phaseenc_plan_ptr->entries_offset - 1 + phaseenc_plan_ptr->encodes_per_shot * shot;
616 
617  return _phaseencoding_coord_pool.entries[shot_start_index + encode];
618 }
#define KS_INIT_PHASEENCODING_COORD
Definition: KSFoundation.h:306
int num_shots
Definition: KSFoundation.h:1789
int is_cleared_on_tgt
Definition: KSFoundation_common.c:573
uint32_t entries_offset
Definition: KSFoundation.h:1790
#define KS_NOTSET
Definition: KSFoundation.h:115
struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool
Definition: KSFoundation_common.c:577
Struct holding a 3D k-space phase encoding location (ky,kz)
Definition: KSFoundation.h:1749
int encodes_per_shot
Definition: KSFoundation.h:1788
KS_PHASEENCODING_COORD * entries
Definition: KSFoundation_common.c:571
uint32_t epoch
Definition: KSFoundation.h:1792
uint32_t epoch
Definition: KSFoundation_common.c:572

◆ ks_phaseencoding_get_shot()

KS_PHASEENCODING_SHOTCOORDS ks_phaseencoding_get_shot ( const KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
int  shot 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
phaseenc_plan_ptrADDTEXTHERE
[in]shotADDTEXTHERE
Return values
KS_PHASEENCODING_SHOTCOORDSADDTEXTHERE
623  {
624 
625 #ifdef IPG
626  int oktoget = (phaseenc_plan_ptr != NULL) && _phaseencoding_coord_pool.is_cleared_on_tgt;
627 #else
628  int oktoget = (phaseenc_plan_ptr != NULL) && phaseenc_plan_ptr->epoch == _phaseencoding_coord_pool.epoch;
629 #endif
630 
631  if (!oktoget ||
632  phaseenc_plan_ptr->encodes_per_shot == KS_NOTSET ||
633  !(phaseenc_plan_ptr->entries_offset) ||
634  shot < 0 ||
635  shot >= phaseenc_plan_ptr->num_shots) {
636 
638  return fake_shot;
639  }
640 
641  const int shot_start_index = phaseenc_plan_ptr->entries_offset - 1 + phaseenc_plan_ptr->encodes_per_shot * shot;
642 
643  KS_PHASEENCODING_SHOTCOORDS shot_coords = {
644  phaseenc_plan_ptr->encodes_per_shot,
645  _phaseencoding_coord_pool.entries + shot_start_index
646  };
647  return shot_coords;
648 }
int num_shots
Definition: KSFoundation.h:1789
int is_cleared_on_tgt
Definition: KSFoundation_common.c:573
ADDTITLEHERE
Definition: KSFoundation.h:1773
uint32_t entries_offset
Definition: KSFoundation.h:1790
#define KS_NOTSET
Definition: KSFoundation.h:115
struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool
Definition: KSFoundation_common.c:577
int encodes_per_shot
Definition: KSFoundation.h:1788
KS_PHASEENCODING_COORD * entries
Definition: KSFoundation_common.c:571
#define KS_INIT_PHASEENCODING_SHOTCOORDS
Definition: KSFoundation.h:1778
uint32_t epoch
Definition: KSFoundation.h:1792
uint32_t epoch
Definition: KSFoundation_common.c:572

◆ ks_phaseencoding_set()

void ks_phaseencoding_set ( KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
int  encode,
int  shot,
int  ky,
int  kz 
)

Set [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given encode and shot

If the .ky and .kz values passed to this function is = KS_NOTSET (-1), it indicates that this encode/shot combination should have zero phase encoding and should be ignored. However, ignored encode/shot combinations are not necessary since the etl*num_shots entries in .entries of KS_PHASEENCODING_PLAN are always initialized to KS_NOTSET by ks_phaseencoding_resize(). Hence, it is only necessary to explicitly set the encode/shot combination for ky/kz coordinates being acquired.

For 2D, kz (5th arg) should always be KS_NOTSET.

Parameters
[in]phaseenc_plan_ptrPointer to KS_PHASEENCODING_PLAN
[in]encodePhase encoding index in the sequence echo train in range [0,encodes_per_shot-1]
[in]shotShot index (in range [0,how many times the sequence is played out per slice - 1]). For 3D, this is the combined number of shots over ky and kz
[in]kyK-space coordinate along the first (only for 2D) phase encoding direction (integer) in range [0, phaser.numlinestoacq-1]
[in]kzK-space coordinate along the second (use KS_NOTSET for 2D) phase encoding direction (integer) in range [0, zphaser.numlinestoacq-1]
Returns
void
653  {
654 
655 #ifdef IPG
656  int oktoset = (phaseenc_plan_ptr != NULL) && _phaseencoding_coord_pool.is_cleared_on_tgt;
657 #else
658  int oktoset = (phaseenc_plan_ptr != NULL) && phaseenc_plan_ptr->epoch == _phaseencoding_coord_pool.epoch;
659 #endif
660 
661  if (!oktoset ||
662  phaseenc_plan_ptr->encodes_per_shot == KS_NOTSET ||
663  !(phaseenc_plan_ptr->entries_offset) ||
664  shot >= phaseenc_plan_ptr->num_shots ||
665  encode < 0 || encode >= phaseenc_plan_ptr->encodes_per_shot) {
666  return;
667  }
668 
669 
670  const int shot_start_index = phaseenc_plan_ptr->entries_offset - 1 + phaseenc_plan_ptr->encodes_per_shot * shot;
671 
672  _phaseencoding_coord_pool.entries[shot_start_index + encode].ky = ky;
673  _phaseencoding_coord_pool.entries[shot_start_index + encode].kz = kz;
674 }
int num_shots
Definition: KSFoundation.h:1789
int is_cleared_on_tgt
Definition: KSFoundation_common.c:573
uint32_t entries_offset
Definition: KSFoundation.h:1790
#define KS_NOTSET
Definition: KSFoundation.h:115
struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool
Definition: KSFoundation_common.c:577
s16 ky
Definition: KSFoundation.h:1750
int encodes_per_shot
Definition: KSFoundation.h:1788
KS_PHASEENCODING_COORD * entries
Definition: KSFoundation_common.c:571
s16 kz
Definition: KSFoundation.h:1751
uint32_t epoch
Definition: KSFoundation.h:1792
uint32_t epoch
Definition: KSFoundation_common.c:572

◆ ks_create_suffixed_description()

void ks_create_suffixed_description ( char *const  out,
const char *const  prefix,
const char *const  suffix,
  ... 
)
679  {
680  char suffix_complete[1000];
681  va_list args;
682  va_start(args, suffix);
683  vsprintf(suffix_complete, suffix, args);
684  va_end(args);
685  if ((strlen(prefix) + strlen(suffix_complete)) > KS_DESCRIPTION_LENGTH) {
686  KS_THROW("Description string (prefix \"%s\", suffix \"%s\") does not fit into a KS_DESCRIPTION (%d%+d > %d)", prefix, suffix_complete, strlen(prefix), strlen(suffix_complete), KS_DESCRIPTION_LENGTH);
687  }
688 #if EPIC_RELEASE > 29 || (EPIC_RELEASE == 29 && EPIC_SUBRELEASE == 1)
689  snprintf(out, KS_DESCRIPTION_LENGTH, "%s%s", prefix, suffix_complete);
690 #else
691  int num_to_print = KS_DESCRIPTION_LENGTH - strlen(prefix);
692  num_to_print = IMin(2, num_to_print, strlen(suffix_complete));
693  sprintf(out, "%s%.*s", prefix, num_to_print, suffix_complete);
694 #endif
695 }
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_phaseencoding_print()

void ks_phaseencoding_print ( const KS_PHASEENCODING_PLAN phaseenc_plan_ptr)

Print out KS_PHASEENCODING_PLAN to a text file

In SIM (WTools), a file ks_phaseencodingtable.txt will be generated in the current directory On HW (MR scanner), the same file will be located in /usr/g/mrraw

Parameters
[in]phaseenc_plan_ptrPointer to KS_PHASEENCODING_PLAN
Returns
void
700  {
702  int shot, encode;
703 #ifdef IPG
704 #define PHASEENCODING_PLAN_FILENAME "ks_phaseencodingtable.tgt.txt"
705 #else
706 #define PHASEENCODING_PLAN_FILENAME "ks_phaseencodingtable.host.txt"
707 #endif
708 
709 #ifdef PSD_HW
710  FILE *fp = fopen("/usr/g/mrraw/" PHASEENCODING_PLAN_FILENAME, "w");
711 #else
712  FILE *fp = fopen("./" PHASEENCODING_PLAN_FILENAME, "w");
713 #endif
714 
715  fprintf(fp, "numshots (vertical): %d, etl (horizontal): %d\n\n", phaseenc_plan_ptr->num_shots, phaseenc_plan_ptr->encodes_per_shot);
716 
717  if (phaseenc_plan_ptr->encodes_per_shot == KS_NOTSET) {
718  fclose(fp);
719  return; /* we haven't set it up yet */
720  }
721 
722  for (shot = 0; shot < phaseenc_plan_ptr->num_shots; shot++) {
723  for (encode = 0; encode < phaseenc_plan_ptr->encodes_per_shot; encode++) {
724  coord = ks_phaseencoding_get(phaseenc_plan_ptr, encode, shot);
725  if (coord.ky != KS_NOTSET) {
726  fprintf(fp, "[%03d", coord.ky);
727  } else {
728  fprintf(fp, "[***");
729  }
730  if (coord.kz != KS_NOTSET) {
731  fprintf(fp, ",%03d] ", coord.kz);
732  } else {
733  fprintf(fp, ",***] ");
734  }
735  }
736  fprintf(fp,"\n");
737  }
738 
739  fclose(fp);
740 
741 }
#define KS_INIT_PHASEENCODING_COORD
Definition: KSFoundation.h:306
int num_shots
Definition: KSFoundation.h:1789
#define KS_NOTSET
Definition: KSFoundation.h:115
s16 ky
Definition: KSFoundation.h:1750
Struct holding a 3D k-space phase encoding location (ky,kz)
Definition: KSFoundation.h:1749
int encodes_per_shot
Definition: KSFoundation.h:1788
#define PHASEENCODING_PLAN_FILENAME
s16 kz
Definition: KSFoundation.h:1751
KS_PHASEENCODING_COORD ks_phaseencoding_get(const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int encode, int shot)
Get [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given encode and shot
Definition: KSFoundation_common.c:597

◆ ks_phaseencoding_alloc()

STATUS ks_phaseencoding_alloc ( KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
int  etl,
int  num_shots 
)

Reallocate memory for KS_PHASEENCODING_PLAN entries

For every (and custom) ks_phaseencoding_generate_** functions, this function must be called before ks_phaseencoding_set() so that there is memory allocataed for the array of KS_PHASEENCODING_COORD

Parameters
[in]phaseenc_plan_ptrPointer to KS_PHASEENCODING_PLAN
[in]etlThe number of acquisition window in the pulse sequence, or echo train length (ETL)
[in]num_shotsNumber of shots (i.e. how many times the sequence is played out per slice). For 3D, shot is over both ky and kz
Returns
void
746  {
747  int i;
748  if (_phaseencoding_coord_pool.size <= 0) {
749  return KS_THROW("Phase encoding memory pool has not been allocated. Did you forget to call ks_phaseencoding_memorypool_init() ?");
750  }
751  if (!phaseenc_plan_ptr) {
752  return ks_error("%s: phaseenc_plan_ptr is NULL", __FUNCTION__);
753  }
754 
755  if (etl < 1 || num_shots < 1) {
756  return KS_THROW("Both etl (%d) and num_shots (%d) needs to be positive", etl, num_shots);
757  }
758 
759  const uint64_t size = etl * num_shots;
760 
762  return KS_THROW("Memory pool full (size is %llu), adjust its size to be at least %llu entries"
763  " with ks_phaseencoding_memorypool_init()",
766  }
767 
768  phaseenc_plan_ptr->entries_offset = _phaseencoding_coord_pool.used_size + 1;
770 
771  phaseenc_plan_ptr->encodes_per_shot = etl;
772  phaseenc_plan_ptr->num_shots = num_shots;
773  phaseenc_plan_ptr->epoch = _phaseencoding_coord_pool.epoch;
774 
775  for (i = 0; i < etl * num_shots; i++) {
776  _phaseencoding_coord_pool.entries[phaseenc_plan_ptr->entries_offset - 1 + i].ky = KS_NOTSET;
777  _phaseencoding_coord_pool.entries[phaseenc_plan_ptr->entries_offset - 1 + i].kz = KS_NOTSET;
778  }
779 
780  return SUCCESS;
781 }
int num_shots
Definition: KSFoundation.h:1789
uint32_t entries_offset
Definition: KSFoundation.h:1790
#define KS_NOTSET
Definition: KSFoundation.h:115
struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool
Definition: KSFoundation_common.c:577
uint64_t size
Definition: KSFoundation_common.c:569
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
s16 ky
Definition: KSFoundation.h:1750
int encodes_per_shot
Definition: KSFoundation.h:1788
KS_PHASEENCODING_COORD * entries
Definition: KSFoundation_common.c:571
s16 kz
Definition: KSFoundation.h:1751
uint32_t epoch
Definition: KSFoundation.h:1792
uint64_t used_size
Definition: KSFoundation_common.c:570
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
uint32_t epoch
Definition: KSFoundation_common.c:572

◆ ks_phaseencoding_isvalid()

int ks_phaseencoding_isvalid ( const KS_PHASEENCODING_PLAN phaseenc_plan_ptr)

ADDTITLEHERE

ADDDESCHERE

Parameters
phaseenc_plan_ptrADDTEXTHERE
Return values
intADDTEXTHERE
786  {
787 
788  const int valid_epoch =
789 #ifndef IPG
790  phaseenc_plan_ptr->epoch == _phaseencoding_coord_pool.epoch;
791 #else
792  1;
793 #endif
794 
795  return (!phaseenc_plan_ptr &&
796  phaseenc_plan_ptr->encodes_per_shot > 0 &&
797  phaseenc_plan_ptr->num_shots > 0 &&
798  valid_epoch);
799 }
int num_shots
Definition: KSFoundation.h:1789
struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool
Definition: KSFoundation_common.c:577
int encodes_per_shot
Definition: KSFoundation.h:1788
uint32_t epoch
Definition: KSFoundation.h:1792
uint32_t epoch
Definition: KSFoundation_common.c:572

◆ ks_fse_calcecho()

STATUS ks_fse_calcecho ( double *  bestecho,
double *  optecho,
int *  nacqlines_to_kspacecenter,
const KS_PHASER *const  pe,
KS_PF_EARLYLATE  pf_direction,
int  TE,
int  etl,
int  esp 
)

Calculates the ETL index corresponding the desired TE given a KS_PHASER object and echo spacing

Given the KS_PHASER object used in the FSE train (containing res and partial ky Fourier info), the desired effective echo time (TE [us]), the echo train length (etl) and the echo spacing between consecutive echoes (esp [us]), this function calculates two echo indices:

  • bestecho: is the 0-based index corresponding to the echo in the FSE train that should be placed in the center of k-space, i.e. the echo that most closely matches the desired TE. If bestecho is an integer value (although it is in double format), the data acquired for this echo should straddle the k-space center. bestecho can also be an interger + 0.5, indicating that there are two echo indices that should be placed around the k-space center. For example, floor(bestecho) corresponds to the echo index that should be placed just below the k-space center and ceil(bestecho) corresponds to the echo index that should be placed just above the k-space center. I.e. when bestecho = *.5, no single echo index will straddle the k-space center, and the k-space line located at ky position +0.5 will come from data acquired from echo #[floor(bestecho)] and ky position -0.5 correspondingly from echo #[ceil(bestecho)].
  • optecho: is the 0-based index corresponding to an ideal TE choice that would allow the data from the echoes in the FSE train to be placed out linearly each time. Doing so will reduce ghosting and T2 blurring. Hence, optecho ignores the input TE value here, but the calling function can use this information to determine k-space acquisition order, but also to suggest a TE (optecho * esp) that would result in optimal image quality for the chosen ETL.
Parameters
[out]bestechoPointer to the echo number in the train that should be placed at the center of k-space given the current ETL and ESP
[out]optechoPointer to the optimal echo number in the train that would allow k-space to be sampled linearly (to reduce T2-blurring and ghosting)
[out]nacqlines_to_kspacecenterPointer to a an integer with the number of k-space lines until center
[in]pePointer to a KS_PHASER
[in]pf_directionShould be either KS_PF_EARLY or KS_PF_LATE (applies to partial Fourier in ky to set if k-space center should be acquired early or late in the EPI train. Has no effect for full ky Fourier)
[in]TE(Echo Time in [us])
[in]etl(EchoTrain Length)
[in]esp(Echo Spacing in [us])
Return values
STATUSSUCCESS or FAILURE
804  {
805  int numshots, i;
806  int nacqlines_fullside, nacqlines_pfside;
807  double numshots_double;
808 
809  if (etl < 1) {
810  return ks_error("%s: ETL (arg 5) must be at least 1", __FUNCTION__);
811  }
812  if (pe->numlinestoacq < 1) {
813  return ks_error("%s: field '.numlinestoacq' in 3rd arg must be at least 1", __FUNCTION__);
814  }
815  if (etl > pe->numlinestoacq) {
816  return ks_error("%s: ETL (arg 5) cannot exceed number of lines to acquire", __FUNCTION__);
817  }
818  if (esp <= 0) {
819  return ks_error("%s: ESP (arg 6) must be larger than 1", __FUNCTION__);
820  }
821  if (pe->nover < 0) {
822  return ks_error("%s: Only top half of k-space supported for pFourier", __FUNCTION__);
823  }
824 
825  /* Number of shots */
826  numshots = CEIL_DIV(pe->numlinestoacq, etl);
827  numshots_double = (double) pe->numlinestoacq / (double) etl;
828 
829  /* index 'i' will stop incrementing as we pass the center of k-space (i=0 is top row of k-space).
830  Note that 'i' will be much less that res/2 (after break) even for full Fourier when
831  we have R > 1 and acslines */
832  for (i = 0; i < pe->numlinestoacq - 1; i++) {
833  if (((pe->res - 1) / 2.0 - pe->linetoacq[i]) < 0)
834  break;
835  }
836 
837  nacqlines_fullside = i;
838  nacqlines_pfside = pe->numlinestoacq - i; /* which is equal or almost equal to nacqlines_fullside for full Fourier */
839 
840  if (pf_direction == KS_PF_EARLY) {
841  *nacqlines_to_kspacecenter = nacqlines_pfside;
842  } else {
843  *nacqlines_to_kspacecenter = nacqlines_fullside;
844  }
845 
846 
847  if (etl % 2) {
848  /* etl is odd. The optimal echo will straddle around the center of k-space */
849 
850  if (optecho != NULL)
851  *optecho = ceil((((double) *nacqlines_to_kspacecenter + numshots_double / 2.0) / numshots_double) - 1e-5); /* integer value since ETL is odd */
852 
853  if (bestecho != NULL) {
854  *bestecho = floor((double) TE / (double) esp + 0.5); /* integer */
855  if (*bestecho < 1)
856  *bestecho = 1;
857  if (*bestecho > etl)
858  *bestecho = etl;
859  }
860 
861  } else {
862  /* etl is even. The optimal two echoes will be placed above and below k-space center, respectively */
863 
864  if (optecho != NULL)
865  *optecho = ceil((double) *nacqlines_to_kspacecenter / numshots_double) + 0.5; /* half-integer value since ETL is even */
866 
867  if (bestecho != NULL) {
868  if (etl == 2) {
869  /* special case for ETL = 2 */
870  if (TE < 1.25 * esp)
871  *bestecho = 1; /* 1st echo straddling around k-space center */
872  else if (TE < 1.75 * esp)
873  *bestecho = 1.5; /* 1st/end echo below/above k-space center */
874  else
875  *bestecho = 2; /* 2nd echo straddling around k-space center */
876  } else {
877  *bestecho = floor((double) TE / (double) esp) + 0.5; /* half-integer */
878  if (*bestecho <= 1.5)
879  *bestecho = 1; /* minTE, back to integer 'bestecho' for center-out encoding */
880  if (*bestecho >= (etl - 0.5))
881  *bestecho = etl; /* max TE, back to integer 'bestecho' for out-center encoding */
882  }
883  }
884 
885  }
886 
887  if (optecho != NULL) {
888  /* Partial Fourier MinTE case, regardless if ETL is even or odd */
889  if ((pe->nover > 0) && (*nacqlines_to_kspacecenter <= numshots / 2))
890  *optecho = 1;
891 
892  /* Partial Fourier MaxTE case, regardless if ETL is even or odd */
893  if ((pe->nover < 0) && (*nacqlines_to_kspacecenter >= (pe->linetoacq[i] - numshots / 2)))
894  *optecho = etl;
895  }
896 
897  return SUCCESS;
898 
899 } /* ks_fse_calcecho() */
int res
Definition: KSFoundation.h:1721
int numlinestoacq
Definition: KSFoundation.h:1727
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int linetoacq[KS_MAX_PHASEDYN]
Definition: KSFoundation.h:1728
Definition: KSFoundation.h:386
int nover
Definition: KSFoundation.h:1722

◆ ks_phaseencoding_generate_simple()

STATUS ks_phaseencoding_generate_simple ( KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
const char *const  desc,
KS_PHASER phaser,
KS_PHASER zphaser,
int  encodes_per_shot 
)

Generation of a KS_PHASEENCODING_PLAN for any sequence having only one echo (or same phasenc step for all echoes)

For sequences having only one echo (ETL=1) or having more echoes but where all echoes have the same ky/kz coordinate, there is no special logic necessary regarding which order to traverse the ky-kz plane over shots.

Parallel imaging in ky (and kz for 3D), with acs lines, is set up as usual using ks_eval_phaser() first before calling this function. For 2D, the phase encoding object (KS_PHASER) is then passed in as the 2nd arg to this function, with the 3rd arg being NULL. For 3D, both KS_PHASERs are passed in as 2nd and 3rd args, each with their own acceleration and resolution. For both 2D and 3D, the KS_PHASEENCODING_PLAN will be set up based on the KS_PHASER(s), but for 2D all entries.kz in the KS_PHASEENCODING_PLAN will be KS_NOTSET (-1)

Parameters
[out]phaseenc_plan_ptrPointer to KS_PHASEENCODING_PLAN
[in]descA description (text string) of the KS_PHASEENCODING_PLAN object. This description is used in the psd plot.
[in]phaserPointer to the KS_PHASER object for the first (3D) / only (2D) phase encoding direction
[in]zphaserPointer to the KS_PHASER object for the second phase encoding direction (NULL for 2D)
[in]encodes_per_shotHow many readouts are acquired for each shot
Returns
void
902  {
903  int etl = encodes_per_shot;
904  int num_shots;
905  int shot, ky, kz;
906  int encode;
907  STATUS status;
908 
909  strncpy(phaseenc_plan_ptr->description, desc, KS_DESCRIPTION_LENGTH - 1);
910  phaseenc_plan_ptr->description[KS_DESCRIPTION_LENGTH - 1] = 0;
911 
912  /* don't allow empty description or a description with leading space */
913  if (phaseenc_plan_ptr->description == NULL || phaseenc_plan_ptr->description[0] == ' ') {
914  return ks_error("%s: description of phase encoding plan (2nd arg) cannot be NULL or leading space", __FUNCTION__);
915  }
916 
917  num_shots = (zphaser != NULL) ? (phaser->numlinestoacq * zphaser->numlinestoacq) : phaser->numlinestoacq;
918 
919  status = ks_phaseencoding_alloc(phaseenc_plan_ptr, etl, num_shots);
920  KS_RAISE(status);
921 
922  shot = 0;
923  if (zphaser != NULL) { /* 3D */
924  for (kz = 0; kz < zphaser->numlinestoacq; kz++) {
925  for (ky = 0; ky < phaser->numlinestoacq / encodes_per_shot; ky++) {
926  for (encode = 0; encode < encodes_per_shot; encode++) {
927  ks_phaseencoding_set(phaseenc_plan_ptr, encode, shot++, phaser->linetoacq[ky], zphaser->linetoacq[kz]);
928  }
929  }
930  }
931  } else { /* 2D */
932  for (ky = 0; ky < phaser->numlinestoacq; ky++) {
933  ks_phaseencoding_set(phaseenc_plan_ptr, 0, shot++, phaser->linetoacq[ky], KS_NOTSET);
934  }
935  }
936 
937  return SUCCESS;
938 }
void ks_phaseencoding_set(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int encode, int shot, int ky, int kz)
Set [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given encode and shot
Definition: KSFoundation_common.c:653
#define KS_NOTSET
Definition: KSFoundation.h:115
int numlinestoacq
Definition: KSFoundation.h:1727
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int linetoacq[KS_MAX_PHASEDYN]
Definition: KSFoundation.h:1728
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
KS_DESCRIPTION description
Definition: KSFoundation.h:1791
#define KS_RAISE(status)
Definition: KSFoundation.h:190
STATUS ks_phaseencoding_alloc(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int etl, int num_shots)
Reallocate memory for KS_PHASEENCODING_PLAN entries
Definition: KSFoundation_common.c:746

◆ ks_phaseencoding_generate_simple_ellipse()

STATUS ks_phaseencoding_generate_simple_ellipse ( KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
const char *const  desc,
KS_PHASER phaser,
KS_PHASER zphaser 
)

Generation of a KS_PHASEENCODING_PLAN for any sequence having only one echo (or same phasenc step for all echoes) - ellipse version

For sequences having only one echo (ETL=1) or having more echoes but where all echoes have the same ky/kz coordinate, there is no special logic necessary regarding which order to traverse the ky-kz plane over shots.

Parallel imaging in ky (and kz for 3D), with acs lines, is set up as usual using ks_eval_phaser() first before calling this function. For 2D, the phase encoding object (KS_PHASER) is then passed in as the 2nd arg to this function, with the 3rd arg being NULL. For 3D, both KS_PHASERs are passed in as 2nd and 3rd args, each with their own acceleration and resolution. For both 2D and 3D, the KS_PHASEENCODING_PLAN will be set up based on the KS_PHASER(s), but for 2D all entries.kz in the KS_PHASEENCODING_PLAN will be KS_NOTSET (-1). This function will create an elliptical k-space in ky/kz. For rectangular k-space, use ks_phaseencoding_generate_simple.

Parameters
[out]phaseenc_plan_ptrPointer to KS_PHASEENCODING_PLAN
[in]descA description (text string) of the KS_PHASEENCODING_PLAN object. This description is used in the psd plot.
[in]phaserPointer to the KS_PHASER object for the first (3D) / only (2D) phase encoding direction
[in]zphaserPointer to the KS_PHASER object for the second phase encoding direction (NULL for 2D)
Returns
void
943  {
944  int etl = 1;
945  int ky, kz, i;
946  float radius_ky, radius_kz, center_ky, center_kz;
947  float x1, x2;
948  STATUS status;
949  int inellipse; /* Number of ky,kz points in the ellipse */
950 
951  strncpy(phaseenc_plan_ptr->description, desc, KS_DESCRIPTION_LENGTH - 1);
952  phaseenc_plan_ptr->description[KS_DESCRIPTION_LENGTH - 1] = 0;
953 
954  /* don't allow empty description or a description with leading space */
955  if (phaseenc_plan_ptr->description == NULL || phaseenc_plan_ptr->description[0] == ' ') {
956  return ks_error("%s: description of phase encoding plan (2nd arg) cannot be NULL or leading space", __FUNCTION__);
957  }
958 
959  if (zphaser == NULL) { /* We can't do ellipse k-space coverage (ky,kz) in 2D */
960  return ks_phaseencoding_generate_simple(phaseenc_plan_ptr, desc, phaser, NULL, 1);
961  }
962 
963 
964  radius_ky = phaser->res/2.0;
965  center_ky = phaser->res/2.0 - 0.5;
966 
967  radius_kz = zphaser->res/2.0;
968  center_kz = zphaser->res/2.0 - 0.5;
969 
970  for (i = 0; i < 2; i++) { /* i = 0: check how many. i = 1: set up coords */
971 
972  if (i == 1) {
973  status = ks_phaseencoding_alloc(phaseenc_plan_ptr, etl, inellipse);
974  KS_RAISE(status);
975  }
976  inellipse = 0;
977 
978  for (kz = 0; kz < zphaser->numlinestoacq; kz++) {
979  for (ky = 0; ky < phaser->numlinestoacq; ky++) {
980  x1 = (phaser->linetoacq[ky] - center_ky) / (float) radius_ky;
981  x2 = (zphaser->linetoacq[kz] - center_kz) / (float) radius_kz;
982  if ((x1 * x1 + x2 * x2) <= 1.0) {
983  if (i == 1) {
984  ks_phaseencoding_set(phaseenc_plan_ptr, 0, inellipse, phaser->linetoacq[ky], zphaser->linetoacq[kz]);
985  }
986  inellipse++;
987  }
988  } /* ky */
989  } /* kz */
990 
991  } /* i */
992 
993  return SUCCESS;
994 }
void ks_phaseencoding_set(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int encode, int shot, int ky, int kz)
Set [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given encode and shot
Definition: KSFoundation_common.c:653
int res
Definition: KSFoundation.h:1721
int numlinestoacq
Definition: KSFoundation.h:1727
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
STATUS ks_phaseencoding_generate_simple(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, const char *const desc, KS_PHASER *phaser, KS_PHASER *zphaser, int encodes_per_shot)
Generation of a KS_PHASEENCODING_PLAN for any sequence having only one echo (or same phasenc step for...
Definition: KSFoundation_common.c:902
int linetoacq[KS_MAX_PHASEDYN]
Definition: KSFoundation.h:1728
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
KS_DESCRIPTION description
Definition: KSFoundation.h:1791
#define KS_RAISE(status)
Definition: KSFoundation.h:190
STATUS ks_phaseencoding_alloc(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int etl, int num_shots)
Reallocate memory for KS_PHASEENCODING_PLAN entries
Definition: KSFoundation_common.c:746

◆ ks_phaseencoding_generate_epi()

STATUS ks_phaseencoding_generate_epi ( KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
const char *const  desc,
const KS_EPI epitrain,
const ks_enum_epiblipsign  blipsign,
const KS_PF_EARLYLATE  pf_direction,
const int  numileavestoacq,
ks_enum_sweep_order  sweep_order,
int  numsegments,
const int  caipi_delta 
)

EPI: Makes a KS_PHASEENCODING_PLAN suitable for 2D or 3D epi

The etl is the number of readouts in the EPI train, derived from the phaser. The number of ky shots is also given by the phaser, while the number of kz shots is given by zphaser. Any partial fourier is handled by the phasers, and acceleration and acs lines in the z direction is handled by zphaser. For 3D EPI, the number of shots in the phase encoding plan will be the product of the number of shots in the ky direction and the number of kz lines to acquire.

Each shot will be played out in a single kz plane. The shot order will be linear in ky and kz. The ky shots will be in the inner loop, unless kzshotsfirst is TRUE.

Parameters
[out]phaseenc_plan_ptrPointer to the phase encoding plan
[in]descA description (text string) of the KS_PHASEENCODING_PLAN object. This description is used in the psd plot.
[in]epitrainPointer to a KS_EPI
[in]blipsignShould be either KS_EPI_POSBLIPS or KS_EPI_NEGBLIPS. Determines distortion direction.
[in]pf_directionShould be either KS_PF_EARLY or KS_PF_LATE (applies to partial Fourier in ky to set if k-space center should be acquired early or late in the EPI train. Has no effect for full ky Fourier)
[in]numileavestoacqNumber of ky interleaves to play. Must be within 1-numInterleaves and an integer factor of numInterleaves. Set =1 for single-shot EPI. Set to phaser.R for full multi-shot EPI.
[in]sweep_orderSweep order for shots as defined in KSFoundation.h (ks_enum_sweep_order). Has no effect on distortions.
[in]numsegmentsNumber of kz encodes to play
[in]caipi_deltaUse CAIPIRINHA sampling pattern (affects 3D epi only)
Return values
STATUSSUCCESS or FAILURE
999  {
1000 
1001  int numileaves = epitrain->blipphaser.R;
1002 
1003  if (epitrain->blipphaser.numlinestoacq < 2 && (numileaves != epitrain->blipphaser.res)) {
1004  return ks_error("%s: field '.numlinestoacq' of epitrain->blipphaser must be at least 2, not %d", __FUNCTION__, epitrain->blipphaser.numlinestoacq);
1005  }
1006 
1007  strncpy(phaseenc_plan_ptr->description, desc, KS_DESCRIPTION_LENGTH - 1);
1008  phaseenc_plan_ptr->description[KS_DESCRIPTION_LENGTH - 1] = 0;
1009 
1010  /* don't allow empty description or a description with leading space */
1011  if (phaseenc_plan_ptr->description == NULL || phaseenc_plan_ptr->description[0] == ' ') {
1012  return ks_error("%s: description of phase encoding plan (2nd arg) cannot be NULL or leading space", __FUNCTION__);
1013  }
1014 
1015  int readout, shot, interleaf, kyview, kzview, kzind;
1016  int etl, numfullsegments, numshotsforsegment, totalnumshots, i;
1017  int shift;
1018  STATUS status;
1019 
1020  /* Number of shots (2D) */
1021  if (numileavestoacq < 1 || numileavestoacq > numileaves || (numileaves % numileavestoacq != 0)) {
1022  return ks_error("%s: numileavestoacq (=%d) must be in range 1-blipphaser.R and an integer factor of blipphaser.R (=%d)", __FUNCTION__, numileavestoacq, numileaves);
1023  }
1024 
1025  /* Number of segments (3D) */
1026  if (epitrain->zphaser.res != KS_NOTSET && (numsegments < 1 || numsegments > epitrain->zphaser.numlinestoacq)) {
1027  return ks_error("%s: numsegments (=%d) must be in range 1-zphaser.numlinestoacq (=%d)", __FUNCTION__, numsegments, epitrain->zphaser.numlinestoacq);
1028  }
1029 
1030  /* Number of readouts per EPI train (etl) */
1031  etl = epitrain->blipphaser.numlinestoacq;
1032 
1033  /* Check number of kz segments and how many should be fully sampled (controlled by zphaser.nacslines) */
1034  if (epitrain->zphaser.res == KS_NOTSET) { /* 2D epi */
1035  numsegments = 1;
1036  numfullsegments = (numileavestoacq == numileaves);
1037  } else { /* 3D epi */
1038  if (epitrain->zphaser.R == 1) {
1039  numfullsegments = epitrain->zphaser.nacslines; /* special interpretation for zR=1 */
1040  } else { /* zR > 1 */
1041  if (epitrain->zphaser.nacslines > 0) {
1042  numfullsegments = 1; /* initialize */
1043  for (kzind = 1; kzind < numsegments; kzind++) {
1044  if (abs(epitrain->zphaser.linetoacq[kzind]-epitrain->zphaser.linetoacq[kzind-1])==1) {
1045  numfullsegments++;
1046  }
1047  }
1048  } else { /* no kz "acs lines" */
1049  numfullsegments = 0;
1050  }
1051  }
1052  }
1053 
1054  /* allocate KS_PHASEENCODING_PLAN table (all entries will be initialized to KS_NOTSET) */
1055  totalnumshots = numfullsegments * numileaves + (numsegments-numfullsegments) * numileavestoacq;
1056  status = ks_phaseencoding_alloc(phaseenc_plan_ptr, etl, totalnumshots);
1057  KS_RAISE(status);
1058 
1059  shot = 0; /* initialize */
1060  int ileaves[numileaves]; /* interleaf indices */
1061 
1062  for (kzind = 0; kzind < numsegments; kzind++) {
1063  kzview = (epitrain->zphaser.numlinestoacq > 0) ? epitrain->zphaser.linetoacq[kzind] : KS_NOTSET;
1064 
1065  if (kzview != KS_NOTSET && abs(kzview*2 - (epitrain->zphaser.res-1)) <= numfullsegments) {
1066  numshotsforsegment = numileaves;
1067  } else {
1068  numshotsforsegment = numileavestoacq;
1069  }
1070 
1071  if (sweep_order == KS_SWEEP_ORDER_TOP_DOWN) {
1072  for (i = 0; i < numshotsforsegment; i++) {
1073  ileaves[i] = i;
1074  }
1075  } else if (sweep_order == KS_SWEEP_ORDER_BOTTOM_UP) {
1076  for (i = 0; i < numshotsforsegment; i++) {
1077  ileaves[numshotsforsegment - i - 1] = i;
1078  }
1079  } else if (sweep_order == KS_SWEEP_ORDER_OUTSIDE_IN) {
1080  for (i = 0; i < numshotsforsegment; i++) {
1081  ileaves[i] = (i % 2) ? numshotsforsegment - 1 - i/2 : i/2;
1082  }
1083  } else if (sweep_order == KS_SWEEP_ORDER_CENTER_OUT) {
1084  for (i = 0; i < numshotsforsegment; i++) {
1085  ileaves[numshotsforsegment - i - 1] = (i % 2) ? numshotsforsegment - 1 - i/2 : i/2;
1086  }
1087  }
1088  for (i = 0; i < numshotsforsegment; i++) {
1089  interleaf = ileaves[i];
1090  for (readout = 0; readout < etl; readout++) {
1091  shift = interleaf * (numileaves / numshotsforsegment); /* interleaf shift */
1092  shift = (shift + (kzview/epitrain->zphaser.R) * caipi_delta) % numileaves; /* CAIPIRINHA shift */
1093  if ((epitrain->blipphaser.nover != 0) && (((pf_direction == KS_PF_LATE) && (blipsign == KS_EPI_POSBLIPS)) || ((pf_direction == KS_PF_EARLY) && (blipsign == KS_EPI_NEGBLIPS))) ) {
1094  /* shift kspace area to lower half */
1095  shift += epitrain->blipphaser.res - (epitrain->blipphaser.res/2 + epitrain->blipphaser.nover);
1096  }
1097  if (blipsign == KS_EPI_NEGBLIPS) {
1098  kyview = epitrain->blipphaser.linetoacq[readout] + shift; /* admittedly, .linetoacq[] has lost its role a bit for EPI with all shifting we do */
1099  } else if (blipsign == KS_EPI_POSBLIPS) {
1100  kyview = epitrain->blipphaser.linetoacq[(etl - 1) - readout] + shift; /* admittedly, .linetoacq[] has lost its role a bit for EPI with all shifting we do */
1101  } else if (blipsign == KS_EPI_NOBLIPS) {
1102  kyview = KS_NOTSET;
1103  kzview = KS_NOTSET;
1104  } else {
1105  return ks_error("%s: blipsign must be KS_EPI_POSBLIPS or KS_EPI_NEGBLIPS, not %d", __FUNCTION__, blipsign);
1106  }
1107  ks_phaseencoding_set(phaseenc_plan_ptr, readout, shot, kyview, kzview);
1108  } /* readout */
1109  shot++;
1110  } /* interleaf */
1111  } /* kzind */
1112 
1113  return SUCCESS;
1114 
1115 } /* ks_phaseencoding_generate_epi() */
void ks_phaseencoding_set(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int encode, int shot, int ky, int kz)
Set [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given encode and shot
Definition: KSFoundation_common.c:653
int R
Definition: KSFoundation.h:1723
int res
Definition: KSFoundation.h:1721
Definition: KSFoundation.h:388
int nacslines
Definition: KSFoundation.h:1724
Definition: KSFoundation.h:2083
#define KS_NOTSET
Definition: KSFoundation.h:115
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
int numlinestoacq
Definition: KSFoundation.h:1727
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
KS_PHASER zphaser
Definition: KSFoundation.h:1938
int linetoacq[KS_MAX_PHASEDYN]
Definition: KSFoundation.h:1728
Definition: KSFoundation.h:386
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
Definition: KSFoundation.h:2084
KS_DESCRIPTION description
Definition: KSFoundation.h:1791
Definition: KSFoundation.h:2081
Definition: KSFoundation.h:2082
Definition: KSFoundation.h:2330
#define KS_RAISE(status)
Definition: KSFoundation.h:190
int nover
Definition: KSFoundation.h:1722
Definition: KSFoundation.h:2330
Definition: KSFoundation.h:2330
STATUS ks_phaseencoding_alloc(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int etl, int num_shots)
Reallocate memory for KS_PHASEENCODING_PLAN entries
Definition: KSFoundation_common.c:746

◆ ks_wave_compute_params()

void ks_wave_compute_params ( KS_WAVE *const  wave)

Fills the members of the KS_WAVE sequence object

max_amp, min_amp, abs_max_amp, abs_max_slew, area

Parameters
[in]waveKS_WAVE object
Return values
void
1123  {
1124  /* pre-compute fields: max_amp, min_amp, abs_max_amp, abs_max_slew, area */
1125  wave->abs_max_slew = 0.0;
1126  float val = wave->waveform[0];
1127  wave->area = val;
1128  wave->min_amp = val;
1129  wave->max_amp = val;
1130 
1131  int i;
1132  for(i = 1; i < wave->res; i++) {
1133  val = wave->waveform[i];
1134  wave->area += val;
1135  if (val < wave->min_amp) {
1136  wave->min_amp = val;
1137  }
1138  if (val > wave->max_amp) {
1139  wave->max_amp = val;
1140  }
1141  float slew = fabs(val - wave->waveform[i-1]);
1142  if (slew > wave->abs_max_slew) {
1143  wave->abs_max_slew = slew;
1144  }
1145  }
1146  float dwell = (float)wave->duration / (float)wave->res;
1147  wave->abs_max_slew /= dwell;
1148  wave->area *= dwell;
1149  /* maximum amplitude in wave (in its own units, like e.g. [G/cm] or [degrees]) */
1150  wave->abs_max_amp = (fabs(wave->min_amp) > fabs(wave->max_amp)) ? fabs(wave->min_amp) : fabs(wave->max_amp);
1151 }
float abs_max_slew
Definition: KSFoundation.h:760
float min_amp
Definition: KSFoundation.h:758
int32_t i
Definition: KSFoundation_tgt.c:1694
float area
Definition: KSFoundation.h:757
float abs_max_amp
Definition: KSFoundation.h:761
float max_amp
Definition: KSFoundation.h:759
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748
int duration
Definition: KSFoundation.h:747

◆ ks_wave_res()

int ks_wave_res ( const KS_WAVE wave)

Returns the number of samples in a KS_WAVE sequence object

Parameters
[in]waveKS_WAVE object
Return values
resResolution (i.e. number of samples) in the KS_WAVE object
1156  {
1157 
1158  if (wave == NULL) {
1159  ks_error("ks_wave_res: wave is NULL");
1160  return KS_NOTSET;
1161  }
1162  if (wave->description == NULL || wave->description[0] == ' ') {
1163  ks_error("ks_wave_res: wave description not initialized or has leading space");
1164  return KS_NOTSET;
1165  }
1166  if (wave->res < 2 || wave->res > KS_MAXWAVELEN) {
1167  ks_error("ks_wave_res(%s): 'res' (%d) is out of valid range [2, %d]", wave->description, wave->res, KS_MAXWAVELEN);
1168  return KS_NOTSET;
1169  }
1170  if (wave->res % 2) {
1171  ks_error("ks_wave_res(%s): 'res' (%d) must be even", wave->description, wave->res);
1172  return KS_NOTSET;
1173  }
1174 
1175  return wave->res;
1176 }
#define KS_NOTSET
Definition: KSFoundation.h:115
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
KS_DESCRIPTION description
Definition: KSFoundation.h:745
int res
Definition: KSFoundation.h:746
#define KS_MAXWAVELEN
Definition: KSFoundation.h:254

◆ ks_echotrain_get_max_kspace_index()

int ks_echotrain_get_max_kspace_index ( KS_ECHOTRAIN echotrain)

Retrieve the total number of echoes this echotrain will produce

Parameters
echotrain- A pointer to a KS_ECHOTRAIN structure that has been eval'ed
Return values
int- The maximum kspace(echo) index.
1181  {
1182  int readout;
1183  int kspace_index;
1184  int max_kspace_index = 0;
1185  int s;
1186  for(s = 0; s < echotrain->numstates; s++) {
1187  for(readout = 0; readout < echotrain->numreadouts; readout++) {
1188  kspace_index = echotrain->controls[readout].state[s].kspace_index;
1189  if (kspace_index > max_kspace_index) {
1190  max_kspace_index = kspace_index;
1191  }
1192  }
1193  }
1194  return max_kspace_index;
1195 } /* ks_echotrain_get_max_kspace_index() */
KS_READCONTROL_STATE state[KS_READCONTROL_MAXSTATE]
Definition: KSFoundation.h:2000
int kspace_index
Definition: KSFoundation.h:1971
int numreadouts
Definition: KSFoundation.h:2020
KS_READCONTROL controls[KS_MAXUNIQUE_READ]
Definition: KSFoundation.h:2015
int numstates
Definition: KSFoundation.h:2022

◆ ks_pg_echotrain_readout()

STATUS ks_pg_echotrain_readout ( KS_ECHOTRAIN echotrain,
int  readout_index,
int  echo_time,
KS_ECHOTRAIN_READOUT_TIMING timing,
KS_SEQ_CONTROL ctrl 
)

ADDTITLEHERE

1204  {
1205 
1206  STATUS status;
1207 
1208  KS_READCONTROL *control = &echotrain->controls[readout_index];
1209  const int object_index = control->pg.object_index;
1210 
1211  KS_SEQLOC loc;
1212  loc.ampscale = control->pg.ampscale;
1213  loc.board = XGRAD;
1214 
1215  switch (control->pg.read_type) {
1216  case KS_READ_TRAP: {
1217  KS_READTRAP* trap = &echotrain->readtraps[object_index];
1218  control->pg.instance_index = ks_numplaced(&trap->acq.base);
1219  /* center acq over echo */
1220  loc.pos = RDN_GRD(echo_time - trap->acq.duration / 2 - trap->acqdelay + control->pg.shift);
1221  status = ks_pg_readtrap(trap, loc, ctrl);
1222  KS_RAISE(status);
1223  timing->start = loc.pos;
1224  timing->start_acq = loc.pos + trap->acqdelay;
1225  timing->end_acq = timing->start_acq + trap->acq.duration;
1226  timing->end = loc.pos + trap->grad.duration;
1227  break;
1228  }
1229  case KS_READ_WAVE: {
1230  KS_READWAVE* wave = &echotrain->readwaves[object_index];
1231  control->pg.instance_index = ks_numplaced(&wave->acq.base);
1232  /* center acq over echo */
1233  loc.pos = RDN_GRD(echo_time - wave->acq.duration / 2 - wave->acqdelay + control->pg.shift);
1234  status = ks_pg_readwave(wave, loc, ctrl);
1235  KS_RAISE(status);
1236  timing->start = loc.pos;
1237  timing->start_acq = loc.pos + wave->acqdelay;
1238  timing->end_acq = timing->start_acq + wave->acq.duration;
1239  timing->end = loc.pos + wave->grad.duration;
1240  break;
1241  }
1242  default: {
1243  return KS_THROW("echo train cannot place undefined read type");
1244  }
1245  }
1246 
1247  return SUCCESS;
1248 }
KS_READTRAP readtraps[KS_ECHOTRAIN_MAX_TRAPS]
Definition: KSFoundation.h:2016
KS_READWAVE readwaves[KS_ECHOTRAIN_MAX_WAVES]
Definition: KSFoundation.h:2017
Wraps pulsegen information and state of each readout in an echotrain
Definition: KSFoundation.h:1998
int object_index
Definition: KSFoundation.h:1985
int pos
Definition: KSFoundation.h:463
int instance_index
Definition: KSFoundation.h:1988
float ampscale
Definition: KSFoundation.h:1987
int end
Definition: KSFoundation.h:2038
int board
Definition: KSFoundation.h:462
int end_acq
Definition: KSFoundation.h:2037
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
KS_READCONTROL_PULSEGEN pg
Definition: KSFoundation.h:2001
KS_TRAP grad
Definition: KSFoundation.h:1561
int start
Definition: KSFoundation.h:2035
KS_WAVE grad
Definition: KSFoundation.h:1604
float ampscale
Definition: KSFoundation.h:464
KS_BASE base
Definition: KSFoundation.h:839
STATUS ks_pg_readwave(KS_READWAVE *readwave, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
ADDTITLEHERE
Definition: KSFoundation_common.c:2232
KS_READ_TYPE read_type
Definition: KSFoundation.h:1984
Definition: KSFoundation.h:1960
Definition: KSFoundation.h:1959
int duration
Definition: KSFoundation.h:841
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
Composite sequence object for data readout using a trapezoid gradient
Definition: KSFoundation.h:1548
Composite sequence object for data readout during a wave (1-D resampling)
Definition: KSFoundation.h:1603
int start_acq
Definition: KSFoundation.h:2036
int acqdelay
Definition: KSFoundation.h:1608
KS_READ acq
Definition: KSFoundation.h:1549
int duration
Definition: KSFoundation.h:673
KS_READ acq
Definition: KSFoundation.h:1606
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
KS_READCONTROL controls[KS_MAXUNIQUE_READ]
Definition: KSFoundation.h:2015
int shift
Definition: KSFoundation.h:1986
STATUS ks_pg_readtrap(KS_READTRAP *readtrap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_READTRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2161
int acqdelay
Definition: KSFoundation.h:1555
int duration
Definition: KSFoundation.h:747

◆ ks_waveform_max()

float ks_waveform_max ( const KS_WAVEFORM  waveform,
int  res 
)

Returns the maximum value in a KS_WAVEFORM

Parameters
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
Return values
maxvalMaximum value
1253  {
1254  float maxv = -1.0e38;
1255  int i;
1256 
1257  if (waveform == NULL) {
1258  ks_error("ks_waveform_max: wave is NULL");
1259  return maxv;
1260  }
1261  if (res <= 0) {
1262  return maxv;
1263  }
1264 
1265  for (i = 0; i < res; i++) {
1266  if (waveform[i] > maxv)
1267  maxv = waveform[i];
1268  }
1269 
1270  return maxv;
1271 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78

◆ ks_wave_max()

float ks_wave_max ( const KS_WAVE wave)

Returns the maximum value in a KS_WAVE sequence object

Parameters
[in]waveKS_WAVE object
Return values
maxvalMaximum value
1276  {
1277  return ks_waveform_max(wave->waveform, wave->res);
1278 }
float ks_waveform_max(const KS_WAVEFORM waveform, int res)
Returns the maximum value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1253
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_min()

float ks_waveform_min ( const KS_WAVEFORM  waveform,
int  res 
)

Returns the minimum value in a KS_WAVEFORM

Parameters
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
Return values
minvalMinimum value
1283  {
1284  float minv = 1.0e38;
1285  int i;
1286 
1287  if (waveform == NULL) {
1288  ks_error("ks_waveform_min: wave is NULL");
1289  return minv;
1290  }
1291  if (res <= 0) {
1292  return minv;
1293  }
1294 
1295  for (i = 0; i < res; i++) {
1296  if (waveform[i] < minv)
1297  minv = waveform[i];
1298  }
1299 
1300  return minv;
1301 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78

◆ ks_wave_min()

float ks_wave_min ( const KS_WAVE wave)

Returns the minimum value in a KS_WAVE sequence object

Parameters
[in]waveKS_WAVE object
Return values
minvalMinimum value
1306  {
1307  return ks_waveform_min(wave->waveform, wave->res);
1308 }
int res
Definition: KSFoundation.h:746
float ks_waveform_min(const KS_WAVEFORM waveform, int res)
Returns the minimum value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1283
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_iwave_absmax()

short ks_iwave_absmax ( const KS_IWAVE  waveform,
int  res 
)

Returns the max amp of a KS_IWAVE between 0 and res

Parameters
[in]waveformKS_WAVE object
[in]resCheck up to this many samples
Return values
maximumamplitude of the waveform
1313  {
1314  short maxv = 0;
1315  int i;
1316 
1317  if (waveform == NULL) {
1318  ks_error("%s: wave is NULL", __FUNCTION__);
1319  return maxv;
1320  }
1321  if (res <= 0) {
1322  return maxv;
1323  }
1324 
1325  for (i = 0; i < res; i++) {
1326  if (abs(waveform[i]) > maxv)
1327  maxv = abs(waveform[i]);
1328  }
1329 
1330  return maxv;
1331 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78

◆ ks_waveform_absmax()

float ks_waveform_absmax ( const KS_WAVEFORM  waveform,
int  res 
)

Returns the maximum absolute value in a KS_WAVEFORM

Parameters
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
Return values
absmaxvalMaximum absolute value
1336  {
1337  float maxv = -1.0e38;
1338  int i;
1339 
1340  if (waveform == NULL) {
1341  ks_error("ks_waveform_absmax: wave is NULL");
1342  return maxv;
1343  }
1344  if (res <= 0) {
1345  return maxv;
1346  }
1347 
1348  for (i = 0; i < res; i++) {
1349  if (fabs(waveform[i]) > maxv)
1350  maxv = fabs(waveform[i]);
1351  }
1352 
1353  return maxv;
1354 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78

◆ ks_wave_absmax()

float ks_wave_absmax ( const KS_WAVE wave)

Returns the maximum absolute value in a KS_WAVE sequence object

Parameters
[in]waveKS_WAVE object
Return values
absmaxvalMaximum absolute value
1359  {
1360  return ks_waveform_absmax(wave->waveform, wave->res);
1361 }
float ks_waveform_absmax(const KS_WAVEFORM waveform, int res)
Returns the maximum absolute value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1336
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_maxslew()

float ks_waveform_maxslew ( const KS_WAVEFORM  waveform,
int  res,
int  duration,
int *  index 
)

Returns the maximum absolute value in a KS_WAVEFORM

Parameters
[in]waveformKS_WAVEFORM
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
[in]durationDuration of the waveform in us
[out]indexIndex in waveform where max slewrate is. Can be NULL if you are not interested.
Return values
absmaxvalMaximum absolute value
1366  {
1367  float maxslew = -1.0e38;
1368  int i;
1369 
1370  if (waveform == NULL) {
1371  ks_error("ks_waveform_absmax: wave is NULL");
1372  return maxslew;
1373  }
1374  if (res <= 0) {
1375  return maxslew;
1376  }
1377  float tmp = 0;
1378  for (i = 0; i < res-1; i++) {
1379  tmp = fabs(waveform[i] - waveform[i+1]);
1380  if (tmp > maxslew) {
1381  maxslew = tmp;
1382  if (index != NULL) {
1383  *index = i;
1384  }
1385  }
1386  }
1387  maxslew = maxslew*res/duration;
1388  return maxslew;
1389 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78

◆ ks_wave_maxslew()

float ks_wave_maxslew ( const KS_WAVE wave)

Returns the maximum absolute value in a KS_WAVE

Parameters
[in]waveKS_WAVE
Return values
absmaxvalMaximum absolute value
1394  {
1395  return ks_waveform_maxslew(wave->waveform, wave->res, wave->duration, NULL);
1396 }
float ks_waveform_maxslew(const KS_WAVEFORM waveform, int res, int duration, int *index)
Returns the maximum absolute value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1366
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748
int duration
Definition: KSFoundation.h:747

◆ ks_wave_time2area()

int ks_wave_time2area ( const KS_WAVE wave,
float  area_in 
)

Calculates the time in [us] that it takes a wave to achieve a certain area

Parameters
[in]wavePointer to KS_WAVE
[in]area_infloat [(G/cm) * us]
Return values
time[us]
1401  {
1402  float dwell = wave->duration / wave->res;
1403  int time_dwells = 0;
1404  float area = 0.0f;
1405  for (time_dwells = 0; time_dwells < wave->res; time_dwells++) {
1406  area += wave->waveform[time_dwells] * dwell;
1407  if (fabs(area) > area_in) { /* area_in should be positive */
1408  break;
1409  }
1410  }
1411  if (time_dwells == wave->res) {
1412  if (areSame(area_in, area)) {
1413  return wave->duration;
1414  }
1415  return KS_NOTSET;
1416  }
1417  /* Now step back and find the fractional part */
1418  area -= wave->waveform[time_dwells] * dwell;
1419  float f = fabs((area_in - fabs(area)) / (wave->waveform[time_dwells] * dwell));
1420  return (int)(((float)(time_dwells) + f) * dwell + 0.5f);
1421 }
#define areSame(a, b)
Definition: KSFoundation.h:144
#define KS_NOTSET
Definition: KSFoundation.h:115
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748
int duration
Definition: KSFoundation.h:747

◆ ks_waveform_area()

float ks_waveform_area ( const KS_WAVEFORM  waveform,
int  start,
int  end,
int  dwelltime 
)

Returns the area of a KS_WAVEFORM over a specified interval given in [us]

Parameters
[in]waveformKS_WAVEFORM (float array)
[in]start[us] Start position of area calculation in [us] (0 = start of waveform)
[in]end[us] End position of area calculation in [us] (res * dwelltime = end of waveform)
[in]dwelltime[us] of each waveform point (duration/res)
Return values
areaThe area of the KS_WAVEFORM over the specified interval in [(G/cm) * us]
1426  {
1427  int i;
1428  double area = 0;
1429  int start_indx = CEIL_DIV(start, dwelltime);
1430  int end_indx = end / dwelltime;
1431 
1432  if (waveform == NULL) {
1433  ks_error("%s: wave is NULL", __FUNCTION__);
1434  }
1435  if (start_indx < 0) {
1436  ks_error("%s: start must be >= 0", __FUNCTION__);
1437  }
1438  if (end_indx > KS_MAXWAVELEN) {
1439  ks_error("%s: end cannot exceed %d", __FUNCTION__, KS_MAXWAVELEN);
1440  }
1441 
1442  for (i = start_indx; i < end_indx; i++) {
1443  area += waveform[i];
1444  }
1445  area *= dwelltime;
1446 
1447  /* add potential partial dwell time due to CEIL_DIV, when start [us] is not divisible by dwelltime */
1448  if ((start_indx * dwelltime) > start && start_indx > 0) {
1449  area += waveform[start_indx - 1] * (((double) start_indx * dwelltime) - (double) start);
1450  }
1451 
1452  /* add potential partial dwell time due to (floor) integer division, when end [us] is not divisible by dwelltime */
1453  if ((end_indx * dwelltime) < end && (end_indx < (KS_MAXWAVELEN - 1))) {
1454  area += waveform[end_indx + 1] * ((double) end - ((double) end_indx * dwelltime));
1455  }
1456 
1457  return ((float) area);
1458 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
#define KS_MAXWAVELEN
Definition: KSFoundation.h:254

◆ ks_iwave_area()

long ks_iwave_area ( const KS_IWAVE  iwave,
int  start,
int  end,
int  dwelltime 
)

Returns the area of an interger waveform (not in use), used for exact areas

Parameters
[in]iwaveKS_IWAVE (short array)
[in]start[us] Start position of area calculation in [us] (0 = start of waveform)
[in]end[us] End position of area calculation in [us] (res * dwelltime = end of waveform)
[in]dwelltime[us] of each waveform point (duration/res)
Return values
areaThe area of the KS_IWAVE over the specified interval in aribtrary units
1463  {
1464  int i;
1465  long area = 0;
1466  int start_indx = CEIL_DIV(start, dwelltime);
1467  int end_indx = end / dwelltime;
1468 
1469  if (iwave == NULL) {
1470  ks_error("%s: wave is NULL", __FUNCTION__);
1471  }
1472  if (start_indx < 0) {
1473  ks_error("%s: start must be >= 0", __FUNCTION__);
1474  }
1475  if (end_indx > KS_MAXWAVELEN) {
1476  ks_error("%s: end cannot exceed %d", __FUNCTION__, KS_MAXWAVELEN);
1477  }
1478 
1479  for (i = start_indx; i < end_indx; i++) {
1480  area += iwave[i];
1481  }
1482  area *= dwelltime;
1483 
1484  /* add potential partial dwell time due to CEIL_DIV, when start [us] is not divisible by dwelltime */
1485  if ((start_indx * dwelltime) > start && start_indx > 0) {
1486  area += iwave[start_indx - 1] * ((start_indx * dwelltime) - start);
1487  }
1488 
1489  /* add potential partial dwell time due to (floor) integer division, when end [us] is not divisible by dwelltime */
1490  if ((end_indx * dwelltime) < end && (end_indx < (KS_MAXWAVELEN - 1))) {
1491  area += iwave[end_indx + 1] * (end - (end_indx * dwelltime));
1492  }
1493 
1494  return area;
1495 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
#define KS_MAXWAVELEN
Definition: KSFoundation.h:254

◆ ks_wave_area()

float ks_wave_area ( const KS_WAVE wave,
int  start,
int  end 
)

Returns the area of a KS_WAVE object over a specified interval given in [us]

Parameters
[in]waveKS_WAVE object
[in]start[us] Start position of area calculation in [us] (0 = start of waveform)
[in]end[us] End position of area calculation in us
Return values
areaThe area of the KS_WAVE object over the specified interval in [(G/cm) * us]
1500  {
1501  int dwelltime = wave->duration / wave->res;
1502  return ks_waveform_area(wave->waveform, start, end, dwelltime);
1503 }
float ks_waveform_area(const KS_WAVEFORM waveform, int start, int end, int dwelltime)
Returns the area of a KS_WAVEFORM over a specified interval given in [us]
Definition: KSFoundation_common.c:1426
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748
int duration
Definition: KSFoundation.h:747

◆ ks_wave_full_area()

float ks_wave_full_area ( const KS_WAVE wave)

Returns the area of a KS_WAVE object over its entire duration

Parameters
[in]waveKS_WAVE object
Return values
areaThe area of the KS_WAVE object in [(G/cm) * us]
1508  {
1509  return ks_wave_area(wave, 0, wave->duration);
1510 }
float ks_wave_area(const KS_WAVE *wave, int start, int end)
Returns the area of a KS_WAVE object over a specified interval given in [us]
Definition: KSFoundation_common.c:1500
int duration
Definition: KSFoundation.h:747

◆ ks_waveform_sum()

float ks_waveform_sum ( const KS_WAVEFORM  waveform,
int  res 
)

Returns the sum of a KS_WAVEFORM

Parameters
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
Return values
sumThe sum of the KS_WAVEFORM
1515  {
1516  int i;
1517  double sum = 0;
1518 
1519  if (waveform == NULL) {
1520  ks_error("ks_waveform_sum: wave is NULL");
1521  }
1522  if (res <= 0) {
1523  ks_error("ks_waveform_sum: res must be positive");
1524  }
1525 
1526  for (i = 0; i < res; i++) {
1527  sum += waveform[i];
1528  }
1529 
1530  return (float)sum;
1531 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78

◆ ks_wave_sum()

float ks_wave_sum ( const KS_WAVE wave)

Returns the sum of a KS_WAVE sequence object

Parameters
[in]waveKS_WAVE object
Return values
sumThe sum of the KS_WAVEFORM
1536  {
1537  return ks_waveform_sum(wave->waveform, wave->res);
1538 }
float ks_waveform_sum(const KS_WAVEFORM waveform, int res)
Returns the sum of a KS_WAVEFORM
Definition: KSFoundation_common.c:1515
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_norm()

float ks_waveform_norm ( const KS_WAVEFORM  waveform,
int  res 
)

Returns the 2-norm of a KS_WAVEFORM

Parameters
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
Return values
norm2The 2-norm of a KS_WAVEFORM
1543  {
1544  int i;
1545  double sum = 0;
1546 
1547  if (waveform == NULL) {
1548  ks_error("ks_waveform_norm: wave is NULL");
1549  }
1550  if (res <= 0) {
1551  ks_error("ks_waveform_norm: res must be positive");
1552  }
1553 
1554  for (i = 0; i < res; i++) {
1555  sum += pow(fabs(waveform[i]), 2.0);
1556  }
1557 
1558  return (float)sqrt(sum);
1559 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78

◆ ks_wave_norm()

float ks_wave_norm ( const KS_WAVE wave)

Returns the 2-norm of a KS_WAVE

Parameters
[in]waveKS_WAVE object
Return values
norm2The 2-norm of a KS_WAVE
1564  {
1565  return ks_waveform_norm(wave->waveform, wave->res);
1566 }
float ks_waveform_norm(const KS_WAVEFORM waveform, int res)
Returns the 2-norm of a KS_WAVEFORM
Definition: KSFoundation_common.c:1543
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_cumsum()

void ks_waveform_cumsum ( KS_WAVEFORM  cumsumwaveform,
const KS_WAVEFORM  waveform,
int  res 
)

Calculates a KS_WAVEFORM with the cumulative sum (i.e. integral) of a KS_WAVEFORM

Parameters
[out]cumsumwaveformKS_WAVEFORM (float array)
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
1571  {
1572  int i, j;
1573 
1574  for (j = 0; j < res; j++) {
1575 
1576  double sum = 0;
1577  for (i = 0; i < j; i++) {
1578  sum += waveform[i];
1579  }
1580 
1581  cumsumwaveform[j] = (float)sum;
1582  }
1583 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_wave_cumsum()

void ks_wave_cumsum ( KS_WAVE cumsumwave,
const KS_WAVE wave 
)

Calculates a KS_WAVE with the cumulative sum (i.e. integral) of a KS_WAVE

Parameters
[out]cumsumwaveKS_WAVE object
[in]waveKS_WAVE
1588  {
1589  int res;
1590  res = (cumsumwave->res > wave->res) ? wave->res : cumsumwave->res; /* smallest of the two */
1591  ks_waveform_cumsum(cumsumwave->waveform, wave->waveform, res);
1592 }
void ks_waveform_cumsum(KS_WAVEFORM cumsumwaveform, const KS_WAVEFORM waveform, int res)
Calculates a KS_WAVEFORM with the cumulative sum (i.e. integral) of a KS_WAVEFORM
Definition: KSFoundation_common.c:1571
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_multiply()

void ks_waveform_multiply ( KS_WAVEFORM  waveform_mod,
const KS_WAVEFORM  waveform,
int  res 
)

In-place multiplication of one KS_WAVEFORM with another KS_WAVEFORM

Multiplication of waveform a (arg 1) with waveform b (arg 2) as: a *= b

Parameters
[in,out]waveform_modKS_WAVE object
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
1597  {
1598  int i;
1599 
1600  for (i = 0; i < res; i++) {
1601  waveform_mod[i] *= waveform[i];
1602  }
1603 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_wave_multiply()

void ks_wave_multiply ( KS_WAVE wave_mod,
const KS_WAVE wave 
)

In-place multiplication of one KS_WAVE with another KS_WAVE

Multiplication of waveform a (arg 1) with waveform b (arg 2) as: a *= b

If the duration of the two KS_WAVE objects have different resolution, the shorter KS_WAVE will be multiplied with the first part of the longer KS_WAVE

Parameters
[in,out]wave_modKS_WAVE object
[in]waveKS_WAVE object
1608  {
1609  int res;
1610  res = (wave_mod->res > wave->res) ? wave->res : wave_mod->res; /* smallest of the two */
1611  ks_waveform_multiply(wave_mod->waveform, wave->waveform, res);
1612 
1613  ks_wave_compute_params(wave_mod);
1614 
1615 }
void ks_waveform_multiply(KS_WAVEFORM waveform_mod, const KS_WAVEFORM waveform, int res)
In-place multiplication of one KS_WAVEFORM with another KS_WAVEFORM
Definition: KSFoundation_common.c:1597
void ks_wave_compute_params(KS_WAVE *const wave)
Fills the members of the KS_WAVE sequence object
Definition: KSFoundation_common.c:1123
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_add()

void ks_waveform_add ( KS_WAVEFORM  waveform_mod,
const KS_WAVEFORM  waveform,
int  res 
)

In-place addition of one KS_WAVEFORM with another KS_WAVEFORM

Addition of waveform a (arg 1) with waveform b (arg 2) as: a += b

Parameters
[in,out]waveform_modKS_WAVEFORM (float array)
[in]waveformKS_WAVEFORM (float array)
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
1620  {
1621  int i;
1622 
1623  for (i = 0; i < res; i++) {
1624  waveform_mod[i] += waveform[i];
1625  }
1626 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_wave_add()

void ks_wave_add ( KS_WAVE wave_mod,
const KS_WAVE wave 
)

In-place addition of one KS_WAVE with another KS_WAVE

Addition of waveform a (arg 1) with waveform b (arg 2) as: a *= b

If the duration of the two KS_WAVE objects have different resolution, the shorter KS_WAVE will be added to the first part of the longer KS_WAVE

Parameters
[in,out]wave_modKS_WAVE object
[in]waveKS_WAVE object
1631  {
1632  int res;
1633  res = (wave_mod->res > wave->res) ? wave->res : wave_mod->res; /* smallest of the two */
1634  ks_waveform_add(wave_mod->waveform, wave->waveform, res);
1635 
1636  ks_wave_compute_params(wave_mod);
1637 }
void ks_wave_compute_params(KS_WAVE *const wave)
Fills the members of the KS_WAVE sequence object
Definition: KSFoundation_common.c:1123
void ks_waveform_add(KS_WAVEFORM waveform_mod, const KS_WAVEFORM waveform, int res)
In-place addition of one KS_WAVEFORM with another KS_WAVEFORM
Definition: KSFoundation_common.c:1620
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_multiplyval()

void ks_waveform_multiplyval ( KS_WAVEFORM  waveform,
float  val,
int  res 
)

In-place scalar multiplication of a KS_WAVEFORM

The values in a KS_WAVEFORM are multiplied with a scalar value val

Parameters
[in,out]waveformKS_WAVEFORM (float array)
[in]valFloating point value to multiply with
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
1642  {
1643  int i;
1644 
1645  for (i = 0; i < res; i++) {
1646  waveform[i] *= val;
1647  }
1648 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_wave_multiplyval()

void ks_wave_multiplyval ( KS_WAVE wave,
float  val 
)

In-place scalar multiplication of a KS_WAVE

The waveform values in a KS_WAVE sequence object (.waveform[]) are multiplied with a scalar value val

Parameters
[in,out]waveKS_WAVE object
[in]valFloating point value to multiply with
1653  {
1654  ks_waveform_multiplyval(wave->waveform, val, wave->res);
1655  /* max_amp, min_amp, abs_max_amp, abs_max_slew, area */
1656  wave->max_amp *= val;
1657  wave->min_amp *= val;
1658  if (val < 0.0) { /* swap min/max for negative val */
1659  float min_amp = wave->max_amp;
1660  wave->max_amp = wave->min_amp;
1661  wave->min_amp = min_amp;
1662  }
1663  wave->abs_max_amp *= fabs(val);
1664  wave->abs_max_slew *= fabs(val);
1665  wave->area *= val;
1666 }
float abs_max_slew
Definition: KSFoundation.h:760
float min_amp
Definition: KSFoundation.h:758
float area
Definition: KSFoundation.h:757
float abs_max_amp
Definition: KSFoundation.h:761
float max_amp
Definition: KSFoundation.h:759
void ks_waveform_multiplyval(KS_WAVEFORM waveform, float val, int res)
In-place scalar multiplication of a KS_WAVEFORM
Definition: KSFoundation_common.c:1642
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_waveform_addval()

void ks_waveform_addval ( KS_WAVEFORM  waveform,
float  val,
int  res 
)

In-place scalar addition of a KS_WAVEFORM

The values in a KS_WAVEFORM are added with a scalar value val

Parameters
[in,out]waveformKS_WAVEFORM (float array)
[in]valFloating point value to add
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
1671  {
1672  int i;
1673 
1674  for (i = 0; i < res; i++) {
1675  waveform[i] += val;
1676  }
1677 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_wave_addval()

void ks_wave_addval ( KS_WAVE wave,
float  val 
)

In-place scalar addition of a KS_WAVE

The waveform values in a KS_WAVE sequence object (.waveform[]) are added with a scalar value val

Parameters
[in,out]waveKS_WAVE object
[in]valFloating point value to add
1682  {
1683  ks_waveform_addval(wave->waveform, val, wave->res);
1684  /* max_amp, min_amp, abs_max_amp, abs_max_slew, area */
1685  wave->max_amp += val;
1686  wave->min_amp += val;
1687  if(-wave->min_amp > wave->max_amp) {
1688  wave->abs_max_amp = -wave->min_amp;
1689  } else {
1690  wave->abs_max_amp = wave->max_amp;
1691  }
1692  wave->area += (val * wave->duration);
1693 }
void ks_waveform_addval(KS_WAVEFORM waveform, float val, int res)
In-place scalar addition of a KS_WAVEFORM
Definition: KSFoundation_common.c:1671
float min_amp
Definition: KSFoundation.h:758
float area
Definition: KSFoundation.h:757
float abs_max_amp
Definition: KSFoundation.h:761
float max_amp
Definition: KSFoundation.h:759
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748
int duration
Definition: KSFoundation.h:747

◆ ks_waveform2iwave()

STATUS ks_waveform2iwave ( KS_IWAVE  iwave,
const KS_WAVEFORM  waveform,
int  res,
int  board,
float  max,
float  fs_factor 
)

(Internal use) Conversion of a KS_WAVEFORM to a short int array for use on hardware

This function is used internally by ks_pg_wave() and there should be no need to call this function directly.

For all boards except THETA, this function auto-scales the (float) values in KS_WAVEFORM so that the maximum absolute value becomes +/- 32766. The output short int (KS_IWAVE) array is to be copied to hardware. For a KS_WAVEFORM on the THETA board, the necessary phase wraps and scaling to short int format is performed using ks_cycles_to_iphase(). GE's requirement of only having even numbers in the waveform except for a final odd value (end-of-waveform) is also taken care of here

Note that the preservation of the physical units are done in ks_pg_wave() by setting the correct instruction amplitude to multiply this auto-scaled waveform with in the sequence's hardware memory

Parameters
[out]iwaveKS_IWAVE (short int array)
[in]waveformKS_WAVEFORM
[in]resResolution (i.e. number of samples) in the KS_WAVEFORM
[in]boardOne of XGRAD, YGRAD, ZGRAD, RHO, THETA, OMEGA
[in]maxmax value of the waveform
[in]fs_factorhow much of the dynamic range to use 1 = FULL
Return values
STATUSSUCCESS or FAILURE
1698  {
1699  int i;
1700  if (board != THETA) {
1701  /* 16383 - FS signed 15bit value (2^15) / 2 - 1 */
1702  const float FS = (float)(max_pg_wamp>>1) * fs_factor / max;
1703  for (i = 0; i < res; i++) {
1704  iwave[i] = ((short) (FS * waveform[i]) << 1);
1705  }
1706  } else {
1707  for (i = 0; i < res; i++) {
1708  /* Theta board used a 14-bit representation */
1709  iwave[i] = ((short) ks_degrees_to_iphase(waveform[i]));
1710  }
1711  }
1712 
1713  /* set end-of-waveform flag */
1714  iwave[res - 1] |= WEOS_BIT;
1715 
1716  return SUCCESS;
1717 
1718 } /* ks_wave2iwave() */
int32_t i
Definition: KSFoundation_tgt.c:1694
unsigned short ks_degrees_to_iphase(double degrees)
Definition: KSFoundation_common.c:379

◆ ks_wave2iwave()

STATUS ks_wave2iwave ( KS_IWAVE  iwave,
const KS_WAVE wave,
int  board 
)

(Internal use) Conversion of waveform content in a KS_WAVE sequence object to a short int array for use on hardware

This function is used internally by ks_pg_wave() and there should be no need to call this function directly.

For all boards except THETA, this function auto-scales the (float) values in the .waveform[] field so that the maximum absolute value becomes +/- 32766. The output short int (KS_IWAVE) array is to be copied to hardware. For a KS_WAVE on the THETA board, the necessary phase wraps and scaling to short int format is performed using ks_cycles_to_iphase(). GE's requirement of only having even numbers in the waveform except for a final odd value (end-of-waveform) is also taken care of here

Note that the preservation of the physical units are done in ks_pg_wave() by setting the correct instruction amplitude to multiply this auto-scaled waveform with in the sequence's hardware memory

Parameters
[out]iwaveKS_IWAVE (short int array)
[in]waveKS_WAVE
[in]boardOne of XGRAD, YGRAD, ZGRAD, RHO, THETA, OMEGA
Return values
STATUSSUCCESS or FAILURE
1721  {
1722  return ks_waveform2iwave(iwave, wave->waveform, wave->res, board, wave->abs_max_amp, wave->fs_factor);
1723 }
float fs_factor
Definition: KSFoundation.h:756
STATUS ks_waveform2iwave(KS_IWAVE iwave, const KS_WAVEFORM waveform, int res, int board, float max, float fs_factor)
(Internal use) Conversion of a KS_WAVEFORM to a short int array for use on hardware
Definition: KSFoundation_common.c:1698
float abs_max_amp
Definition: KSFoundation.h:761
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_pg_echossp()

WF_PULSE* ks_pg_echossp ( WF_PULSE *  echo,
const char *  suffix 
)

Returns the pointer to XTR or RBA for an echo WF_PULSE (internal use)

This function is used internally by ks_pg_read() to get pointers to the XTR and RBA SSP packets for an acquisition window

Parameters
[in]echoPointer to an echo (WF_PULSE)
[in]suffixString being "xtr", "rba", or empty
Return values
wfptrPointer to a WF_PULSE
1738  {
1739 
1740  if (!strcmp(suffix, "xtr")) {
1741  return echo->assoc_pulse;
1742  } else if (!strcmp(suffix, "rba")) {
1743  return echo->assoc_pulse->assoc_pulse;
1744  } else {
1745  return echo;
1746  }
1747 
1748 }

◆ ks_pg_trap_make_symramps()

void ks_pg_trap_make_symramps ( KS_TRAP trap,
float  min_fs_factor,
KS_IWAVE  attack,
KS_IWAVE  decay 
)
1753  {
1754  const int res = trap->ramptime / GRAD_UPDATE_TIME;
1755  /* for exact shape in iwave for half steps */
1756  int step_size = 2 * res;
1757 
1758  /* compute the nearest lowest fs_factor that allows exact ramp representation */
1759  float fs = trap->fs_factor * (float)(max_pg_wamp>>1);
1760  if (fs > 0.0f) {
1761  trap->fs_factor *= ((int)(fs / step_size) * step_size) / fs;
1762  }
1763 
1764  /* compute the minimum fs_factor for exact ramp */
1765  float min_fs = min_fs_factor * (float)(max_pg_wamp>>1);
1766  min_fs_factor *= ((int)(min_fs / step_size + 1.0f) * step_size) / min_fs;
1767 
1768  /* change fs_factor to min if needed */
1769  if (trap->fs_factor < min_fs_factor) {
1770  trap->fs_factor = min_fs_factor;
1771  }
1772 
1773  /* fullscale in iwave memory */
1774  short fs_exact = (short)(trap->fs_factor * (float)(max_pg_wamp>>1));
1775 
1776  /* use float in case an exact slope is not possible */
1777  float half_ramp_slope = (float)fs_exact / (float)step_size;
1778 
1779  if (trap->fs_factor > 1.0f) {
1780  /* an exact representation of the ramp is not possible */
1781  trap->fs_factor = 1.0f;
1782  fs_exact = (max_pg_wamp>>1);
1783  half_ramp_slope = (float)fs_exact / (float)step_size;
1784  }
1785 
1786  /* form ramps and exploit symmetry */
1787  int i = 0;
1788  for(i = 0; i < res; i++) {
1789  attack[i] = (int)(half_ramp_slope + 2 * half_ramp_slope * i) << 1;
1790  decay[res - 1 - i] = attack[i];
1791  }
1792  /* set end-of-waveform flag */
1793  attack[res - 1] |= WEOS_BIT;
1794  decay[res - 1] |= WEOS_BIT;
1795 }
int32_t i
Definition: KSFoundation_tgt.c:1694
float fs_factor
Definition: KSFoundation.h:677
int ramptime
Definition: KSFoundation.h:671

◆ ks_pg_trap()

STATUS ks_pg_trap ( KS_TRAP trap,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places a KS_TRAP sequence object on a board at some position in the pulse sequence

This function should be called in the @pg section to place out a KS_TRAP sequence object that creates a static trapezoid in the pulse sequence. The same KS_TRAP object can be freely placed on XGRAD, YGRAD and ZGRAD as many times as desired, by only changing the second argument each time (to avoid waveform overlaps). The second argument is a KS_SEQLOC struct with three fields:

  • .board: Choose between XGRAD, YGRAD, ZGRAD (or OMEGA)
  • .pos: Absolute time in [us] of the start of the attack ramp of the trapezoid
  • .ampscale: A factor that must be in range [-1.0,1.0] that is multiplied with .amp to yield a per-instance (i.e. per-placement) amplitude ([G/cm]). The simplest is to use 1.0, which makes the KS_TRAP object to be placed out on the board as initially designed using ks_eval_trap(). For the OMEGA board, this factor must be 1.0.

Regardless of the order placed out in the @pg section, and on which boards (XGRAD, YGRAD, ZGRAD) the KS_TRAP object is placed, the instance number of the KS_TRAP is automatically sorted in time. If two instances of one KS_TRAP occur at the same time (.pos) on different boards, XGRAD comes before YGRAD, which comes before ZGRAD. These abstract, sorted, instance numbers are used by ks_scan_***() functions in scan() to refer to a specific instance of a KS_TRAP object in the sequence

If the .duration field in the KS_TRAP object is 0, ks_pg_trap() will return SUCCESS and quietly ignore placing it out. This is a part of the mechanism that setting the .duration field to 0 in cveval() should eliminate its existance in both timing calulations and in the pulse sequence generation in @pg

When a trapezoid is placed on OMEGA, neither the designed amplitude (the .amp field in KS_TRAP) nor the .ampscale (in KS_SEQLOC) has an effect on the final frequency modulation. Instead the run-time amplitude of a KS_TRAP object on the OMEGA board is controlled in scan() via a function called ks_scan_omegatrap_hz()

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

Parameters
[in,out]trapPointer to a KS_TRAP sequence object
[in]locKS_SEQLOC struct to specify when and where to place the KS_TRAP
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_TRAP
Return values
STATUSSUCCESS or FAILURE
1802  {
1803  float boardmax;
1804  char boardc[8] = "xyz---o";
1805 
1806  boardmax = ks_syslimits_gradtarget(loggrd, loc.board); /* returns 1.0 for OMEGA board */
1807 
1808  /* checking for NULL pointers */
1809  if (trap == NULL) {
1810  return ks_error("ks_pg_trap: First argument is NULL");
1811  }
1812  /* duration of 0 should not throw an error as this is a sign of that it has not been set up
1813  or has manually been disabled this way */
1814  if (trap->duration == 0) {
1815  return SUCCESS;
1816  }
1817 
1818  if (trap->description == NULL || trap->description[0] == 0 || trap->description[0] == ' ') {
1819  return ks_error("ks_pg_trap: Invalid description ('%s')", trap->description);
1820  }
1821 
1822 #ifdef IPG
1823  /* TGT: Don't place anything on hardware if ctrl->duration = 0.
1824  This is in concert with:
1825  - not performing createseq() in KS_SEQLENGTH if seqctrl.duration = 0
1826  - not playing sequence modules in scan() using ks_scan_playsequence() if seqctrl.duration = 0
1827  */
1828  if (ctrl->duration == 0) {
1829  return ks_error("%s(%s): Refusing to place trap since seqctrl.duration = 0 (indicating `%s` not to be played in scan())", __FUNCTION__, trap->description, ctrl->description);
1830  }
1831 #endif
1832 
1833  /* input validation */
1834  if ((trap->ramptime % 4) || (trap->plateautime % 4) || (trap->duration % 4)) {
1835  return ks_error("ks_pg_trap(%s): All timing parameters must be divisible by 4", trap->description);
1836  }
1837 
1838  if ((trap->ramptime < 4) || (trap->plateautime < 4) || (trap->duration < 4)) {
1839  return ks_error("ks_pg_trap(%s): All timing parameters must be at least 4 us", trap->description);
1840  }
1841 
1842  if (isNaN(loc.ampscale)) {
1843  return ks_error("ks_pg_trap(%s): loc.ampscale NaN", trap->description);
1844  }
1845 
1846  if (loc.pos < GRAD_UPDATE_TIME || loc.pos > 4e6) {
1847  return ks_error("ks_pg_trap(%s): Invalid position %d, it must be between 4us and 4s", trap->description, loc.pos);
1848  }
1849 
1850  if (loc.board == OMEGA && !areSame(loc.ampscale,1.0)) {
1851  return ks_error("ks_pg_trap(%s): ampscale must be +1.0 for OMEGA", trap->description);
1852  }
1853 
1854  if (loc.ampscale < -1.0 || loc.ampscale > 1.0) {
1855  return ks_error("ks_pg_trap(%s): Invalid ampscale %g, it must be between -1.0 and 1.0", trap->description, loc.ampscale);
1856  }
1857 
1858  if (loc.board != XGRAD && loc.board != YGRAD && loc.board != ZGRAD && loc.board != OMEGA) {
1859  return ks_error("ks_pg_trap(%s): Invalid board code %d, it must be %d (XGRAD), %d (YGRAD), %d (ZGRAD) or %d (OMEGA)", trap->description, loc.board, XGRAD, YGRAD, ZGRAD, OMEGA);
1860  }
1861 
1862  /* compute the minimum fs_factor */
1863  float min_fs_factor = fabs(trap->amp) / boardmax;
1864  /* change fs_factor to min if needed */
1865  if (trap->fs_factor < min_fs_factor) {
1866  ks_dbg("%s: (%s) trap->fs_factor too low, modified from %1.2f to: %1.2f", __FUNCTION__, trap->description, trap->fs_factor, min_fs_factor);
1867  trap->fs_factor = min_fs_factor;
1868  }
1869 
1870  if (trap->fs_factor > 1.0f) {
1871  ks_error("ks_pg_trap(%s): Corner case where an exact representation of the trap shape is not possible amp %g [g/cm] with a ramp period of %i us", trap->description, trap->amp, trap->ramptime);
1872  }
1873 
1874  if (fabs(trap->amp * loc.ampscale) > boardmax) {
1875  return ks_error("ks_pg_trap(%s): trapezoid amplitude %g exceeds maximum (%g) for board %c", trap->description, trap->amp * loc.ampscale, boardmax, boardc[loc.board]);
1876  }
1877 
1878  loc.pos = RUP_GRD(loc.pos);
1879 
1880 #ifdef IPG
1881  {
1882 
1883  int i;
1884 
1885  char tmpstr[KS_DESCRIPTION_LENGTH + 7];
1886  tmpstr[KS_DESCRIPTION_LENGTH + 7 - 1] = 0;
1887 
1888  if (trap->base.ngenerated >= trap->base.ninst) {
1889  return ks_error("ks_pg_trap @tgt(%s): the number of instances generated on the target exceeds the number of ones generated on the host", trap->description);
1890  }
1891 
1892  if (!ctrl->gradrf.is_cleared_on_tgt) /* Reset gradrfctrl on tgt to remove dead pointers copied from host. */
1893  {
1895  }
1896 
1897  const int res = trap->ramptime / GRAD_UPDATE_TIME;
1898  short * attack = (short *) AllocNode(res * sizeof(short));
1899  short * decay = (short *) AllocNode(res * sizeof(short));
1900 
1902 
1903  ks_pg_trap_make_symramps(trap, min_fs_factor, attack, decay);
1904 
1905  }
1906  /* now set the plateau once all adjustments of fs_factor are over */
1907  short plateau = (short)(trap->fs_factor * max_pg_wamp);
1908 
1909  /* TODO: consider freeing memory if ngenerated is zero -- EA */
1910 
1911  if (trap->wfpulse == NULL) {
1912  WF_PULSE wfInit = INITPULSE;
1913 
1914  trap->wfpulse = (WF_PULSE **) AllocNode(8 * sizeof(WF_PULSE *)); /* X, Y, Z, (OMEGA = 6). Not applicable to other boards */
1915 
1916  for (i = XGRAD; i <= OMEGA; i++) {
1917 
1918  if (i == XGRAD || i == YGRAD || i == ZGRAD || i == OMEGA) {
1919 
1920  trap->wfpulse[i] = (WF_PULSE *) AllocNode(3 * sizeof(WF_PULSE)); /* attack, plateau, decay */
1921 
1922  /* init pulse structure */
1923  trap->wfpulse[i][G_ATTACK] = wfInit;
1924  trap->wfpulse[i][G_PLATEAU] = wfInit;
1925  trap->wfpulse[i][G_DECAY] = wfInit;
1926 
1927  /* Name for WF_PULSEs */
1928  sprintf(tmpstr, "%s.%ca", trap->description, boardc[i]); pulsename(&(trap->wfpulse[i][G_ATTACK]), tmpstr);
1929  sprintf(tmpstr, "%s.%c", trap->description, boardc[i]); pulsename(&(trap->wfpulse[i][G_PLATEAU]), tmpstr);
1930  sprintf(tmpstr, "%s.%cd", trap->description, boardc[i]); pulsename(&(trap->wfpulse[i][G_DECAY]), tmpstr);
1931 
1933  createreserve(&trap->wfpulse[i][G_ATTACK], (WF_PROCESSOR) i, res);
1934  trap->wfpulse[i][G_ATTACK].type = TYPEXTERNAL;
1935  movewaveimm(attack, &trap->wfpulse[i][G_ATTACK], (int) 0, res, TOHARDWARE);
1936 
1937  createreserve(&trap->wfpulse[i][G_DECAY], (WF_PROCESSOR) i, res);
1938  trap->wfpulse[i][G_DECAY].type = TYPEXTERNAL;
1939  movewaveimm(decay, &trap->wfpulse[i][G_DECAY], (int) 0, res, TOHARDWARE);
1940  } else {
1941  createramp(&(trap->wfpulse[i][G_ATTACK]), (WF_PROCESSOR) i, trap->ramptime, 0, plateau, res, 1.0);
1942  createramp(&(trap->wfpulse[i][G_DECAY]), (WF_PROCESSOR) i, trap->ramptime, plateau, 0, res, 1.0);
1943  }
1944  createconst(&(trap->wfpulse[i][G_PLATEAU]), (WF_PROCESSOR) i, trap->plateautime, plateau);
1945 
1946  linkpulses(3, &(trap->wfpulse[i][G_PLATEAU]), &(trap->wfpulse[i][G_ATTACK]), &(trap->wfpulse[i][G_DECAY]));
1947 
1948  } else {
1949 
1950  trap->wfpulse[i] = NULL;
1951 
1952  }
1953 
1954  } /* per board */
1955  FreeNode(attack);
1956  FreeNode(decay);
1957 
1958  } /* wfpulse == NULL */
1959 
1960 
1961  /* allocate the array of WFINSTANCE's if needed */
1962  if (!trap->wfi) {
1963  trap->wfi = (KS_WFINSTANCE *) AllocNode(trap->base.ninst * sizeof(KS_WFINSTANCE));
1964  }
1965 
1966  /* Set instruction amplitudes at the proper position and board */
1967  {
1968  const int corrected_pos = loc.pos + (loc.board == OMEGA)*psd_rf_wait;
1969  /* creating new instructions */
1970  createinstr(&(trap->wfpulse[loc.board][G_ATTACK]),
1971  corrected_pos,
1972  trap->ramptime,
1973  (int)(trap->amp * loc.ampscale * MAX_PG_IAMP / (trap->fs_factor * boardmax)));
1974  createinstr(&(trap->wfpulse[loc.board][G_PLATEAU]),
1975  corrected_pos + trap->ramptime,
1976  trap->plateautime,
1977  (int)(trap->amp * loc.ampscale * MAX_PG_IAMP / (trap->fs_factor * boardmax)));
1978  createinstr(&(trap->wfpulse[loc.board][G_DECAY]),
1979  corrected_pos + trap->ramptime + trap->plateautime,
1980  trap->ramptime,
1981  (int)(trap->amp * loc.ampscale * MAX_PG_IAMP / (trap->fs_factor * boardmax)));
1982  }
1983 
1984  /* initializing the corresponding KS_WFINSTANCE */
1985  trap->wfi[trap->base.ngenerated].boardinstance = trap->wfpulse[loc.board][G_PLATEAU].ninsts - 1; /* zero based */
1986  trap->wfi[trap->base.ngenerated].wf = &(trap->wfpulse[loc.board][G_PLATEAU]);
1987  trap->wfi[trap->base.ngenerated].loc = loc;
1988 
1989  trap->base.ngenerated++;
1990 
1991  /* sort after the last instance is generated */
1992  if (trap->base.ngenerated == trap->base.ninst) {
1993  ks_sort_wfi_by_timeboard(trap->wfi, trap->base.ninst);
1994  }
1995  }
1996 #else /* TGT(IPG) or HOST */
1997  {
1998  /* HOST */
1999  /* update instance counter on host only. This counter is used to allocate the right amount of WFINSTANCEs on IPG */
2000  trap->base.ninst++;
2001 
2002  KS_SEQLOC *locs = (KS_SEQLOC *) realloc(trap->locs, sizeof(KS_SEQLOC)*trap->base.ninst);
2003  if (!locs) {
2004  return KS_THROW("Realloc failed");
2005  }
2006  trap->locs = locs;
2007  trap->locs[trap->base.ninst-1] = loc;
2008 
2009 
2010  ks_sort_loc_by_timeboard(trap->locs, trap->base.ninst);
2011 
2012  /* for trap, we also need to keep track of #instances per X, Y, Z for gradient heating calculations.
2013  As this needs to be done in HOST before the IPG (target), we can't use the wfi[...].boardinstance or .loc information above for this */
2014  if (loc.board == XGRAD || loc.board == YGRAD || loc.board == ZGRAD)
2015  trap->gradnum[loc.board]++;
2016 
2017  }
2018 
2019 #endif /* IPG */
2020  /* register this KS_TRAP for later heating calculations */
2021  {
2022  STATUS status = ks_eval_addtraptogradrfctrl(&ctrl->gradrf, trap);
2023  KS_RAISE(status);
2024  }
2025  return SUCCESS;
2026 
2027 } /* ks_pg_trap */
STATUS ks_eval_addtraptogradrfctrl(KS_GRADRFCTRL *gradrfctrl, KS_TRAP *trap)
*Internal use*. Adds a trapezoid (KS_TRAP) to the KS_GRADRFCTRL struct for later gradient heating cal...
Definition: KSFoundation_common.c:4656
void ks_sort_wfi_by_timeboard(KS_WFINSTANCE *a, int nitems)
Sort WF_INSTANCEs in time, then board
Definition: KSFoundation_common.c:4120
int plateautime
Definition: KSFoundation.h:672
int boardinstance
Definition: KSFoundation.h:484
#define areSame(a, b)
Definition: KSFoundation.h:144
KS_BASE base
Definition: KSFoundation.h:667
KS_DISCRETE_REPRESENTATION discrete_representation
Definition: KSFoundation.h:1233
int pos
Definition: KSFoundation.h:463
(Internal use) Structure being a part of various sequence objects to sort them in time across boards...
Definition: KSFoundation.h:483
int ninst
Definition: KSFoundation.h:494
int32_t i
Definition: KSFoundation_tgt.c:1694
KS_SEQLOC * locs
Definition: KSFoundation.h:678
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
STATUS ks_dbg(const char *format,...)
Definition: KSFoundation_common.c:157
int board
Definition: KSFoundation.h:462
int duration
Definition: KSFoundation.h:1227
float ks_syslimits_gradtarget(LOG_GRAD loggrd, int board)
Returns the maximum target amplitude for a board (internal use)
Definition: KSFoundation_common.c:264
float ampscale
Definition: KSFoundation.h:464
Definition: KSFoundation.h:2310
KS_GRADRFCTRL gradrf
Definition: KSFoundation.h:1236
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
int isNaN(float a)
Definition: KSFoundation_common.c:58
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
KS_SEQLOC loc
Definition: KSFoundation.h:486
float fs_factor
Definition: KSFoundation.h:677
LOG_GRAD loggrd
int is_cleared_on_tgt
Definition: KSFoundation.h:1065
#define KS_RAISE(status)
Definition: KSFoundation.h:190
float amp
Definition: KSFoundation.h:669
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
WF_PULSE * wf
Definition: KSFoundation.h:485
KS_DESCRIPTION description
Definition: KSFoundation.h:668
void ks_tgt_reset_gradrfctrl(KS_GRADRFCTRL *gradrfctrl)
Definition: KSFoundation_tgt.c:1797
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
Definition: KSFoundation.h:419
int ngenerated
Definition: KSFoundation.h:496
void ks_pg_trap_make_symramps(KS_TRAP *trap, float min_fs_factor, KS_IWAVE attack, KS_IWAVE decay)
Definition: KSFoundation_common.c:1753
Definition: KSFoundation.h:2310
WF_PULSE ** wfpulse
Definition: KSFoundation.h:679
int duration
Definition: KSFoundation.h:673
int psd_rf_wait
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int gradnum[3]
Definition: KSFoundation.h:674
Definition: KSFoundation.h:2310
int ramptime
Definition: KSFoundation.h:671
void ks_sort_loc_by_timeboard(KS_SEQLOC *a, int nitems)
Sort KS_SEQLOCs in time, then board
Definition: KSFoundation_common.c:4128

◆ ks_pg_phaser()

STATUS ks_pg_phaser ( KS_PHASER phaser,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places a KS_PHASER sequence object on a board at some position in the pulse sequence

This function should be called in the @pg section to place out a KS_PHASER sequence object that creates a dynamic trapezoid for phase encoding. For 3D applications, two different KS_PHASER objects should have been designed by calling ks_eval_phaser() on each KS_PHASER as FOV and resolution typically differ for the two phase encoding directions. The same KS_PHASER object can be freely placed on XGRAD, YGRAD and ZGRAD as many times as desired, by only changing the second argument each time (to avoid waveform overlaps). For Cartesian applications, phase encoding gradients such as KS_PHASER are typically placed out on YGRAD (phase encoding axis), for 3D also on ZGRAD. For 3D, the KS_PHASER object may embed a slice rephaser (static trapezoid) by setting .areaoffset to a non-zero value (see ks_eval_phaser()). The second argument is a KS_SEQLOC struct with three fields:

Regardless of the order placed out in the @pg section, and on which boards (XGRAD, YGRAD, ZGRAD) the KS_PHASER object is placed, the instance number of the KS_PHASER is automatically sorted in time. If two instances of one KS_PHASER occur at the same time (.pos) on different boards, XGRAD comes before YGRAD, which comes before ZGRAD. These abstract, sorted, instance numbers are used by ks_scan_***() functions in scan() to refer to a specific instance of a KS_PHASER object in the sequence

If the .duration field in the KS_PHASER object is 0, ks_pg_phaser() will return SUCCESS and quietly ignore placing it out. This is a part of the mechanism that setting the .duration field to 0 in cveval() should eliminate its existance in both timing calulations and in the pulse sequence generation in @pg

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

Parameters
[in,out]phaserPointer to a KS_PHASER sequence object
[in]locKS_SEQLOC struct to specify when and where to place the KS_PHASER
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_PHASER
Return values
STATUSSUCCESS or FAILURE
2031  {
2032 
2033 
2034  /* loc.ampscale != 1.0 is not allowed */
2035  if (!areSame(loc.ampscale,1.0)) {
2036  return ks_error("ks_pg_phaser(%s): field 'ampscale' in 2nd arg must be 1.0", phaser->grad.description);
2037  }
2038 
2039  /* loc.board must be one of XGRAD, YGRAD, ZGRAD */
2040  if (loc.board != XGRAD && loc.board != YGRAD && loc.board != ZGRAD) {
2041  return ks_error("ks_pg_phaser(%s): field 'board' in 2nd arg must be XGRAD, YGRAD, or ZGRAD", phaser->grad.description);
2042  }
2043 
2044  return ks_pg_trap(&phaser->grad, loc, ctrl);
2045 
2046 }
#define areSame(a, b)
Definition: KSFoundation.h:144
KS_TRAP grad
Definition: KSFoundation.h:1719
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
float ampscale
Definition: KSFoundation.h:464
KS_DESCRIPTION description
Definition: KSFoundation.h:668
STATUS ks_pg_trap(KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_TRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1802

◆ ks_pg_read()

STATUS ks_pg_read ( KS_READ read,
int  pos,
KS_SEQ_CONTROL ctrl 
)

Places a KS_READ sequence object at some position in the pulse sequence

This function should be called in the @pg section to place out a KS_READ sequence object that creates an acquisition window in the pulse sequence. The same KS_READ object can be freely placed as many times as desired, by only changing the second argument each time (to avoid overlaps). The second argument is an integer with the absolute time in [us] of the start of the acquisition. System gradient delays are accounted for in ks_pg_read() by internally adjusting the position by adding the system variable psd_grd_wait to the position value. This assures the gradients boards and acquisition window are in sync on the MR system.

Regardless of the order the acquisition windows are placed out in the @pg section, the instance number of the KS_READ is automatically sorted in time

If the .duration field in the KS_READ object is 0, ks_pg_read() will return SUCCESS and quietly ignore placing it out. This is a part of the mechanism that setting the .duration field to 0 in cveval() should eliminate its existance in both timing calulations and in the pulse sequence generation in @pg

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

Parameters
[in,out]readPointer to a KS_READ sequence object
[in]posAbsolute time in [us] when to start data acquisition
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_READ
Return values
STATUSSUCCESS or FAILURE
2051  {
2052 #ifdef IPG
2053  int acqwin_start;
2054  int placementindx;
2055  long dab_pos;
2056  char tmpstr[KS_DESCRIPTION_LENGTH + 7];
2057 #endif
2058  STATUS status;
2059 
2060  /* duration of 0 should not throw an error as this is a sign of that it has not been set up or has manually been disabled this way */
2061  if (read->duration == 0) {
2062  return SUCCESS;
2063  }
2064 
2065 #ifdef IPG
2066  {
2067  tmpstr[KS_DESCRIPTION_LENGTH + 7 - 1] = 0;
2068 
2069  if (read->base.ngenerated >= read->base.ninst) {
2070  return ks_error("ks_pg_read @tgt(%s): the number of instances generated on the target exceeds the number of ones generated on the host", read->description);
2071  }
2072 
2073  if (!ctrl->gradrf.is_cleared_on_tgt) { /* Reset gradrfctrl on tgt to remove dead pointers copied from host. */
2075  }
2076 
2077  if (read->echo == NULL) {
2078  /* this relies on that we have run the sequence in cveval() (i.e. on host) before to get proper grad.ninst */
2079  read->echo = (WF_PULSE *) AllocNode(read->base.ninst * sizeof(WF_PULSE));
2080  }
2081 
2082  placementindx = read->base.ngenerated; /* not sorted in time, but in placement order */
2083 
2084  /* the ADC start time is the bin center so we need to shift by half a tsp */
2085  /* tsp is always a multiple of 2, so div by two is exact here for int representation */
2086  acqwin_start = pos + psd_grd_wait + (int)(read->filt.tsp / 2.0f);
2087  /* in symmetric mode the waveforms are shifted half a GRAD_UPDATE_TIME earlier */
2089  acqwin_start -= GRAD_UPDATE_TIME / 2;
2090  }
2091 
2092  if (placementindx == 0 || read->filt.tdaq > 200) {
2093  dab_pos = DEFAULTPOS; /* results in 200 us before RBA (DEFAULTPOS is defined as 0. See: /ESE_.../psd/include/private/pulsegen.h) */
2094  } else {
2095  /* For small matrix sizes, the acq window is so short that the DAB packet
2096  for current lobe may collide with the RBA belonging to the previous lobe.
2097  We are not allowed to decrease the DAB-RBA distance below 200us. Instead,
2098  let's put it right after the end of the previous XTR pulse.
2099  With the default XTR-RBA offset of 143us, and since the RBA-RBA distance
2100  is equal to read->grad.duration, we will get a DAB-RBA offset of
2101  acqwin_duration + 143us - 17us (XTR duration)
2102  */
2103  dab_pos = pbegallssp(ks_pg_echossp(&read->echo[placementindx - 1], "xtr"), 0) + 32 /* LONG_DAB_length = 31 */;
2104  if (dab_pos + 200 > acqwin_start)
2105  dab_pos = DEFAULTPOS; /* fallback to default pos. Perhaps the readouts were not placed out in time order in the PSD ? */
2106  }
2107 
2108  /* name the ACQ pulse */
2109  sprintf(tmpstr, "%s%03d", read->description, placementindx); pulsename(&(read->echo[placementindx]), tmpstr);
2110 
2111  if (read->filt.fslot == KS_NOTSET) {
2112  /* add 'return' before ks_error once we've got an answer from GE regarding acqq and setrfltrs() */
2113  ks_error("ks_pg_read @tgt(%s): WARNING no filter slot assigned. First run setfilter(&read.filt)", read->description);
2114  }
2115 
2116  /* place the ACQ pulse */
2117  acqq_longdab(&(read->echo[placementindx]),
2118  (long) acqwin_start,
2119  (long) dab_pos, /* DAB */
2120  (long) DEFAULTPOS, /* XTR */
2121  read->filt.fslot /* filter slot */);
2122 
2123  read->base.ngenerated++;
2124 
2125  /* sort after the last instance is generated */
2126  if (read->base.ngenerated == read->base.ninst) {
2127  ks_sort_wfp_by_time(read->echo, read->base.ninst);
2128  }
2129 
2130  /* Associate this echo with a global filter slot number
2131  This number is generated by the GE function setfilter() in e.g. predownload(), before this function is called.
2132  For main sequences, there is also the wrapper function GEReq_predownload_setfilter() */
2133  if (read->filt.fslot >= 0 && read->filt.fslot <= MAX_FILTER_SLOT) {
2134  setrfltrs((int) read->filt.fslot, &(read->echo[placementindx]));
2135  }
2136 
2137  }
2138 #else /* IPG */
2139  {
2140  read->base.ninst++; /* update acq counter on host */
2141 
2142  int *locs = (int*) realloc(read->pos, sizeof(int)*read->base.ninst);
2143  if (!locs) {
2144  return KS_THROW("Realloc failed");
2145  }
2146  read->pos = locs;
2147  read->pos[read->base.ninst-1] = pos;
2148  }
2149 #endif /* IPG */
2150 
2151  status = ks_eval_addreadtogradrfctrl(&ctrl->gradrf, read);
2152  KS_RAISE(status);
2153  return SUCCESS;
2154 }
WF_PULSE * echo
Definition: KSFoundation.h:846
KS_DISCRETE_REPRESENTATION discrete_representation
Definition: KSFoundation.h:1233
void ks_sort_wfp_by_time(WF_PULSE *a, int nitems)
Sort WF_PULSEs in time
Definition: KSFoundation_common.c:4143
#define KS_NOTSET
Definition: KSFoundation.h:115
int ninst
Definition: KSFoundation.h:494
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int * pos
Definition: KSFoundation.h:844
STATUS ks_eval_addreadtogradrfctrl(KS_GRADRFCTRL *gradrfctrl, KS_READ *read)
*Internal use*. Adds an acquisition to the KS_GRADRFCTRL struct. Used for plotting
Definition: KSFoundation_common.c:4799
KS_BASE base
Definition: KSFoundation.h:839
KS_GRADRFCTRL gradrf
Definition: KSFoundation.h:1236
KS_DESCRIPTION description
Definition: KSFoundation.h:840
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
int is_cleared_on_tgt
Definition: KSFoundation.h:1065
int duration
Definition: KSFoundation.h:841
#define KS_RAISE(status)
Definition: KSFoundation.h:190
WF_PULSE * ks_pg_echossp(WF_PULSE *echo, const char *suffix)
Returns the pointer to XTR or RBA for an echo WF_PULSE (internal use)
Definition: KSFoundation_common.c:1738
STATUS acqq_longdab(WF_PULSE_ADDR pulse, LONG pos_ref, LONG dab_ref, LONG xtr_ref, LONG fslot_value)
Definition: KSFoundation_tgt.c:1840
FILTER_INFO filt
Definition: KSFoundation.h:843
int psd_grd_wait
void ks_tgt_reset_gradrfctrl(KS_GRADRFCTRL *gradrfctrl)
Definition: KSFoundation_tgt.c:1797
Definition: KSFoundation.h:419
int ngenerated
Definition: KSFoundation.h:496
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_pg_readtrap()

STATUS ks_pg_readtrap ( KS_READTRAP readtrap,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places a KS_READTRAP sequence object on a board at some position in the pulse sequence

This function should be called in the @pg section to place out a KS_READTRAP sequence object consisting of a trapezoid (KS_TRAP) and an acquisition window (KS_READ). The same KS_READTRAP object can be freely placed on XGRAD, YGRAD and ZGRAD as many times as desired, by only changing the second argument each time (to avoid waveform overlaps). For Cartesian applications, readouts such as KS_READTRAP are typically placed on XGRAD (frequency encoding axis). The second argument is a KS_SEQLOC struct with three fields:

  • .board: Choose between XGRAD, YGRAD, ZGRAD
  • .pos: Absolute time in [us] of the start of the attack ramp of the readout trapezoid
  • .ampscale: For KS_READTRAP objects, this must be either +1.0 or -1.0 so that the FOV is not altered. Negative amplitudes will automatically be taken into account in ks_scan_offsetfov() to create the necessary frequency offset

Regardless of the order placed out in the @pg section, and on which boards (XGRAD, YGRAD, ZGRAD) the KS_READTRAP object is placed, the instance number of the KS_READTRAP is automatically sorted in time. If two instances of one KS_READTRAP occur at the same time (.pos) on different boards, XGRAD comes before YGRAD, which comes before ZGRAD. These abstract, sorted, instance numbers are used by ks_scan_***() functions in scan() to refer to a specific instance of a KS_READTRAP object in the sequence.

If the .duration field in the KS_READTRAP object is 0, ks_pg_readtrap() will return SUCCESS and quietly ignore placing it out. This is a part of the mechanism that setting the .duration field to 0 in cveval() should eliminate its existance in both timing calulations and in the pulse sequence generation in @pg

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

Parameters
[in,out]readtrapPointer to a KS_READTRAP sequence object
[in]locKS_SEQLOC struct to specify when and where to place the KS_READTRAP
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_READTRAP
Return values
STATUSSUCCESS or FAILURE
2161  {
2162 
2163  STATUS status;
2164  KS_SEQLOC omegaloc;
2165 
2166  /* checking for NULL pointers */
2167  if (readtrap == NULL) {
2168  return ks_error("%s: First argument is NULL", __FUNCTION__);
2169  }
2170  /* duration of 0 should not throw an error as this is a sign of that it has not been set up
2171  or has manually been disabled this way */
2172  if (readtrap->grad.duration == 0) {
2173  return SUCCESS;
2174  }
2175  if (readtrap->grad.description == NULL || readtrap->grad.description[0] == 0 || readtrap->grad.description[0] == ' ') {
2176  return ks_error("%s: Invalid description ('%s')", __FUNCTION__, readtrap->grad.description);
2177  }
2178 
2179 #ifdef IPG
2180  /* TGT (IPG): Don't place anything on hardware if ctrl->duration = 0.
2181  This is in concert with:
2182  - not performing createseq() in KS_SEQLENGTH if seqctrl.duration = 0
2183  - not playing sequence modules in scan() using ks_scan_playsequence() if seqctrl.duration = 0
2184  */
2185  if (ctrl->duration == 0) {
2186  return ks_error("%s(%s): Refusing to place readtrap since seqctrl.duration = 0 (indicating `%s` not to be played in scan())", __FUNCTION__, readtrap->grad.description, ctrl->description);
2187  }
2188 #endif
2189 
2190  if (!areSame(loc.ampscale, 1.0) && !areSame(loc.ampscale, -1.0) && !areSame(loc.ampscale, 0.0)) {
2191  return ks_error("%s(%s): .ampscale %g must be exactly +1, 0 or -1 for readout gradients", __FUNCTION__, readtrap->grad.description, loc.ampscale);
2192  }
2193 
2194  /*** acq ***/
2195  status = ks_pg_read(&readtrap->acq, loc.pos + readtrap->acqdelay, ctrl);
2196  KS_RAISE(status);
2197 
2198  /*** trapezoid ***/
2199  status = ks_pg_trap(&readtrap->grad, loc, ctrl);
2200  KS_RAISE(status);
2201 
2202  /* also place the omega wave form for rampsampled cases */
2203  if (readtrap->omega.duration > 0) {
2204  /* omega trapezoid matching the readout lobe to allow for FOV offsets in freq dir. with ramp sampling */
2205  omegaloc.board = OMEGA;
2206  omegaloc.pos = loc.pos + readtrap->acqdelay;
2207  omegaloc.ampscale = 1.0; /* just unity value for conformance. It does not matter during scanning, since ks_scan_omegahz() ignores this value */
2208  status = ks_pg_wave(&readtrap->omega, omegaloc, ctrl);
2209  KS_RAISE(status);
2210 
2211 #ifdef IPG
2212  short * iwave = (short *) AllocNode(readtrap->omega.res * sizeof(short));
2213  movewaveimm(iwave, &readtrap->omega.wfpulse[OMEGA][0], 0, readtrap->omega.res, FROMHARDWARE);
2214 
2215  /* phase is accumulated at 10 MHz */
2216  int k;
2217  readtrap->omega_iwave_phase_at_echo = 0;
2218  for(k = 0; k < (readtrap->time2center - readtrap->acqdelay); k++) {
2219  readtrap->omega_iwave_phase_at_echo += 10 * iwave[k / GRAD_UPDATE_TIME];
2220  }
2221  FreeNode(iwave);
2222 #endif
2223 
2224  }
2225 
2226  return SUCCESS;
2227 
2228 
2229 } /* ks_pg_readtrap */
STATUS ks_pg_read(KS_READ *read, int pos, KS_SEQ_CONTROL *ctrl)
Places a KS_READ sequence object at some position in the pulse sequence
Definition: KSFoundation_common.c:2051
STATUS ks_pg_wave(KS_WAVE *wave, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_WAVE sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2289
#define areSame(a, b)
Definition: KSFoundation.h:144
int pos
Definition: KSFoundation.h:463
KS_WAVE omega
Definition: KSFoundation.h:1562
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
int duration
Definition: KSFoundation.h:1227
KS_TRAP grad
Definition: KSFoundation.h:1561
float ampscale
Definition: KSFoundation.h:464
int omega_iwave_phase_at_echo
Definition: KSFoundation.h:1564
WF_PULSE ** wfpulse
Definition: KSFoundation.h:753
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
KS_DESCRIPTION description
Definition: KSFoundation.h:668
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
KS_READ acq
Definition: KSFoundation.h:1549
int duration
Definition: KSFoundation.h:673
STATUS ks_pg_trap(KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_TRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1802
int time2center
Definition: KSFoundation.h:1560
int res
Definition: KSFoundation.h:746
int acqdelay
Definition: KSFoundation.h:1555
int duration
Definition: KSFoundation.h:747

◆ ks_pg_readwave()

STATUS ks_pg_readwave ( KS_READWAVE readwave,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

ADDTITLEHERE

2232  {
2233  STATUS status;
2234 
2235  int startpos = loc.pos;
2236  KS_SEQLOC omegaloc = KS_INIT_SEQLOC;
2237  omegaloc.board = OMEGA;
2238  omegaloc.pos = startpos + readwave->acqdelay;
2239  omegaloc.ampscale = 1.0f;
2240 
2241  /* Readout waveforms */
2242  /* readwave->delay should be 0 */
2243  loc.pos = startpos + readwave->delay;
2244 
2245 
2246 
2247  status = ks_pg_wave(&readwave->grad, loc, ctrl);
2248  KS_RAISE(status);
2249 
2250  /* Omega */
2251  status = ks_pg_wave(&readwave->omega, omegaloc, ctrl);
2252  KS_RAISE(status);
2253 
2254  int state;
2255  for (state = 0; state < KS_READCONTROL_MAXSTATE; state++) {
2256  if (readwave->grad.p_waveformstates[state] != NULL ) {
2257  ks_pg_addwaveformstate(&readwave->grad, readwave->grad_states[state], state);
2258  }
2259  if (readwave->omega.p_waveformstates[state] != NULL ) {
2260  ks_pg_addwaveformstate(&readwave->omega, readwave->omega_states[state], state);
2261  }
2262  }
2263 
2264  /* Acquisition */
2265  status = ks_pg_read(&readwave->acq, omegaloc.pos, ctrl);
2266  KS_RAISE(status);
2267 
2268 #ifdef IPG
2269  short * iwave = (short *) AllocNode(readwave->omega.res * sizeof(short));
2270  movewaveimm(iwave, &readwave->omega.wfpulse[OMEGA][0], 0, readwave->omega.res, FROMHARDWARE);
2271 
2272  /* phase is accumulated at 10 MHz */
2273  int k;
2274  readwave->omega_iwave_phase_at_echo = 0;
2275  for(k = 0; k < (readwave->time2center - readwave->acqdelay); k++) {
2276  readwave->omega_iwave_phase_at_echo += 10 * iwave[k / GRAD_UPDATE_TIME];
2277  }
2278  FreeNode(iwave);
2279 #endif
2280 
2281  return SUCCESS;
2282 }
STATUS ks_pg_read(KS_READ *read, int pos, KS_SEQ_CONTROL *ctrl)
Places a KS_READ sequence object at some position in the pulse sequence
Definition: KSFoundation_common.c:2051
STATUS ks_pg_wave(KS_WAVE *wave, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_WAVE sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2289
KS_WAVEFORM omega_states[KS_READCONTROL_MAXSTATE]
Definition: KSFoundation.h:1619
int pos
Definition: KSFoundation.h:463
KS_WAVE omega
Definition: KSFoundation.h:1605
int time2center
Definition: KSFoundation.h:1615
int board
Definition: KSFoundation.h:462
KS_WAVE grad
Definition: KSFoundation.h:1604
float ampscale
Definition: KSFoundation.h:464
WF_PULSE ** wfpulse
Definition: KSFoundation.h:753
int delay
Definition: KSFoundation.h:1607
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
KS_WAVEFORM grad_states[KS_READCONTROL_MAXSTATE]
Definition: KSFoundation.h:1618
int omega_iwave_phase_at_echo
Definition: KSFoundation.h:1617
float * p_waveformstates[KS_WAVE_MAXNSTATES]
Definition: KSFoundation.h:749
STATUS ks_pg_addwaveformstate(KS_WAVE *wave, KS_WAVEFORM waveform, int state_index)
Allocates an additional waveformstate in sequencer memory
Definition: KSFoundation_common.c:2544
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
int acqdelay
Definition: KSFoundation.h:1608
KS_READ acq
Definition: KSFoundation.h:1606
int res
Definition: KSFoundation.h:746
#define KS_READCONTROL_MAXSTATE
Definition: KSFoundation.h:259

◆ ks_pg_wave()

STATUS ks_pg_wave ( KS_WAVE wave,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places a KS_WAVE sequence object on a board at some position in the pulse sequence

pg_wave.svg
graphical description

This function should be called in the @pg section to place out a KS_WAVE sequence object that creates an arbitrary waveform in the pulse sequence. The same KS_WAVE object can be placed on any board as many times as desired, by only changing the second argument each time (to avoid waveform overlaps). However, the RHO (RF) board should be avoided as this bypasses RF scaling and SAR calculations, providing no control over the flip angle. For RF waveforms, always use KS_RF (or KS_SELRF). The second argument is a KS_SEQLOC struct with three fields:

  • .board: Choose between XGRAD, YGRAD, ZGRAD, OMEGA, THETA
  • .pos: Absolute time in [us] of the start of the waveform. For RF, OMEGA and THETA, pos_rf_wait will be added to this time to take system delays into account
  • .ampscale: For gradient boards, this factor must be in range [-1.0,1.0] that is multiplied with the waveform to yield a per-instance (i.e. per-placement) amplitude ([G/cm]). For THETA, only values of +1.0 and -1.0 is allowed, and for OMEGA only 1.0 is allowed

The KS_WAVE sequence object contains a KS_WAVEFORM (float[KS_MAXWAVELEN]) to hold the waveform. The physical unit of the waveform in the KS_WAVE object depends the board on which it is placed using ks_pg_wave(). For the

  • gradient boards (XGRAD, YGRAD, ZGRAD), the unit is [G/cm]
  • THETA board, the unit is [degrees]
  • RF (RHO) and OMEGA boards, the units are arbitrary (c.f. ks_eval_rf() and ks_eval_wave()). Don't call ks_pg_wave() directly to place a KS_WAVE on the RF board

When a waveform is placed on OMEGA, neither the waveform amplitude nor the .ampscale (in KS_SEQLOC) affects the final frequency modulation. Instead the run-time amplitude of a KS_WAVE object on the OMEGA board is controlled in scan() via a function called ks_scan_omegawave_hz(), where the largest value in the field .waveform[] in the KS_WAVE will correspond to the value in [Hz] provided.

If the .duration field in the KS_WAVE object is 0, ks_pg_wave() will return SUCCESS and quietly ignore placing it out. This is a part of the mechanism that setting the .duration field to 0 in cveval() should eliminate its existance in both timing calulations and in the pulse sequence generation in @pg

This function adds an instruction and a waveform (state 0) in the sequencer memory. If you intend to use states this function must always be called first, before you try: ks_pg_addwaveformstate. For more infor see ks_pg_addwaveformstate

Regardless of the order placed out in the @pg section, and on which boards (XGRAD, YGRAD, ZGRAD) the KS_WAVE object is placed, the instance number of the KS_WAVE is automatically sorted in time. If two instances of one KS_WAVE occur at the same time (.pos) on different boards, XGRAD comes before YGRAD, which comes before ZGRAD. These abstract, sorted, instance numbers are used by ks_scan_***() functions in scan() to refer to a specific instance of a KS_WAVE object in the sequence.

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

Parameters
[in,out]wavePointer to a KS_WAVE sequence object
[in]locKS_SEQLOC struct to specify when and where to place the KS_WAVE
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_WAVE
Return values
STATUSSUCCESS or FAILURE
2289  {
2290 
2291  STATUS status;
2292  (void)status;
2293 
2294  float boardmax;
2295  char boardc[8] = "xyzrrto"; /* x,y,z,rho1,rho2,theta,omega */
2296 
2297  boardmax = ks_syslimits_gradtarget(loggrd, loc.board); /* returns 1.0 for non-gradients boards */
2298 
2299  float min_fs_factor = wave->abs_max_amp / boardmax;
2300  if (wave->fs_factor < min_fs_factor) {
2301  wave->fs_factor = min_fs_factor;
2302  }
2303 
2304  /* checking for NULL pointers */
2305  if (wave == NULL) {
2306  return ks_error("ks_pg_wave: First argument is NULL");
2307  }
2308  /* duration of 0 should not throw an error as this is a sign of that it has not been set up
2309  or has manually been disabled this way */
2310  if (wave->duration == 0) {
2311  return SUCCESS;
2312  }
2313  if (wave->description == NULL || wave->description[0] == 0 || wave->description[0] == ' ') {
2314  return ks_error("ks_pg_wave: Invalid description ('%s')", wave->description);
2315  }
2316 
2317 #ifndef IPG
2318  /* HOST: eval the wave to ensure its members have been computed correctly */
2319  int isGrad = (loc.board == XGRAD || loc.board == YGRAD || loc.board == ZGRAD);
2320  ks_wave_compute_params(wave);
2321  /* we use config variables because loggrd or physgrd may be derated for silent scanning purposes selrf waves are timing sensitive */
2322  extern float cfxfs, cfyfs, cfzfs;
2323  extern int cfrmp2xfs, cfrmp2yfs, cfrmp2zfs;
2324  float slew_limit = sqrt(3.0) * FMin(3, cfxfs, cfyfs, cfzfs)/IMax(3,cfrmp2xfs,cfrmp2yfs,cfrmp2zfs);
2325  /* multiply by 1.00001 to account for errors cause by floating point calcs */
2326  if ((isGrad) && (fabs(wave->abs_max_slew * loc.ampscale) > (1.00001 * slew_limit))) {
2327  int _i;
2328  ks_waveform_maxslew(wave->waveform, wave->res, wave->duration, &_i);
2329  KS_THROW("wave(%s) exceeds the least conservative gradient slew rate limit at index %d. This will not scan. %f > %f", wave->description, _i, fabs(wave->abs_max_slew * loc.ampscale), (1.00001 * slew_limit));
2330 #ifdef PSD_HW
2331  return FAILURE; /* TODO: why not return the error on the host? */
2332 #endif
2333  }
2334 #endif
2335 
2336 #ifdef IPG
2337  /* TGT: Don't place anything on hardware if ctrl->duration = 0.
2338  This is in concert with:
2339  - not performing createseq() in KS_SEQLENGTH if seqctrl.duration = 0
2340  - not playing sequence modules in scan() using ks_scan_playsequence() if seqctrl.duration = 0
2341  */
2342  if (ctrl->duration == 0) {
2343  return KS_THROW("%s: Refusing to place wave since seqctrl.duration = 0 (indicating `%s` not to be played in scan())", wave->description, ctrl->description);
2344  }
2345 
2346  if (!ctrl->gradrf.is_cleared_on_tgt) /* Reset gradrfctrl on tgt to remove dead pointers copied from host. */
2347  {
2349  }
2350 
2351 #endif
2352 
2353  /* input validation */
2354  if (wave->duration % 4) {
2355  return ks_error("ks_pg_wave(%s): field 'duration' (%d) must be divisible by 4", wave->description, wave->duration);
2356  }
2357  if (wave->res == 0) {
2358  return ks_error("ks_pg_wave(%s): field 'res' cannot be 0", wave->description);
2359  }
2360  if (wave->duration % wave->res) {
2361  return ks_error("ks_pg_wave(%s): field 'duration' (%d) must be divisible by 'res' %d", wave->description, wave->duration, wave->res);
2362  }
2363  if (loc.board == XGRAD || loc.board == YGRAD || loc.board == ZGRAD) {
2364  if ((wave->duration / wave->res) % GRAD_UPDATE_TIME) {
2365  return ks_error("ks_pg_wave(%s): field 'duration' (%d) must a multiple of %d times 'res' (%d) for gradient boards", wave->description, wave->duration, GRAD_UPDATE_TIME, wave->res);
2366  }
2367  if (wave->gradwave_units == KS_GRADWAVE_ABSOLUTE && !areSame(loc.ampscale,1.0)) {
2368  ks_error("ks_pg_wave(%s): ampscale must be +1.0 for gradwave with absolute units", wave->description); /* TODO: missing return */
2369  }
2370  } else {
2371  if ((wave->duration / wave->res) % RF_UPDATE_TIME) {
2372  return ks_error("ks_pg_wave(%s): field 'duration' (%d) must a multiple of 2 times 'res' (%d) for non-gradient boards", wave->description, wave->duration, wave->res);
2373  }
2374  }
2375 
2376  if (isNaN(loc.ampscale)) {
2377  return ks_error("ks_pg_wave(%s): loc.ampscale NaN", wave->description);
2378  }
2379  if (loc.pos < GRAD_UPDATE_TIME || loc.pos > 4e6) {
2380  return ks_error("ks_pg_wave(%s): Invalid position %d, it must be between 4us and 4s", wave->description, loc.pos);
2381  }
2382  if (loc.board == OMEGA && !areSame(loc.ampscale,1.0)) {
2383  return ks_error("ks_pg_wave(%s): ampscale must be +1.0 for OMEGA", wave->description);
2384  }
2385  if (loc.board == THETA && !areSame(loc.ampscale,1.0) && !areSame(loc.ampscale,-1.0)) {
2386  return ks_error("ks_pg_wave(%s): ampscale must be +1.0 or -1.0 for THETA", wave->description);
2387  }
2388  if (loc.ampscale < -1.0 || loc.ampscale > 1.0) {
2389  return ks_error("ks_pg_wave(%s): Invalid ampscale %g, it must be between -1.0 and 1.0", wave->description, loc.ampscale);
2390  }
2391  if (fabs(wave->abs_max_amp * loc.ampscale) > boardmax && loc.board != THETA && loc.board != OMEGA) {
2392  return ks_error("ks_pg_wave(%s): wave amplitude (%.2f) exceeds maximum (%g) for board %c", wave->description, wave->abs_max_amp * loc.ampscale, boardmax, boardc[loc.board]);
2393  }
2394 
2395  if (loc.board != OMEGA) {
2396  loc.pos = RUP_GRD(loc.pos);
2397  }
2398 
2399 #ifdef HOST_TGT
2400 
2401  /* HOST */
2402  /* update instance counter on host only. This counter is used to allocate the right amount of WFINSTANCEs on IPG */
2403  wave->base.ninst++;
2404 
2405  KS_SEQLOC *locs = (KS_SEQLOC*) realloc(wave->locs, sizeof(KS_SEQLOC)*wave->base.ninst);
2406  if (!locs) {
2407  return KS_THROW("Realloc failed");
2408  }
2409  wave->locs = locs;
2410  wave->locs[wave->base.ninst-1] = loc;
2411 
2412  ks_sort_loc_by_timeboard(wave->locs, wave->base.ninst);
2413 
2414  /* To check if pg has been called */
2415  wave->base.nstates = 1; /* this function will create state0 */
2416  wave->p_waveformstates[0] = wave->waveform;
2417  /* for wave, we also need to keep track of #instances per X, Y, Z for gradient heating calculations.
2418  As this needs to be done in HOST before the IPG (target), we can't use the wfi[...].boardinstance or .loc information above for this */
2419  if (loc.board == XGRAD || loc.board == YGRAD || loc.board == ZGRAD) {
2420  wave->gradnum[loc.board]++;
2421  }
2422 
2423 #else
2424 
2425  {
2426 
2427  short i;
2428  int isrf;
2429  char tmpstr[KS_DESCRIPTION_LENGTH + 14];
2430 
2431  if (wave->base.ngenerated >= wave->base.ninst) {
2432  return ks_error("ks_pg_wave @tgt(%s): the number of instances generated on the target (%d) exceeds the number of ones generated on the host (%d)", wave->description, wave->base.ngenerated + 1, wave->base.ninst);
2433  }
2434 
2435 
2436  /* first call on TGT, allocate WF_PULSE * array where each element corresponds to one board */
2437  if (wave->wfpulse == NULL) {
2438  wave->wfpulse = (WF_PULSE **) AllocNode(7 * sizeof(WF_PULSE *)); /* WF pointers for all boards (XGRAD->OMEGA) */
2439  } /* wfpulse == NULL */
2440 
2441 
2442  /* first call on TGT using this loc.board, make waveform memory */
2443  if (wave->wfpulse[loc.board] == NULL) {
2444  WF_PULSE wfInit = INITPULSE;
2445  wave->wfpulse[loc.board] = (WF_PULSE *) AllocNode(wave->base.nstates * sizeof(WF_PULSE)); /* allocate memory for nstates */
2446  wave->wave_ptrs = (LONG *) AllocNode(wave->base.nstates * sizeof(LONG));
2447  /* give the pulse for each state a unqiue name */
2448  for (i = 0; i < wave->base.nstates; i++) {
2449  wave->wfpulse[loc.board][i] = wfInit;
2450  sprintf(tmpstr, "%s.state%d.%c", wave->description, i, boardc[loc.board]);
2451  pulsename(&(wave->wfpulse[loc.board][i]), tmpstr);
2452  wave->wfpulse[loc.board][i].type = TYPEXTERNAL;
2453  }
2454 
2455  /* wave -> short int wave for hardware use. All waveforms but THETA are autoscaled to +/- max_pg_wamp (32766)*/
2456  short * iwave = (short *) AllocNode(wave->res * sizeof(short));
2457  status = ks_wave2iwave(iwave, wave, loc.board);
2458  KS_RAISE(status);
2459 
2460  /* STATE 0 is the primary waveform; we reserve the memory for this pulse here*/
2461  createreserve(&wave->wfpulse[loc.board][0], (WF_PROCESSOR) loc.board, wave->res);
2462  movewaveimm(iwave, &wave->wfpulse[loc.board][0], (int) 0, wave->res, TOHARDWARE);
2463  getwave(&wave->wave_ptrs[0], &wave->wfpulse[loc.board][0]);
2464  FreeNode(iwave);
2465  } /* wfpulse[loc.board] == NULL */
2466 
2467  int iamp;
2468 
2469  /* create instruction at the current position */
2470  isrf = loc.board == RHO || loc.board == RHO2 || loc.board == THETA || loc.board == OMEGA;
2471 
2472  switch (loc.board) {
2473  case RHO:
2474  case RHO2:
2475  {
2476  wave->fs_factor = 1.0f;
2477  iamp = (int)((wave->abs_max_amp * loc.ampscale / boardmax) * MAX_PG_IAMP);
2478  break;
2479  }
2480  case XGRAD:
2481  case YGRAD:
2482  case ZGRAD:
2483  {
2484  iamp = (int)((wave->abs_max_amp * loc.ampscale / (wave->fs_factor * boardmax)) * MAX_PG_IAMP);
2485  break;
2486  }
2487  case OMEGA:
2488  {
2489  /* The TARDIS_FREQ_RES = 10e6 / (1 << 24) is the effect of one bit. This is the overflow period of the 24-bit register
2490  when incremented by 1 at 10 MHz = 0.586 Hz.
2491  The product of iwave and iamp is only 16 bit wide and is therefore shift left 8 bits before being added to the accumulator,
2492  this effectively mulitplies this value by 256 - so we need to shift 8 to the right here to be in the correct units [Hz] */
2493  iamp = (int)((wave->abs_max_amp * loc.ampscale / (wave->fs_factor * TARDIS_FREQ_RES))) >> 8;
2494  break;
2495  }
2496  case THETA:
2497  {
2498  iamp = (int)(loc.ampscale * MAX_PG_IAMP);
2499  break;
2500  }
2501  default:
2502  KS_RAISE(ks_error("Wave scaling is currently not implemented for board: %i", loc.board));
2503  }
2504 
2505  createinstr(&wave->wfpulse[loc.board][0],
2506  (long) (loc.pos + (psd_rf_wait * isrf)),
2507  (long) wave->duration,
2508  (long) iamp);
2509 
2510  /* WF instance bookkeeping */
2511  if (wave->wfi == NULL) {
2512  wave->wfi = (KS_WFINSTANCE *) AllocNode(wave->base.ninst * sizeof(KS_WFINSTANCE));
2513  }
2514  wave->wfi[wave->base.ngenerated].boardinstance = wave->wfpulse[loc.board][0].ninsts - 1;
2515  wave->wfi[wave->base.ngenerated].wf = wave->wfpulse[loc.board];
2516  wave->wfi[wave->base.ngenerated].loc = loc;
2517 
2518  wave->base.ngenerated++;
2519 
2520  wave->p_waveformstates[0] = wave->waveform;
2521 
2522  /* sort after the last instance is generated */
2523  if (wave->base.ngenerated == wave->base.ninst) {
2524  ks_sort_wfi_by_timeboard(wave->wfi, wave->base.ninst);
2525  }
2526 
2527  }
2528 
2529 #endif /* IPG or HOST */
2530 
2531  /* register this KS_WAVE for later heating calculations */
2532  {
2533  STATUS status = ks_eval_addwavetogradrfctrl(&ctrl->gradrf, wave);
2534  KS_RAISE(status);
2535  }
2536  wave->current_state = (int *) AllocNode(wave->base.ngenerated * sizeof(int*));
2537 
2538  return SUCCESS;
2539 
2540 } /* ks_pg_wave */
Definition: KSFoundation.h:2359
void ks_sort_wfi_by_timeboard(KS_WFINSTANCE *a, int nitems)
Sort WF_INSTANCEs in time, then board
Definition: KSFoundation_common.c:4120
float fs_factor
Definition: KSFoundation.h:756
int boardinstance
Definition: KSFoundation.h:484
float abs_max_slew
Definition: KSFoundation.h:760
#define areSame(a, b)
Definition: KSFoundation.h:144
KS_SEQLOC * locs
Definition: KSFoundation.h:752
int pos
Definition: KSFoundation.h:463
(Internal use) Structure being a part of various sequence objects to sort them in time across boards...
Definition: KSFoundation.h:483
int ninst
Definition: KSFoundation.h:494
int gradwave_units
Definition: KSFoundation.h:751
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
int duration
Definition: KSFoundation.h:1227
float ks_syslimits_gradtarget(LOG_GRAD loggrd, int board)
Returns the maximum target amplitude for a board (internal use)
Definition: KSFoundation_common.c:264
float ampscale
Definition: KSFoundation.h:464
KS_GRADRFCTRL gradrf
Definition: KSFoundation.h:1236
int isNaN(float a)
Definition: KSFoundation_common.c:58
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
int gradnum[3]
Definition: KSFoundation.h:750
float abs_max_amp
Definition: KSFoundation.h:761
void ks_wave_compute_params(KS_WAVE *const wave)
Fills the members of the KS_WAVE sequence object
Definition: KSFoundation_common.c:1123
KS_SEQLOC loc
Definition: KSFoundation.h:486
KS_DESCRIPTION description
Definition: KSFoundation.h:745
LOG_GRAD loggrd
LONG * wave_ptrs
Definition: KSFoundation.h:763
int is_cleared_on_tgt
Definition: KSFoundation.h:1065
STATUS ks_eval_addwavetogradrfctrl(KS_GRADRFCTRL *gradrfctrl, KS_WAVE *wave)
*Internal use*. Adds a wave (KS_WAVE) - if it is not a part of a KS_RF object - to the KS_GRADRFCTRL ...
Definition: KSFoundation_common.c:4735
WF_PULSE ** wfpulse
Definition: KSFoundation.h:753
KS_BASE base
Definition: KSFoundation.h:744
#define KS_RAISE(status)
Definition: KSFoundation.h:190
float ks_waveform_maxslew(const KS_WAVEFORM waveform, int res, int duration, int *index)
Returns the maximum absolute value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1366
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
WF_PULSE * wf
Definition: KSFoundation.h:485
int nstates
Definition: KSFoundation.h:495
int * current_state
Definition: KSFoundation.h:762
float * p_waveformstates[KS_WAVE_MAXNSTATES]
Definition: KSFoundation.h:749
void ks_tgt_reset_gradrfctrl(KS_GRADRFCTRL *gradrfctrl)
Definition: KSFoundation_tgt.c:1797
STATUS ks_wave2iwave(KS_IWAVE iwave, const KS_WAVE *wave, int board)
(Internal use) Conversion of waveform content in a KS_WAVE sequence object to a short int array for u...
Definition: KSFoundation_common.c:1721
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
int ngenerated
Definition: KSFoundation.h:496
int psd_rf_wait
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748
int duration
Definition: KSFoundation.h:747
void ks_sort_loc_by_timeboard(KS_SEQLOC *a, int nitems)
Sort KS_SEQLOCs in time, then board
Definition: KSFoundation_common.c:4128

◆ ks_pg_addwaveformstate()

STATUS ks_pg_addwaveformstate ( KS_WAVE wave,
KS_WAVEFORM  waveform,
int  state_index 
)

Allocates an additional waveformstate in sequencer memory

pg_addwaveformstate.svg
graphical description

This function reserves additional space on the sequencer waveform memory and assignes the state=state_index to the waveform. During the scan it is then possible to make any instance of theat KS_WAVE object point to an alternative state using the fuction ks_scan_setwavestate, effectively changing the waveform shape in real time. This approach is much more effecient and safer than ks_scan_wave2hardware because we can ensure the waveform states used pass gradient and SAR limits. A drawback is that sequencer memory is not unlimited, so we have limited the number of states to #define KS_WAVE_MAXNSTATES 16 (in future we will increase this). If you require more waveform shapes than that, then you would have to use the more complicated ks_scan_wave2hardware.

ks_pg_wave needs to be called on the KS_WAVE object before you can use this function. It is also important to note that ks_pg_wave reserves state0, so don't overwrite 0 if you intend to use it. This function can be used on any KS_WAVE object. eg. if you would like to add multiple RF envelopes to a KS_SELRF compound object you can add additional states to the KS_WAVE members (like &myselrf->rf.wave) once you have called the pg_selrf function.

Parameters
[in,out]wavePointer to a KS_WAVE sequence object
[in]waveformA KS_WAVEFORM representing a new state/shape
[in]state_index
2544  {
2545 
2546  STATUS status;
2547  (void)status;
2548 
2549 #ifdef HOST_TGT
2550  const float waveform_abs_max = ks_waveform_absmax(waveform, wave->res);
2551  if(wave->base.nstates == 0) {
2552  return ks_error("%s [%s]: cannot add state before ks_wave_pg is called.", __FUNCTION__, wave->description);
2553  }
2554 
2555  if (state_index == wave->base.nstates) {
2556  wave->base.nstates = state_index + 1;
2557  }
2558 
2559  if(wave->max_amp < waveform_abs_max) {
2560  return ks_error("%s [%s]: can't add a waveform state with a larger amplitude.", __FUNCTION__, wave->description);
2561  }
2562 
2563  int idx_slew_max;
2564  float slew_max = ks_waveform_maxslew(waveform, wave->res, wave->duration, &idx_slew_max);
2565  /* times > 1 in case of float rounding */
2566  extern float cfxfs, cfyfs, cfzfs;
2567  extern int cfrmp2xfs, cfrmp2yfs, cfrmp2zfs;
2568  float slew_limit = sqrt(3.0) * FMin(3, cfxfs, cfyfs, cfzfs)/IMax(3,cfrmp2xfs,cfrmp2yfs,cfrmp2zfs)* 1.00001;
2569  int i = 0;
2570  for (; i < wave->base.ninst; i++) {
2571  KS_SEQLOC loc = wave->locs[i];
2572  int isGrad = (loc.board == XGRAD || loc.board == YGRAD || loc.board == ZGRAD);
2573  if ((isGrad) && (slew_max > slew_limit)) {
2574  /* TODO: no return? */
2575 #ifdef PSD_HW
2576  return KS_THROW("[%s]: state %i exceeds the least conservative gradient slew rate limit at index %d. %f > %f",
2577  wave->description, state_index, idx_slew_max, slew_max, slew_limit);
2578 #else
2579  KS_THROW("[%s]: state %i exceeds the least conservative gradient slew rate limit at index %d. This will not scan %f > %f",
2580  wave->description, state_index, idx_slew_max, slew_max, slew_limit);
2581 #endif
2582  }
2583  if (loc.board == RHO) {
2584  if (waveform_abs_max > 1.0f) {
2585  return KS_THROW("[%s]: RHO waves must be normalised (%1.3f > 1)", wave->description, waveform_abs_max);
2586  }
2587  }
2588  }
2589 #endif
2590 
2591  if (state_index < KS_WAVE_MAXNSTATES) {
2592  wave->p_waveformstates[state_index] = waveform;
2593  } else {
2594  return ks_error("%s [%s]: you have exceeded the maximum number of wavestates = %i", __FUNCTION__, wave->description, KS_WAVE_MAXNSTATES);
2595  }
2596 
2597  /*TODO: test slew rate for this board if(wave->abs_max_slew < ks_waveform_maxslew(waveform, wave->res, wave->duration)) {
2598  return ks_error("%s [%s]: can't add a waveform state with a higher max slew rate", __FUNCTION__, wave->description);
2599  }*/
2600 
2601 #ifndef HOST_TGT
2602  if(state_index > wave->base.nstates)
2603  return ks_error("ks_pg_addwavestate: state_index too large");
2604  /* wave -> short int wave for hardware use. All waveforms but THETA are autoscaled to +/- max_pg_wamp (32766)*/
2605  WF_PULSE * wfpulse;
2606  int board;
2607  short * iwave = (short *) AllocNode(wave->res * sizeof(short));
2608  int skippedboards = 0;
2609  for(board = 0; board < 7; board++) {
2610  wfpulse = wave->wfpulse[board];
2611  if (!wfpulse) {
2612  skippedboards++;
2613  continue;
2614  }
2615 
2616  float max_amp;
2617  if (board == RHO) {
2618  /* RHO waves are scaled after predownload */
2619  max_amp = 1.0;
2620  } else {
2621  max_amp = wave->abs_max_amp;
2622  }
2623  /* Here we adjust the iwave amplitude to achieve the correct final amplitude iamp*iwave*/
2624  status = ks_waveform2iwave(iwave,
2625  waveform,
2626  wave->res,
2627  board,
2628  max_amp,
2629  wave->fs_factor);
2630  KS_RAISE(status);
2631 
2632  createreserve(&wfpulse[state_index], (WF_PROCESSOR) board, wave->res);
2633  movewaveimm(iwave, &wfpulse[state_index], (int) 0, wave->res, TOHARDWARE);
2634  getwave(&wave->wave_ptrs[state_index], &wave->wfpulse[board][state_index]);
2635  }
2636  FreeNode(iwave);
2637 
2638  if (skippedboards == 7) {
2639  return ks_error("%s [%s] -> state %d: no WF_PULSES have been allocated, something is very wrong!", __FUNCTION__, wave->description, state_index);
2640  }
2641 
2642 #endif
2643 
2644  return SUCCESS;
2645 }
float fs_factor
Definition: KSFoundation.h:756
KS_SEQLOC * locs
Definition: KSFoundation.h:752
int ninst
Definition: KSFoundation.h:494
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
STATUS ks_waveform2iwave(KS_IWAVE iwave, const KS_WAVEFORM waveform, int res, int board, float max, float fs_factor)
(Internal use) Conversion of a KS_WAVEFORM to a short int array for use on hardware
Definition: KSFoundation_common.c:1698
int board
Definition: KSFoundation.h:462
float abs_max_amp
Definition: KSFoundation.h:761
KS_DESCRIPTION description
Definition: KSFoundation.h:745
LONG * wave_ptrs
Definition: KSFoundation.h:763
WF_PULSE ** wfpulse
Definition: KSFoundation.h:753
KS_BASE base
Definition: KSFoundation.h:744
float max_amp
Definition: KSFoundation.h:759
#define KS_RAISE(status)
Definition: KSFoundation.h:190
float ks_waveform_maxslew(const KS_WAVEFORM waveform, int res, int duration, int *index)
Returns the maximum absolute value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1366
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
#define KS_WAVE_MAXNSTATES
Definition: KSFoundation.h:293
float ks_waveform_absmax(const KS_WAVEFORM waveform, int res)
Returns the maximum absolute value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1336
int nstates
Definition: KSFoundation.h:495
float * p_waveformstates[KS_WAVE_MAXNSTATES]
Definition: KSFoundation.h:749
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int res
Definition: KSFoundation.h:746
int duration
Definition: KSFoundation.h:747

◆ ks_pg_rf()

STATUS ks_pg_rf ( KS_RF rf,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places a KS_RF sequence object on a board at some position in the pulse sequence

This function should be called in the @pg section to place out a KS_RF sequence object that creates an RF pulse in the pulse sequence. The same KS_RF object can be placed out as many times as desired, by only changing the second argument each time (to avoid waveform overlaps). The second argument is a KS_SEQLOC struct with three fields:

  • .board: Ignored. .rfwave will always be placed on RHO. If the resolution of .omegawave is non-zero it will be placed on OMEGA, and correspondingly for .thetawave on THETA
  • .pos: Absolute time in [us] of the start of the waveform
  • .ampscale: A factor that must be in range [-1.0,1.0] that is multiplied with .amp to yield a per-instance (i.e. per-placement) amplitude. For KS_RF objects this will cause the flip angle to be reduced on a per-instance basis. This can be used to generate a variable flip-angle train of RF pulses using a single KS_RF object. An .ampscale of -1.0 is equivalent to adding a 180 degree RF phase shift to the RF pulse

If the rfwave.duration field in the KS_RF object is 0, ks_pg_rf() will return SUCCESS and quietly ignore placing it out. This is a part of the mechanism that setting the .duration field to 0 in cveval() should eliminate its existance in both timing calulations and in the pulse sequence generation in @pg

As ks_pg_rf() internally calls ks_pg_wave() for its KS_WAVEs, see ks_scan_setwavestate, ks_scan_wave2hardware if you want to modiy waveforms during the scan.

Regardless of the order placed out in the @pg section the KS_RF object is placed, the instance number of the KS_RF is automatically sorted in time. These abstract, sorted, instance numbers are used by ks_scan_***() functions in scan() to refer to a specific instance of a KS_RF object in the sequence.

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

When ks_pg_rf() is run in cveval() (on HOST), the field .rfpulse.activity that was first set to 0 by ks_eval_rf() is now set to PSD_APS2_ON + PSD_MPS2_ON + PSD_SCAN_ON by ks_pg_rf(). This triggers the RF functions used in ks_eval_hwlimits() to include this KS_RF object in RF scaling and SAR calculations. Each time ks_pg_rf() is called, the field .rfpulse.num is incremented after being first set to 0 by ks_eval_rf(). Hence, it is crucial that the sequence generating function (c.f. KS_SEQ_CONTROL) containing all ks_pg_***() calls is executed between the ks_eval_rf() setup call and the call to ks_eval_hwlimits()

Parameters
[in,out]rfPointer to a KS_RF sequence object
[in]locKS_SEQLOC struct to specify when to place the KS_RF
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_RF
Return values
STATUSSUCCESS or FAILURE
2652  {
2653 
2654  STATUS status;
2655 
2656  /* input validation */
2657  if (rf == NULL) {
2658  return ks_error("%s: First argument is NULL", __FUNCTION__);
2659  }
2660 
2661  /* duration of 0 should not throw an error as this is a sign of that it has not been set up
2662  or has manually been disabled this way */
2663  if (rf->rfwave.duration == 0) {
2664  return SUCCESS;
2665  }
2666  if (rf->rfwave.description == NULL || rf->rfwave.description[0] == 0 || rf->rfwave.description[0] == ' ') {
2667  return ks_error("ks_pg_rf: Invalid description ('%s')", rf->rfwave.description);
2668  }
2669 
2670 #ifdef IPG
2671  /* TGT: Don't place anything on hardware if ctrl->duration = 0.
2672  This is in concert with:
2673  - not performing createseq() in KS_SEQLENGTH if seqctrl.duration = 0
2674  - not playing sequence modules in scan() using ks_scan_playsequence() if seqctrl.duration = 0
2675  */
2676  if (ctrl->duration == 0) {
2677  return ks_error("%s(%s): Refusing to place RF since seqctrl.duration = 0 (indicating `%s` not to be played in scan())", __FUNCTION__, rf->rfwave.description, ctrl->description);
2678  }
2679  /* TGT: make sure (the RF pulses in) the sequence module were a part of the seqcollection when GEReq_eval_rfscaling() was called */
2680  if (ctrl->rfscalingdone == FALSE && ctrl->duration > 0) {
2681  return ks_error("%s(%s): Missing RF scaling for sequence module with non-zero duration. Add `%s` to seqcollection *before* calling GEReq_eval_rfscaling(seqcollection)", __FUNCTION__, rf->rfwave.description, ctrl->description);
2682  }
2683 
2684  if (!ctrl->gradrf.is_cleared_on_tgt) /* Reset gradrfctrl on tgt to remove dead pointers copied from host. */
2685  {
2687  }
2688 
2689 #endif
2690 
2691  loc.pos = RUP_RF(loc.pos);
2692 
2693  RFEnvelopeWaveformGeneratorCheck(rf->rfwave.description, (WF_PROCESSOR) ks_rhoboard);
2694 
2695  if (rf->omegawave.res) {
2696  if (rf->omegawave.duration != rf->rfwave.duration) {
2697  return ks_error("ks_pg_rf (%s): The duration of the omega waveform must be equal to the RF duration", rf->rfwave.description);
2698  }
2699  }
2700  if (rf->thetawave.res) {
2701  if (rf->thetawave.duration != rf->rfwave.duration) {
2702  return ks_error("ks_pg_rf (%s): The duration of the theta waveform must be equal to the RF duration", rf->rfwave.description);
2703  }
2704  }
2705 
2706  /* Set ctrl->momentstart if this is an excitation pulse */
2707  if (rf->role == KS_RF_ROLE_EXC) {
2708  ctrl->momentstart = RUP_GRD(loc.pos + rf->start2iso); /* RUP_GRD: make sure it is on a 4us raster too for gradient timing calcs */
2709  }
2710 
2711  /* register this KS_RF for later heating calculations - and do this *before* calls to ks_pg_wave() below (in this function) to avoid double registrations (c.f. ks_eval_addwavetogradrfctrl()).
2712  N.B.: While RF/sar calcs (ks_eval_rfscaling()) are not affected by this, registering the rf->rfwave both as a part of the RF object and as a separate wave in ctrl->gradrf would otherwise lead to problems for
2713  ks_gnuplot_seqmodule(). This would cause the RF pulse to show up twice in the plot / pdf / image.
2714  ks_eval_addwavetogradrfctrl() is called in ks_pg_wave() and checks if this wave also belongs to a parent registered RF pulse in which case the wave will not be registered again */
2715  {
2716  STATUS status = ks_eval_addrftogradrfctrl(&ctrl->gradrf, rf);
2717  KS_RAISE(status);
2718  }
2719 
2720 #ifdef HOST_TGT
2721 
2722  /* update rfpulse.num counter on host only. We can use this ninst variable as info
2723  for RF heating calculations */
2724  rf->rfpulse.num++;
2725 
2726  /* now that we have shown that we are really going to use this pulse, set its
2727  activity flag to SCAN, APS2, MPS2 */
2728  rf->rfpulse.activity = PSD_APS2_ON + PSD_MPS2_ON + PSD_SCAN_ON;
2729 
2730 #else
2731 
2732  if (areSame(rf->rfpulse.num, 0)) {
2733  return ks_error("ks_pg_rf @tgt(%s): pulsegen was never run on HOST (rf->rfpulse.num = 0)", rf->rfwave.description);
2734  }
2735 
2736  if (rf->rfpulse.activity == 0) {
2737  return ks_error("ks_pg_rf @tgt(%s): RF pulse with zero activity", rf->rfwave.description);
2738  }
2739 
2740  /* The values in rf->rfwave.waveform[] are relative (unit-less). The actual amplitude of the RF wave
2741  is only controlled by rf->amp (which in turn is set by GE's setScale() and indirectly by peakB1()).
2742  Prepare RF waveform with correct amplitude on TGT side that can be used with ks_pg_wave() to give the right
2743  RF amplitude, after we have done RF scaling on HOST and hence have a final value for rf->amp.
2744  The units of this RF waveform, before and after calling ks_wave_multiplywal(), are relative (not [G])
2745  due to GE's RF scaling process involving e.g. xmtaddScan.
2746  Look in GERequired.e:GEReq_eval_gradrflimits() for more info on how peakB1() and setScale() are used. */
2747 
2748  ks_wave_multiplyval(&rf->rfwave, rf->amp / ks_wave_absmax(&rf->rfwave));
2749 
2750 #endif
2751 
2752 
2753 
2754  /* place the RF wave */
2755  loc.board = RHO;
2756  status = ks_pg_wave(&rf->rfwave, loc, ctrl);
2757  KS_RAISE(status);
2758 
2759 #ifdef IPG
2760  /* add SSP RF bits that handles the frequency control and blanking/unblanking the receiver */
2761  addrfbits(&rf->rfwave.wfpulse[RHO][0], 0, loc.pos + psd_rf_wait, rf->rfwave.duration);
2762  /* set RF frequency offset */
2763  setfrequency((int)(rf->cf_offset / TARDIS_FREQ_RES), &rf->rfwave.wfpulse[RHO][0], rf->rfwave.base.ngenerated - 1);
2764 #endif
2765 
2766  /* set ampscale to 1. If you want to scale the omega or theata board, do it seperatly */
2767  loc.ampscale = 1;
2768 
2769  /* place the OMEGA wave */
2770  loc.board = OMEGA;
2771  if (rf->omegawave.res) {
2772  status = ks_pg_wave(&rf->omegawave, loc, ctrl);
2773  KS_RAISE(status);
2774 
2775 #ifdef IPG
2776  short * iwave = (short *) AllocNode(rf->omegawave.res * sizeof(short));
2777  movewaveimm(iwave, &rf->omegawave.wfpulse[OMEGA][0], 0, rf->omegawave.res, FROMHARDWARE);
2778 
2779  /* phase is accumulated at 10 MHz */
2780  int k;
2781  rf->omega_iwave_phase_at_iso = 0;
2782  for(k = 0; k < rf->start2iso; k++) {
2783  rf->omega_iwave_phase_at_iso += 10 * iwave[k / GRAD_UPDATE_TIME];
2784  }
2785  FreeNode(iwave);
2786 #endif
2787  }
2788 
2789 #ifdef IPG
2790  if (rf->omegawave.res) {
2791  /* add SSP RF bits that handles the frequency control and blanking/unblanking the receiver */
2792  addrfbits(&rf->omegawave.wfpulse[OMEGA][0], 0, loc.pos + psd_rf_wait, rf->omegawave.duration);
2793  }
2794 #endif
2795 
2796  /* place the THETA wave */
2797  loc.board = THETA;
2798  if (rf->thetawave.res) {
2799  status = ks_pg_wave(&rf->thetawave, loc, ctrl);
2800  KS_RAISE(status);
2801  }
2802 
2803 #ifdef IPG
2804  if (rf->thetawave.res) {
2805  /* add SSP RF bits that handles the frequency control and blanking/unblanking the receiver */
2806  addrfbits(&rf->thetawave.wfpulse[THETA][0], 0, loc.pos + psd_rf_wait, rf->thetawave.duration);
2807  }
2808 #endif
2809 
2810  return SUCCESS;
2811 
2812 } /* ks_pg_rf */
STATUS ks_pg_wave(KS_WAVE *wave, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_WAVE sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2289
float cf_offset
Definition: KSFoundation.h:1030
int start2iso
Definition: KSFoundation.h:1032
#define areSame(a, b)
Definition: KSFoundation.h:144
float ks_wave_absmax(const KS_WAVE *wave)
Returns the maximum absolute value in a KS_WAVE sequence object
Definition: KSFoundation_common.c:1359
int pos
Definition: KSFoundation.h:463
int role
Definition: KSFoundation.h:1027
int ks_rhoboard
Definition: KSFoundation_common.c:42
int omega_iwave_phase_at_iso
Definition: KSFoundation.h:1040
RF_PULSE rfpulse
Definition: KSFoundation.h:1036
int rfscalingdone
Definition: KSFoundation.h:1231
int momentstart
Definition: KSFoundation.h:1228
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
int duration
Definition: KSFoundation.h:1227
Definition: KSFoundation.h:2340
float ampscale
Definition: KSFoundation.h:464
KS_GRADRFCTRL gradrf
Definition: KSFoundation.h:1236
KS_WAVE thetawave
Definition: KSFoundation.h:1039
KS_DESCRIPTION description
Definition: KSFoundation.h:745
int is_cleared_on_tgt
Definition: KSFoundation.h:1065
WF_PULSE ** wfpulse
Definition: KSFoundation.h:753
KS_WAVE rfwave
Definition: KSFoundation.h:1037
KS_BASE base
Definition: KSFoundation.h:744
float amp
Definition: KSFoundation.h:1031
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ks_tgt_reset_gradrfctrl(KS_GRADRFCTRL *gradrfctrl)
Definition: KSFoundation_tgt.c:1797
STATUS ks_eval_addrftogradrfctrl(KS_GRADRFCTRL *gradrfctrl, KS_RF *rf)
*Internal use*. Adds an RF pulse to the KS_GRADRFCTRL struct for later SAR & RF power calculations in...
Definition: KSFoundation_common.c:4771
KS_WAVE omegawave
Definition: KSFoundation.h:1038
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
int ngenerated
Definition: KSFoundation.h:496
void ks_wave_multiplyval(KS_WAVE *wave, float val)
In-place scalar multiplication of a KS_WAVE
Definition: KSFoundation_common.c:1653
int psd_rf_wait
int res
Definition: KSFoundation.h:746
int duration
Definition: KSFoundation.h:747

◆ ks_pg_selrf()

STATUS ks_pg_selrf ( KS_SELRF selrf,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places a KS_SELRF sequence object on a gradient (and RF) board at some position in the pulse sequence

This function should be called in the @pg section to place out a KS_SELRF sequence object that creates an RF pulse with associated trapezoids in the pulse sequence. The same KS_SELRF object can be placed out as many times as desired, by only changing the second argument each time (to avoid waveform overlaps). The second argument is a KS_SEQLOC struct with three fields:

  • .board: Choose between XGRAD, YGRAD, ZGRAD for the board on which .pregrad, .grad (or .gradwave) and .postgrad should be placed
  • .pos: Absolute time in [us] of the start of the .pregrad attack ramp. If .pregrad has zero duration, .pos will in effect refer to the start of the .grad attack ramp
  • .ampscale: A factor that must be in range [-1.0,1.0] that is multiplied with rf.rfwave.amp to yield a per-instance (i.e. per-placement) amplitude. For KS_SELRF objects the .ampscale value will be passed on its internal call to ks_pg_rf(), but not to its internal ks_pg_trap() calls. Hence .ampscale will have the same effect for ks_pg_selrf() as for ks_pg_rf(), with no per-instance control of the amplitude of the gradients involved. A reduced .ampscale will cause the flip angle to be reduced on a per-instance basis. This can be used to generate a variable flip-angle train of selective RF pulses using a single KS_SELRF object. An .ampscale of -1.0 is equivalent to adding a 180 degree RF phase shift to the RF pulse

If the .gradwave field has a non-zero resolution, ks_pg_selrf() will place out the .gradwave (KS_WAVE) instead of the .grad (KS_TRAP) during the time the RF pulse is played out. An error is thrown if .gradwave.duration (if .gradwave.res > 0) is not equal to the .rf.rfwave.duration. If .pregrad or .postgrad has zero duration, they will not be placed out. The existance of non-zero .pregrad and .postgrad is determined by ks_eval_selrf() based on .rf.role

As ks_pg_selrf() internally calls ks_pg_wave() for its KS_WAVEs, see ks_scan_setwavestate, ks_scan_wave2hardware if you want to modiy waveforms during the scan.

Regardless of the order placed out in the @pg section the KS_SELRF object is placed, the instance number of the KS_SELRF is automatically sorted in time. These abstract, sorted, instance numbers are used by ks_scan_***() functions in scan() to refer to a specific instance of a KS_SELRF object in the sequence.

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

Parameters
[in,out]selrfPointer to a KS_SELRF sequence object
[in]locKS_SEQLOC struct to specify when and where to place the KS_SELRF
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_SELRF
Return values
STATUSSUCCESS or FAILURE
2817  {
2818 
2819  STATUS status;
2820  KS_SEQLOC rfloc;
2821  KS_SEQLOC gradloc;
2822 
2823  if (loc.board != XGRAD && loc.board != YGRAD && loc.board != ZGRAD) {
2824  return ks_error("%s(%s): loc.board (2nd arg) must be a gradient board", __FUNCTION__, selrf->rf.rfwave.description);
2825  }
2826 
2827  gradloc = loc; gradloc.ampscale = 1.0;
2828  rfloc = loc; rfloc.board = RHO;
2829 
2830  /* RF starts after the preselgrad (if present) and ramp of slicesel (if present) */
2831  rfloc.pos += selrf->grad2rf_start;
2832 
2833  /************* generate the RF (incl. optional THETA & OMEGA) *************/
2834 
2835  status = ks_pg_rf(&selrf->rf, rfloc, ctrl);
2836  KS_RAISE(status);
2837 
2838  /************************ place gradients *********************************/
2839 
2840  gradloc.ampscale = (selrf->rf.role != KS_RF_ROLE_EXC) ? loc.ampscale2 : 1.0;
2841  /* Pre-slice sel gradient. Roles: e.g. left crusher or dephasing gradient in bSSFP */
2842  status = ks_pg_trap(&selrf->pregrad, gradloc, ctrl);
2843  KS_RAISE(status);
2844  gradloc.pos += selrf->pregrad.duration;
2845 
2846 
2847 
2848  /* slice select gradient */
2849  gradloc.ampscale = 1.0;
2850 
2851  if (selrf->gradwave.res) {
2852  /* use gradwave (not trapezoid) */
2853  status = ks_pg_wave(&selrf->gradwave, gradloc, ctrl);
2854  KS_RAISE(status);
2855 
2856  gradloc.pos += selrf->gradwave.duration;
2857 
2858  } else {
2859  /* use trapezoid (not gradwave) */
2860 
2861  if (selrf->grad.plateautime != selrf->rf.rfwave.duration) {
2862  return ks_error("%s(%s): Plateau time of slice select (%d) != RF duration (%d)", __FUNCTION__, selrf->rf.rfwave.description, selrf->grad.plateautime, selrf->rf.rfwave.duration);
2863  } else {
2864  status = ks_pg_trap(&selrf->grad, gradloc, ctrl);
2865  KS_RAISE(status);
2866 
2867  gradloc.pos += selrf->grad.duration;
2868  }
2869 
2870  } /* slice select */
2871 
2872 
2873  /* post-slice sel gradient. Roles: e.g. right crusher or refocusing gradient */
2874  gradloc.ampscale = (selrf->rf.role != KS_RF_ROLE_EXC) ? loc.ampscale2 : 1.0;
2875  status = ks_pg_trap(&selrf->postgrad, gradloc, ctrl);
2876  KS_RAISE(status);
2877  gradloc.pos += selrf->postgrad.duration;
2878 
2879 
2880  return SUCCESS;
2881 
2882 } /* ks_pg_selrf */
float ampscale2
Definition: KSFoundation.h:465
int plateautime
Definition: KSFoundation.h:672
KS_TRAP grad
Definition: KSFoundation.h:1463
STATUS ks_pg_wave(KS_WAVE *wave, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_WAVE sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2289
int pos
Definition: KSFoundation.h:463
int role
Definition: KSFoundation.h:1027
KS_WAVE gradwave
Definition: KSFoundation.h:1465
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
Definition: KSFoundation.h:2340
float ampscale
Definition: KSFoundation.h:464
KS_TRAP pregrad
Definition: KSFoundation.h:1462
int grad2rf_start
Definition: KSFoundation.h:1466
STATUS ks_pg_rf(KS_RF *rf, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_RF sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2652
KS_RF rf
Definition: KSFoundation.h:1454
KS_DESCRIPTION description
Definition: KSFoundation.h:745
KS_WAVE rfwave
Definition: KSFoundation.h:1037
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
KS_TRAP postgrad
Definition: KSFoundation.h:1464
int duration
Definition: KSFoundation.h:673
STATUS ks_pg_trap(KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_TRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1802
int res
Definition: KSFoundation.h:746
int duration
Definition: KSFoundation.h:747

◆ ks_pg_wait()

STATUS ks_pg_wait ( KS_WAIT wait,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places a KS_WAIT sequence object on all boards at some position in the pulse sequence

This function should be called in the @pg section to place out a KS_WAIT sequence object that creates a wait pulse. The same KS_WAIT object can be placed out as many times as desired, by only changing the second argument each time (to avoid waveform overlaps). The second argument is a KS_SEQLOC struct with three fields:

  • .board: Ignored
  • .pos: Absolute time in [us] of the start of the wait pulse
  • .ampscale: Ignored

This function will insert a deadtime of duration equal to the .duration field in the KS_WAIT object at position .pos. This delay can be changed in run-time by calling ks_scan_wait().

GENERAL NOTE: It is a requirement that the function in the @pg section containing all ks_pg_***() calls is also called exactly once in cveval() after the calls to the corresponding ks_eval_***() functions that design the KS_*** sequence objects. Each ks_pg_***() will throw an error if this has not been done.

Parameters
[in,out]waitPointer to a KS_WAIT sequence object
[in]locKS_SEQLOC struct to specify when and where to place the KS_WAIT
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_WAIT
Return values
STATUSSUCCESS or FAILURE
2889  {
2890  int i;
2891  const int first = loc.board == KS_ALL ? XGRAD : loc.board;
2892  const int last = loc.board == KS_ALL ? SSP : loc.board;
2893 
2894  /* checking for NULL pointers */
2895  if (wait == NULL) {
2896  return ks_error("ks_pg_wait: First argument is NULL");
2897  }
2898 
2899  /* duration of 0 should not throw an error as this is a sign of that it has not been set up
2900  or has manually been disabled this way */
2901  if (wait->max_duration == 0 || wait->pg_duration == 0) {
2902  return SUCCESS;
2903  }
2904 
2905  if (wait->description == NULL || wait->description[0] == 0 || wait->description[0] == ' ') {
2906  return ks_error("ks_pg_wait: Invalid description ('%s')", wait->description);
2907  }
2908 
2909  /* disallow EPI dual boards */
2910  if (loc.board >= KS_FREQX_PHASEY && loc.board <= KS_XYZ) {
2911  return ks_error("ks_pg_wait(%s): Invalid board selection: %d", wait->description, loc.board);
2912  }
2913 
2914  loc.pos = RUP_GRD(loc.pos);
2915 
2916 #ifdef IPG
2917  {
2918 
2919  /* TGT: Don't place anything on hardware if ctrl->duration = 0.
2920  This is in concert with:
2921  - not performing createseq() in KS_SEQLENGTH if seqctrl.duration = 0
2922  - not playing sequence modules in scan() using ks_scan_playsequence() if seqctrl.duration = 0
2923  */
2924  if (ctrl->duration == 0) {
2925  ks_dbg("%s(%s): Refusing to place wait pulse since seqctrl.duration = 0 (indicating `%s` not to be played in scan())", __FUNCTION__, wait->description, ctrl->description);
2926  return SUCCESS;
2927  }
2928 
2929  if (wait->base.ngenerated >= wait->base.ninst) {
2930  return ks_error("ks_pg_wait @tgt(%s): the number of instances generated on the target exceed the number of ones generated on the host", wait->description);
2931  }
2932 
2933  if (wait->wfpulse == NULL) {
2934  WF_PULSE wfInit = INITPULSE;
2935 
2936  const char boardc[9] = "xyzrrtos";
2937  char tmpstr[KS_DESCRIPTION_LENGTH + 4];
2938  tmpstr[KS_DESCRIPTION_LENGTH + 4 - 1] = 0;
2939 
2940  wait->wfpulse = (WF_PULSE *) AllocNode(8 * sizeof(WF_PULSE));
2941  for (i = XGRAD; i <= SSP; i++) {
2942  if (i != RHO2){
2943  /* init pulse structure */
2944  wait->wfpulse[i] = wfInit;
2945 
2946  /* Name for WF_PULSEs */
2947  sprintf(tmpstr, "%s.w%c", wait->description, boardc[i]); pulsename(&(wait->wfpulse[i]), tmpstr);
2948  createconst(&(wait->wfpulse[i]), (WF_PROCESSOR) i, wait->pg_duration, 0);
2949 
2950  } /* per board */
2951  }
2952 
2953  } /* wfpulse == NULL */
2954 
2955  if (!wait->wfi) {
2956  wait->wfi = (KS_WFINSTANCE *) AllocNode(wait->base.ninst * sizeof(KS_WAIT));
2957  }
2958 
2959  for (i = first; i <= last; ++i) {
2960  if (i == KS_RHO2) continue; /* skip RHO2 */
2961 
2962  loc.board = i;
2963  int isrf = loc.board == RHO || loc.board == RHO2 || loc.board == THETA || loc.board == OMEGA;
2964  int isssp = loc.board == SSP;
2965 
2966  createinstr(&(wait->wfpulse[i]), loc.pos + (isrf * psd_rf_wait) + (isssp * psd_grd_wait), wait->pg_duration, 0);
2967  wait->wfi[wait->base.ngenerated].boardinstance = wait->wfpulse[i].ninsts - 1; /* zero based */
2968  wait->wfi[wait->base.ngenerated].wf = &(wait->wfpulse[i]);
2969  wait->wfi[wait->base.ngenerated].loc = loc;
2970  wait->base.ngenerated++;
2971  }
2972 
2973  /* sort after the last instance is generated */
2974  if (wait->base.ngenerated == wait->base.ninst) {
2975  ks_sort_wfi_by_timeboard(wait->wfi, wait->base.ninst);
2976  }
2977  }
2978 #else
2979  {
2980  KS_SEQLOC *locs = (KS_SEQLOC*) realloc(wait->locs, sizeof(KS_SEQLOC)*(wait->base.ninst + last - first + 1));
2981  if (!locs) {
2982  return KS_THROW("Realloc failed");
2983  }
2984  wait->locs = locs;
2985 
2986  for (i = first; i <= last; ++i) {
2987  if (i == KS_RHO2) continue; /* skip RHO2 */
2988  loc.board = i;
2989  wait->locs[wait->base.ninst] = loc;
2990  wait->base.ninst++;
2991  ks_sort_loc_by_timeboard(wait->locs, wait->base.ninst);
2992  STATUS status = ks_eval_addwaittogradrfctrl(&ctrl->gradrf, wait);
2993  KS_RAISE(status);
2994  }
2995  }
2996 #endif
2997 
2998  return SUCCESS;
2999 
3000 } /* ks_pg_wait */
void ks_sort_wfi_by_timeboard(KS_WFINSTANCE *a, int nitems)
Sort WF_INSTANCEs in time, then board
Definition: KSFoundation_common.c:4120
Definition: KSFoundation.h:2319
int boardinstance
Definition: KSFoundation.h:484
int pos
Definition: KSFoundation.h:463
Definition: KSFoundation.h:2315
(Internal use) Structure being a part of various sequence objects to sort them in time across boards...
Definition: KSFoundation.h:483
int ninst
Definition: KSFoundation.h:494
Core sequence object that adds wait periods in the pulse sequence (see ks_eval_wait(), ks_pg_wait()). Can be placed on any sequence board
Definition: KSFoundation.h:542
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
STATUS ks_dbg(const char *format,...)
Definition: KSFoundation_common.c:157
int board
Definition: KSFoundation.h:462
Definition: KSFoundation.h:2325
int duration
Definition: KSFoundation.h:1227
KS_DESCRIPTION description
Definition: KSFoundation.h:544
Definition: KSFoundation.h:2326
KS_GRADRFCTRL gradrf
Definition: KSFoundation.h:1236
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
KS_SEQLOC loc
Definition: KSFoundation.h:486
KS_BASE base
Definition: KSFoundation.h:543
KS_SEQLOC * locs
Definition: KSFoundation.h:547
#define KS_RAISE(status)
Definition: KSFoundation.h:190
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:549
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
WF_PULSE * wf
Definition: KSFoundation.h:485
int pg_duration
Definition: KSFoundation.h:545
int max_duration
Definition: KSFoundation.h:546
int psd_grd_wait
WF_PULSE * wfpulse
Definition: KSFoundation.h:548
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
int ngenerated
Definition: KSFoundation.h:496
STATUS ks_eval_addwaittogradrfctrl(KS_GRADRFCTRL *gradrfctrl, KS_WAIT *wait)
*Internal use*. Adds a wait pulse to the KS_GRADRFCTRL struct. Used for plotting
Definition: KSFoundation_common.c:4684
int psd_rf_wait
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
void ks_sort_loc_by_timeboard(KS_SEQLOC *a, int nitems)
Sort KS_SEQLOCs in time, then board
Definition: KSFoundation_common.c:4128

◆ ks_pg_isirot()

STATUS ks_pg_isirot ( KS_ISIROT isirot,
SCAN_INFO  scan_info,
int  pos,
void(*)()  rotfun,
KS_SEQ_CONTROL ctrl 
)

Places out an intersequence interrupt at a specific time in the sequence module

This function connects the execution of a psd-specific rotation function in realtime when time passes this point in the sequence. This is done by two KS_WAIT pulses (being part of KS_ISIROT) on the SSP board.

Example of use in a myseqmodule_pg() function of the sequence module (in pulsegen()):

// add some padding time before the SSP pulses (not well tested how much of KS_ISI_predelay that is necessary)
mypos += RUP_GRD(KS_ISI_predelay);
status = ks_pg_isirot(&myisirot, myscaninfo, mypos, myisirotatefun, myseqctrl);
KS_RAISE(status);
// add some padding time after the SSP pulses (not well tested how much of KS_ISI_postdelay that is necessary)
mypos += RUP_GRD(myisirot.duration + KS_ISI_postdelay);

where the psd-specific rotation function is declared as:

// Intra sequence interrupts placed as WAIT pulses on the SSP board may be used to call for an immediate
// rotation of the logical coordinate system in real time as these WAIT pulses are played out, as
// opposed to during the SSI time for the sequence module.
// The WAIT pulse is assigned a control number (isi number) that is then connected to this void function
// using `isivector()` in ks_pg_isirot(). No input arguments can be passed to this function. Instead the
// rotation information specific to the sequence module is provided in `myscaninfo.oprot`. The acutal
// rotation work, incl. keeping track of number of isi pulses played out is done by ks_scan_isirotate().
void myisirotatefun() {
#ifdef IPG
ks_scan_isirotate(&myisirot);
#endif
}

Note that the only difference between the psd-specific myisirotatefun() and the general ks_scan_isirotate() is that myisirotatefun() has no input arguments. Input arguments cannot be used as it is called from an interrupt routine, not from some other parent function.

Care must be taken when mixing the use of ks_scan_rotate() (executing during the SSI time) and these ISI interrupts, so that they are executed in the correct order. One way is to consistently avoid the use of ks_scan_rotate() and instead return to the prescribed slice rotation by calling ks_pg_isirot() again, last in the same myseqmodule_pg() function, this time using the prescribed scan_info struct:

status = ks_pg_isirot(&myisirot, ks_scan_info[0], mypos, myisirotatefun, myseqctrl);
KS_RAISE(status);
Parameters
[in,out]isirotPointer to a KS_ISIROT sequence object
[in]scan_infoSCAN_INFO struct holding an .oprot matrix to be used for real-time rotation
[in]posAbsolute position in [us] in the pulse sequence when this rotation should occur
[in]rotfunFunction pointer to the psd-specific rotation function
[in,out]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module
Return values
STATUSSUCCESS or FAILURE
3004  {
3005  STATUS status;
3006  KS_SEQLOC tmploc = KS_INIT_SEQLOC;
3007 
3008  if (! isirot->duration) {
3009  /* must have called ks_eval_isirot() first */
3010  return SUCCESS;
3011  }
3012 
3013  if (rotfun == NULL)
3014  return ks_error("%s: 4th arg (rotfun) cannot be NULL", __FUNCTION__);
3015 
3016 
3017  /* Set the ctrl_word to binary match the isi vector interupt number */
3018  /* /--------------------------------------------------------------\ */
3019  /* | interupt number | ctrl_word | */
3020  /* |--------------------------------------------------------------| */
3021  /* | 4 | PSD_ISI2_BIT | */
3022  /* | 5 | PSD_ISI0_BIT + PSD_ISI2_BIT | */
3023  /* | 6 | PSD_ISI1_BIT + PSD_ISI2_BIT | */
3024  /* | 7 | PSD_ISI0_BIT + PSD_ISI1_BIT + PSD_ISI2_BIT | */
3025  /* \--------------------------------------------------------------/ */
3026 
3027  tmploc.board = SSP;
3028  tmploc.pos = RUP_GRD(pos);
3029 
3030  status = ks_pg_wait(&isirot->waitfun, tmploc, ctrl);
3031  KS_RAISE(status);
3032 
3033  tmploc.pos += RUP_GRD(isirot->waitfun.max_duration);
3034 
3035  status = ks_pg_wait(&isirot->waitrot, tmploc, ctrl);
3036  KS_RAISE(status);
3037 
3038 
3039 #ifdef IPG
3040  {
3041  long ctrl_word = 0;
3042  int placementindx = isirot->waitfun.base.ngenerated - 1;
3043 
3044  /* SSP ISI number */
3045  getctrl(&ctrl_word, &isirot->waitfun.wfpulse[SSP], isirot->waitfun.wfpulse[SSP].ninsts - 1);
3046 
3047  if (isirot->isinumber == 4)
3048  ctrl_word = ctrl_word | PSD_ISI2_BIT;
3049  else if (isirot->isinumber == 5)
3050  ctrl_word = ctrl_word | PSD_ISI0_BIT | PSD_ISI2_BIT;
3051  else if (isirot->isinumber == 6)
3052  ctrl_word = ctrl_word | PSD_ISI1_BIT | PSD_ISI2_BIT;
3053  else if (isirot->isinumber == 7)
3054  ctrl_word = ctrl_word | PSD_ISI0_BIT | PSD_ISI1_BIT | PSD_ISI2_BIT;
3055 
3056  setctrl(ctrl_word, &isirot->waitfun.wfpulse[SSP], isirot->waitfun.wfpulse[SSP].ninsts - 1);
3057 
3058  /* SSP Rotation */
3059  getctrl(&ctrl_word, &isirot->waitrot.wfpulse[SSP], isirot->waitrot.wfpulse[SSP].ninsts - 1);
3060  ctrl_word |= PSD_MTX_UPDT;
3061  setctrl(ctrl_word, &isirot->waitrot.wfpulse[SSP], isirot->waitrot.wfpulse[SSP].ninsts - 1);
3062 
3063  /* Allocate memory for scan info array */
3064  if (isirot->scan_info == NULL) {
3065  isirot->scan_info = (SCAN_INFO *) AllocNode(isirot->numinstances * sizeof(SCAN_INFO));
3066  }
3067 
3068  /* Store the scan info for current ISI, where scan_info.oprot contains the rotation matrix */
3069  isirot->scan_info[placementindx] = scan_info;
3070 
3071  /* Reset num ISI and counter */
3072  isirot->counter = 0; /* make sure it is zero before scan starts */
3073 
3074  /* Connect ths isi number with the function pointer */
3075  isivector((short) isirot->isinumber, rotfun, (short) FALSE);
3076 
3077  }
3078 #else
3079 
3080  if (0) { /* make sure the WAIT pulses have been placed out in temporal order */
3081  int i;
3082  int lastpos = -1;
3083  WF_INSTR_HDR *instr = isirot->waitfun.wfpulse[SSP].inst_hdr_tail;
3084  for (i = 0; i < (isirot->waitfun.base.ninst - 1); i++) {
3085  if (lastpos > instr->start) {
3086  return ks_error("%s: Must place the ISI pulses in temporal order", __FUNCTION__);
3087  } else {
3088  lastpos = instr->start;
3089  instr = instr->next;
3090  }
3091  }
3092  }
3093 
3094  /* copy for convenience */
3095  isirot->numinstances = isirot->waitfun.base.ninst;
3096 
3097 #endif
3098 
3099  return SUCCESS;
3100 
3101 } /* ks_pg_isirot() */
int isinumber
Definition: KSFoundation.h:561
SCAN_INFO * scan_info
Definition: KSFoundation.h:560
int pos
Definition: KSFoundation.h:463
int ninst
Definition: KSFoundation.h:494
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
KS_WAIT waitfun
Definition: KSFoundation.h:558
KS_BASE base
Definition: KSFoundation.h:543
SCAN_INFO scan_info[]
int counter
Definition: KSFoundation.h:563
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
int numinstances
Definition: KSFoundation.h:564
KS_WAIT waitrot
Definition: KSFoundation.h:559
int max_duration
Definition: KSFoundation.h:546
STATUS ks_pg_wait(KS_WAIT *wait, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_WAIT sequence object on all boards at some position in the pulse sequence
Definition: KSFoundation_common.c:2889
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
WF_PULSE * wfpulse
Definition: KSFoundation.h:548
int duration
Definition: KSFoundation.h:562
int ngenerated
Definition: KSFoundation.h:496

◆ ks_pg_epi_dephasers()

STATUS ks_pg_epi_dephasers ( KS_EPI epi,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places out the dephasing gradients of a KS_EPI object (used by ks_pg_epi())

This function is called internally by ks_pg_epi() to place out the dephasing gradients of a KS_EPI object. See ks_pg_epi() for more details

For advanced usage of KS_EPI, it is possible to call ks_pg_epi_dephaser(), ks_pg_epi_echo() and ks_pg_epi_rephasers() separately instead of the single call to ks_pg_epi(). This allows the dephasing and rephasing gradients to be detached from the core EPI readout part

Parameters
[in,out]epiPointer to a KS_EPI sequence object
[in]locKS_SEQLOC struct to specify when and where to place the dephasers of the KS_EPI object
[in]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_EPI
Return values
STATUSSUCCESS or FAILURE
3106  {
3107 
3108  STATUS status;
3109  int readaxis, blipaxis, sliceaxis;
3110  KS_SEQLOC tmploc = KS_INIT_SEQLOC;
3111  int maxduration;
3112 
3113  if (!epi) { return ks_error("Ops"); }
3114 
3115  /* loc.ampscale may only be +1 or -1 and will control the read polarity.
3116  The blip polarity is controlled in run time with ks_scan_epi_shotcontrol() */
3117  if (!areSame(loc.ampscale, 1.0) && !areSame(loc.ampscale, -1.0)) {
3118  return ks_error("ks_pg_epi_dephasers: loc.ampscale must be +1 or -1 (controls read polarity)");
3119  }
3120 
3121  loc.pos = RDN_GRD(loc.pos);
3122 
3123  switch (loc.board) {
3124  case KS_FREQX_PHASEY:
3125  readaxis = XGRAD; blipaxis = YGRAD; sliceaxis = ZGRAD; break;
3126  case KS_FREQY_PHASEX:
3127  readaxis = YGRAD; blipaxis = XGRAD; sliceaxis = ZGRAD; break;
3128  case KS_FREQX_PHASEZ:
3129  readaxis = XGRAD; blipaxis = ZGRAD; sliceaxis = YGRAD; break;
3130  case KS_FREQZ_PHASEX:
3131  readaxis = ZGRAD; blipaxis = XGRAD; sliceaxis = YGRAD; break;
3132  case KS_FREQY_PHASEZ:
3133  readaxis = YGRAD; blipaxis = ZGRAD; sliceaxis = XGRAD; break;
3134  case KS_FREQZ_PHASEY:
3135  readaxis = ZGRAD; blipaxis = YGRAD; sliceaxis = XGRAD; break;
3136  default:
3137  return ks_error("ks_pg_epi_dephasers: loc.board is not valid: %d", loc.board);
3138  }
3139 
3140  /* allocate time corresponding to the longest of the three, but push the dephasers to the right below */
3141  maxduration = IMax(3, epi->readphaser.duration, epi->blipphaser.grad.duration, epi->zphaser.grad.duration);
3142 
3143  /* read phaser (same KS_TRAP for DE/REphasing => 2 instances per EPI) */
3144  if (epi->readphaser.duration > 0) {
3145  tmploc.board = readaxis;
3146  tmploc.ampscale = loc.ampscale;
3147  tmploc.pos = loc.pos + maxduration - epi->readphaser.duration;
3148  status = ks_pg_trap(&epi->readphaser, tmploc, ctrl);
3149  KS_RAISE(status);
3150  }
3151 
3152  /* blip phaser (same KS_PHASER for DE/REphasing => 2 instances per EPI) */
3153  if (epi->blipphaser.grad.duration > 0) {
3154  tmploc.board = blipaxis;
3155  tmploc.ampscale = 1.0;
3156  tmploc.pos = loc.pos + maxduration - epi->blipphaser.grad.duration;
3157  status = ks_pg_phaser(&epi->blipphaser, tmploc, ctrl);
3158  KS_RAISE(status);
3159  }
3160 
3161  /* balancing CAIPI-blip */
3162  if (epi->caipiblip.duration > 0) {
3163  tmploc.board = sliceaxis;
3164  tmploc.pos = loc.pos + maxduration - epi->caipiblip.duration;
3165  tmploc.ampscale = fabs(loc.ampscale);
3166  if (ks_pg_trap(&epi->caipiblip, tmploc, ctrl) == FAILURE)
3167  return FAILURE;
3168  }
3169 
3170  /* slice phaser (same KS_PHASER for DE/REphasing => 2 instances per EPI) */
3171  if (epi->zphaser.grad.duration > 0) {
3172  tmploc.board = sliceaxis;
3173  tmploc.ampscale = 1.0;
3174  tmploc.pos = loc.pos + maxduration - epi->zphaser.grad.duration;
3175  status = ks_pg_phaser(&epi->zphaser, tmploc, ctrl);
3176  KS_RAISE(status);
3177  }
3178 
3179  return SUCCESS;
3180 } /* ks_pg_epi_dephasers */
STATUS ks_pg_phaser(KS_PHASER *phaser, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_PHASER sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2031
Definition: KSFoundation.h:2319
#define areSame(a, b)
Definition: KSFoundation.h:144
KS_TRAP grad
Definition: KSFoundation.h:1719
int pos
Definition: KSFoundation.h:463
Definition: KSFoundation.h:2321
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
KS_PHASER zphaser
Definition: KSFoundation.h:1938
Definition: KSFoundation.h:2324
float ampscale
Definition: KSFoundation.h:464
Definition: KSFoundation.h:2322
Definition: KSFoundation.h:2320
KS_TRAP caipiblip
Definition: KSFoundation.h:1936
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
Definition: KSFoundation.h:2323
KS_TRAP readphaser
Definition: KSFoundation.h:1934
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
int duration
Definition: KSFoundation.h:673
STATUS ks_pg_trap(KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_TRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1802

◆ ks_pg_epi_rephasers()

STATUS ks_pg_epi_rephasers ( KS_EPI epi,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places out the rephasing gradients of a KS_EPI object (used by ks_pg_epi())

This function is called internally by ks_pg_epi() to place out the rephasing gradients of a KS_EPI object. See ks_pg_epi() for more details

For advanced usage of KS_EPI, it is possible to call ks_pg_epi_dephaser(), ks_pg_epi_echo() and ks_pg_epi_rephasers() separately instead of the single call to ks_pg_epi(). This allows the dephasing and rephasing gradients to be detached from the core EPI readout part

Parameters
[in,out]epiPointer to a KS_EPI sequence object
[in]locKS_SEQLOC struct to specify when to place the rephasers of the KS_EPI object
[in]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_EPI
Return values
STATUSSUCCESS or FAILURE
3184  {
3185 
3186  STATUS status;
3187  int readaxis, blipaxis, sliceaxis;
3188  KS_SEQLOC tmploc = KS_INIT_SEQLOC;
3189 
3190  if (!epi) { return ks_error("Ops"); }
3191 
3192  /* loc.ampscale may only be +1 or -1 and will control the read polarity.
3193  The blip polarity is controlled in run time with ks_scan_epi_shotcontrol() */
3194  if (!areSame(loc.ampscale, 1.0) && !areSame(loc.ampscale, -1.0)) {
3195  return ks_error("ks_pg_epi_rephasers: loc.ampscale must be +1 or -1 (controls read polarity)");
3196  }
3197 
3198  loc.pos = RDN_GRD(loc.pos);
3199 
3200  switch (loc.board) {
3201  case KS_FREQX_PHASEY:
3202  readaxis = XGRAD; blipaxis = YGRAD; sliceaxis = ZGRAD; break;
3203  case KS_FREQY_PHASEX:
3204  readaxis = YGRAD; blipaxis = XGRAD; sliceaxis = ZGRAD; break;
3205  case KS_FREQX_PHASEZ:
3206  readaxis = XGRAD; blipaxis = ZGRAD; sliceaxis = YGRAD; break;
3207  case KS_FREQZ_PHASEX:
3208  readaxis = ZGRAD; blipaxis = XGRAD; sliceaxis = YGRAD; break;
3209  case KS_FREQY_PHASEZ:
3210  readaxis = YGRAD; blipaxis = ZGRAD; sliceaxis = XGRAD; break;
3211  case KS_FREQZ_PHASEY:
3212  readaxis = ZGRAD; blipaxis = YGRAD; sliceaxis = XGRAD; break;
3213  default:
3214  return ks_error("ks_pg_epi_rephasers: loc.board is not valid: %d", loc.board);
3215  }
3216 
3217  /* read phaser (same KS_TRAP for DE/REphasing => 2 instances per EPI) */
3218  if (epi->readphaser.duration > 0) {
3219  tmploc.board = readaxis;
3220  tmploc.pos = loc.pos;
3221  if ((epi->etl % 2 && !(epi->epi_readout_mode == KS_EPI_BIPOLAR)) || (epi->epi_readout_mode == KS_EPI_FLYBACK)) {
3222  /* same polarity of rephaser as dephaser if odd ETL and not epi->splitoddeven, or flyback */
3223  tmploc.ampscale = loc.ampscale;
3224  } else {
3225  tmploc.ampscale = -loc.ampscale;
3226  }
3227  status = ks_pg_trap(&epi->readphaser, tmploc, ctrl);
3228  KS_RAISE(status);
3229  }
3230 
3231  /* blip phaser (same KS_PHASER for DE/REphasing => 2 instances per EPI) */
3232  if (epi->blipphaser.grad.duration > 0) {
3233  tmploc.board = blipaxis;
3234  tmploc.pos = loc.pos;
3235  tmploc.ampscale = 1.0;
3236  status = ks_pg_phaser(&epi->blipphaser, tmploc, ctrl);
3237  KS_RAISE(status);
3238  }
3239 
3240  /* balancing CAIPI-blip */
3241  if (epi->caipiblip.duration > 0) {
3242  tmploc.board = sliceaxis;
3243  tmploc.pos = loc.pos;
3244  tmploc.ampscale = fabs(loc.ampscale);
3245  if (ks_pg_trap(&epi->caipiblip, tmploc, ctrl) == FAILURE)
3246  return FAILURE;
3247  }
3248 
3249  /* slice phaser (same KS_PHASER for DE/REphasing => 2 instances per EPI) */
3250  if (epi->zphaser.grad.duration > 0) {
3251  tmploc.board = sliceaxis;
3252  tmploc.pos = loc.pos;
3253  tmploc.ampscale = 1.0;
3254  status = ks_pg_phaser(&epi->zphaser, tmploc, ctrl);
3255  KS_RAISE(status);
3256  }
3257 
3258  return SUCCESS;
3259 } /* ks_pg_epi_rephasers */
STATUS ks_pg_phaser(KS_PHASER *phaser, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_PHASER sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2031
Definition: KSFoundation.h:2319
#define areSame(a, b)
Definition: KSFoundation.h:144
KS_TRAP grad
Definition: KSFoundation.h:1719
int pos
Definition: KSFoundation.h:463
Definition: KSFoundation.h:2321
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
KS_PHASER zphaser
Definition: KSFoundation.h:1938
Definition: KSFoundation.h:2324
float ampscale
Definition: KSFoundation.h:464
Definition: KSFoundation.h:2322
int etl
Definition: KSFoundation.h:1941
Definition: KSFoundation.h:2320
int epi_readout_mode
Definition: KSFoundation.h:1939
KS_TRAP caipiblip
Definition: KSFoundation.h:1936
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
Definition: KSFoundation.h:2323
KS_TRAP readphaser
Definition: KSFoundation.h:1934
Definition: KSFoundation.h:2329
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
Definition: KSFoundation.h:2329
int duration
Definition: KSFoundation.h:673
STATUS ks_pg_trap(KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_TRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1802

◆ ks_pg_epi_echo()

STATUS ks_pg_epi_echo ( KS_EPI epi,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places out the core part a KS_EPI object (used by ks_pg_epi())

This function is called internally by ks_pg_epi() to place out the core part of a KS_EPI object. The core part is the EPI train without leading dephaser gradients or trailing rephaser gradients. See ks_pg_epi() for more details

For advanced usage of KS_EPI, it is possible to call ks_pg_epi_dephaser(), ks_pg_epi_echo() and ks_pg_epi_rephasers() separately instead of the single call to ks_pg_epi(). This allows the dephasing and rephasing gradients to be detached from the core EPI readout part

Parameters
[in,out]epiPointer to a KS_EPI sequence object
[in]locKS_SEQLOC struct to specify when to place the core part of the KS_EPI object
[in]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_EPI
Return values
STATUSSUCCESS or FAILURE
3263  {
3264 
3265  STATUS status;
3266  int readaxis, blipaxis, caipiaxis;
3267  KS_SEQLOC readloc = KS_INIT_SEQLOC;
3268  KS_SEQLOC bliploc = KS_INIT_SEQLOC;
3269  int i, s;
3270 
3271  if (!epi || !epi->read.grad.description) { return ks_error("Ops"); }
3272 
3273  /* loc.ampscale may only be +1 or -1 and will control the read polarity.</
3274  The blip polarity is controlled in run time with ks_scan_epi_shotcontrol() */
3275  if (!areSame(loc.ampscale, 1.0) && !areSame(loc.ampscale, -1.0)) {
3276  return ks_error("ks_pg_epi_echo: loc.ampscale must be +1 or -1 (controls read polarity)");
3277  }
3278 
3279  loc.pos = RUP_GRD(loc.pos);
3280 
3281  readloc.pos = loc.pos;
3282 
3283  switch (loc.board) {
3284  case KS_FREQX_PHASEY:
3285  readaxis = XGRAD; blipaxis = YGRAD; caipiaxis = ZGRAD; break;
3286  case KS_FREQY_PHASEX:
3287  readaxis = YGRAD; blipaxis = XGRAD; caipiaxis = ZGRAD; break;
3288  case KS_FREQX_PHASEZ:
3289  readaxis = XGRAD; blipaxis = ZGRAD; caipiaxis = YGRAD; break;
3290  case KS_FREQZ_PHASEX:
3291  readaxis = ZGRAD; blipaxis = XGRAD; caipiaxis = YGRAD; break;
3292  case KS_FREQY_PHASEZ:
3293  readaxis = YGRAD; blipaxis = ZGRAD; caipiaxis = XGRAD; break;
3294  case KS_FREQZ_PHASEY:
3295  readaxis = ZGRAD; blipaxis = YGRAD; caipiaxis = XGRAD; break;
3296  default:
3297  return ks_error("ks_pg_epi_echo: field 'board' in 2nd arg is not valid: %d", loc.board);
3298  }
3299 
3300  if (!areSame(fabs(loc.ampscale), 1.0)) {
3301  return ks_error("ks_pg_epi_echo: field 'ampscale' in 2nd arg must be +1 or -1 (controls read lobe polarity)");
3302  }
3303 
3304  /* read trapezoid */
3305  readloc.board = readaxis;
3306  for (i = 0; i < epi->etl; i++) {
3307  if (epi->epi_readout_mode == KS_EPI_FLYBACK){
3308  status = ks_pg_readtrap(&epi->read, readloc, ctrl);
3309  KS_RAISE(status);
3310 
3311  readloc.pos += RUP_GRD(epi->read.grad.duration);
3312 
3313  /* No flyback needed for the last echo */
3314  if (i < epi->etl - 1){
3315  readloc.ampscale *= -1;
3316  status = ks_pg_trap(&epi->read_flyback, readloc, ctrl);
3317  KS_RAISE(status);
3318 
3319  readloc.ampscale *= -1;
3320  readloc.pos += RUP_GRD(epi->read_flyback.duration + epi->read_spacing);
3321  }
3322 
3323  } else {
3324  int n_readouts_per_blip = (epi->epi_readout_mode == KS_EPI_SPLITODDEVEN ? 2 : 1);
3325  for (s = 0; s < n_readouts_per_blip; s++) { /* epi->splitoddeven can be 0 or 1 */
3326 
3327  if (epi->epi_readout_mode == KS_EPI_SPLITODDEVEN) {
3328  readloc.ampscale = (s % 2) ? -loc.ampscale : loc.ampscale; /* +1 or -1 */
3329  } else {
3330  readloc.ampscale = (i % 2) ? -loc.ampscale : loc.ampscale; /* +1 or -1 */
3331  }
3332  status = ks_pg_readtrap(&epi->read, readloc, ctrl);
3333  KS_RAISE(status);
3334 
3335  /* read_spacing is additional gap between lobes (normally 0) */
3336  readloc.pos += RUP_GRD(epi->read.grad.duration + epi->read_spacing);
3337 
3338  } /* for s */
3339  }
3340 
3341  /* phase encoding blip */
3342  if (i < epi->etl - 1) {
3343  /* etl-1, since no blip after the last read lobe */
3344  bliploc.board = blipaxis;
3345  bliploc.pos = RUP_GRD(readloc.pos - epi->blip.duration / 2 - epi->read_spacing / 2);
3346  bliploc.ampscale = fabs(loc.ampscale);
3347  status = ks_pg_trap(&epi->blip, bliploc, ctrl);
3348  KS_RAISE(status);
3349 
3350  bliploc.board = caipiaxis;
3351  bliploc.pos = RUP_GRD(readloc.pos - epi->caipiblip.duration / 2 + epi->read_spacing / 2);
3352  status = ks_pg_trap(&epi->caipiblip, bliploc, ctrl);
3353  KS_RAISE(status);
3354  }
3355 
3356  } /* etl */
3357 
3358 
3359  return SUCCESS;
3360 
3361 } /* ks_pg_epi_echo */
KS_TRAP blip
Definition: KSFoundation.h:1935
Definition: KSFoundation.h:2319
KS_TRAP read_flyback
Definition: KSFoundation.h:1933
#define areSame(a, b)
Definition: KSFoundation.h:144
int pos
Definition: KSFoundation.h:463
Definition: KSFoundation.h:2321
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int board
Definition: KSFoundation.h:462
Definition: KSFoundation.h:2324
KS_TRAP grad
Definition: KSFoundation.h:1561
float ampscale
Definition: KSFoundation.h:464
Definition: KSFoundation.h:2322
int etl
Definition: KSFoundation.h:1941
KS_READTRAP read
Definition: KSFoundation.h:1932
Definition: KSFoundation.h:2329
Definition: KSFoundation.h:2320
int epi_readout_mode
Definition: KSFoundation.h:1939
KS_TRAP caipiblip
Definition: KSFoundation.h:1936
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
KS_DESCRIPTION description
Definition: KSFoundation.h:668
Definition: KSFoundation.h:2323
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
int read_spacing
Definition: KSFoundation.h:1942
Definition: KSFoundation.h:2329
int duration
Definition: KSFoundation.h:673
STATUS ks_pg_readtrap(KS_READTRAP *readtrap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_READTRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2161
STATUS ks_pg_trap(KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places a KS_TRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1802

◆ ks_pg_epi()

STATUS ks_pg_epi ( KS_EPI epi,
KS_SEQLOC  loc,
KS_SEQ_CONTROL ctrl 
)

Places out a KS_EPI object (EPI train including dephaser and rephaser gradients)

This function should be called in the @pg section to place out a KS_EPI sequence object that creates an EPI readout including dephaser and rephaser gradients. The moments of all trapezoids in the KS_EPI object sum to zero on the two axes the KS_EPI object is placed on. The KS_EPI object is to be placed on two out of three gradients, why special values for the field loc.board must be used. The value should state which logical board (X,Y or Z) that should be used for the readout lobes (FREQ) and which logical board (X, Y or Z) that should be used for the blips (PHASE). One example is KS_FREQX_PHASEY, which will put the EPI readout lobes on XGRAD and the phase encoding blips on YGRAD

The same KS_EPI object can be placed out 16 times per sequence. This limitation is due to the hard limitation on the number of echoes (i.e. different k-spaces per image plane and image volume) that can be acquired per scan. Each time an instance of the KS_EPI object is placed out using ks_pg_epi(), the second argument (the KS_SEQLOC struct) should be modified:

  • .board: Choose between KS_FREQX_PHASEY, KS_FREQY_PHASEX, KS_FREQX_PHASEZ, KS_FREQZ_PHASEX, KS_FREQY_PHASEZ, KS_FREQZ_PHASEY
  • .pos: Absolute time in [us] of the start of the first dephaser gradient
  • .ampscale: For KS_EPI objects, valid values are only +1.0 and -1.0, and this will control the polarity of the first readout gradient. This is rarely needed, and 1.0 should be the standard choice as this does only affect gradient delays and Nyquist ghosting, not the geometric distortion direction.

The sign of the EPI blips will control the direction of the geometric distortions, and this is not done via .ampscale but in run-time using ks_scan_epi_shotcontrol()

For advanced usage of KS_EPI, it is possible to call ks_pg_epi_dephaser(), ks_pg_epi_echo() and ks_pg_epi_rephasers() separately instead of the single call to ks_pg_epi(). This allows the dephasing and rephasing gradients to be detached from the core EPI readout part

Parameters
[in,out]epiPointer to a KS_EPI sequence object
[in]locKS_SEQLOC struct to specify when to place the core part of the KS_EPI object
[in]ctrlPointer to the KS_SEQ_CONTROL struct corresponding to the sequence module for this KS_EPI
Return values
STATUSSUCCESS or FAILURE
3365  {
3366 
3367  STATUS status;
3368  KS_SEQLOC tmploc = loc;
3369  const int readfact = (epi->epi_readout_mode == KS_EPI_SPLITODDEVEN) ? 2 : 1;
3370 
3371  /* loc.ampscale may only be +1 or -1 and will control the read polarity.
3372  The blip polarity is controlled in run time with ks_scan_epi_shotcontrol() */
3373  if (!areSame(loc.ampscale, 1.0) && !areSame(loc.ampscale, -1.0)) {
3374  return ks_error("ks_pg_epi: loc.ampscale must be +1 or -1 (controls read polarity)");
3375  }
3376 
3377  status = ks_pg_epi_dephasers(epi, tmploc, ctrl);
3378  KS_RAISE(status);
3379 
3380  tmploc.pos += IMax(3, epi->readphaser.duration, epi->blipphaser.grad.duration, epi->zphaser.grad.duration);
3381 
3382  /* main epi train (w/o DE/REphasers) */
3383  status = ks_pg_epi_echo(epi, tmploc, ctrl);
3384  KS_RAISE(status);
3385 
3386  tmploc.pos += (epi->etl * readfact) * epi->read.grad.duration + ((epi->etl * readfact) - 1) * (epi->read_flyback.duration + epi->read_spacing);
3387 
3388  status = ks_pg_epi_rephasers(epi, tmploc, ctrl);
3389  KS_RAISE(status);
3390 
3391  return SUCCESS;
3392 } /* ks_pg_epi */
KS_TRAP read_flyback
Definition: KSFoundation.h:1933
#define areSame(a, b)
Definition: KSFoundation.h:144
KS_TRAP grad
Definition: KSFoundation.h:1719
int pos
Definition: KSFoundation.h:463
STATUS ks_pg_epi_echo(KS_EPI *epi, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places out the core part a KS_EPI object (used by ks_pg_epi())
Definition: KSFoundation_common.c:3263
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
KS_PHASER zphaser
Definition: KSFoundation.h:1938
KS_TRAP grad
Definition: KSFoundation.h:1561
float ampscale
Definition: KSFoundation.h:464
int etl
Definition: KSFoundation.h:1941
KS_READTRAP read
Definition: KSFoundation.h:1932
Definition: KSFoundation.h:2329
STATUS ks_pg_epi_dephasers(KS_EPI *epi, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places out the dephasing gradients of a KS_EPI object (used by ks_pg_epi())
Definition: KSFoundation_common.c:3106
int epi_readout_mode
Definition: KSFoundation.h:1939
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
KS_TRAP readphaser
Definition: KSFoundation.h:1934
int read_spacing
Definition: KSFoundation.h:1942
int duration
Definition: KSFoundation.h:673
STATUS ks_pg_epi_rephasers(KS_EPI *epi, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl)
Places out the rephasing gradients of a KS_EPI object (used by ks_pg_epi())
Definition: KSFoundation_common.c:3184

◆ ks_pg_mod_fse_rfpulse_structs()

void ks_pg_mod_fse_rfpulse_structs ( KS_SELRF rf1,
KS_SELRF rf2,
KS_SELRF rf3,
const double *  flip_angles,
const int  etl 
)

ADDTITLEHERE

3399  {
3400 
3401  float SAR_scale_1 = 0.0;
3402  float SAR_scale_2 = 0.0;
3403  float SAR_scale_3 = 0.0;
3404  int i;
3405 
3406  SAR_scale_1 = pow(flip_angles[0] / rf1->rf.flip, 2.0);
3407  SAR_scale_2 = pow(flip_angles[1] / rf2->rf.flip, 2.0);
3408  for (i = 2; i < etl; i++) {
3409  SAR_scale_3 += pow(flip_angles[i] / rf3->rf.flip, 2.0);
3410  }
3411  SAR_scale_3 /= etl - 2;
3412 
3413  rf1->rf.rfpulse.effwidth *= SAR_scale_1;
3414  rf1->rf.rfpulse.max_rms_b1 *= sqrt(SAR_scale_1);
3415  rf1->rf.rfpulse.abswidth *= sqrt(SAR_scale_1);
3416 
3417  rf2->rf.rfpulse.effwidth *= SAR_scale_2;
3418  rf2->rf.rfpulse.max_rms_b1 *= sqrt(SAR_scale_2);
3419  rf2->rf.rfpulse.abswidth *= sqrt(SAR_scale_2);
3420 
3421  rf3->rf.rfpulse.effwidth *= SAR_scale_3;
3422  rf3->rf.rfpulse.max_rms_b1 *= sqrt(SAR_scale_3);
3423  rf3->rf.rfpulse.abswidth *= sqrt(SAR_scale_3);
3424 
3425 } /* ks_pg_mod_fse_rfpulse_structs */
RF_PULSE rfpulse
Definition: KSFoundation.h:1036
int32_t i
Definition: KSFoundation_tgt.c:1694
float flip
Definition: KSFoundation.h:1028
KS_RF rf
Definition: KSFoundation.h:1454

◆ ks_pg_fse_flip_angle_taperoff()

STATUS ks_pg_fse_flip_angle_taperoff ( double *  flip_angles,
int  etl,
double  flip1,
double  flip2,
double  flip3,
double  target_flip,
int  start_middle 
)

ADDTITLEHERE

3434  {
3435 
3436  int i;
3437 
3438  flip_angles[0] = flip1;
3439  flip_angles[1] = flip2;
3440  for (i = 2; i < etl; i++) {
3441  flip_angles[i] = flip3;
3442  }
3443 
3444  if (flip3 <= target_flip || etl < 5) {
3445  /* flip3 must be larger than target_flip and etl must be larger than 4 */
3446  return SUCCESS;
3447  }
3448 
3449  /* after half of the echo train or third pulse, ramp down flip angles to last_flip */
3450  double first_flip = flip3;
3451  double last_flip = target_flip;
3452  int start_pulse = start_middle ? etl/2 : 2;
3453  for (i = start_pulse; i < etl; i++) {
3454  flip_angles[i] = first_flip + (((last_flip - first_flip)/(etl - start_pulse - 1)) * (i - start_pulse));
3455  }
3456 
3457  return SUCCESS;
3458 
3459 } /* ks_pg_fse_flip_angle_taperoff */
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_pg_get_trap_loc()

KS_SEQLOC ks_pg_get_trap_loc ( KS_TRAP trap,
int  instance 
)

Returns the location of a trap

This function should be called in the @pg section to find the SEQLOC of a PGed trap. If instance = -1 it returns the last SEQLOC of the last instance.

Parameters
[in]trap
[in]instance
Return values
KS_SEQLOC
3462  {
3463 
3464  if (ks_numplaced(&trap->base) <= instance || instance < -1) {
3465  KS_THROW("%s: instance (%d) out of range [-1-%d)", __FUNCTION__, instance, trap->base.ngenerated);
3466  KS_SEQLOC tmploc = KS_INIT_SEQLOC;
3467  return tmploc;
3468  }
3469 
3470  instance = (instance == -1) ? ks_numplaced(&trap->base) - 1 : instance;
3471 
3472 #ifdef HOST_TGT
3473  /* HOST */
3474  return trap->locs[instance];
3475 #else
3476  /* TARGET */
3477  return trap->wfi[instance].loc;
3478 #endif
3479 }
KS_BASE base
Definition: KSFoundation.h:667
KS_SEQLOC * locs
Definition: KSFoundation.h:678
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
KS_SEQLOC loc
Definition: KSFoundation.h:486
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
int ngenerated
Definition: KSFoundation.h:496
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_pg_get_wave_loc()

KS_SEQLOC ks_pg_get_wave_loc ( KS_WAVE wave,
int  instance 
)

Returns the location of a wave

This function should be called in the @pg section to find the SEQLOC of a PGed wave. If instance = -1 it returns the last SEQLOC of the last instance.

Parameters
[in]wave
[in]instance
Return values
KS_SEQLOC
3484  {
3485 
3486  if (ks_numplaced(&wave->base) <= instance || instance < -1) {
3487  KS_THROW("%s: instance (%d) out of range [-1-%d)", __FUNCTION__, instance, wave->base.ngenerated);
3488  KS_SEQLOC tmploc = KS_INIT_SEQLOC;
3489  return tmploc;
3490  }
3491 
3492  instance = (instance == -1) ? ks_numplaced(&wave->base) - 1 : instance;
3493 
3494 #ifdef HOST_TGT
3495  /* HOST */
3496  return wave->locs[instance];
3497 #else
3498  /* TARGET */
3499  return wave->wfi[instance].loc;
3500 #endif
3501 }
KS_SEQLOC * locs
Definition: KSFoundation.h:752
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
KS_SEQLOC loc
Definition: KSFoundation.h:486
KS_BASE base
Definition: KSFoundation.h:744
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
int ngenerated
Definition: KSFoundation.h:496
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_init_rtscalelog()

void ks_init_rtscalelog ( KS_RT_SCALE_LOG *const  rtscale)

Resets a KS_RT_SCALE_LOG instance

Parameters
[in,out]rtscalePointer to a KS_RT_SCALE_LOG instance
Returns
void
3506  {
3507  if (!rtscale) {return; }
3508 
3509  float *ampscales = rtscale->ampscales;
3510  int *states = rtscale->states;
3511  int num_instances = rtscale->num_instances;
3512 
3513  /* Use a temp object to be consistent with the default values */
3514  KS_RT_SCALE_LOG tmp_rtscale = KS_INIT_RT_SCALE_LOG;
3515  *rtscale = tmp_rtscale;
3516 
3517  rtscale->ampscales = ampscales;
3518  rtscale->states = states;
3519  rtscale->buffer_size = ampscales ? num_instances : 0;
3520  rtscale->buffer_size_states = states ? num_instances : 0;
3521 }
int buffer_size
Definition: KSFoundation.h:474
int num_instances
Definition: KSFoundation.h:476
int * states
Definition: KSFoundation.h:473
int buffer_size_states
Definition: KSFoundation.h:475
float * ampscales
Definition: KSFoundation.h:472
Log of real-time scaling amplitudes.
Definition: KSFoundation.h:471
#define KS_INIT_RT_SCALE_LOG
Definition: KSFoundation.h:290

◆ ks_instancereset_trap()

void ks_instancereset_trap ( KS_TRAP trap)

Resets the usage counters on TGT for a KS_TRAP sequence object (advanced use)

This function is for advanced use where a single sequence generating function is used in parallel in multiple sequences (i.e. in different SEQLENGTH()). This should be called after calling ks_copy_and_reset_obj()

The function sets .base.ngenerated to 0 (counter for number of times placed out on TGT), and sets .wfpulse and .wfi to NULL to trigger the allocation of new hardware memory, before running the sequence generating function again.

Parameters
[in,out]trapPointer to a KS_TRAP sequence object
Returns
void
3527  {
3528  if (!trap) { return; }
3529 
3530  trap->base.ngenerated = 0;
3531  trap->wfpulse = NULL;
3532  trap->wfi = NULL;
3533 }
KS_BASE base
Definition: KSFoundation.h:667
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
int ngenerated
Definition: KSFoundation.h:496
WF_PULSE ** wfpulse
Definition: KSFoundation.h:679

◆ ks_instancereset_wave()

void ks_instancereset_wave ( KS_WAVE wave)
3538  {
3539  if (!wave) { return; }
3540 
3541  wave->base.ngenerated = 0;
3542  wave->wfpulse = NULL;
3543  wave->wfi = NULL;
3544 }
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
WF_PULSE ** wfpulse
Definition: KSFoundation.h:753
KS_BASE base
Definition: KSFoundation.h:744
int ngenerated
Definition: KSFoundation.h:496

◆ ks_instancereset_wait()

void ks_instancereset_wait ( KS_WAIT wait)

Resets the usage counters on TGT for a KS_WAIT sequence object (advanced use)

This function is for advanced use where a single sequence generating function is used in parallel in multiple sequences (i.e. in different SEQLENGTH()). This should be called after calling ks_copy_and_reset_obj()

The function sets .base.ngenerated to 0 (counter for number of times placed out on TGT), and sets .wfpulse and .wfi to NULL to trigger the allocation of new hardware memory, before running the sequence generating function again.

Parameters
[in,out]waitPointer to a KS_WAIT sequence object
Returns
void
3549  {
3550  if (!wait) { return; }
3551 
3552  wait->base.ngenerated = 0;
3553  wait->wfpulse = NULL;
3554  wait->wfi = NULL;
3555 }
KS_BASE base
Definition: KSFoundation.h:543
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:549
WF_PULSE * wfpulse
Definition: KSFoundation.h:548
int ngenerated
Definition: KSFoundation.h:496

◆ ks_instancereset_phaser()

void ks_instancereset_phaser ( KS_PHASER phaser)

Resets the usage counters on TGT for a KS_PHASER sequence object (advanced use)

This function is for advanced use where a single sequence generating function is used in parallel in multiple sequences (i.e. in different SEQLENGTH()). This should be called after calling ks_copy_and_reset_obj()

The function sets .base.ngenerated to 0 (counter for number of times placed out on TGT), and sets .wfpulse and .wfi to NULL to trigger the allocation of new hardware memory, before running the sequence generating function again.

Parameters
[in,out]phaserPointer to a KS_PHASER sequence object
Returns
void
3560  {
3561  if (!phaser) { return; }
3562 
3563  ks_instancereset_trap(&phaser->grad);
3564 }
KS_TRAP grad
Definition: KSFoundation.h:1719
void ks_instancereset_trap(KS_TRAP *trap)
Resets the usage counters on TGT for a KS_TRAP sequence object (advanced use)
Definition: KSFoundation_common.c:3527

◆ ks_instancereset_readtrap()

void ks_instancereset_readtrap ( KS_READTRAP readtrap)

Resets the usage counters on TGT for a KS_READTRAP sequence object (advanced use)

This function is for advanced use where a single sequence generating function is used in parallel in multiple sequences (i.e. in different SEQLENGTH()). This should be called after calling ks_copy_and_reset_obj()

The function sets .base.ngenerated to 0 (counter for number of times placed out on TGT), and sets .wfpulse and .wfi to NULL to trigger the allocation of new hardware memory, before running the sequence generating function again.

Parameters
[in,out]readtrapPointer to a KS_READTRAP sequence object
Returns
void
3569  {
3570  if (!read) { return; }
3571 
3572  read->acq.base.ngenerated = 0;
3573  read->acq.echo = NULL;
3574 
3575  ks_instancereset_trap(&read->grad);
3576  ks_instancereset_wave(&read->omega);
3577 }
WF_PULSE * echo
Definition: KSFoundation.h:846
KS_WAVE omega
Definition: KSFoundation.h:1562
KS_TRAP grad
Definition: KSFoundation.h:1561
KS_BASE base
Definition: KSFoundation.h:839
void ks_instancereset_wave(KS_WAVE *wave)
Definition: KSFoundation_common.c:3538
void ks_instancereset_trap(KS_TRAP *trap)
Resets the usage counters on TGT for a KS_TRAP sequence object (advanced use)
Definition: KSFoundation_common.c:3527
int ngenerated
Definition: KSFoundation.h:496
KS_READ acq
Definition: KSFoundation.h:1549

◆ ks_instancereset_rf()

void ks_instancereset_rf ( KS_RF rf)

Resets the usage counters on TGT for a KS_RF sequence object (advanced use)

This function is for advanced use where a single sequence generating function is used in parallel in multiple sequences (i.e. in different SEQLENGTH()). This should be called after calling ks_copy_and_reset_obj()

The function sets .base.ngenerated to 0 (counter for number of times placed out on TGT), and sets .wfpulse and .wfi to NULL to trigger the allocation of new hardware memory, before running the sequence generating function again.

Parameters
[in,out]rfPointer to a KS_RF sequence object
Returns
void
3582  {
3583  if (!rf) { return; }
3584 
3588 
3589 }
KS_WAVE thetawave
Definition: KSFoundation.h:1039
KS_WAVE rfwave
Definition: KSFoundation.h:1037
void ks_instancereset_wave(KS_WAVE *wave)
Definition: KSFoundation_common.c:3538
KS_WAVE omegawave
Definition: KSFoundation.h:1038

◆ ks_instancereset_selrf()

void ks_instancereset_selrf ( KS_SELRF selrf)

Resets the usage counters on TGT for a KS_SELRF sequence object (advanced use)

This function is for advanced use where a single sequence generating function is used in parallel in multiple sequences (i.e. in different SEQLENGTH()). This should be called after calling ks_copy_and_reset_obj()

The function sets .base.ngenerated to 0 (counter for number of times placed out on TGT), and sets .wfpulse and .wfi to NULL to trigger the allocation of new hardware memory, before running the sequence generating function again.

Parameters
[in,out]selrfPointer to a KS_SELRF sequence object
Returns
void
3594  {
3595  if (!selrf) { return; }
3596 
3597  ks_instancereset_rf(&selrf->rf);
3598  ks_instancereset_trap(&selrf->pregrad);
3599  ks_instancereset_trap(&selrf->grad);
3601 
3603 
3604 }
KS_TRAP grad
Definition: KSFoundation.h:1463
KS_WAVE gradwave
Definition: KSFoundation.h:1465
KS_TRAP pregrad
Definition: KSFoundation.h:1462
KS_RF rf
Definition: KSFoundation.h:1454
void ks_instancereset_wave(KS_WAVE *wave)
Definition: KSFoundation_common.c:3538
void ks_instancereset_rf(KS_RF *rf)
Resets the usage counters on TGT for a KS_RF sequence object (advanced use)
Definition: KSFoundation_common.c:3582
KS_TRAP postgrad
Definition: KSFoundation.h:1464
void ks_instancereset_trap(KS_TRAP *trap)
Resets the usage counters on TGT for a KS_TRAP sequence object (advanced use)
Definition: KSFoundation_common.c:3527

◆ ks_instancereset_epi()

void ks_instancereset_epi ( KS_EPI epi)

Resets the usage counters on TGT for a KS_EPI sequence object (advanced use)

This function is for advanced use where a single sequence generating function is used in parallel in multiple sequences (i.e. in different SEQLENGTH()). This should be called after calling ks_copy_and_reset_obj()

The function sets .base.ngenerated to 0 (counter for number of times placed out on TGT), and sets .wfpulse and .wfi to NULL to trigger the allocation of new hardware memory, before running the sequence generating function again.

Parameters
[in,out]epiPointer to a KS_EPI sequence object
Returns
void
3609  {
3610  if (!epi) { return; }
3611 
3614  ks_instancereset_trap(&epi->blip);
3616 }
KS_TRAP blip
Definition: KSFoundation.h:1935
void ks_instancereset_phaser(KS_PHASER *phaser)
Resets the usage counters on TGT for a KS_PHASER sequence object (advanced use)
Definition: KSFoundation_common.c:3560
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
void ks_instancereset_readtrap(KS_READTRAP *read)
Resets the usage counters on TGT for a KS_READTRAP sequence object (advanced use)
Definition: KSFoundation_common.c:3569
KS_READTRAP read
Definition: KSFoundation.h:1932
KS_TRAP readphaser
Definition: KSFoundation.h:1934
void ks_instancereset_trap(KS_TRAP *trap)
Resets the usage counters on TGT for a KS_TRAP sequence object (advanced use)
Definition: KSFoundation_common.c:3527

◆ ks_mat4_zero()

void ks_mat4_zero ( KS_MAT4x4  m)

Makes a 4x4 zero matrix

Parameters
[in,out]mMatrix (KS_MAT4x4)
Returns
void
3624  {
3625  int i;
3626  for (i = 0; i < 16; i++) {
3627  m[i] = 0.0;
3628  }
3629 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat4_identity()

void ks_mat4_identity ( KS_MAT4x4  m)

Creates a 4x4 identity matrix

Parameters
[in,out]mMatrix (KS_MAT4x4)
Returns
void
3635  {
3636  int i;
3637  ks_mat4_zero(m);
3638  for (i = 0; i < 4; i++) {
3639  m[i + (i * 4)] = 1.0;
3640  }
3641 }
void ks_mat4_zero(KS_MAT4x4 m)
Makes a 4x4 zero matrix
Definition: KSFoundation_common.c:3624
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat4_print()

void ks_mat4_print ( const KS_MAT4x4  m)

Prints a 4x4 matrix to stdout

Parameters
[in]mMatrix (KS_MAT4x4)
Returns
void
3646  {
3647  int i;
3648  for (i = 0; i < 4; i++) {
3649  printf("| %0.4f %0.4f %0.4f %0.4f |\n", m[i], m[i + 4], m[i + 8], m[i + 12]);
3650  }
3651  fflush(stdout);
3652 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat4_multiply()

void ks_mat4_multiply ( KS_MAT4x4  lhs,
const KS_MAT4x4  rhs_left,
const KS_MAT4x4  rhs_right 
)

Multiplication of two 4x4 matrices

Matrix product: [rhs_left] * [rhs_right]

Parameters
[out]lhsMatrix product (KS_MAT4x4)
[in]rhs_leftLeft matrix (KS_MAT4x4)
[in]rhs_rightRight matrix (KS_MAT4x4)
Returns
void
3658  {
3659 
3660  /* Define local variables */
3661  int m, n, k;
3662  int msize = 4;
3663  KS_MAT4x4 Mtmp;
3664  double *ptr;
3665 
3666  if (lhs == rhs_left || lhs == rhs_right) { /* Check if output is equal to any input */
3667  ptr = Mtmp;
3668  } else {
3669  ptr = lhs;
3670  }
3671  for (k = 0; k < (msize * msize); k++) { /* Zero left-hand side*/
3672  ptr[k] = 0.0;
3673  }
3674 
3675  /* Multiply the matrices*/
3676  for (n = 0; n < msize; n++) {
3677  for (m = 0; m < msize; m++) {
3678  for (k = 0; k < msize; k++) {
3679  ptr[m + (n * msize)] += rhs_left[m + (k * msize)] * rhs_right[k + (n * msize)];
3680  }
3681  }
3682  }
3683 
3684  if (lhs == rhs_left || lhs == rhs_right ) { /* Write back (if needed) */
3685  for (k = 0; k < (msize * msize); k++) {
3686  lhs[k] = ptr[k];
3687  }
3688  }
3689 }
double KS_MAT4x4[16]
Definition: KSFoundation.h:356

◆ ks_mat4_invert()

void ks_mat4_invert ( KS_MAT4x4  lhs,
const KS_MAT4x4  rhs 
)

Inversion of a 4x4 matrix

4x4 matrix inversion (http://download.intel.com/design/PentiumIII/sml/24504301.pdf

Parameters
[out]lhsInverted matrix (KS_MAT4x4)
[in]rhsMatrix to be inverted (KS_MAT4x4)
Returns
void
3695  {
3696  double tmp[12]; /* temp array for pairs */
3697  double src[16]; /* array of transpose source rhsrix */
3698  double det; /* determinant */
3699  int i, j;
3700 
3701  /* transpose rhsrix */
3702  for (i = 0; i < 4; i++) {
3703  src[i] = rhs[i * 4];
3704  src[i + 4] = rhs[i * 4 + 1];
3705  src[i + 8] = rhs[i * 4 + 2];
3706  src[i + 12] = rhs[i * 4 + 3];
3707  }
3708 
3709  /* calculate pairs for first 8 elements (cofactors) */
3710  tmp[0] = src[10] * src[15];
3711  tmp[1] = src[11] * src[14];
3712  tmp[2] = src[9] * src[15];
3713  tmp[3] = src[11] * src[13];
3714  tmp[4] = src[9] * src[14];
3715  tmp[5] = src[10] * src[13];
3716  tmp[6] = src[8] * src[15];
3717  tmp[7] = src[11] * src[12];
3718  tmp[8] = src[8] * src[14];
3719  tmp[9] = src[10] * src[12];
3720  tmp[10] = src[8] * src[13];
3721  tmp[11] = src[9] * src[12];
3722 
3723  /* calculate first 8 elements (cofactors) */
3724  lhs[0] = tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7];
3725  lhs[0] -= tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7];
3726  lhs[1] = tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7];
3727  lhs[1] -= tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7];
3728  lhs[2] = tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7];
3729  lhs[2] -= tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7];
3730  lhs[3] = tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6];
3731  lhs[3] -= tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6];
3732  lhs[4] = tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3];
3733  lhs[4] -= tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3];
3734  lhs[5] = tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3];
3735  lhs[5] -= tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3];
3736  lhs[6] = tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3];
3737  lhs[6] -= tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3];
3738  lhs[7] = tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2];
3739  lhs[7] -= tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2];
3740 
3741  /* calculate pairs for second 8 elements (cofactors) */
3742  tmp[0] = src[2] * src[7];
3743  tmp[1] = src[3] * src[6];
3744  tmp[2] = src[1] * src[7];
3745  tmp[3] = src[3] * src[5];
3746  tmp[4] = src[1] * src[6];
3747  tmp[5] = src[2] * src[5];
3748  tmp[6] = src[0] * src[7];
3749  tmp[7] = src[3] * src[4];
3750  tmp[8] = src[0] * src[6];
3751  tmp[9] = src[2] * src[4];
3752  tmp[10] = src[0] * src[5];
3753  tmp[11] = src[1] * src[4];
3754 
3755  /* calculate second 8 elements (cofactors) */
3756  lhs[8] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15];
3757  lhs[8] -= tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15];
3758  lhs[9] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15];
3759  lhs[9] -= tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15];
3760  lhs[10] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15];
3761  lhs[10] -= tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15];
3762  lhs[11] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14];
3763  lhs[11] -= tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14];
3764  lhs[12] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9];
3765  lhs[12] -= tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10];
3766  lhs[13] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10];
3767  lhs[13] -= tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8];
3768  lhs[14] = tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8];
3769  lhs[14] -= tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9];
3770  lhs[15] = tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9];
3771  lhs[15] -= tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8];
3772 
3773  /* calculate determinant */
3774  det = src[0] * lhs[0] + src[1] * lhs[1] + src[2] * lhs[2] + src[3] * lhs[3];
3775 
3776  /* calculate rhsrix inverse */
3777  det = 1 / det;
3778  for (j = 0; j < 16; j++)
3779  lhs[j] *= det;
3780 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat4_double_to_float()

void ks_mat4_double_to_float ( KS_MAT4x4f  out,
const KS_MAT4x4  in 
)

Conversion of a 4x4 matrix from double to float

Parameters
[out]outFloat matrix (KS_MAT4x4f)
[in]inDouble matrix (KS_MAT4x4)
Returns
void
3785  {
3786  int n = 0;
3787  for (; n < 16; n++) {
3788  out[n] = (float) in[n];
3789  }
3790 } /* ks_mat_double_to_float */

◆ ks_mat4_float_to_double()

void ks_mat4_float_to_double ( KS_MAT4x4  out,
const KS_MAT4x4f  in 
)

Conversion of a 4x4 matrix from float to double

Parameters
[out]outDouble matrix (KS_MAT4x4)
[in]inFloat matrix (KS_MAT4x4f)
Returns
void
3793  {
3794  int n = 0;
3795  for (; n < 16; n++) {
3796  out[n] = (double) in[n];
3797  }
3798 } /* ks_mat_float_to_double */

◆ ks_mat4_setgeometry()

void ks_mat4_setgeometry ( KS_MAT4x4  lhs,
float  x,
float  y,
float  z,
float  xr,
float  yr,
float  zr 
)

Set geometry for KS_MAT4x4

Parameters
[out]lhsset matrix (KS_MAT4x4)
[in]xdisplacement (mm)
[in]ydisplacement (mm)
[in]zdisplacement (mm)
[in]xrrotation (deg)
[in]yrrotation (deg)
[in]zrrotation (deg)
Returns
void
3800  {
3801  double cosa;
3802  double sina;
3803  double cosb;
3804  double sinb;
3805  double cosg;
3806  double sing;
3807 
3808  ks_mat4_identity(lhs);
3809 
3810  xr *= PI / 180.0;
3811  yr *= PI / 180.0;
3812  zr *= PI / 180.0;
3813 
3814  /*
3815  Rotation matrices for positive counterclockwise angles about the positive
3816  coordinate axis for a right handed coordinate system:
3817 
3818  | 1 0 0 |
3819  R1(xr) = | 0 cos(xr) -sin(xr)|
3820  | 0 sin(xr) cos(xr)|
3821 
3822 
3823  | cos(yr) 0 sin(yr) |
3824  R2(yr) = | 0 1 0 |
3825  | -sin(yr) 0 cos(yr) |
3826 
3827  | cos(zr) -sin(zr) 0 |
3828  R3(zr) = | sin(zr) cos(zr) 0 |
3829  | 0 0 1 |
3830  */
3831 
3832  cosa = cos(xr);
3833  sina = sin(xr);
3834  cosb = cos(yr);
3835  sinb = sin(yr);
3836  cosg = cos(zr);
3837  sing = sin(zr);
3838 
3839  /* Rotations: R_z * R_y * R_x */
3840  lhs[ 0] = cosb * cosg;
3841  lhs[ 1] = sina * sinb * cosg - cosa * sing;
3842  lhs[ 2] = cosa * sinb * cosg + sina * sing;
3843  lhs[ 4] = cosb * sing;
3844  lhs[ 5] = sina * sinb * sing + cosa * cosg;
3845  lhs[ 6] = cosa * sinb * sing - sina * cosg;
3846  lhs[ 8] = -sinb;
3847  lhs[ 9] = sina * cosb;
3848  lhs[10] = cosa * cosb;
3849 
3850  /* Translations */
3851  lhs[ 3] = x;
3852  lhs[ 7] = y;
3853  lhs[11] = z;
3854 } /* ks_mat4_setgeometry */
void ks_mat4_identity(KS_MAT4x4 m)
Creates a 4x4 identity matrix
Definition: KSFoundation_common.c:3635

◆ ks_mat4f_setgeometry()

void ks_mat4f_setgeometry ( KS_MAT4x4f  lhs,
float  x,
float  y,
float  z,
float  xr,
float  yr,
float  zr 
)
3856  {
3858  ks_mat4_setgeometry(tmp, x, y, z, xr, yr, zr);
3859  ks_mat4_double_to_float(lhs, tmp);
3860 } /* ks_mat4f_setgeometry */
void ks_mat4_double_to_float(KS_MAT4x4f out, const KS_MAT4x4 in)
Conversion of a 4x4 matrix from double to float
Definition: KSFoundation_common.c:3785
double KS_MAT4x4[16]
Definition: KSFoundation.h:356
#define KS_MAT4x4_IDENTITY
Definition: KSFoundation.h:340
void ks_mat4_setgeometry(KS_MAT4x4 lhs, float x, float y, float z, float xr, float yr, float zr)
Set geometry for KS_MAT4x4
Definition: KSFoundation_common.c:3800

◆ ks_mat4_setrotation1axis()

void ks_mat4_setrotation1axis ( KS_MAT4x4  rhs,
float  rot,
char  axis 
)

Create a new 4x4 matrix with a rotation around a single axis

Parameters
[out]rhsRotation matrix (KS_MAT4x4)
[in]rotAmount of rotation around axis [degrees]
[in]axisOne of (include the quotes): 'x', 'y', 'z'
Returns
void
3863  {
3864  ks_mat4_identity(rhs);
3865 
3866  rot *= PI / 180.0; /* deg->rad */
3867 
3868  switch (axis) {
3869  case 'x':
3870  rhs[5] = cos(rot);
3871  rhs[6] = sin(rot);
3872  rhs[9] = -sin(rot);
3873  rhs[10] = cos(rot);
3874  break;
3875  case 'y':
3876  rhs[0] = cos(rot);
3877  rhs[2] = sin(rot);
3878  rhs[8] = -sin(rot);
3879  rhs[10] = cos(rot);
3880  break;
3881  case 'z':
3882  rhs[0] = cos(rot);
3883  rhs[1] = sin(rot);
3884  rhs[4] = -sin(rot);
3885  rhs[5] = cos(rot);
3886  break;
3887  }
3888 
3889 }
void ks_mat4_identity(KS_MAT4x4 m)
Creates a 4x4 identity matrix
Definition: KSFoundation_common.c:3635

◆ ks_mat4_extractrotation()

void ks_mat4_extractrotation ( KS_MAT3x3  R,
const KS_MAT4x4  M 
)

Extract a 3x3 rotation matrix from a 4x4 transformation matrix

Parameters
[out]R3x3 rotation matrix (KS_MAT3x3), row major
[in]MTransformation matrix (KS_MAT4x4), row major
Returns
void
3894  {
3895  int i, j;
3896  for (i = 0; i < 3; ++i) {
3897  for (j = 0; j < 3; ++j) {
3898  R[3 * i + j] = M[4 * i + j];
3899  }
3900  }
3901 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat4_extracttranslation()

void ks_mat4_extracttranslation ( double *  T,
const KS_MAT4x4  M 
)

Extract a 3 element array with translations from a 4x4 transformation matrix

Parameters
[out]TFloat array with 3 elements (must be allocated)
[in]MTransformation matrix (KS_MAT4x4), row major
Returns
void
3906  {
3907  int i;
3908  for (i = 0; i < 3; ++i) {
3909  T[i] = M[4 * i + 3];
3910  }
3911 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat3_identity()

void ks_mat3_identity ( KS_MAT3x3  m)

Creates a 3x3 identity matrix

Parameters
[in,out]mMatrix (KS_MAT3x3)
Returns
void
3916  {
3917  int i;
3918  for (i = 0; i < 9; ++i) {
3919  m[i] = 0;
3920  }
3921  m[0] = 1;
3922  m[4] = 1;
3923  m[8] = 1;
3924 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat3_multiply()

void ks_mat3_multiply ( KS_MAT3x3  lhs,
const KS_MAT3x3  rhs_left,
const KS_MAT3x3  rhs_right 
)

Multiplication of two 3x3 matrices

Matrix product: [rhs_left] * [rhs_right]

Parameters
[out]lhsMatrix product (KS_MAT3x3)
[in]rhs_leftLeft matrix (KS_MAT3x3)
[in]rhs_rightRight matrix (KS_MAT3x3)
Returns
void
3929  {
3930 
3931  /* TODO: add checks for overlapping arrays */
3932 
3933  int i, j, k;
3934  for (i = 0; i < 3; ++i) {
3935  for (j = 0; j < 3; ++j) {
3936  double acc = 0;
3937  for (k = 0; k < 3; ++k) {
3938  acc += rhs_left[3 * i + k] * rhs_right[3 * k + j];
3939  }
3940  lhs[3 * i + j] = acc;
3941  }
3942  }
3943 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat3_print()

void ks_mat3_print ( const KS_MAT3x3  m)

Prints a 3x3 matrix to stdout

Parameters
[in]mMatrix (KS_MAT3x3)
Returns
void
3948  {
3949  int i;
3950  for (i = 0; i < 3; ++i) {
3951  fprintf(stderr, "|%.2f,\t%.2f\t%.2f|\n", m[3 * i], m[3 * i + 1], m[3 * i + 2]);
3952  }
3953  fprintf(stderr, "\n");
3954 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat3_apply()

void ks_mat3_apply ( double *  w,
const KS_MAT3x3  R,
const double *  v 
)

Rotate a 3x1 vector by a 3x3 rotation matrix (alibi)

Apply an active (alibi) rotation – i.e w = R * v

Parameters
[out]wOutput vector (float array with 3 elements)
[in]RRotation matrix (KS_MAT3x3)
[in]vInput vector (float array with 3 elements)
Returns
void
3959  {
3960  int i, j;
3961  for (i = 0; i < 3; ++i) {
3962  double acc = 0;
3963  for (j = 0; j < 3; ++j) {
3964  acc += R[3 * i + j] * v[j];
3965  }
3966  w[i] = acc;
3967  }
3968 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat3_invapply()

void ks_mat3_invapply ( double *  w,
const KS_MAT3x3  R,
const double *  v 
)

Rotate a 3x1 vector by the inverse of 3x3 rotation matrix (alias)

Apply a passive (alias) rotation – i.e w = R' * v = R^-1 * v

Parameters
[out]wOutput vector (float array with 3 elements)
[in]RRotation matrix (KS_MAT3x3)
[in]vInput vector (float array with 3 elements)
Returns
void
3973  {
3974  int i, j;
3975  for (i = 0; i < 3; ++i) {
3976  double acc = 0;
3977  for (j = 0; j < 3; ++j) {
3978  acc += v[j] * R[3 * j + i];
3979  }
3980  w[i] = acc;
3981  }
3982 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat3f_apply()

void ks_mat3f_apply ( float *  w,
const KS_MAT3x3f  R,
const float *  v 
)

Rotate a vector with a 3x3 matrix

Parameters
[in]wcolumn vector (3)
[in]Rrotation matrix
vresult of R.dot(v)
Returns
void
3987  {
3988  int i, j;
3989  for (i = 0; i < 3; ++i) {
3990  double acc = 0;
3991  for (j = 0; j < 3; ++j) {
3992  acc += R[3 * i + j] * (double)v[j];
3993  }
3994  w[i] = acc;
3995  }
3996 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_mat3f_invapply()

void ks_mat3f_invapply ( float *  w,
const KS_MAT3x3f  R,
const float *  v 
)

Same as ks_mat3f_apply but use transpose of Rotation (R)

Parameters
[in]wcolumn vector (3)
[in]Rrotation matrix
vresult of R.dot(v)
Returns
void
4001  {
4002  int i, j;
4003  for (i = 0; i < 3; ++i) {
4004  double acc = 0;
4005  for (j = 0; j < 3; ++j) {
4006  acc += v[j] * (double)R[3 * j + i];
4007  }
4008  w[i] = acc;
4009  }
4010 }
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_scan_update_slice_location()

void ks_scan_update_slice_location ( SCAN_INFO *  new_loc,
const SCAN_INFO  orig_loc,
const KS_MAT4x4  M_physical,
const KS_MAT4x4  M_logical 
)

Updates a SCAN_INFO struct using physical and logical 4x4 transformation matrices

Updates the slice location – e.g for motion correction (physical space) or propeller rotations (logical space)

M_physical and M_logical are row-major 4x4 matricies that describe rotations (R_physical, R_logical) and translations (T_physical, T_logical) of the FOV in the physical and logical coordinate systems, respectively. If R_slice and T_slice describe the position of the prescribed FOV contained in orig_loc then new_loc will describe the overall rotation R_new and translation T_new of the FOV such that:

R_new = R_physical * R_slice * R_logical

T_new = R_logical^-1 * (R_slice^-1 * R_physical^-1 * T_physical + T_slice + T_logical)

NOTE: All transformations are expected to be active (alibi) that denote a change of position/orientation, not passive (alias) that denote a change of coordinates system. See https://en.wikipedia.org/wiki/Active_and_passive_transformation

SCAN_INFO is defined in $ESE_TOP/psd/include/epic_geometry_types.h and the global scan_info variable is an array of SCAN_INFO structs holding information of the graphically prescribed slices

Parameters
[out]new_locPointer to a SCAN_INFO struct holding the new slice information
[in]orig_locSCAN_INFO struct holding the original slice information
[in]M_physicalTransformation matrix (4x4) in the physical space
[in]M_logicalTransformation matrix (4x4) in the logical (i.e. XGRAD, YGRAD, ZGRAD) space
Returns
void
4015  {
4016  int i;
4017  KS_MAT3x3 R_m;
4018  KS_MAT3x3 R_l;
4019  KS_MAT3x3 R_ms;
4020  KS_MAT3x3 R_msl;
4021 
4022  const double T_s[3] = {orig_loc.oprloc, orig_loc.opphasoff, orig_loc.optloc};
4023  double T_m[3];
4024  double T_l[3];
4025  double T_msl[3];
4026  double T_new[3];
4027 
4028  /* initialize to identity matrix (will be used if NULL in 3rd or 4th arg) */
4029  KS_MAT4x4 Mphys = KS_MAT4x4_IDENTITY;
4031 
4032  /* copy slice rotation and translation */
4033  KS_MAT3x3 R_s;
4034  for (i = 0; i < 9; i++) {
4035  R_s[i] = orig_loc.oprot[i];
4036  }
4037 
4038  /* copy transformation matrices (if they are not NULL) to local matrices */
4039  if (M_physical != NULL) {
4040  memcpy(Mphys, M_physical, sizeof(KS_MAT4x4));
4041  }
4042  if (M_logical != NULL) {
4043  memcpy(Mlog, M_logical, sizeof(KS_MAT4x4));
4044  }
4045 
4046  ks_mat4_extractrotation(R_m, Mphys);
4047  ks_mat4_extractrotation(R_l, Mlog);
4048 
4049  ks_mat4_extracttranslation(T_m, Mphys);
4050  ks_mat4_extracttranslation(T_l, Mlog);
4051 
4052  /* R_ms = R_m * R_s */
4053  ks_mat3_multiply(R_ms, R_m, R_s);
4054 
4055  /* R_ms^-1 * T_m = T_m' * R_ms' */
4056  ks_mat3_invapply(T_msl, R_ms, T_m);
4057 
4058  for (i = 0; i < 3; ++i) {
4059  T_msl[i] += T_s[i] + T_l[i];
4060  }
4061 
4062  ks_mat3_invapply(T_new, R_l, T_msl);
4063  new_loc->oprloc = T_new[0];
4064  new_loc->opphasoff = T_new[1];
4065  new_loc->optloc = T_new[2];
4066 
4067  ks_mat3_multiply(R_msl, R_ms, R_l);
4068  for (i=0; i<9; ++i) {
4069  new_loc->oprot[i] = R_msl[i];
4070  }
4071 } /* ks_scan_update_slice_location */
void ks_mat3_invapply(double *w, const KS_MAT3x3 R, const double *v)
Rotate a 3x1 vector by the inverse of 3x3 rotation matrix (alias)
Definition: KSFoundation_common.c:3973
double KS_MAT4x4[16]
Definition: KSFoundation.h:356
int32_t i
Definition: KSFoundation_tgt.c:1694
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ks_mat4_extractrotation(KS_MAT3x3 R, const KS_MAT4x4 M)
Extract a 3x3 rotation matrix from a 4x4 transformation matrix
Definition: KSFoundation_common.c:3894
#define KS_MAT4x4_IDENTITY
Definition: KSFoundation.h:340
void ks_mat4_extracttranslation(double *T, const KS_MAT4x4 M)
Extract a 3 element array with translations from a 4x4 transformation matrix
Definition: KSFoundation_common.c:3906
void ks_mat3_multiply(KS_MAT3x3 lhs, const KS_MAT3x3 rhs_left, const KS_MAT3x3 rhs_right)
Multiplication of two 3x3 matrices
Definition: KSFoundation_common.c:3929

◆ ks_scan_update_slice_location_float()

void ks_scan_update_slice_location_float ( SCAN_INFO *  new_loc,
const SCAN_INFO  orig_loc,
const KS_MAT4x4f  M_physical,
const KS_MAT4x4f  M_logical 
)
4074  {
4075  KS_MAT4x4 Mphysical = KS_MAT4x4_IDENTITY;
4076  KS_MAT4x4 Mlogical = KS_MAT4x4_IDENTITY;
4077  ks_mat4_float_to_double(Mphysical, M_physical);
4078  ks_mat4_float_to_double(Mlogical, M_logical);
4079  ks_scan_update_slice_location(new_loc, orig_loc, Mphysical, Mlogical);
4080 } /* ks_scan_update_slice_location_float */
void ks_mat4_float_to_double(KS_MAT4x4 out, const KS_MAT4x4f in)
Conversion of a 4x4 matrix from float to double
Definition: KSFoundation_common.c:3793
double KS_MAT4x4[16]
Definition: KSFoundation.h:356
#define KS_MAT4x4_IDENTITY
Definition: KSFoundation.h:340
void ks_scan_update_slice_location(SCAN_INFO *new_loc, const SCAN_INFO orig_loc, const KS_MAT4x4 M_physical, const KS_MAT4x4 M_logical)
Updates a SCAN_INFO struct using physical and logical 4x4 transformation matrices
Definition: KSFoundation_common.c:4015

◆ ks_compare_loc_by_timeboard()

int ks_compare_loc_by_timeboard ( const KS_SEQLOC a,
const KS_SEQLOC b 
)
4086  {
4087 
4088 return (a->pos > b->pos) - (a->pos < b->pos) +
4089  (a->pos == b->pos) * ((a->board > b->board) - (a->board < b->board));
4090 }
int pos
Definition: KSFoundation.h:463
int board
Definition: KSFoundation.h:462

◆ ks_compare_wfi_by_timeboard()

int ks_compare_wfi_by_timeboard ( const KS_WFINSTANCE a,
const KS_WFINSTANCE b 
)

Compares two WF_INSTANCEs by time, then board

This function is used by the qsort() routine in ks_compare_wfi_by_timeboard()

If two WF_INSTANCEs occur at the same time, XGRAD will come before YGRAD and YGRAD before ZGRAD

Parameters
[in]aPointer to the first KS_WFINSTANCE
[in]bPointer to the second KS_WFINSTANCE
Return values
valueLarger or less than 0 depending on sorting order
4095  {
4096 
4097  return ks_compare_loc_by_timeboard(&a->loc, &b->loc);
4098 }
int ks_compare_loc_by_timeboard(const KS_SEQLOC *a, const KS_SEQLOC *b)
Definition: KSFoundation_common.c:4086
KS_SEQLOC loc
Definition: KSFoundation.h:486

◆ ks_compare_wfi_by_boardtime()

int ks_compare_wfi_by_boardtime ( const KS_WFINSTANCE a,
const KS_WFINSTANCE b 
)

Compares two WF_INSTANCES by board, then time

This function is used by the qsort() routine in ks_compare_wfi_by_boardtime()

WF_INSTANCEs are sorted first by board. If two WF_INSTANCEs occur on the same board, t they will be sorted in time

Parameters
[in]aPointer to the first KS_WFINSTANCE
[in]bPointer to the second KS_WFINSTANCE
Return values
valueLarger or less than 0 depending on sorting order
4103  {
4104 
4105  return (a->loc.board > b->loc.board) - (a->loc.board < b->loc.board) +
4106  (a->loc.board == b->loc.board) * ((a->loc.pos > b->loc.pos) - (a->loc.pos < b->loc.pos));
4107 }
int pos
Definition: KSFoundation.h:463
int board
Definition: KSFoundation.h:462
KS_SEQLOC loc
Definition: KSFoundation.h:486

◆ ks_compare_wfp_by_time()

int ks_compare_wfp_by_time ( const WF_PULSE *  a,
const WF_PULSE *  b 
)

Compares two WF_PULSES in time

This function is used by the qsort() routine in ks_sort_wfp_by_time(), which is called from ks_pg_read() for data acquisition sorting purposes. It is assumed both WF_PULSEs have only one instance

Parameters
[in]aPointer to the first WF_PULSE
[in]bPointer to the second WF_PULSE
Return values
valueLarger or less than 0 depending on sorting order
4112  {
4113 
4114  return (a->inst_hdr_head->start > b->inst_hdr_head->start) - (a->inst_hdr_head->start < b->inst_hdr_head->start);
4115 }

◆ ks_sort_wfi_by_timeboard()

void ks_sort_wfi_by_timeboard ( KS_WFINSTANCE a,
int  nitems 
)

Sort WF_INSTANCEs in time, then board

This is the sorting method used in all ks_pg_***() functions on tgt

Parameters
[in,out]aArray of KS_WFINSTANCE elements
[in]nitemsNumber of elements in array
Returns
void
4120  {
4121  qsort(a, nitems, sizeof(KS_WFINSTANCE),
4122  (int(*)(const void *, const void *))ks_compare_wfi_by_timeboard);
4123 }
(Internal use) Structure being a part of various sequence objects to sort them in time across boards...
Definition: KSFoundation.h:483
int ks_compare_wfi_by_timeboard(const KS_WFINSTANCE *a, const KS_WFINSTANCE *b)
Compares two WF_INSTANCEs by time, then board
Definition: KSFoundation_common.c:4095

◆ ks_sort_loc_by_timeboard()

void ks_sort_loc_by_timeboard ( KS_SEQLOC a,
int  nitems 
)

Sort KS_SEQLOCs in time, then board

This is the sorting method used in all ks_pg_***() on host

Parameters
[in,out]aArray of KS_SEQLOC elements
[in]nitemsNumber of elements in array
Returns
void
4128  {
4129  qsort(a, nitems, sizeof(KS_SEQLOC),
4130  (int(*)(const void *, const void *))ks_compare_loc_by_timeboard);
4131 }
int ks_compare_loc_by_timeboard(const KS_SEQLOC *a, const KS_SEQLOC *b)
Definition: KSFoundation_common.c:4086
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461

◆ ks_sort_wfi_by_boardtime()

void ks_sort_wfi_by_boardtime ( KS_WFINSTANCE a,
int  nitems 
)

Sort WF_INSTANCEs by board, then time

This function is an alternative to ks_sort_wfi_by_timeboard(), which is not used at the moment

Parameters
[in,out]aArray of KS_WFINSTANCE elements
[in]nitemsNumber of elements in array
Returns
void
4136  {
4137  qsort(a, nitems, sizeof(KS_WFINSTANCE), (int(*)(const void *, const void *))ks_compare_wfi_by_boardtime);
4138 }
(Internal use) Structure being a part of various sequence objects to sort them in time across boards...
Definition: KSFoundation.h:483
int ks_compare_wfi_by_boardtime(const KS_WFINSTANCE *a, const KS_WFINSTANCE *b)
Compares two WF_INSTANCES by board, then time
Definition: KSFoundation_common.c:4103

◆ ks_sort_wfp_by_time()

void ks_sort_wfp_by_time ( WF_PULSE *  a,
int  nitems 
)

Sort WF_PULSEs in time

This is the sorting method used in ks_pg_read()

It is assumed that all a[idx] for idx in [0,nitems) have only one instance each

Parameters
[in,out]aArray of WF_PULSE elements
[in]nitemsNumber of elements in array
Returns
void
4143  {
4144  qsort(a, nitems, sizeof(WF_PULSE),
4145  (int(*)(const void *, const void *))ks_compare_wfp_by_time);
4146 }
int ks_compare_wfp_by_time(const WF_PULSE *a, const WF_PULSE *b)
Compares two WF_PULSES in time
Definition: KSFoundation_common.c:4112

◆ ks_compare_pshort()

int ks_compare_pshort ( const void *  v1,
const void *  v2 
)

Compares two short pointers

Parameters
[in]v1Pointer to the first short pointer
[in]v2Pointer to the second shot pointer
Return values
valueLarger or less than 0 depending on sorting order
4151  {
4152  const short i1 = **(const short **) v1;
4153  const short i2 = **(const short **) v2;
4154 
4155  return i1 < i2 ? -1 : (i1 > i2);
4156 }

◆ ks_compare_pint()

int ks_compare_pint ( const void *  v1,
const void *  v2 
)

Compares two int pointers

Parameters
[in]v1Pointer to the first int pointer
[in]v2Pointer to the second int pointer
Return values
valueLarger or less than 0 depending on sorting order
4161  {
4162  const int i1 = **(const int **) v1;
4163  const int i2 = **(const int **) v2;
4164 
4165  return i1 < i2 ? -1 : (i1 > i2);
4166 }

◆ ks_compare_pfloat()

int ks_compare_pfloat ( const void *  v1,
const void *  v2 
)

Compares two float pointers

Parameters
[in]v1Pointer to the first float pointer
[in]v2Pointer to the second float pointer
Return values
valueLarger or less than 0 depending on sorting order
4171  {
4172  const float i1 = **(const float **) v1;
4173  const float i2 = **(const float **) v2;
4174 
4175  return i1 < i2 ? -1 : (i1 > i2);
4176 }

◆ ks_compare_short()

int ks_compare_short ( const void *  v1,
const void *  v2 
)

Compares two integers (short)

Parameters
[in]v1Pointer to the first short
[in]v2Pointer to the second short
Return values
valueLarger or less than 0 depending on sorting order
4181  {
4182  const short i1 = *(const short *) v1;
4183  const short i2 = *(const short *) v2;
4184 
4185  return i1 < i2 ? -1 : (i1 > i2);
4186 }

◆ ks_compare_int()

int ks_compare_int ( const void *  v1,
const void *  v2 
)

Compares two integers (int)

Parameters
[in]v1Pointer to the first int
[in]v2Pointer to the second int
Return values
valueLarger or less than 0 depending on sorting order
4191  {
4192  const int i1 = *(const int *) v1;
4193  const int i2 = *(const int *) v2;
4194 
4195  return i1 < i2 ? -1 : (i1 > i2);
4196 }

◆ ks_compare_float()

int ks_compare_float ( const void *  v1,
const void *  v2 
)

Compares two floats

Parameters
[in]v1Pointer to the first float
[in]v2Pointer to the second float
Return values
valueLarger or less than 0 depending on sorting order
4201  {
4202  const float i1 = *(const float *) v1;
4203  const float i2 = *(const float *) v2;
4204 
4205  return i1 < i2 ? -1 : (i1 > i2);
4206 }

◆ ks_sort_getsortedindx()

void ks_sort_getsortedindx ( int *  sortedindx,
int *  array,
int  n 
)

Sort an array of integers (int)

Parameters
[out]sortedindxArray of indices into the array to make it sorted
[in,out]arrayArray to be sorted
[in]nNumber of elements in array
Returns
void
4211  {
4212  int i;
4213  int *parray[n];
4214 
4215  for (i = 0; i < n; i++)
4216  parray[i] = &array[i];
4217 
4218  qsort(parray, n, sizeof * parray, ks_compare_pint);
4219 
4220  for (i = 0; i < n; i++)
4221  sortedindx[i] = parray[i] - array;
4222 
4223 }
int32_t i
Definition: KSFoundation_tgt.c:1694
int ks_compare_pint(const void *v1, const void *v2)
Compares two int pointers
Definition: KSFoundation_common.c:4161

◆ ks_sort_getsortedindx_s()

void ks_sort_getsortedindx_s ( int *  sortedindx,
short *  array,
int  n 
)

Sort an array of integers (short)

Parameters
[out]sortedindxArray of indices into the array to make it sorted
[in,out]arrayArray to be sorted
[in]nNumber of elements in array
Returns
void
4228  {
4229  int i;
4230  short *parray[n];
4231 
4232  for (i = 0; i < n; i++)
4233  parray[i] = &array[i];
4234 
4235  qsort(parray, n, sizeof * parray, ks_compare_pshort);
4236 
4237  for (i = 0; i < n; i++)
4238  sortedindx[i] = parray[i] - array;
4239 
4240 }
int32_t i
Definition: KSFoundation_tgt.c:1694
int ks_compare_pshort(const void *v1, const void *v2)
Compares two short pointers
Definition: KSFoundation_common.c:4151

◆ ks_sort_getsortedindx_f()

void ks_sort_getsortedindx_f ( int *  sortedindx,
float *  array,
int  n 
)

Sort an array of floats

Parameters
[out]sortedindxArray of indices into the array to make it sorted
[in,out]arrayArray to be sorted
[in]nNumber of elements in array
Returns
void
4245  {
4246  int i;
4247  float *parray[n];
4248 
4249  for (i = 0; i < n; i++)
4250  parray[i] = &array[i];
4251 
4252  qsort(parray, n, sizeof * parray, ks_compare_pfloat);
4253 
4254  for (i = 0; i < n; i++)
4255  sortedindx[i] = parray[i] - array;
4256 
4257 }
int ks_compare_pfloat(const void *v1, const void *v2)
Compares two float pointers
Definition: KSFoundation_common.c:4171
int32_t i
Definition: KSFoundation_tgt.c:1694

◆ ks_plot_slicetime_begin()

void ks_plot_slicetime_begin ( )

ADDTITLEHERE

ADDDESCHERE

Returns
void
4266  {
4267 #ifdef IPG
4268  return;
4269 #endif
4271 }
void ks_plot_host_slicetime_begin()
ADDTITLEHERE
Definition: KSFoundation_host.c:7320

◆ ks_plot_slicetime()

void ks_plot_slicetime ( const KS_SEQ_CONTROL ctrl,
int  nslices,
float *  slicepos_mm,
float  slthick_mm,
KS_PLOT_EXCITATION_MODE  exctype 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
ctrlADDTEXTHERE
[in]nslicesADDTEXTHERE
slicepos_mmADDTEXTHERE
[in]slthick_mmADDTEXTHERE
[in]exctypeADDTEXTHERE
Returns
void
4276  {
4277 #ifdef IPG
4278  return;
4279 #endif
4280  ks_plot_host_slicetime(ctrl, nslices, slicepos_mm, slthick_mm, excmode);
4281 }
void ks_plot_host_slicetime(const KS_SEQ_CONTROL *ctrl, int nslices, float *slicepos_mm, float slthick_mm, KS_PLOT_EXCITATION_MODE exctype)
ADDTITLEHERE
Definition: KSFoundation_host.c:7449

◆ ks_plot_slicetime_endofpass()

void ks_plot_slicetime_endofpass ( KS_PLOT_PASS_MODE  pass_mode)

ADDTITLEHERE

ADDDESCHERE

Parameters
[in]pass_modeADDTEXTHERE
Returns
void
4286  {
4287 #ifdef IPG
4288  return;
4289 #endif
4291 }
void ks_plot_host_slicetime_endofpass(KS_PLOT_PASS_MODE pass_mode)
ADDTITLEHERE
Definition: KSFoundation_host.c:7400

◆ ks_plot_slicetime_endofslicegroup_tagged()

void ks_plot_slicetime_endofslicegroup_tagged ( const char *  desc,
const KS_PLOT_SLICEGROUP_MODE  tag 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
descADDTEXTHERE
[in]tagADDTEXTHERE
Returns
void
4296  {
4297 #ifdef IPG
4298  return;
4299 #endif
4301 }
void ks_plot_host_slicetime_endofslicegroup(const char *desc, const KS_PLOT_SLICEGROUP_MODE tag)
ADDTITLEHERE
Definition: KSFoundation_host.c:7354

◆ ks_plot_slicetime_endofslicegroup()

void ks_plot_slicetime_endofslicegroup ( const char *  desc)

ADDTITLEHERE

ADDDESCHERE

Parameters
descADDTEXTHERE
Returns
void
4306  {
4307 #ifdef IPG
4308  return;
4309 #endif
4311 }
Definition: KSFoundation.h:415
void ks_plot_host_slicetime_endofslicegroup(const char *desc, const KS_PLOT_SLICEGROUP_MODE tag)
ADDTITLEHERE
Definition: KSFoundation_host.c:7354

◆ ks_plot_slicetime_end()

void ks_plot_slicetime_end ( )

ADDTITLEHERE

ADDDESCHERE

Returns
void
4316  {
4317 #ifdef IPG
4318  return;
4319 #endif
4321 }
void ks_plot_host_slicetime_end()
ADDTITLEHERE
Definition: KSFoundation_host.c:7512

◆ ks_plot_tgt_reset()

void ks_plot_tgt_reset ( KS_SEQ_CONTROL ctrl)

ADDTITLEHERE

ADDDESCHERE

Parameters
ctrlADDTEXTHERE
Returns
void
4326  {
4327  FILE *fp;
4328  char fname_json[1000];
4329  char cmd[200];
4330  #ifdef PSD_HW
4331  return;
4332  #endif
4333 
4334 
4335  if (ks_plot_filefmt == KS_PLOT_OFF) {
4336  return;
4337  }
4338 
4339  system("mkdir -p ./plot/tgt/");
4340  sprintf(fname_json, "./plot/tgt/psdplot_tgt_%s_%s.json", ks_psdname, ctrl->description);
4341  sprintf(cmd, "rm -f %s ./plot/tgt/%s_%s_*_tgt.*",
4342  fname_json, ks_psdname, ctrl->description);
4343  system(cmd);
4344  fp = fopen(fname_json, "w");
4345  fprintf(fp, "{\n"
4346  "\"metadata\": {\n"
4347  "\t\"mode\": \"tgt\",\n"
4348  "\t\"psdname\": \"%s\",\n"
4349  "\t\"sequence\": \"%s\",\n"
4350  "\t\"duration\": %0.3f,\n"
4351  "\t\"min_duration\": %0.3f,\n"
4352  "\t\"ssi_time\": %0.3f,\n"
4353  "\t\"momentstart\": %.3f\n"
4354  "},\n"
4355  "\"frames\": [\n"
4356  "{}]}",
4357  ks_psdname,
4358  ctrl->description,
4359  ctrl->duration/1000.0,
4360  ctrl->min_duration/1000.0,
4361  ctrl->ssi_time/1000.0,
4362  ctrl->momentstart/1000.0
4363  );
4364  fclose(fp);
4365 }
Definition: KSFoundation.h:397
int momentstart
Definition: KSFoundation.h:1228
int duration
Definition: KSFoundation.h:1227
int ks_plot_filefmt
Definition: GERequired.e:272
int min_duration
Definition: KSFoundation.h:1224
int ssi_time
Definition: KSFoundation.h:1226
char ks_psdname[256]
Definition: GERequired.e:245
KS_DESCRIPTION description
Definition: KSFoundation.h:1234

◆ ks_plot_tgt_addframe()

void ks_plot_tgt_addframe ( KS_SEQ_CONTROL ctrl)

Writes a plot frame to file

Parameters
ctrlPointer to sequence control
4370  {
4371  #if (!(defined(SIM) && defined(IPG)))
4372  return;
4373  #endif
4374 
4375  if (ks_plot_filefmt == KS_PLOT_OFF) {
4376  return;
4377  }
4378 
4379  char boardc[8] = "xyzrRto"; /* x,y,z,rho1, rho2, theta, omega*/
4380  char fname[1000];
4381  sprintf(fname, "./plot/tgt/psdplot_tgt_%s_%s.json", ks_psdname, ctrl->description);
4382  FILE *fp;
4383  int i, w, inst, boardinstance;
4384  KS_SEQLOC loc;
4385  fp = fopen(fname, "r+");
4386  fseek(fp, -2, SEEK_END);
4387  fputs(",{\n", fp);
4388  short iamp;
4389  float gradmax;
4390  float amp;
4391 
4392  /* TRAPEZOIDS */
4393  fprintf(fp, "\"trapz\": {\n");
4394  fflush(fp);
4395  KS_TRAP* trap;
4396  for (i = 0; i < ctrl->gradrf.numtrap; i++) { /* Each unique trap object */
4397  trap = ctrl->gradrf.trapptr[i];
4398  fprintf(fp, "\t\"%s\": {\n", trap->description);
4399  fprintf(fp, "\t\t\"ramptime\": %0.3f,\n", trap->ramptime / 1000.0);
4400  fprintf(fp, "\t\t\"plateautime\": %0.3f,\n", trap->plateautime / 1000.0);
4401  fprintf(fp, "\t\t\"duration\": %0.3f,\n", trap->duration / 1000.0);
4402  fprintf(fp, "\t\t\"amp\": %0.6f,\n", 1.0);
4403  fprintf(fp, "\t\t\"instances\": [{\n");
4404  fflush(fp);
4405  for (inst = 0; inst < ctrl->gradrf.trapptr[i]->base.ngenerated; inst++) { /* Each instance of this trap */
4406  loc = trap->locs[inst];
4407  fprintf(fp, "\t\t\t\"board\": \"%c\",\n", boardc[loc.board]);
4408  fprintf(fp, "\t\t\t\"time\": %0.3f,\n", loc.pos / 1000.0);
4409 
4410  WF_PULSE* plateau_ptr = trap->wfi[inst].wf;
4411  boardinstance = trap->wfi[inst].boardinstance;
4412  /* Get the linked list of the plateau (used to get the position of all wf instances) */
4413  /* WF_INSTR_HDR instr_plateau = plateau_ptr->inst_hdr_tail; */
4414  /* WF_INSTR_HDR instr_attack = plateau_ptr->assoc_pulse->inst_hdr_tail; */ /* Attack is the associated pulse of the plateau */
4415  /* WF_INSTR_HDR instr_decay = plateau_ptr->assoc_pulse->assoc_pulse->inst_hdr_tail; */ /* Decay is the associated pulse of the attack */
4416  /*
4417  for (idx = 0; idx < (boardinstance); idx++) {
4418  instr_plateau = instr_plateau->next;
4419  instr_attack = instr_attack->next;
4420  instr_decay = instr_decay->next;
4421  }
4422  */
4423  /* Plateau amplitude is written in G/cm */
4424  getiamp(&iamp, plateau_ptr, boardinstance);
4425  fprintf(fp, "\t\t\t\"ampscale\": 1.0,\n");
4426  gradmax = ks_syslimits_gradtarget(loggrd, trap->wfi[inst].loc.board);
4427  if (loc.board == OMEGA || loc.board == THETA) {
4428  gradmax = 1;
4429  }
4430  amp = gradmax * (float)iamp / MAX_PG_IAMP;
4431  fprintf(fp, "\t\t\t\"rtscale\": %.12f\n", amp);
4432 
4433  /* char pulsename[100]; */
4434  /* (float)pbeg(plateau_ptr, pulsename, boardinstance)/1000.0 */
4435  /* sprintf(pulsename, "%s%s", plateau_ptr->pulsename, "a"); */
4436 
4437  if (inst == (trap->base.ngenerated -1)) {
4438  fprintf(fp, "\t\t}]\n");
4439  } else {
4440  fprintf(fp, "\t\t},{\n");
4441  }
4442  } /* inst */
4443  if (i == (ctrl->gradrf.numtrap -1)) {
4444  fprintf(fp, "\t}\n");
4445  } else {
4446  fprintf(fp, "\t},\n");
4447  }
4448  }
4449  fprintf(fp, "},\n"); /* Trapezoids */
4450 
4451  fprintf(fp, "\"acquisitions\": [\n");
4452  /* ACQUISITIONS */
4453  for (i = 0; i < ctrl->gradrf.numacq; i++) { /* Each unique KS_READ object */
4454  KS_READ* acq = ctrl->gradrf.readptr[i];
4455  fprintf(fp, "\t{\n");
4456  fprintf(fp, "\t\t\"description\": \"%s\",\n", acq->description);
4457  fprintf(fp, "\t\t\"duration\": %0.3f,\n", acq->duration / 1000.0);
4458  fprintf(fp, "\t\t\"rbw\": %0.3f,\n", acq->rbw);
4459  fprintf(fp, "\t\t\"samples\": %d,\n", acq->filt.outputs);
4460  fprintf(fp, "\t\t\"time\": [");
4461  for (inst = 0; inst < acq->base.ngenerated; ++inst) {
4462  fprintf(fp, "%0.3f", acq->pos[inst] / 1000.0);
4463  if (inst == (acq->base.ninst -1)) {
4464  fprintf(fp, "]\n");
4465  } else {
4466  fprintf(fp, ", ");
4467  }
4468  } /* inst */
4469  if (i == (ctrl->gradrf.numacq -1)) {
4470  fprintf(fp, "\t}\n");
4471  } else {
4472  fprintf(fp, "\t},\n");
4473  }
4474  } /* ACQUISITIONS */
4475  fprintf(fp, "],\n"); /* End acquisitions */
4476 
4477  /* RF */
4478  WF_PULSE* rf_wf;
4479  WF_PULSE* omega_wf;
4480  WF_PULSE* theta_wf;
4481  short new_wave_iamp;
4482  KS_IWAVE acquired_wave; /* short int array */
4483  fprintf(fp, "\"rf\": {\n");
4484  for (i = 0; i < ctrl->gradrf.numrf; ++i) { /* Each unique KS_RF object */
4485  KS_RF* rfptr = ctrl->gradrf.rfptr[i];
4486 
4487  if (rfptr->rfwave.res > 0) {
4488  /* RHO */
4489  char roledesc[50];
4490  if (rfptr->role == KS_RF_ROLE_EXC) {
4491  strcpy(roledesc,"KS_RF_ROLE_EXC");
4492  } else if (rfptr->role == KS_RF_ROLE_REF) {
4493  strcpy(roledesc,"KS_RF_ROLE_REF");
4494  } else if (rfptr->role == KS_RF_ROLE_CHEMSAT) {
4495  strcpy(roledesc, "KS_RF_ROLE_CHEMSAT");
4496  } else if (rfptr->role == KS_RF_ROLE_INV) {
4497  strcpy(roledesc, "KS_RF_ROLE_INV");
4498  } else if (rfptr->role == KS_RF_ROLE_SPSAT) {
4499  strcpy(roledesc, "KS_RF_ROLE_SPSAT");
4500  } else {
4501  strcpy(roledesc,"NONE");
4502  }
4503  fprintf(fp, "\t\"%s\": {\n", rfptr->rfwave.description);
4504  fprintf(fp, "\t\t\"description\": \"%s\",\n", rfptr->rfwave.description);
4505  fprintf(fp, "\t\t\"flipangle\": %0.3f,\n", rfptr->flip);
4506  fprintf(fp, "\t\t\"nominal_flipangle\": %0.3f,\n", rfptr->rfpulse.nom_fa);
4507  fprintf(fp, "\t\t\"max_b1\": %0.6f,\n", rfptr->rfpulse.max_b1);
4508  fprintf(fp, "\t\t\"isodelay\": %0.3f,\n", rfptr->start2iso / 1000.0);
4509  fprintf(fp, "\t\t\"duration\": %0.3f,\n", rfptr->rfwave.duration / 1000.0);
4510  fprintf(fp, "\t\t\"role\": \"%s\",\n", roledesc);
4511  fprintf(fp, "\t\t\"amp\": %.3f,\n", rfptr->amp);
4512  /* OMEGA */
4513  fprintf(fp, "\t\t\"omega\": {\n");
4514  if (rfptr->omegawave.res > 0) {
4515  fprintf(fp, "\t\t\t\"description\": \"%s\",\n", rfptr->omegawave.description);
4516  fprintf(fp, "\t\t\t\"duration\": %0.3f,\n", rfptr->omegawave.duration / 1000.0);
4517  fprintf(fp, "\t\t\t\"instances\": [{\n");
4518  for (inst = 0; inst < rfptr->omegawave.base.ngenerated; ++inst) {
4519  loc = rfptr->omegawave.locs[inst];
4520  boardinstance = rfptr->omegawave.wfi[inst].boardinstance;
4521  omega_wf = &(rfptr->omegawave.wfpulse[OMEGA][0]);
4522  movewaveimm(acquired_wave, omega_wf, boardinstance, rfptr->omegawave.res, FROMHARDWARE);
4523  getiamp(&new_wave_iamp, omega_wf, boardinstance);
4524  fprintf(fp, "\t\t\t\t\"waveform\": [0,");
4525  for (w = 0; w < rfptr->omegawave.res; w++) {
4526  fprintf(fp, "%d,", acquired_wave[w]);
4527  }
4528  fprintf(fp, "0],\n");
4529  fprintf(fp, "\t\t\t\t\"time\": %0.3f,\n", loc.pos/1000.0);
4530  fprintf(fp, "\t\t\t\t\"board\": \"%c\",\n", boardc[loc.board]);
4531  fprintf(fp, "\t\t\t\t\"ampscale\": 1.0,\n");
4532  fprintf(fp, "\t\t\t\t\"rtscale\": %0.12f\n", (float)(new_wave_iamp) / (max_pg_wamp * max_pg_wamp));
4533  if (inst == (rfptr->omegawave.base.ngenerated -1)) {
4534  fprintf(fp, "\t\t\t}]\n");
4535  } else {
4536  fprintf(fp, "\t\t\t},{\n");
4537  }
4538  }
4539  }
4540  fprintf(fp, "\t\t},\n"); /* Omega */
4541 
4542  /* THETA */
4543  fprintf(fp, "\t\t\"theta\": {\n");
4544  if (rfptr->thetawave.res > 0) {
4545  fprintf(fp, "\t\t\t\"description\": \"%s\",\n", rfptr->thetawave.description);
4546  fprintf(fp, "\t\t\t\"duration\": %0.3f,\n", rfptr->thetawave.duration / 1000.0);
4547  fprintf(fp, "\t\t\t\"instances\": [{\n");
4548  for (inst = 0; inst < rfptr->thetawave.base.ngenerated; ++inst) {
4549  loc = rfptr->thetawave.locs[inst];
4550  boardinstance = rfptr->thetawave.wfi[inst].boardinstance;
4551  theta_wf = &(rfptr->thetawave.wfpulse[THETA][0]);
4552  movewaveimm(acquired_wave, theta_wf, boardinstance, rfptr->thetawave.res, FROMHARDWARE);
4553  getiamp(&new_wave_iamp, theta_wf, boardinstance);
4554  fprintf(fp, "\t\t\t\t\"waveform\": [0");
4555  for (w = 0; w < rfptr->thetawave.res; w++) {
4556  fprintf(fp, "%d,", acquired_wave[w]);
4557  }
4558  fprintf(fp, "0],\n");
4559  fprintf(fp, "\t\t\t\t\"time\": %0.3f,\n", loc.pos/1000.0);
4560  fprintf(fp, "\t\t\t\t\"board\": \"%c\",\n", boardc[loc.board]);
4561  fprintf(fp, "\t\t\t\t\"ampscale\": 1.0,\n");
4562  fprintf(fp, "\t\t\t\t\"rtscale\": %0.12f\n", (float)(new_wave_iamp) / (max_pg_wamp * max_pg_wamp));
4563  if (inst == (rfptr->thetawave.base.ngenerated -1)) {
4564  fprintf(fp, "\t\t\t}]\n");
4565  } else {
4566  fprintf(fp, "\t\t\t},{\n");
4567  }
4568  }
4569  }
4570  fprintf(fp, "\t\t},\n"); /* Theta */
4571 
4572  fprintf(fp, "\t\t\"instances\": [{\n");
4573  for (inst = 0; inst < rfptr->rfwave.base.ngenerated; ++inst) {
4574  loc = rfptr->rfwave.locs[inst];
4575  boardinstance = rfptr->rfwave.wfi[inst].boardinstance;
4576  rf_wf = &(rfptr->rfwave.wfpulse[RHO][0]);
4577  /* Get waveform from hardware */
4578  movewaveimm(acquired_wave, rf_wf, boardinstance, rfptr->rfwave.res, FROMHARDWARE);
4579  /* B1max recalculations */
4580  getiamp(&new_wave_iamp, rf_wf, boardinstance);
4581  fprintf(fp, "\t\t\t\"waveform\": [0,");
4582  for (w = 0; w < rfptr->rfwave.res; w++) {
4583  fprintf(fp, "%d,", acquired_wave[w]);
4584  }
4585  fprintf(fp, "0],\n");
4586  fprintf(fp, "\t\t\t\"board\": \"%c\",\n", boardc[loc.board]);
4587  fprintf(fp, "\t\t\t\"time\": %0.3f,\n", loc.pos/1000.0);
4588  fprintf(fp, "\t\t\t\"ampscale\": 1.0,\n");
4589  fprintf(fp, "\t\t\t\"rtscale\": %0.12f\n", (float)new_wave_iamp / (rfptr->amp * max_pg_wamp * max_pg_wamp));
4590  if (inst == (rfptr->rfwave.base.ngenerated -1)) {
4591  fprintf(fp, "\t\t}]\n");
4592  } else {
4593  fprintf(fp, "\t\t},{\n");
4594  }
4595  }
4596  if (i == (ctrl->gradrf.numrf -1)) {
4597  fprintf(fp, "\t}\n");
4598  } else {
4599  fprintf(fp, "\t},\n");
4600  }
4601  } /* res > 0 */
4602 
4603 
4604  } /* End RF */
4605  fprintf(fp, "},\n"); /* End RF */
4606  /* other (non-RF) waves */
4607  fprintf(fp, "\"waves\": {\n");
4608 
4609  for (i = 0; i < ctrl->gradrf.numwave; i++) { /* each unique wave object */
4610  KS_WAVE* waveptr = ctrl->gradrf.waveptr[i];
4611  if (waveptr->res > 0) {
4612  fprintf(fp, "\t\"%s\": {\n", waveptr->description);
4613  fprintf(fp, "\t\t\"description\": \"%s\",\n", waveptr->description);
4614  fprintf(fp, "\t\t\"duration\": %0.3f,\n", waveptr->duration / 1000.0);
4615  fprintf(fp, "\t\t\"instances\": [{\n");
4616  for (inst = 0; inst < waveptr->base.ninst; inst++) { /* each instance of the wave */
4617  loc = waveptr->locs[inst];
4618  boardinstance = waveptr->wfi[inst].boardinstance;
4619  WF_PULSE* other_wf = &(waveptr->wfpulse[loc.board][0]);
4620  movewaveimm(acquired_wave, other_wf, boardinstance, waveptr->res, FROMHARDWARE);
4621  getiamp(&new_wave_iamp, other_wf, boardinstance);
4622  fprintf(fp, "\t\t\t\"waveform\": [0,");
4623  for (w = 0; w < waveptr->res; w++) {
4624  fprintf(fp, "%d,", acquired_wave[w]); /* Or just waveptr->waveform[w] ? */
4625  }
4626  fprintf(fp, "0],\n");
4627  fprintf(fp, "\t\t\t\"board\": \"%c\",\n", boardc[loc.board]);
4628  fprintf(fp, "\t\t\t\"time\": %0.3f,\n", loc.pos/1000.0);
4629  fprintf(fp, "\t\t\t\"ampscale\": 1.0,\n");
4630  fprintf(fp, "\t\t\t\"rtscale\": %0.12f\n", ks_syslimits_gradtarget(loggrd, loc.board) * (float)new_wave_iamp / (max_pg_wamp * max_pg_wamp));
4631  if (inst == (waveptr->base.ninst -1)) {
4632  fprintf(fp, "\t\t}]\n");
4633  } else {
4634  fprintf(fp, "\t\t},{\n");
4635  }
4636  }
4637  if (i == (ctrl->gradrf.numwave -1)) {
4638  fprintf(fp, "\t}\n");
4639  } else {
4640  fprintf(fp, "\t},\n");
4641  }
4642  } /* res > 0 */
4643  }
4644  fprintf(fp, "}\n"); /* End waves */
4645  fprintf(fp, "}\n"); /* End frame */
4646  fprintf(fp,"]}"); /* End frames*/
4647 
4648  fflush(fp);
4649  fclose(fp);
4650  return;
4651 }
int plateautime
Definition: KSFoundation.h:672
short KS_IWAVE[KS_MAXWAVELEN]
Definition: KSFoundation.h:353
int boardinstance
Definition: KSFoundation.h:484
Core sequence object for making trapezoids on X,Y,Z, and OMEGA boards
Definition: KSFoundation.h:666
int start2iso
Definition: KSFoundation.h:1032
KS_BASE base
Definition: KSFoundation.h:667
Definition: KSFoundation.h:397
KS_SEQLOC * locs
Definition: KSFoundation.h:752
int pos
Definition: KSFoundation.h:463
KS_RF * rfptr[KS_MAXUNIQUE_RF]
Definition: KSFoundation.h:1055
int role
Definition: KSFoundation.h:1027
Core sequence object making arbitrary waveforms on any board (using float data format)
Definition: KSFoundation.h:743
RF_PULSE rfpulse
Definition: KSFoundation.h:1036
Definition: KSFoundation.h:2340
Definition: KSFoundation.h:2340
int numtrap
Definition: KSFoundation.h:1058
int ninst
Definition: KSFoundation.h:494
int32_t i
Definition: KSFoundation_tgt.c:1694
KS_SEQLOC * locs
Definition: KSFoundation.h:678
int board
Definition: KSFoundation.h:462
int * pos
Definition: KSFoundation.h:844
float rbw
Definition: KSFoundation.h:842
float ks_syslimits_gradtarget(LOG_GRAD loggrd, int board)
Returns the maximum target amplitude for a board (internal use)
Definition: KSFoundation_common.c:264
Definition: KSFoundation.h:2340
int numrf
Definition: KSFoundation.h:1056
float flip
Definition: KSFoundation.h:1028
KS_BASE base
Definition: KSFoundation.h:839
KS_GRADRFCTRL gradrf
Definition: KSFoundation.h:1236
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
KS_DESCRIPTION description
Definition: KSFoundation.h:840
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
Composite sequence object for RF (with optional OMEGA & THETA pulses)
Definition: KSFoundation.h:1026
KS_WAVE thetawave
Definition: KSFoundation.h:1039
KS_SEQLOC loc
Definition: KSFoundation.h:486
KS_WAVE * waveptr[KS_MAXUNIQUE_WAVE]
Definition: KSFoundation.h:1059
KS_DESCRIPTION description
Definition: KSFoundation.h:745
LOG_GRAD loggrd
WF_PULSE ** wfpulse
Definition: KSFoundation.h:753
KS_WAVE rfwave
Definition: KSFoundation.h:1037
int ks_plot_filefmt
Definition: GERequired.e:272
KS_BASE base
Definition: KSFoundation.h:744
Core sequence object that handles a data acquisition window
Definition: KSFoundation.h:838
int duration
Definition: KSFoundation.h:841
float amp
Definition: KSFoundation.h:1031
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
WF_PULSE * wf
Definition: KSFoundation.h:485
KS_TRAP * trapptr[KS_MAXUNIQUE_TRAP]
Definition: KSFoundation.h:1057
KS_DESCRIPTION description
Definition: KSFoundation.h:668
int numwave
Definition: KSFoundation.h:1060
Definition: KSFoundation.h:2340
FILTER_INFO filt
Definition: KSFoundation.h:843
char ks_psdname[256]
Definition: GERequired.e:245
KS_WAVE omegawave
Definition: KSFoundation.h:1038
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
int ngenerated
Definition: KSFoundation.h:496
int duration
Definition: KSFoundation.h:673
KS_READ * readptr[KS_MAXUNIQUE_READ]
Definition: KSFoundation.h:1061
int res
Definition: KSFoundation.h:746
Definition: KSFoundation.h:2340
int ramptime
Definition: KSFoundation.h:671
int duration
Definition: KSFoundation.h:747
int numacq
Definition: KSFoundation.h:1062

◆ ks_eval_addtraptogradrfctrl()

STATUS ks_eval_addtraptogradrfctrl ( KS_GRADRFCTRL gradrfctrl,
KS_TRAP trap 
)

*Internal use*. Adds a trapezoid (KS_TRAP) to the KS_GRADRFCTRL struct for later gradient heating calculations in ks_eval_hwlimits()

The KS_TRAP object will be ignored if added previously

Parameters
[in,out]gradrfctrlPointer to the KS_GRADRFCTRL for the sequence
[in]trapPointer to KS_TRAP
Return values
STATUSSUCCESS or FAILURE
4656  {
4657  int i;
4658  if (trap == NULL) return SUCCESS;
4659 
4660  if (gradrfctrl == NULL) {
4661  return ks_error("%s: gradrfctrl is NULL", __FUNCTION__);
4662  }
4663 
4664  if (gradrfctrl->numtrap >= KS_MAXUNIQUE_TRAP) {
4665  return ks_error("%s: ERROR - too many unique KS_TRAP in sequence", __FUNCTION__);
4666  }
4667 
4668  /* check for previous registrations of this trap's memory address. If found, return */
4669  if (gradrfctrl->numtrap > 0) {
4670  for (i = 0; i < gradrfctrl->numtrap; i++) {
4671  if (gradrfctrl->trapptr[i] == trap)
4672  return SUCCESS;
4673  }
4674  }
4675 
4676  gradrfctrl->trapptr[gradrfctrl->numtrap++] = trap;
4677 
4678  return SUCCESS;
4679 }
int numtrap
Definition: KSFoundation.h:1058
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
#define KS_MAXUNIQUE_TRAP
Definition: KSFoundation.h:256
KS_TRAP * trapptr[KS_MAXUNIQUE_TRAP]
Definition: KSFoundation.h:1057

◆ ks_eval_addwaittogradrfctrl()

STATUS ks_eval_addwaittogradrfctrl ( KS_GRADRFCTRL gradrfctrl,
KS_WAIT wait 
)

*Internal use*. Adds a wait pulse to the KS_GRADRFCTRL struct. Used for plotting

Parameters
[in,out]gradrfctrlPointer to the KS_GRADRFCTRL for the sequence
[in]waitPointer to the wait object.
Return values
STATUSSUCCESS or FAILURE
4684  {
4685  int i;
4686  if (wait == NULL) {
4687  return SUCCESS;
4688  }
4689 
4690  if (gradrfctrl == NULL) {
4691  return ks_error("%s: gradrfctrl is NULL", __FUNCTION__);
4692  }
4693 
4694  if (gradrfctrl->numwait >= KS_MAXUNIQUE_WAIT) {
4695  return ks_error("%s: ERROR - too many unique KS_WAIT in sequence (max %d)", __FUNCTION__, KS_MAXUNIQUE_WAIT);
4696  }
4697 
4698  /* check for previous registrations of this wait's memory address. If found, return */
4699  if (gradrfctrl->numwait > 0) {
4700  for (i = 0; i < gradrfctrl->numwait; i++) {
4701  if (gradrfctrl->waitptr[i] == wait)
4702  return SUCCESS;
4703  }
4704  }
4705 
4706  gradrfctrl->waitptr[gradrfctrl->numwait++] = wait;
4707 
4708  return SUCCESS;
4709 
4710 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int numwait
Definition: KSFoundation.h:1064
KS_WAIT * waitptr[KS_MAXUNIQUE_WAIT]
Definition: KSFoundation.h:1063
#define KS_MAXUNIQUE_WAIT
Definition: KSFoundation.h:258

◆ ks_open_file_in_embed()

FILE* ks_open_file_in_embed ( const char *  fname,
const char *  write_mode 
)

ADDTITLEHERE

4715  {
4716  char embedfile_uid[512];
4717  #ifdef PSD_HW /* on MR-scanner */
4718  char outputdir_uid[512];
4719  char cmd[512];
4720  sprintf(outputdir_uid, "/usr/g/mrraw/kstmp/%010d/embed/", rhkacq_uid);
4721  sprintf(embedfile_uid, "%s/%s", outputdir_uid, fname);
4722  sprintf(cmd, "mkdir -p %s > /dev/null", outputdir_uid);
4723  system(cmd);
4724  #else
4725  sprintf(embedfile_uid, "./%s", fname);
4726  #endif
4727 
4728  return fopen(embedfile_uid, write_mode);
4729  /* to do add error handling */
4730 }
int rhkacq_uid

◆ ks_eval_addwavetogradrfctrl()

STATUS ks_eval_addwavetogradrfctrl ( KS_GRADRFCTRL gradrfctrl,
KS_WAVE wave 
)

*Internal use*. Adds a wave (KS_WAVE) - if it is not a part of a KS_RF object - to the KS_GRADRFCTRL struct for later gradient heating calculations in ks_eval_hwlimits()

The KS_WAVE object will be ignored if added previously

Parameters
[in,out]gradrfctrlPointer to the KS_GRADRFCTRL for the sequence
[in]wavePointer to KS_WAVE
Return values
STATUSSUCCESS or FAILURE
4735  {
4736  int i;
4737  if (wave == NULL) return SUCCESS;
4738 
4739  if (gradrfctrl == NULL) {
4740  return ks_error("%s: gradrfctrl is NULL", __FUNCTION__);
4741  }
4742 
4743  if (gradrfctrl->numwave >= KS_MAXUNIQUE_WAVE) {
4744  return ks_error("%s: ERROR - too many unique KS_WAVE in sequence", __FUNCTION__);
4745  }
4746 
4747  /* check for previous registrations of this trap's memory address. If found, return */
4748  if (gradrfctrl->numwave > 0) {
4749  for (i = 0; i < gradrfctrl->numwave; i++) {
4750  if (gradrfctrl->waveptr[i] == wave)
4751  return SUCCESS;
4752  }
4753  }
4754 
4755  /* check also for previous waves in KS_RF (rfwave, omegawave, thetawave). If found, return */
4756  if (gradrfctrl->numrf > 0) {
4757  for (i = 0; i < gradrfctrl->numrf; i++) {
4758  if (&(gradrfctrl->rfptr[i]->rfwave) == wave || &(gradrfctrl->rfptr[i]->omegawave) == wave || &(gradrfctrl->rfptr[i]->thetawave) == wave)
4759  return SUCCESS;
4760  }
4761  }
4762 
4763  gradrfctrl->waveptr[gradrfctrl->numwave++] = wave;
4764 
4765  return SUCCESS;
4766 }
KS_RF * rfptr[KS_MAXUNIQUE_RF]
Definition: KSFoundation.h:1055
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int numrf
Definition: KSFoundation.h:1056
KS_WAVE thetawave
Definition: KSFoundation.h:1039
KS_WAVE * waveptr[KS_MAXUNIQUE_WAVE]
Definition: KSFoundation.h:1059
KS_WAVE rfwave
Definition: KSFoundation.h:1037
#define KS_MAXUNIQUE_WAVE
Definition: KSFoundation.h:257
int numwave
Definition: KSFoundation.h:1060
KS_WAVE omegawave
Definition: KSFoundation.h:1038

◆ ks_eval_addrftogradrfctrl()

STATUS ks_eval_addrftogradrfctrl ( KS_GRADRFCTRL gradrfctrl,
KS_RF rf 
)

*Internal use*. Adds an RF pulse to the KS_GRADRFCTRL struct for later SAR & RF power calculations in ks_eval_hwlimits()

The RF object will be ignored if added previously

Parameters
[in,out]gradrfctrlPointer to the KS_GRADRFCTRL for the sequence
[in]rfPointer to KS_RF
Return values
STATUSSUCCESS or FAILURE
4771  {
4772  int i;
4773  if (rf == NULL) return SUCCESS;
4774 
4775  if (gradrfctrl == NULL) {
4776  return ks_error("%s: gradrfctrl is NULL", __FUNCTION__);
4777  }
4778 
4779  if (gradrfctrl->numrf >= KS_MAXUNIQUE_RF) {
4780  return ks_error("%s: ERROR - too many unique KS_RF in sequence", __FUNCTION__);
4781  }
4782 
4783  /* check for previous registrations of this rf's memory address. If found, return */
4784  if (gradrfctrl->numrf > 0) {
4785  for (i = 0; i < gradrfctrl->numrf; i++) {
4786  if (gradrfctrl->rfptr[i] == rf)
4787  return SUCCESS;
4788  }
4789  }
4790 
4791  gradrfctrl->rfptr[gradrfctrl->numrf++] = rf;
4792 
4793  return SUCCESS;
4794 }
#define KS_MAXUNIQUE_RF
Definition: KSFoundation.h:255
KS_RF * rfptr[KS_MAXUNIQUE_RF]
Definition: KSFoundation.h:1055
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
int numrf
Definition: KSFoundation.h:1056

◆ ks_eval_addreadtogradrfctrl()

STATUS ks_eval_addreadtogradrfctrl ( KS_GRADRFCTRL gradrfctrl,
KS_READ read 
)

*Internal use*. Adds an acquisition to the KS_GRADRFCTRL struct. Used for plotting

Parameters
[in,out]gradrfctrlPointer to the KS_GRADRFCTRL for the sequence
[in]readPointer to acquisition object.
Return values
STATUSSUCCESS or FAILURE
4799  {
4800  int i;
4801  if (read == NULL) return SUCCESS;
4802 
4803  if (gradrfctrl == NULL) {
4804  return ks_error("%s: gradrfctrl is NULL", __FUNCTION__);
4805  }
4806 
4807  if (gradrfctrl->numacq >= KS_MAXUNIQUE_READ) {
4808  return ks_error("%s: ERROR - too many readouts in sequence", __FUNCTION__);
4809  }
4810 
4811  /* check for previous registrations of the pointer. If found, return */
4812  if (gradrfctrl->numacq > 0) {
4813  for (i = 0; i < gradrfctrl->numacq; i++) {
4814  if (gradrfctrl->readptr[i] == read)
4815  return SUCCESS;
4816  }
4817  }
4818 
4819  gradrfctrl->readptr[gradrfctrl->numacq++] = read;
4820 
4821  return SUCCESS;
4822 }
int32_t i
Definition: KSFoundation_tgt.c:1694
STATUS ks_error(const char *format,...)
Definition: KSFoundation_common.c:78
#define KS_MAXUNIQUE_READ
Definition: KSFoundation.h:264
KS_READ * readptr[KS_MAXUNIQUE_READ]
Definition: KSFoundation.h:1061
int numacq
Definition: KSFoundation.h:1062

◆ ks_scan_rf_phase_spoiling()

float ks_scan_rf_phase_spoiling ( int  counter)

Returns spoiling phase for a given RF counter

Parameters
[in]counter[RF number]
Returns
phase [Phase in degrees]
4827  {
4828  unsigned int phase = 117 * ( counter * (counter + 1) + 2) / 2;
4829 
4830  /* fmod() does not seem to work on TGT on hardware (MR scanner) */
4831 
4832  return ((float) (phase%360));
4833 }

◆ ks_numplaced()

int ks_numplaced ( KS_BASE base)

ADDTITLEHERE

4838  {
4839 #ifdef IPG
4840  return base->ngenerated;
4841 #else
4842  return base->ninst;
4843 #endif
4844 }
int ninst
Definition: KSFoundation.h:494
int ngenerated
Definition: KSFoundation.h:496

◆ ks_scan_gettherightshot()

int ks_scan_gettherightshot ( const KS_DYNAMIC_STATE *  dynamic)

shot vs inner shot logic for ksepi.cc

Parameters
dynamic
Returns
int
4849  {
4850  int shot = 0;
4851 
4852  if (dynamic) {
4853  shot = (dynamic->shot == 0) ? dynamic->inner_shot : dynamic->shot;
4854  }
4855 
4856  return shot;
4857 
4858 }

◆ ks_get_trapamp_instance()

float ks_get_trapamp_instance ( const KS_TRAP trap,
int  instance 
)

Get the amplitude in G/cm for an instance of a KS_TRAP (excluding realtime changes)

Parameters
[in]trapPointer to KS_TRAP
[in]instance0-based instance (up to .base.ninst-1)
Returns
float Gradient amplitude in G/cm
4862  {
4863  float trapamp = -999.0;
4864 
4865 #ifdef IPG
4866  /* getiamp(&readiamp, trap->wfi[i].wf, trap->wfi[i].boardinstance); */
4867  trapamp = trap->wfi[instance].loc.ampscale * trap->amp;
4868 #else
4869  trapamp = trap->locs[instance].ampscale * trap->amp;
4870 #endif
4871 
4872  return trapamp;
4873 }
KS_SEQLOC * locs
Definition: KSFoundation.h:678
float ampscale
Definition: KSFoundation.h:464
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
KS_SEQLOC loc
Definition: KSFoundation.h:486
float amp
Definition: KSFoundation.h:669

◆ ks_get_read_in_echotrain()

const KS_READ* ks_get_read_in_echotrain ( const KS_ECHOTRAIN echotrain,
const int  readout_index 
)

ADDTITLEHERE

Parameters
[in]echotrainADDTEXTHERE
[in]readout_indexADDTEXTHERE
Returns
void
4877  {
4878  int object_index = echotrain->controls[readout_index].pg.object_index;
4879  KS_READ_TYPE type = echotrain->controls[readout_index].pg.read_type;
4880  if (type == KS_READ_TRAP) {
4881  return &echotrain->readtraps[object_index].acq;
4882  } else {
4883  return &echotrain->readwaves[object_index].acq;
4884  }
4885 }
KS_READTRAP readtraps[KS_ECHOTRAIN_MAX_TRAPS]
Definition: KSFoundation.h:2016
KS_READWAVE readwaves[KS_ECHOTRAIN_MAX_WAVES]
Definition: KSFoundation.h:2017
int object_index
Definition: KSFoundation.h:1985
KS_READ_TYPE
The read object type, used in KS_READCONTROL_PULSEGEN
Definition: KSFoundation.h:1957
KS_READCONTROL_PULSEGEN pg
Definition: KSFoundation.h:2001
KS_READ_TYPE read_type
Definition: KSFoundation.h:1984
Definition: KSFoundation.h:1959
KS_READ acq
Definition: KSFoundation.h:1549
KS_READ acq
Definition: KSFoundation.h:1606
KS_READCONTROL controls[KS_MAXUNIQUE_READ]
Definition: KSFoundation.h:2015

◆ ks_rt_scale_log_set()

void ks_rt_scale_log_set ( KS_RT_SCALE_LOG log,
int  instance_idx,
float  ampscale 
)
4890  {
4891 
4892  if (!log) {
4893  KS_THROW("null input");
4894  return;
4895  }
4896 
4897  if (log->num_completed_playouts > 0 && log->num_instances < 1) {
4898  KS_THROW("inconsistent state");
4899  return;
4900  }
4901 
4902  if (instance_idx < 0 || instance_idx >=log->num_instances) {
4903  KS_THROW("instance number (%d) out of range [0,%d]", instance_idx, log->num_instances);
4904  return;
4905  }
4906 
4907  const int prev_buffer_size = log->buffer_size;
4908  log->buffer_size = (log->num_completed_playouts + 1)*log->num_instances;
4909 
4910  float *p = (float*)realloc(log->ampscales, log->buffer_size*sizeof(float));
4911  if (!p) {
4912  KS_THROW("Reallocation failed");
4913  return;
4914  }
4915 
4916  log->ampscales = p;
4917  int i = prev_buffer_size;
4918  for (; i < log->buffer_size; i++) {
4919  /* Initialize to the last used ampscale for the same instance, if available */
4920  const int last_idx = i - log->num_instances;
4921  log->ampscales[i] = last_idx < 0 ? 1.0f : log->ampscales[last_idx];
4922  }
4923  log->ampscales[log->num_completed_playouts*log->num_instances + instance_idx] = ampscale;
4924 }
int num_completed_playouts
Definition: KSFoundation.h:477
int32_t i
Definition: KSFoundation_tgt.c:1694
int buffer_size
Definition: KSFoundation.h:474
int num_instances
Definition: KSFoundation.h:476
float * ampscales
Definition: KSFoundation.h:472
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_rt_scale_log_set_state()

void ks_rt_scale_log_set_state ( KS_RT_SCALE_LOG log,
int  instance_idx,
int  state 
)
4929  {
4930 
4931  if (!log) {
4932  KS_THROW("null input");
4933  return;
4934  }
4935 
4936  if (log->num_completed_playouts > 0 && log->num_instances < 1) {
4937  KS_THROW("inconsistent state");
4938  return;
4939  }
4940 
4941  if (instance_idx < 0 || instance_idx >=log->num_instances) {
4942  KS_THROW("instance number (%d) out of range [0,%d]", instance_idx, log->num_instances);
4943  return;
4944  }
4945 
4946  const int prev_buffer_size = log->buffer_size_states;
4947  log->buffer_size_states = (log->num_completed_playouts + 1) * log->num_instances;
4948 
4949  int* p = (int*)realloc(log->states, log->buffer_size_states * sizeof(int));
4950  if (!p) {
4951  KS_THROW("Reallocation failed");
4952  return;
4953  }
4954 
4955  log->states = p;
4956  int i = prev_buffer_size;
4957  for (; i < log->buffer_size_states; i++) {
4958  /* Initialize to the last used state for the same instance, if available */
4959  const int last_idx = i - log->num_instances;
4960  log->states[i] = last_idx < 0 ? 0 : log->states[last_idx];
4961  }
4962 
4963  log->states[log->num_completed_playouts * log->num_instances + instance_idx] = state;
4964 }
int num_completed_playouts
Definition: KSFoundation.h:477
int32_t i
Definition: KSFoundation_tgt.c:1694
int num_instances
Definition: KSFoundation.h:476
int * states
Definition: KSFoundation.h:473
int buffer_size_states
Definition: KSFoundation.h:475
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_rt_scale_log_next()

void ks_rt_scale_log_next ( KS_RT_SCALE_LOG log)
4969  {
4970  if (!log) {
4971  KS_THROW("null input");
4972  return;
4973  }
4974 
4975  log->num_completed_playouts = IMax(2, log->num_completed_playouts + 1, 1);
4976 }
int num_completed_playouts
Definition: KSFoundation.h:477
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_rt_scale_log_get()

float ks_rt_scale_log_get ( const KS_RT_SCALE_LOG log,
int  instance_idx,
int  playout_idx 
)
4981  {
4982 
4983  if (instance_idx < 0 || instance_idx >=log->num_instances || !log->ampscales) {
4984  return 1.0f;
4985  }
4986  if (playout_idx >=log->num_completed_playouts) {
4987  KS_THROW("playout number (%d) must be less than %d", playout_idx, log->num_completed_playouts);
4988  return 1.0f;
4989  }
4990 
4991  /* negative -> last */
4992  if (playout_idx < 0) {
4993  playout_idx = log->num_completed_playouts - 1;
4994  }
4995 
4996  const float ampscale = log->ampscales[playout_idx*log->num_instances + instance_idx];
4997  const float absscale = fabs(ampscale);
4998 
4999  if (absscale <= 0 || (absscale <= sqrt(3) && absscale > 1.0f/(1 << 15))) {
5000  return ampscale;
5001  }
5002 
5003  /* If it is too big, too small (but non zero) or NaN we should end up here.
5004  This check is necessary because entries might be left uninitialized if
5005  no scaling is applied during the relevant playout. */
5006  KS_THROW("abnormal amplitude scale (%f), maybe it was not set", ampscale);
5007  return 1.0f;
5008 }
int num_completed_playouts
Definition: KSFoundation.h:477
int num_instances
Definition: KSFoundation.h:476
float * ampscales
Definition: KSFoundation.h:472
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_rt_scale_log_get_state()

int ks_rt_scale_log_get_state ( const KS_RT_SCALE_LOG log,
int  instance_idx,
int  playout_idx 
)
5013  {
5014 
5015  if (instance_idx < 0 || instance_idx >=log->num_instances) {
5016  return 0;
5017  }
5018  if (playout_idx >=log->num_completed_playouts) {
5019  KS_THROW("playout number (%d) must be less than %d", playout_idx, log->num_completed_playouts);
5020  return 0;
5021  }
5022 
5023  /* negative -> last */
5024  if (playout_idx < 0) {
5025  playout_idx = log->num_completed_playouts - 1;
5026  }
5027 
5028  return log->states[playout_idx*log->num_instances + instance_idx];
5029 }
int num_completed_playouts
Definition: KSFoundation.h:477
int num_instances
Definition: KSFoundation.h:476
int * states
Definition: KSFoundation.h:473
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

Variable Documentation

◆ maxGradRes

int maxGradRes

◆ psd_rf_wait

int psd_rf_wait

◆ psd_grd_wait

int psd_grd_wait

◆ cfssctype

int cfssctype

◆ opfov

float opfov

◆ opxres

int opxres

◆ opyres

int opyres

◆ opslthick

float opslthick

◆ rhkacq_uid

int rhkacq_uid

◆ ks_plot_filefmt

int ks_plot_filefmt

◆ ks_psdname

char ks_psdname[256]

◆ abort_on_kserror

int abort_on_kserror = ABORT_ON_KSERROR

◆ ks_rhoboard

int ks_rhoboard = TYPRHO1

◆ _phaseencoding_coord_pool

struct _phaseencoding_coord_pool_s _phaseencoding_coord_pool = _INIT_PHASEENCODING_COORD_POOL