KSFoundation  [October2024]
A platform for structured EPIC programming on GE MR systems
KSFoundation_tgt.c File Reference
#include <RtpPsd.h>
#include <PromoCommon.h>
#include "stddef_ep.h"
#include "pulsegen.h"
#include "epic.global.h"
#include "epicfuns.h"
#include "epicmsg.h"
#include "epicconf.h"
#include "ca_filt.h"
#include "psdutil.h"

Data Structures

union  Indices
 

Functions

STATUS scale (FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)
 
unsigned short ks_scan_omegawave_hz (KS_WAVE *wave, int instanceno, float Hz, int omega_iwave_phase_at_null)
 
unsigned short ks_scan_omegatrap_hz (KS_TRAP *trp, int instanceno, float Hz, int omega_iwave_phase_at_null)
 
void ks_scan_wait (KS_WAIT *wait, int waitperiod)
 
void ks_scan_wave_ampscale (KS_WAVE *wave, int instanceno, float ampscale)
 
void ks_scan_trap_ampscale (KS_TRAP *trp, int instanceno, float ampscale)
 
void ks_scan_trap_ampscale_slice (KS_TRAP *trp, int start, int skip, int count, float ampscale)
 
void ks_scan_phaser_kmove (KS_PHASER *phaser, int instanceno, double pixelunits)
 
double ks_scan_phaser_compute_kmove (KS_PHASER *phaser, int view)
 
void ks_scan_phaser_toline (KS_PHASER *phaser, int instanceno, int view)
 
void ks_scan_phaser_fromline (KS_PHASER *phaser, int instanceno, int view)
 
void ks_scan_phaser_average (KS_PHASER *phaser, int instanceno)
 
void ks_scan_phaser_max (KS_PHASER *phaser, int instanceno)
 
void ks_scan_rf_ampscale (KS_RF *rf, int instanceno, float ampscale)
 
void ks_scan_rf_on (KS_RF *rf, int instanceno)
 
void ks_scan_rf_on_chop (KS_RF *rf, int instanceno)
 
void ks_scan_rf_off (KS_RF *rf, int instanceno)
 
void ks_scan_selrf_setfreqphase_pins (KS_SELRF *selrf, int instanceno, SCAN_INFO sliceinfo, int sms_multiband_factor, float sms_slice_gap, float rfphase)
 
void ks_scan_selrf_setfreqphase (KS_SELRF *selrf, int instanceno, SCAN_INFO sliceinfo, float rfphase)
 
void ks_scan_rf_setphase (KS_RF *rf, int instanceno, float rfphase)
 
void ks_scan_setwavestate (KS_WAVE *wave, int state, int instance)
 
void ks_scan_wave2hardware (KS_WAVE *wave, const KS_WAVEFORM newwaveform, int state)
 
void ks_scan_offsetfov_iso (KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, double ky, double kz, double rcvphase)
 
void ks_scan_offsetfov_iso_readwave (KS_READWAVE *readwave, int instanceno, SCAN_INFO sliceinfo, double ky, double kz, double rcvphase)
 
void ks_scan_offsetfov (KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, float ky, float phasefovratio, float rcvphase)
 
void ks_scan_offsetfov3D (KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, float ky, float phasefovratio, float kz, float zphasefovratio, float rcvphase)
 
void ks_scan_offsetfov_readwave (KS_READWAVE *readwave, int instanceno, SCAN_INFO sliceinfo, float ky, float phasefovratio, float rcvphase)
 
void ks_scan_offsetfov3D_readwave (KS_READWAVE *readwave, int instanceno, SCAN_INFO sliceinfo, float ky, float phasefovratio, float kz, float zphasefovratio, float rcvphase)
 
float * ks_scan_getrotate (void)
 
void ks_scan_rotate (SCAN_INFO slice_pos)
 
void ks_scan_isirotate (KS_ISIROT *isirot)
 
int ks_scan_getsliceloc (const KS_SLICE_PLAN *slice_plan, int passindx, int sltimeinpass)
 
int ks_scan_getslicetime (const KS_SLICE_PLAN *slice_plan, int passindx, int slloc)
 
ks_enum_epiblipsign ks_scan_epi_verify_phaseenc_plan (KS_EPI *epi, KS_PHASEENCODING_PLAN *phaseenc_plan, int shot)
 
ks_enum_epiblipsign _compute_epi_blipsign (KS_EPI *epi, KS_PHASEENCODING_COORD starting_coord)
 
void ks_scan_epi_shotcontrol_sms (KS_EPI *epi, int echo, SCAN_INFO sliceinfo, KS_PHASEENCODING_COORD starting_coord, ks_enum_epiblipsign blipsign, float rcvphase, int sms_factor, float sms_slice_gap, int caipi_factor, int sms_slice_encoding_direction)
 
void ks_scan_epi_shotcontrol (KS_EPI *epi, int echo, SCAN_INFO sliceinfo, KS_PHASEENCODING_COORD starting_coord, ks_enum_epiblipsign blipsign, float rcvphase)
 
void ks_scan_epi_loadecho (KS_EPI *epi, int echo, int storeecho, int slice, KS_PHASEENCODING_COORD starting_coord, ks_enum_epiblipsign blipsign, KS_DYNAMIC_STATE *dynamic)
 
void ks_set_opcode (WF_PULSE_ADDR echo, short opcode)
 
void ks_loaddab_reserved (WF_PULSE_ADDR echo, short state, short resampler_index)
 
void ks_loaddab (WF_PULSE_ADDR echo, const char *custom_dab_array)
 
void ks_loaddab_full (WF_PULSE_ADDR echo, const char *custom_dab_array)
 
WF_PULSE_ADDR ks_get_wf_pulse (KS_ECHOTRAIN *echotrain, const int readout_index)
 
LONG ks_get_override_R1 (KS_ECHOTRAIN *echotrain, const int readout_index)
 
void ks_scan_acq_to_rtp (KS_READ *acq, TYPDAB_PACKETS dabacqctrl, float fatoffset)
 
STATUS boffset (long *offsets)
 
void ks_scan_switch_to_sequence (KS_SEQ_CONTROL *ctrl)
 
STATUS setssitime (long)
 
STATUS startseq (s16, s16)
 
int ks_scan_playsequence (KS_SEQ_CONTROL *ctrl)
 
STATUS ks_scan_loaddabwithindices_nex (WF_PULSE_ADDR pulse, LONG slice, LONG echo, LONG view, uint8_t acq, uint8_t vol, LONG operation, TYPDAB_PACKETS acqon_flag)
 
STATUS ks_scan_loaddabwithindices (WF_PULSE_ADDR pulse, LONG slice, LONG echo, LONG view, uint8_t acq, uint8_t vol, TYPDAB_PACKETS acqon_flag)
 
int ks_scan_wait_for_rtp (void *rtpmsg, int maxmsgsize, int maxwait, KS_SEQ_CONTROL *waitctrl)
 
void ks_copy_and_reset_obj (void *pobj)
 
void ks_tgt_reset_gradrfctrl (KS_GRADRFCTRL *gradrfctrl)
 
void ks_show_clock (FLOAT scantime)
 
STATUS acqq_longdab (WF_PULSE_ADDR pulse, LONG pos_ref, LONG dab_ref, LONG xtr_ref, LONG fslot_value)
 

Variables

int cfreceiveroffsetfreq
 
int rspent
 
int pscR1
 
int cfcoilswitchmethod
 
long rsprot [TRIG_ROT_MAX][9]
 
int cfhwgut
 
int opslicecnt
 
int piviews
 
float pitslice
 

Detailed Description

This file contains functions only accessible on TGT

Function Documentation

◆ scale()

STATUS scale ( FLOAT(*)  inrotmat[9],
long(*)  outrotmat[9],
INT  slquant,
LOG_GRAD *  lgrad,
PHYS_GRAD *  pgrad,
INT  contdebug 
)

◆ ks_scan_omegawave_hz()

unsigned short ks_scan_omegawave_hz ( KS_WAVE wave,
int  instanceno,
float  Hz,
int  omega_iwave_phase_at_null 
)

Updates a KS_WAVE object on the OMEGA board to produce a frequency offset

A KS_WAVE object on OMEGA can be used to perform a dynamic frequency offset

  1. while an RF pulse is played out. One example is Spectral-Spatial RF pulses
  2. during data acquisition
Parameters
[in,out]wavePointer to KS_WAVE
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]HzDesired frequency offset in [Hz] for the point in the KS_WAVE with the largest absolute amplitude
[in]omega_iwave_phase_at_nullthe area of the integer waveform at the null point
Return values
iphasecorrection to be applied with XTR packet
56  {
57  int iamp;
58  float omega_scale = 256.0;
59  unsigned short iphase_omega = 0;
60 
61  iamp = (int) (Hz / (TARDIS_FREQ_RES * omega_scale * wave->fs_factor));
62 
63  if (abs(iamp) > 32768) {
64  ks_error("ks_scan_omegawave_hz(%s): the integer amplitude is too large (%d) for instance %d", wave->description, iamp, instanceno);
65  return 0;
66  }
67 
68 #ifdef IPG
69 
70  if (wave->wfi[instanceno].loc.board != OMEGA) {
71  ks_error("ks_scan_omegawave_hz(%s): Only omega board is supported", wave->description);
72  return 0;
73  }
74 
75  /* input validation */
76  if (instanceno < 0 || instanceno >= wave->base.ngenerated) {
77  ks_error("ks_scan_omegawave_hz(%s): instanceno (%d) out of range [0,%d)", wave->description, instanceno, wave->base.ngenerated);
78  return 0;
79  }
80 
81  if (setiamp((short) iamp, wave->wfi[instanceno].wf, wave->wfi[instanceno].boardinstance) != SUCCESS) {
82  ks_error("ks_scan_omegawave_hz(%s): An error occurred calling 'setiamp()'", wave->description);
83  return 0;
84  }
85 
86  int phase_accum = 0;
87  phase_accum = (omega_iwave_phase_at_null * iamp) >> 7;
88  /* Convert integer phase with 24-bit period to integer phase with 16-bit period compatible with setiphase function */
89  iphase_omega = phase_accum >> 8;
90 
91 #else
92  int numplaced = wave->base.ninst;
93  if (!numplaced) {
94  return 0;
95  }
96 
97  wave->rtscaling.num_instances = numplaced;
98  ks_rt_scale_log_set(&wave->rtscaling, instanceno, Hz < 0 ? -1 : 1);
99 
100 #endif
101 
102  return iphase_omega;
103 
104 } /* ks_scan_omegawave_hz */
float fs_factor
Definition: KSFoundation.h:756
int boardinstance
Definition: KSFoundation.h:484
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
int board
Definition: KSFoundation.h:462
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:755
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
KS_SEQLOC loc
Definition: KSFoundation.h:486
int num_instances
Definition: KSFoundation.h:476
KS_DESCRIPTION description
Definition: KSFoundation.h:745
KS_BASE base
Definition: KSFoundation.h:744
WF_PULSE * wf
Definition: KSFoundation.h:485
int ngenerated
Definition: KSFoundation.h:496
void ks_rt_scale_log_set(KS_RT_SCALE_LOG *log, int instance_idx, float ampscale)
Definition: KSFoundation_common.c:4890

◆ ks_scan_omegatrap_hz()

unsigned short ks_scan_omegatrap_hz ( KS_TRAP trap,
int  instanceno,
float  Hz,
int  omega_iwave_phase_at_null 
)

Updates a KS_TRAP object on the OMEGA board to produce a frequency offset

A KS_TRAP object on OMEGA is used for rampsampled acquisitions and is placed out using ks_pg_readtrap() for a KS_READTRAP object if the field .rampsampling = 1. This will cause a trapezoidal frequency shift during the readout instead of a fixed frequency offset when rampsampling is not used. An error is returned if the current instance of the KS_TRAP is on another board than OMEGA

For Cartesian applications, there is no need to call this function directly, since ks_scan_offsetfov() already calls this function

Special note for OMEGA: Neither the .amp field nor the .ampscale field passed in to ks_pg_trap() has an effect. Only the Hz argument controls the frequency shift

Parameters
[in,out]trapPointer to KS_TRAP
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]HzDesired frequency offset in [Hz] at the plateau of the trapezoid
[in]omega_iwave_phase_at_nullthe area of the integer waveform at the null point
Return values
iphasecorrection to be applied with XTR packet
108  {
109  int iamp;
110  float omega_scale = 256.0;
111  short iphase_omega = 0;
112 
113  iamp = (int) (Hz / (TARDIS_FREQ_RES * omega_scale * trp->fs_factor));
114  if (abs(iamp) > 32768) {
115  ks_error("ks_scan_omegatrap_hz(%s): the integer amplitude is too large (%d) for instance %d", trp->description, iamp, instanceno);
116  return 0;
117  }
118 
119 #ifdef IPG
120 
121  if (trp->wfi[instanceno].loc.board != OMEGA) {
122  ks_error("ks_scan_omegatrap_hz(%s): Wrong function - use ks_scan_trap_ampscale() KS_TRAPs on XGRAD, YGRAD, ZGRAD", trp->description);
123  return 0;
124  }
125 
126  /* input validation */
127  if (instanceno < 0 || instanceno >= trp->base.ngenerated) {
128  ks_error("ks_scan_omegatrap_hz(%s): instanceno (%d) out of range [0,%d)", trp->description, instanceno, trp->base.ngenerated);
129  return 0;
130  }
131 
132  if (setiampt((short) iamp, trp->wfi[instanceno].wf, trp->wfi[instanceno].boardinstance) != SUCCESS) {
133  ks_error("ks_scan_omegatrap_hz(%s): An error occurred calling 'setiampt()'", trp->description);
134  return 0;
135  }
136 
137 
138  int phase_accum = 0;
139  phase_accum = (omega_iwave_phase_at_null * iamp) >> 7;
140  /* Convert integer phase with 24-bit period to integer phase
141  with 16-bit period compatible with setiphase function */
142  iphase_omega = phase_accum >> 8;
143 
144 #else
145  int numplaced = trp->base.ninst;
146  if (!numplaced) {
147  return 0;
148  }
149 
150  trp->rtscaling.num_instances = numplaced;
151  ks_rt_scale_log_set(&trp->rtscaling, instanceno, Hz < 0 ? -1 : 1);
152 
153 #endif
154 
155  return iphase_omega;
156 
157 } /* ks_scan_omegatrap_hz */
int boardinstance
Definition: KSFoundation.h:484
KS_BASE base
Definition: KSFoundation.h:667
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
int board
Definition: KSFoundation.h:462
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:681
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
KS_SEQLOC loc
Definition: KSFoundation.h:486
float fs_factor
Definition: KSFoundation.h:677
int num_instances
Definition: KSFoundation.h:476
WF_PULSE * wf
Definition: KSFoundation.h:485
KS_DESCRIPTION description
Definition: KSFoundation.h:668
int ngenerated
Definition: KSFoundation.h:496
void ks_rt_scale_log_set(KS_RT_SCALE_LOG *log, int instance_idx, float ampscale)
Definition: KSFoundation_common.c:4890

◆ ks_scan_wait()

void ks_scan_wait ( KS_WAIT wait,
int  waitperiod 
)

Updates the wait period of all instances of a KS_WAIT sequence object. The value of waitperiod must not exceed

.duration.

Parameters
[in,out]waitPointer to KS_WAIT
[in]waitperiodTime in [us] to wait
Return values
STATUSSUCCESS or FAILURE
161  {
162  int numplaced = ks_numplaced(&wait->base);
163  if (numplaced == 0) {
164  return;
165  }
166 
167  int i;
168 
169  /* input validation */
170  if (waitperiod < 0) {
171  ks_error("ks_scan_wait(%s): wait period %d is negative", wait->description, waitperiod);
172  return;
173  }
174  if (waitperiod < GRAD_UPDATE_TIME) {
175  waitperiod = GRAD_UPDATE_TIME;
176  }
177  if (waitperiod % GRAD_UPDATE_TIME) {
178  ks_error("ks_scan_wait(%s): waitperiod (3rd arg) on gradient boards must be divisible by 4", wait->description);
179  return;
180  }
181 
182 #ifdef IPG
183 
184  if (wait->wfi == NULL) {
185  ks_error("ks_scan_wait(%s): WF_INSTANCE of trap is NULL", wait->description);
186  }
187 
188  /* set amplitude(s) */
189  for (i = 0; i < numplaced; i++) {
190 
191  if (setperiod(waitperiod, wait->wfi[i].wf, wait->wfi[i].boardinstance) != SUCCESS) {
192  ks_error("ks_scan_wait(%s): An error occurred calling 'setperiod()'", wait->description);
193  return;
194  }
195  }
196 # else
197  wait->rtscaling.num_instances = numplaced;
198  for (i = 0; i < numplaced; i++) {
199  /* We use state to indicate the duration in µs instead of ampscaling since the former is an int */
200  ks_rt_scale_log_set_state(&wait->rtscaling, i, waitperiod);
201  }
202 
203 #endif
204 
205 } /* ks_scan_wait */
int boardinstance
Definition: KSFoundation.h:484
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
KS_DESCRIPTION description
Definition: KSFoundation.h:544
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:550
int num_instances
Definition: KSFoundation.h:476
KS_BASE base
Definition: KSFoundation.h:543
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:549
WF_PULSE * wf
Definition: KSFoundation.h:485
void ks_rt_scale_log_set_state(KS_RT_SCALE_LOG *log, int instance_idx, int state)
Definition: KSFoundation_common.c:4929

◆ ks_scan_wave_ampscale()

void ks_scan_wave_ampscale ( KS_WAVE wave,
int  instanceno,
float  ampscale 
)

Updates the amplitude of one or all instances of a KS_WAVE sequence object

This function multiplies one instance of a KS_WAVE object with an amplitude scale factor (3rd arg) that should be in range [-1.0,1.0] to avoid slewrate issues. To change all instances of a KS_TRAP object, use INSTRALL as the 2nd argument.

The actual amplitude for an instance of a KS_WAVE object is the multiplication of the three factors:

  1. The designed amplitude [G/cm] in the KS_WAVEFORM array
  2. The per-instance .ampscale in the KS_SEQLOC struct passed to ks_pg_trap()
  3. The ampscale value passed in as 3rd argument to this function.
Parameters
[in,out]wavePointer to KS_WAVE
[in]instancenoInstance of KS_TRAP to change (INSTRALL changes all instances)
[in]ampscaleGradient amplitude scale factor, normally in range [-1.0,1.0], but the range [-1.2, 1.2] is allowed to allow certain run-time gradient corrections
Return values
STATUSSUCCESS or FAILURE
209  {
210  int firstinstance, lastinstance, i;
211 #ifdef IPG
212  int iamp;
213  float gradmax;
214  int numplaced = wave->base.ngenerated;
215 #else
216  int numplaced = wave->base.ninst;
217  if (!numplaced) {
218  return;
219  }
220 
221  wave->rtscaling.num_instances = numplaced;
222 
223 #endif
224 
225  if (instanceno == INSTRALL) {
226  firstinstance = 0;
227  lastinstance = numplaced - 1;
228  } else {
229  firstinstance = instanceno;
230  lastinstance = instanceno;
231  }
232 
233  /* input validation */
234  if (numplaced == 0) {
235  return;
236  }
237  if (firstinstance < 0 || lastinstance >= numplaced) {
238  ks_error("ks_scan_wave_ampscale(%s): instanceno (%d) out of range [0,%d]", wave->description, instanceno, numplaced - 1);
239  return;
240  }
241 
242  if (fabs(ampscale) > 1.0) {
243  ks_error("ks_scan_wave_ampscale(%s): ampscale too large (%f)", wave->description, ampscale);
244  return;
245  }
246 
247 #ifdef IPG
248 
249  if (wave->wfi == NULL) {
250  ks_error("ks_scan_wave_ampscale(%s): WF_INSTANCE of trap is NULL", wave->description);
251  return;
252  }
253 
254  /* set amplitude(s) */
255  for (i = firstinstance; i <= lastinstance; i++) {
256  const int board = wave->wfi[i].loc.board;
257  gradmax = ks_syslimits_gradtarget(loggrd, board);
258  switch (board) {
259  case XGRAD:
260  case YGRAD:
261  case ZGRAD:
262  {
263  iamp = (int)((wave->abs_max_amp * ampscale * wave->wfi[i].loc.ampscale / (wave->fs_factor * gradmax)) * MAX_PG_IAMP);
264  break;
265  }
266  case OMEGA:
267  {
268  /* The TARDIS_FREQ_RES = 10e6 / (1 << 24) is the effect of one bit. This is the overflow period of the 24-bit register
269  when incremented by 1 at 10 MHz = 0.586 Hz.
270  The product of iwave and iamp is 32 bit wide [the most significant 8-bits appear to be discarded as it is truncated to 24-bits],
271  this effectively mulitplies this value by 256 - so we need to shift 8-bits to the right here to be in the correct units [Hz] */
272  iamp = (int)((wave->abs_max_amp * ampscale * wave->wfi[i].loc.ampscale / (wave->fs_factor * TARDIS_FREQ_RES))) >> 8;
273  break;
274  }
275  case THETA:
276  {
277  iamp = (int)(wave->wfi[i].loc.ampscale * MAX_PG_IAMP);
278  break;
279  }
280  default:
281  ks_error("Wave scaling is currently not implemented for board: %i", board);
282  return;
283  }
284 
285  if (abs(iamp) > MAX_PG_IAMP) {
286  ks_error("ks_scan_wave_ampscale(%s): the integer amplitude is too large (%d) for instance %d", wave->description, iamp, i);
287  return;
288  }
289  if (setiamp((short) iamp, wave->wfi[i].wf, wave->wfi[i].boardinstance) != SUCCESS) {
290  ks_error("ks_scan_wave_ampscale(%s): An error occurred calling 'setiamp()'", wave->description);
291  return;
292  }
293 
294  }
295 
296 #else
297  for (i = firstinstance; i <= lastinstance; i++) {
298  ks_rt_scale_log_set(&wave->rtscaling, i, ampscale);
299  }
300 #endif
301 } /* ks_scan_wave_ampscale */
float fs_factor
Definition: KSFoundation.h:756
int boardinstance
Definition: KSFoundation.h:484
float ks_syslimits_gradtarget(LOG_GRAD loggrd, int board)
Returns the maximum target amplitude for a board (internal use)
Definition: KSFoundation_common.c:264
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
int board
Definition: KSFoundation.h:462
float ampscale
Definition: KSFoundation.h:464
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:755
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
float abs_max_amp
Definition: KSFoundation.h:761
KS_SEQLOC loc
Definition: KSFoundation.h:486
int num_instances
Definition: KSFoundation.h:476
KS_DESCRIPTION description
Definition: KSFoundation.h:745
LOG_GRAD loggrd
KS_BASE base
Definition: KSFoundation.h:744
WF_PULSE * wf
Definition: KSFoundation.h:485
int ngenerated
Definition: KSFoundation.h:496
void ks_rt_scale_log_set(KS_RT_SCALE_LOG *log, int instance_idx, float ampscale)
Definition: KSFoundation_common.c:4890

◆ ks_scan_trap_ampscale()

void ks_scan_trap_ampscale ( KS_TRAP trap,
int  instanceno,
float  ampscale 
)

Updates the amplitude of one or all instances of a KS_TRAP sequence object

This function multiplies one instance of a KS_TRAP object with an amplitude scale factor (3rd arg) that should be in range [-1.0,1.0] to avoid slewrate issues. To change all instances of a KS_TRAP object, use INSTRALL as the 2nd argument.

The actual amplitude for an instance of a KS_TRAP object is the multiplication of the three factors:

  1. The designed amplitude [G/cm]
  2. The per-instance .ampscale in the KS_SEQLOC struct passed to ks_pg_trap()
  3. The ampscale value passed in as 3rd argument to this function.
Parameters
[in,out]trapPointer to KS_TRAP
[in]instancenoInstance of KS_TRAP to change (INSTRALL changes all instances)
[in]ampscaleGradient amplitude scale factor, normally in range [-1.0,1.0], but the range [-1.2, 1.2] is allowed to allow certain run-time gradient corrections
Return values
STATUSSUCCESS or FAILURE
306  {
307  int firstinstance, lastinstance, i;
308 #ifdef IPG
309  int iamp;
310  float gradmax;
311  int numplaced = trp->base.ngenerated;
312 #else
313  int numplaced = trp->base.ninst;
314  if (!numplaced) {
315  return;
316  }
317 
318  trp->rtscaling.num_instances = numplaced;
319 
320 #endif
321 
322  if (instanceno == INSTRALL) {
323  firstinstance = 0;
324  lastinstance = numplaced - 1;
325  } else {
326  firstinstance = instanceno;
327  lastinstance = instanceno;
328  }
329 
330  /* input validation */
331  if (numplaced == 0) {
332  return;
333  }
334  if (firstinstance < 0 || lastinstance >= numplaced) {
335  ks_error("ks_scan_trap_ampscale(%s): instanceno (%d) out of range [0,%d]", trp->description, instanceno, numplaced - 1);
336  return;
337  }
338 
339  /* Allow ampscale to be 20% larger than 1. This, to allow future minor runtime changes of trapezoid amplitudes
340  for e.g. (future possible implementations):
341  - oblique ghost correction for EPI, where odd/even blip amps need to be made smaller/larger depending on slice angle and delays
342  - eddy current correction for DW-EPI, where readout lobe amp needs to be changed per diffusion direction etc.
343  If 'ampscale' is larger than 1.0 (i.e. between 1.0 and 1.2), the trapezoid must have been designed with a slewrate that is slightly
344  under the very limit of the system (and the dB/dt limits for PNS). Use with caution. */
345 
346  if (fabs(ampscale) > sqrt(3)) {
347  ks_error("ks_scan_trap_ampscale(%s): ampscale too large (%f)", trp->description, ampscale);
348  return;
349  }
350 
351  /*
352  - trp->amp: The amplitude that was initially designed for the KS_TRAP. Should never be exceeded, or slew rate issues will occur
353  - trp->wfi[i].loc.ampscale: -1.0 -> +1.0. Amp scale factor for each instance of the KS_TRAP placed in the sequence.
354  - ampscale (3rd input arg): -1.0 -> +1.0 (in normal cases). The dynamic amp scale (i.e. over time, or TRs).
355  The product [trp->wfi[i].loc.ampscale * ampscale] should be in range [-1, 1] to avoid slew rate issues.
356  */
357 
358 #ifdef IPG
359 
360  if (trp->wfi == NULL) {
361  ks_error("ks_scan_trap_ampscale(%s): WF_INSTANCE of trap is NULL", trp->description);
362  return;
363  }
364 
365  /* set amplitude(s) */
366  for (i = firstinstance; i <= lastinstance; i++) {
367  gradmax = ks_syslimits_gradtarget(loggrd, trp->wfi[i].loc.board);
368  iamp = (int)((ampscale * trp->wfi[i].loc.ampscale * trp->amp / (gradmax * trp->fs_factor)) * MAX_PG_IAMP);
369 
370  if (abs(iamp) > 32768) {
371  ks_error("ks_scan_trap_ampscale(%s): the integer amplitude is too large (%d) (ampscale %1.5f, amplitude %1.5f G/cm, boardmax %1.5f, fs_factor %1.5f), for instance %d", trp->description, iamp, ampscale, trp->wfi[i].loc.ampscale * trp->amp, gradmax, trp->fs_factor, i);
372  return;
373  }
374  if (trp->wfi[i].loc.board == OMEGA) {
375  ks_error("ks_scan_trap_ampscale(%s): Instance %d on board OMEGA. Please use ks_scan_omegatrap_hz() instead", trp->description, i);
376  return;
377  }
378  if (setiampt((short) iamp, trp->wfi[i].wf, trp->wfi[i].boardinstance) != SUCCESS) {
379  ks_error("ks_scan_trap_ampscale(%s): An error occurred calling 'setiampt()'", trp->description);
380  return;
381  }
382 
383  }
384 
385 #else
386  for (i = firstinstance; i <= lastinstance; i++) {
387  ks_rt_scale_log_set(&trp->rtscaling, i, ampscale);
388  }
389 #endif
390 } /* ks_scan_trap_ampscale */
int boardinstance
Definition: KSFoundation.h:484
KS_BASE base
Definition: KSFoundation.h:667
float ks_syslimits_gradtarget(LOG_GRAD loggrd, int board)
Returns the maximum target amplitude for a board (internal use)
Definition: KSFoundation_common.c:264
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
int board
Definition: KSFoundation.h:462
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:681
float ampscale
Definition: KSFoundation.h:464
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
KS_SEQLOC loc
Definition: KSFoundation.h:486
float fs_factor
Definition: KSFoundation.h:677
int num_instances
Definition: KSFoundation.h:476
LOG_GRAD loggrd
float amp
Definition: KSFoundation.h:669
WF_PULSE * wf
Definition: KSFoundation.h:485
KS_DESCRIPTION description
Definition: KSFoundation.h:668
int ngenerated
Definition: KSFoundation.h:496
void ks_rt_scale_log_set(KS_RT_SCALE_LOG *log, int instance_idx, float ampscale)
Definition: KSFoundation_common.c:4890

◆ ks_scan_trap_ampscale_slice()

void ks_scan_trap_ampscale_slice ( KS_TRAP trap,
int  start,
int  skip,
int  count,
float  ampscale 
)

Updates the amplitude of a selection of instances of a KS_TRAP sequence object

This function multiplies some instances of a KS_TRAP object with an amplitude scale factor (5th arg) that should be in range [-1.0,1.0] to avoid slewrate issues.

The instances to change are start + i * skip, where i goes from 0 to count. FAILURE is returned if either start or start + count * skip out of range or count is negative

Parameters
[in,out]trapPointer to KS_TRAP
[in]startFirst instance number of the KS_TRAP
[in]skipDifference in instance number between consecutive instances
[in]countNumber of instances to change in total
[in]ampscaleGradient amplitude scale factor, normally in range [-1.0,1.0], but the range [-1.2, 1.2] is allowed to allow certain run-time gradient corrections
Return values
STATUSSUCCESS or FAILURE
394  {
395  int i;
396 #ifdef IPG
397  int numplaced = trp->base.ngenerated;
398 #else
399  int numplaced = trp->base.ninst;
400 #endif
401 
402  if (numplaced == 0) {
403  return;
404  }
405 
406  /* check range */
407  const int end = start + (count - 1) * skip;
408 
409  if (start < 0 || start >= numplaced || end < 0 || end >= numplaced || count < 0) {
410  ks_error("ks_scan_trap_ampscale_slice(%s): slice with start = %d, skip = %d and count = %d has endpoints outside [0,%d)", trp->description, start, skip, count, numplaced);
411  return;
412  }
413 
414  for (i = 0; i < count; ++i) {
415  ks_scan_trap_ampscale(trp, start + i * skip, ampscale);
416  }
417 
418 } /* ks_scan_trap_ampscale_slice */
KS_BASE base
Definition: KSFoundation.h:667
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
KS_DESCRIPTION description
Definition: KSFoundation.h:668
void ks_scan_trap_ampscale(KS_TRAP *trp, int instanceno, float ampscale)
Updates the amplitude of one or all instances of a KS_TRAP sequence object
Definition: KSFoundation_tgt.c:306
int ngenerated
Definition: KSFoundation.h:496

◆ ks_scan_phaser_kmove()

void ks_scan_phaser_kmove ( KS_PHASER phaser,
int  instanceno,
double  pixelunits 
)

Updates the amplitude of a KS_PHASER sequence object to move some arbitrary distance in k-space

This function sets the amplitude of the gradient for a KS_PHASER object so that a shift in k-space of pixelunits number of pixels is produced. If pixelunits is 1.0, the gradient area corresponds to one pixel shift in a fully sampled k-space (no parallel imaging) along the board the KS_PHASER object is placed on. pixelunits is of type float and any non-integer value is accepted, and the sign of pixelunits determines the direction of k-space shift

Parameters
[in,out]phaserPointer to KS_PHASER
[in]instancenoInstance of KS_TRAP to change (INSTRALL changes all instances)
[in]pixelunitsNon-integer pixel units in a fully sampled k-space to move
Return values
STATUSSUCCESS or FAILURE
422  {
423  double phasepixelarea = (double) ks_calc_fov2gradareapixel(phaser->fov);
424  double newarea = pixelunits * phasepixelarea + (double) phaser->areaoffset;
425  double ampscale = newarea / phaser->grad.area;
426 
427  if (phaser == NULL)
428  return;
429 
430  if (fabs(ampscale) > 1.00003) { /* 1.00003 corresponds to 32768 / 32767, i.e. excess of one short int */
431 #ifndef IPG
432  ks_error("ks_scan_phaser_kmove(%s): Too large value (%g) in 3rd arg", phaser->grad.description, pixelunits);
433 #endif
434  } else if (fabs(ampscale) > 1.0) {
435  /* small round-off fix when ampscale is in range [1.0, 1.00003] */
436  ampscale = ampscale < 0 ? -1.0 : 1.0;
437  }
438 
439  ks_scan_trap_ampscale(&phaser->grad, instanceno, ampscale);
440 
441 } /* ks_scan_phaser_kmove */
KS_TRAP grad
Definition: KSFoundation.h:1719
float ks_calc_fov2gradareapixel(float fov)
Calculates the gradient area needed to move one pixel in k-space
Definition: KSFoundation_common.c:492
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
float areaoffset
Definition: KSFoundation.h:1726
float area
Definition: KSFoundation.h:670
KS_DESCRIPTION description
Definition: KSFoundation.h:668
void ks_scan_trap_ampscale(KS_TRAP *trp, int instanceno, float ampscale)
Updates the amplitude of one or all instances of a KS_TRAP sequence object
Definition: KSFoundation_tgt.c:306
float fov
Definition: KSFoundation.h:1720

◆ ks_scan_phaser_compute_kmove()

double ks_scan_phaser_compute_kmove ( KS_PHASER phaser,
int  view 
)
444  {
445 
446  if (phaser == NULL)
447  return 0;
448 
449  if (view < 0 || view >= phaser->res) {
450  return 0;
451  }
452 
453  /* KSFoundation 'view' is always 0-based: e.g. res = 256: view = 0->255. */
454  double kmax = ((phaser->res - 1.0) / 2.0);
455 
456  return kmax - view;
457 
458 } /* ks_scan_phaser_toline */
int res
Definition: KSFoundation.h:1721
int view
Definition: GERequired.e:3728

◆ ks_scan_phaser_toline()

void ks_scan_phaser_toline ( KS_PHASER phaser,
int  instanceno,
int  view 
)

Updates the amplitude of a KS_PHASER sequence object to move from the k-space center to a desired k-space line

This function sets the amplitude of the gradient for a KS_PHASER object to produce a k-space shift from the center of k-space to the view number (3rd arg). The view number must be an integer in range [0, .res-1], and the number refers to a fully sampled k-space (without parallel imaging)

Parameters
[in,out]phaserPointer to KS_PHASER
[in]instancenoInstance of KS_TRAP to change (INSTRALL changes all instances)
[in]viewPhase encoding line to acquire with index corresponding to a fully sampled k-space [0, res-1]
Return values
STATUSSUCCESS or FAILURE
460  {
461 
462  if (phaser == NULL)
463  return;
464 
465  const double kmove = ks_scan_phaser_compute_kmove(phaser, view);
466 
467  ks_scan_phaser_kmove(phaser, instanceno, kmove);
468 
469 } /* ks_scan_phaser_toline */
double ks_scan_phaser_compute_kmove(KS_PHASER *phaser, int view)
Definition: KSFoundation_tgt.c:444
void ks_scan_phaser_kmove(KS_PHASER *phaser, int instanceno, double pixelunits)
Updates the amplitude of a KS_PHASER sequence object to move some arbitrary distance in k-space...
Definition: KSFoundation_tgt.c:422
int view
Definition: GERequired.e:3728

◆ ks_scan_phaser_fromline()

void ks_scan_phaser_fromline ( KS_PHASER phaser,
int  instanceno,
int  view 
)

Updates the amplitude of a KS_PHASER sequence object to move from a k-space line to the k-space center

This function sets the amplitude of the gradient for a KS_PHASER object to produce a k-space shift from the view number (3rd arg) to the k-space center. The view number must be an integer in range [0, .res-1], and the number refers to a fully sampled k-space (without parallel imaging)

Parameters
[in,out]phaserPointer to KS_PHASER
[in]instancenoInstance of KS_TRAP to change (INSTRALL changes all instances)
[in]viewPhase encoding line to acquire with index corresponding to a fully sampled k-space [0, res-1]
Return values
STATUSSUCCESS or FAILURE
472  {
473  double kmax;
474 
475  if (phaser == NULL)
476  return;
477 
478  if (view < 0 || view >= phaser->res) {
479  ks_scan_phaser_kmove(phaser, instanceno, 0.0);
480  return;
481  }
482 
483  /* KSFoundation 'view' is always 0-based: e.g. res = 256: view = 0->255. */
484  kmax = ((phaser->res - 1.0) / 2.0);
485  ks_scan_phaser_kmove(phaser, instanceno, view - kmax);
486 
487 } /* ks_scan_phaser_fromline */
int res
Definition: KSFoundation.h:1721
void ks_scan_phaser_kmove(KS_PHASER *phaser, int instanceno, double pixelunits)
Updates the amplitude of a KS_PHASER sequence object to move some arbitrary distance in k-space...
Definition: KSFoundation_tgt.c:422
int view
Definition: GERequired.e:3728

◆ ks_scan_phaser_average()

void ks_scan_phaser_average ( KS_PHASER phaser,
int  instanceno 
)

ADDTITLEHERE

490  {
491  ks_scan_trap_ampscale(&phaser->grad, instanceno, 0.58);
492 }
KS_TRAP grad
Definition: KSFoundation.h:1719
void ks_scan_trap_ampscale(KS_TRAP *trp, int instanceno, float ampscale)
Updates the amplitude of one or all instances of a KS_TRAP sequence object
Definition: KSFoundation_tgt.c:306

◆ ks_scan_phaser_max()

void ks_scan_phaser_max ( KS_PHASER phaser,
int  instanceno 
)

ADDTITLEHERE

497  {
498  ks_scan_trap_ampscale(&phaser->grad, instanceno, 1.0);
499 }
KS_TRAP grad
Definition: KSFoundation.h:1719
void ks_scan_trap_ampscale(KS_TRAP *trp, int instanceno, float ampscale)
Updates the amplitude of one or all instances of a KS_TRAP sequence object
Definition: KSFoundation_tgt.c:306

◆ ks_scan_rf_ampscale()

void ks_scan_rf_ampscale ( KS_RF rf,
int  instanceno,
float  ampscale 
)

Changes the amplitude of one or all instances of an RF pulse (KS_RF)

This function multiplies one instance of a KS_RF object with an amplitude scale factor (3rd arg) that must be in range [-1.0,1.0]. To change all instances of a KS_RF object, use INSTRALL as the 2nd argument.

The actual flip angle for an instance of a KS_RF object is the multiplication of the three factors:

  1. The designed flip angle
  2. The per-instance .ampscale in the KS_SEQLOC struct passed to ks_pg_rf()
  3. The ampscale value passed in as 3rd argument to this function. Since both ampscale factors are forced to be in range [-1.0,1.0], it is not possible to increase the flip angle beyond the designed value (.flip)
Parameters
[in,out]rfPointer to KS_RF
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]ampscaleRF amplitude scale factor in range [-1.0,1.0]
506  {
507  int firstinstance, lastinstance, i;
508 #ifdef IPG
509  int instramp;
510  KS_WFINSTANCE *wfi;
511  int numplaced = rf->rfwave.base.ngenerated;
512 #else
513  int numplaced = rf->rfwave.base.ninst;
514  if (!numplaced) {
515  return;
516  }
517 
518  rf->rfwave.rtscaling.num_instances = numplaced;
519 
520 #endif
521 
522  if (instanceno == INSTRALL) {
523  firstinstance = 0;
524  lastinstance = numplaced - 1;
525  } else {
526  firstinstance = instanceno;
527  lastinstance = instanceno;
528  }
529 
530  /* input validation */
531  if (numplaced == 0) {
532  return;
533  }
534 
535  if (firstinstance < 0 || lastinstance >= numplaced) {
536  ks_error("ks_scan_rf_ampscale(%s): instanceno (%d) out of range [0,%d]", rf->rfwave.description, instanceno, numplaced - 1);
537  return;
538  }
539 
540  if (fabs(ampscale) > 1.0) {
541  ks_error("ks_scan_rf_ampscale(%s): ampscale too large (%f)", rf->rfwave.description, ampscale);
542  return;
543  }
544 
545 #ifdef IPG
546 
547  /* set amplitude(s) */
548  for (i = firstinstance; i <= lastinstance; i++) {
549  wfi = &rf->rfwave.wfi[i];
550  instramp = (int)(rf->amp * wfi->loc.ampscale * ampscale * MAX_PG_IAMP);
551  setiamp(instramp, wfi->wf, wfi->boardinstance);
552  } /* for */
553 
554 #else
555  for (i = firstinstance; i <= lastinstance; i++) {
556  ks_rt_scale_log_set(&rf->rfwave.rtscaling, i, ampscale);
557  }
558 #endif
559 
560 } /* ks_scan_rf_ampscale */
int boardinstance
Definition: KSFoundation.h:484
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
(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
float ampscale
Definition: KSFoundation.h:464
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:755
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
KS_SEQLOC loc
Definition: KSFoundation.h:486
int num_instances
Definition: KSFoundation.h:476
KS_DESCRIPTION description
Definition: KSFoundation.h:745
KS_WAVE rfwave
Definition: KSFoundation.h:1037
KS_BASE base
Definition: KSFoundation.h:744
float amp
Definition: KSFoundation.h:1031
WF_PULSE * wf
Definition: KSFoundation.h:485
int ngenerated
Definition: KSFoundation.h:496
void ks_rt_scale_log_set(KS_RT_SCALE_LOG *log, int instance_idx, float ampscale)
Definition: KSFoundation_common.c:4890

◆ ks_scan_rf_on()

void ks_scan_rf_on ( KS_RF rf,
int  instanceno 
)

Resets the amplitude of one or all instances of an RF pulse (KS_RF)

This function (re)sets the RF amplitude to the state given by ks_pg_rf()

Parameters
[in,out]rfPointer to KS_RF
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
566  {
567 
568  ks_scan_rf_ampscale(rf, instanceno, 1.0);
569 
570 }
void ks_scan_rf_ampscale(KS_RF *rf, int instanceno, float ampscale)
Changes the amplitude of one or all instances of an RF pulse (KS_RF)
Definition: KSFoundation_tgt.c:506

◆ ks_scan_rf_on_chop()

void ks_scan_rf_on_chop ( KS_RF rf,
int  instanceno 
)

Resets the amplitude of one or all instances of an RF pulse (KS_RF) and toggles the sign (chopping)

Everytime this function is called, the magnitude of the RF amplitude will be (re)set the RF amplitude to the state given by ks_pg_rf() and the polarity of the RF amplitude will be changed. If this function is called each TR (RF chopping) for a linear single-line k-space acquisition, a FOV/2 shift will occur in the image with any DC component shifted out to the edges of the image FOV.

Parameters
[in,out]rfPointer to KS_RF
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
583  {
584  static float chopsign = 1.0;
585 
586  ks_scan_rf_ampscale(rf, instanceno, chopsign);
587 
588  chopsign *= -1.0;
589 
590 }
void ks_scan_rf_ampscale(KS_RF *rf, int instanceno, float ampscale)
Changes the amplitude of one or all instances of an RF pulse (KS_RF)
Definition: KSFoundation_tgt.c:506

◆ ks_scan_rf_off()

void ks_scan_rf_off ( KS_RF rf,
int  instanceno 
)

Sets the amplitude of one or all instances of an RF pulse (KS_RF) to zero

This can be undone by calling ks_scan_rf_on(), ks_scan_rf_on_chop(), or ks_scan_rf_ampscale()

Parameters
[in,out]rfPointer to KS_RF
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
597  {
598 
599  ks_scan_rf_ampscale(rf, instanceno, 0.0);
600 
601 }
void ks_scan_rf_ampscale(KS_RF *rf, int instanceno, float ampscale)
Changes the amplitude of one or all instances of an RF pulse (KS_RF)
Definition: KSFoundation_tgt.c:506

◆ ks_scan_selrf_setfreqphase_pins()

void ks_scan_selrf_setfreqphase_pins ( KS_SELRF selrf,
int  instanceno,
SCAN_INFO  sliceinfo,
int  sms_multiband_factor,
float  sms_slice_gap,
float  rfphase 
)

Updates the off-center phase-modulation of one or all instances of a PINS RF pulse (KS_SELRF)

This function alters the phase of the PINS RF pulse in a KS_SELRF object to excite spatial locations corresponding to the information in sliceinfo.tloc.

Parameters
[in,out]selrfPointer to KS_SELRF
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]sliceinfoSCAN_INFO struct for the current slice to be played out
[in]sms_multiband_factor
[in]sms_slice_gapin [mm]
[in]rfphasePhase of the RF pulse in [degrees]
Return values
STATUSSUCCESS or FAILURE
611  {
612 
613  int firstinstance, lastinstance, j;
614  int phaseIndex = 1;
615  KS_WAVE newwave = KS_INIT_WAVE;
616  float locOffset;
617  float phaseIncrement;
618 #ifdef IPG
619  int i;
620  int numplaced = selrf->rf.rfwave.base.ngenerated;
621 #else
622  int numplaced = selrf->rf.rfwave.base.ninst;
623 #endif
624 
625  if (instanceno == INSTRALL) {
626  firstinstance = 0;
627  lastinstance = numplaced - 1;
628  } else {
629  firstinstance = instanceno;
630  lastinstance = instanceno;
631  }
632 
633  if (numplaced == 0) {
634  return;
635  }
636 
637  if (firstinstance < 0 || lastinstance >= numplaced) {
638  ks_error("ks_scan_selrf_setfreqphase_pins(%s): instanceno (%d) out of range [0,%d]", selrf->rf.rfwave.description, instanceno, numplaced - 1);
639  return;
640  }
641 
642  newwave = selrf->rf.thetawave;
643 
644  locOffset = sliceinfo.optloc;
645  phaseIncrement = (360.0 / sms_slice_gap) * locOffset;
646 
647  /* If the MB-factor is even, center the slice group */
648  if (sms_multiband_factor % 2 == 0) {
649  phaseIncrement += 180.0;
650  }
651 
652  for (j = 0; j < selrf->rf.thetawave.res; j++) {
653 
654  if (!areSame(selrf->rf.rfwave.waveform[j], 0.0)) {
655  newwave.waveform[j] = selrf->rf.thetawave.waveform[j] + ((float)phaseIndex * phaseIncrement) + rfphase;
656  }
657 
658  if (j < selrf->rf.thetawave.res - 1) {
659  if (!areSame(selrf->rf.rfwave.waveform[j], 0.0) && areSame(selrf->rf.rfwave.waveform[j + 1], 0.0)) {
660  phaseIndex++;
661  }
662  }
663  }
664 
665 #ifdef IPG
666 
667  for (i = firstinstance; i <= lastinstance; i++) {
668  /* set RF frequency & phase offset to zero */
669  setfrequency(0, selrf->rf.rfwave.wfi[i].wf, selrf->rf.rfwave.wfi[i].boardinstance);
670  setphase(0.0, selrf->rf.rfwave.wfi[i].wf, selrf->rf.rfwave.wfi[i].boardinstance);
671 
672  /* move modified thetawave to hardware */
673  ks_scan_wave2hardware(&selrf->rf.thetawave, newwave.waveform, (selrf->rf.thetawave.current_state[i])+1 % selrf->rf.thetawave.base.nstates);
674  }
675 
676 #endif
677 
678 } /* ks_scan_selrf_setfreqphase_pins */
int boardinstance
Definition: KSFoundation.h:484
#define areSame(a, b)
Definition: KSFoundation.h:144
Core sequence object making arbitrary waveforms on any board (using float data format)
Definition: KSFoundation.h:743
#define KS_INIT_WAVE
Definition: KSFoundation.h:295
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
void ks_scan_wave2hardware(KS_WAVE *wave, const KS_WAVEFORM newwaveform, int state)
Writes over an existing waveform state in sequencer memory
Definition: KSFoundation_tgt.c:876
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
KS_WAVE thetawave
Definition: KSFoundation.h:1039
KS_RF rf
Definition: KSFoundation.h:1454
KS_DESCRIPTION description
Definition: KSFoundation.h:745
KS_WAVE rfwave
Definition: KSFoundation.h:1037
KS_BASE base
Definition: KSFoundation.h:744
WF_PULSE * wf
Definition: KSFoundation.h:485
int nstates
Definition: KSFoundation.h:495
int * current_state
Definition: KSFoundation.h:762
int ngenerated
Definition: KSFoundation.h:496
int res
Definition: KSFoundation.h:746
KS_WAVEFORM waveform
Definition: KSFoundation.h:748

◆ ks_scan_selrf_setfreqphase()

void ks_scan_selrf_setfreqphase ( KS_SELRF selrf,
int  instanceno,
SCAN_INFO  sliceinfo,
float  rfphase 
)

Updates the frequency and phase of one or all instances of a slice selective RF pulse (KS_SELRF)

This function alters the frequency of the RF pulse in a KS_SELRF object to excite a spatial location corresponding to the information in sliceinfo.tloc. The phase of the RF pulse is also updated

Parameters
[in,out]selrfPointer to KS_SELRF
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]sliceinfoSCAN_INFO struct for the current slice to be played out
[in]rfphasePhase of the RF pulse in [degrees]
Return values
STATUSSUCCESS or FAILURE
683  {
684  int firstinstance, lastinstance;
685  int i;
686  float freqoffHz, hertzPerMm, ampscale;
687 #ifdef IPG
688  float tloc = sliceinfo.optloc;
689  int numplaced = selrf->rf.rfwave.base.ngenerated;
690 #else
691  float tloc = 1.0; /* Simulate offset of 1 mm for plotting in units of [Hz/mm] */
692  int numplaced = selrf->rf.rfwave.base.ninst;
693 #endif
694 
695  if (instanceno == INSTRALL) {
696  firstinstance = 0;
697  lastinstance = numplaced - 1;
698  } else {
699  firstinstance = instanceno;
700  lastinstance = instanceno;
701  }
702 
703  if (numplaced == 0) {
704  return;
705  }
706  if (firstinstance < 0 || lastinstance >= numplaced) {
707  ks_error("ks_scan_selrf_setfreqphase(%s): instanceno (%d) out of range [0,%d]", selrf->rf.rfwave.description, instanceno, numplaced - 1);
708  return;
709  }
710 
711  /* set frequency */
712  for (i = firstinstance; i <= lastinstance; i++) {
713 #ifdef IPG
714  if (!(i < selrf->rf.rfwave.base.ngenerated &&
715  selrf->rf.rfwave.wfi[i].wf->wavegen_type == TYPRHO1 &&
716  selrf->rf.rfwave.wfi[i].wf->assoc_pulse->tag == SSPFREQ)) { /* make sure it has been set up properly */
717  ks_error("ks_scan_rf_setfreqphase(%s): RF pulse not properly set up or instance # too high", selrf->rf.rfwave.description);
718  return;
719  }
720  if (selrf->gradwave.res > 0) {
721  /* gradwave */
722  if (selrf->gradwave.wfi != NULL) {
723  ampscale = selrf->gradwave.wfi[i].loc.ampscale;
724  } else {
725  ks_error("ks_scan_rf_setfreqphase(%s): no gradwave has been set up, setting ampscale = 0", selrf->rf.rfwave.description);
726  ampscale = 0;
727  }
728  } else {
729  /* trapezoid */
730  if (selrf->grad.wfi != NULL) {
731  ampscale = selrf->grad.wfi[i].loc.ampscale;
732  } else {
733  ks_error("ks_scan_rf_setfreqphase(%s): no grad has been set up, setting ampscale = 0", selrf->rf.rfwave.description);
734  ampscale = 0; /* protect against wfi[i] = NULL, then return 0 amp */
735  }
736  }
737 #else
738  ampscale = (selrf->gradwave.res > 0) ? selrf->gradwave.locs[i].ampscale
739  : selrf->grad.locs[i].ampscale;
740 #endif
741 
742  /* ampscale (a.u.) * GAM [Hz/G] / 10.0 [cm->mm] * gradamp [G/cm] = [Hz/mm] */
743  hertzPerMm = ampscale * GAM / 10.0 *
744  ((selrf->gradwave.res > 0) ? ks_calc_selgradamp(selrf->rf.bw, selrf->slthick) /* gradwave slice selection */
745  : selrf->grad.amp); /* trapezoid slice selection */
746  freqoffHz = selrf->rf.cf_offset; /* [Hz] */
747  unsigned short iphase_omega = 0;
748  /* optloc-dependent freq offset */
749  if (selrf->rf.omegawave.res > 0) {
750  iphase_omega = -ks_scan_omegawave_hz(&selrf->rf.omegawave, i, hertzPerMm * tloc /* [Hz] */, selrf->rf.omega_iwave_phase_at_iso);
751  } else {
752  freqoffHz += hertzPerMm * tloc; /* [Hz] */
753  }
754 
755 #ifdef IPG
756  /* set RF frequency offset */
757  setfrequency((int)(freqoffHz / TARDIS_FREQ_RES), selrf->rf.rfwave.wfi[i].wf, selrf->rf.rfwave.wfi[i].boardinstance);
758 
759  /* calculate phase */
760  {
761  double ftime_delay; /* floating point time delay in seconds */
762  double temp_freq; /* frequency offset */
763  unsigned short tmpphase;
764  int syncpos, rfstartpos, time_delay;
765 
766  /* start of RF pulse wave form (for 1st boardinstance) */
767  rfstartpos = selrf->rf.rfwave.wfi[i].wf->inst_hdr_tail->start;
768  /* start of RF SSP frq pulse (for 1st boardinstance) */
769  syncpos = selrf->rf.rfwave.wfi[i].wf->assoc_pulse->inst_hdr_tail->start;
770 
771  /* time difference between SSP frq and start of RF pulse */
772  time_delay = rfstartpos - syncpos - 9 /* frq2sync_dly */;
773 
774  /*** Modified from GE's setupphases() ***/
775  ftime_delay = ((double)(time_delay + selrf->rf.start2iso)) / ((double) 1.0e6);
776  temp_freq = (double) freqoffHz;
777  tmpphase = ks_degrees_to_iphase(rfphase) /* deg->iphase */ + ks_cycles_to_iphase( - temp_freq * ftime_delay ) + iphase_omega; /* iphase */
778  setiphase((long)tmpphase, selrf->rf.rfwave.wfi[i].wf, selrf->rf.rfwave.wfi[i].boardinstance);
779  }
780 #else
781  (void)iphase_omega;
782 #endif
783  } /* for each instance */
784 } /* ks_scan_selrf_setfreqphase */
KS_TRAP grad
Definition: KSFoundation.h:1463
int boardinstance
Definition: KSFoundation.h:484
float cf_offset
Definition: KSFoundation.h:1030
int start2iso
Definition: KSFoundation.h:1032
KS_SEQLOC * locs
Definition: KSFoundation.h:752
unsigned short ks_scan_omegawave_hz(KS_WAVE *wave, int instanceno, float Hz, int omega_iwave_phase_at_null)
Updates a KS_WAVE object on the OMEGA board to produce a frequency offset
Definition: KSFoundation_tgt.c:56
KS_WAVE gradwave
Definition: KSFoundation.h:1465
int omega_iwave_phase_at_iso
Definition: KSFoundation.h:1040
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
KS_SEQLOC * locs
Definition: KSFoundation.h:678
float ampscale
Definition: KSFoundation.h:464
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
KS_SEQLOC loc
Definition: KSFoundation.h:486
KS_RF rf
Definition: KSFoundation.h:1454
KS_DESCRIPTION description
Definition: KSFoundation.h:745
KS_WAVE rfwave
Definition: KSFoundation.h:1037
KS_BASE base
Definition: KSFoundation.h:744
WF_PULSE * wf
Definition: KSFoundation.h:485
float ks_calc_selgradamp(float rfbw, float slthick)
Returns the gradient amplitude in [G/cm] necessary for slice selection (internal use)
Definition: KSFoundation_common.c:448
unsigned short ks_cycles_to_iphase(double cycles)
Returns the integer phase (internal use)
Definition: KSFoundation_common.c:367
KS_WAVE omegawave
Definition: KSFoundation.h:1038
int ngenerated
Definition: KSFoundation.h:496
unsigned short ks_degrees_to_iphase(double degrees)
Definition: KSFoundation_common.c:379
int res
Definition: KSFoundation.h:746
float slthick
Definition: KSFoundation.h:1456
float bw
Definition: KSFoundation.h:1029

◆ ks_scan_rf_setphase()

void ks_scan_rf_setphase ( KS_RF rf,
int  instanceno,
float  rfphase 
)

Updates the phase of one or all instances of an RF pulse (KS_RF)

This function sets the phase of an RF pulse object (KS_RF). Can be used for RF spoiling

Parameters
[in,out]rfPointer to KS_SEL
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]rfphasePhase of the RF pulse in [degrees]
789  {
790  int firstinstance, lastinstance;
791  #ifdef IPG
792  int i;
793  int numplaced = rf->rfwave.base.ngenerated;
794  #else
795  int numplaced = rf->rfwave.base.ninst;
796  #endif
797 
798  if (instanceno == INSTRALL) {
799  firstinstance = 0;
800  lastinstance = numplaced - 1;
801  } else {
802  firstinstance = instanceno;
803  lastinstance = instanceno;
804  }
805 
806  if (numplaced == 0) {
807  return;
808  }
809  if (firstinstance < 0 || lastinstance >= numplaced) {
810  ks_error("%s(%s): instanceno (%d) out of range [0,%d]", __FUNCTION__, rf->rfwave.description, instanceno, numplaced - 1);
811  return;
812  }
813 
814  #ifdef IPG
815  /* set frequency */
816  for (i = firstinstance; i <= lastinstance; i++) {
817  /* calculate phase */
818  {
819  double ftime_delay; /* floating point time delay in seconds */
820  double cf_offset = (double) rf->cf_offset; /* frequency offset */
821  unsigned short tmpphase;
822  int syncpos, rfstartpos, time_delay;
823 
824  /* start of RF pulse wave form (for 1st boardinstance) */
825  rfstartpos = rf->rfwave.wfi[i].wf->inst_hdr_tail->start;
826  /* start of RF SSP frq pulse (for 1st boardinstance) */
827  syncpos = rf->rfwave.wfi[i].wf->assoc_pulse->inst_hdr_tail->start;
828 
829  /* time difference between SSP frq and isocenter of RF pulse */
830  time_delay = rfstartpos - syncpos - 9 /* frq2sync_dly */ + RUP_FACTOR(rf->rfwave.duration - rf->iso2end, 2);
831 
832  /*** Modified from GE's setupphases() ***/
833  ftime_delay = ((double)time_delay) / ((double) 1.0e6);
834  tmpphase = ks_degrees_to_iphase(rfphase) /* deg->iphase */ + ks_cycles_to_iphase( - cf_offset * ftime_delay ); /* iphase */
835  setiphase((long)tmpphase, rf->rfwave.wfi[i].wf, rf->rfwave.wfi[i].boardinstance);
836  }
837 
838  } /* for each instance */
839 
840  #endif
841 
842 
843 } /* ks_scan_rf_setphase */
int boardinstance
Definition: KSFoundation.h:484
float cf_offset
Definition: KSFoundation.h:1030
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
KS_DESCRIPTION description
Definition: KSFoundation.h:745
KS_WAVE rfwave
Definition: KSFoundation.h:1037
KS_BASE base
Definition: KSFoundation.h:744
int iso2end
Definition: KSFoundation.h:1033
WF_PULSE * wf
Definition: KSFoundation.h:485
unsigned short ks_cycles_to_iphase(double cycles)
Returns the integer phase (internal use)
Definition: KSFoundation_common.c:367
int ngenerated
Definition: KSFoundation.h:496
unsigned short ks_degrees_to_iphase(double degrees)
Definition: KSFoundation_common.c:379
int duration
Definition: KSFoundation.h:747

◆ ks_scan_setwavestate()

void ks_scan_setwavestate ( KS_WAVE wave,
int  state,
int  instance 
)

Change the address of an instruction instance to point to a different state

scan_setwavestate.svg
graphical description

During the ks_pg_addwaveform state calls we keep track of the address of each new waveform that was added. This function then allows you to switch to a new waveform by simply changing the address in the intstruction. Be aware that each instance of the KS_WAVE has a unique instruction. This allows you change wave_state on an instance granularity level.

Parameters
[in]wavePointer to a KS_WAVE sequence object
[in]stateThe new state to switch to (previously added by ks_pg_addwaveformstate)
[in]instanceWhich instance you would like to change state (INSTRALL affects all)
845  {
846 
847 
848  if (ks_numplaced(&wave->base) == 0) {
849  return;
850  }
851 
852 #ifdef IPG
853  setwave(wave->wave_ptrs[state], wave->wfi[instance].wf, wave->wfi[instance].boardinstance);
854 #else
855  if (state < 0) {
856  KS_THROW("%s: tried to set to negative state: %i", wave->description, state);
857  } else if (state >= KS_WAVE_MAXNSTATES) {
858  KS_THROW("%s: invalid state: %d > %d ", wave->description, state, KS_WAVE_MAXNSTATES-1);
859  } else if (wave->p_waveformstates[state] == NULL || state >= wave->base.nstates) {
860  KS_THROW("%s: invalid state %d. Did you forget to call ks_pg_addwaveformstate() ?", wave->description, state);
861  }
862 
863  if (instance < 0) {
864  KS_THROW("%s: tried to modify negative instance: %i [this function is not compatible with INSTRALL(=%d)]", wave->description, instance, INSTRALL);
865  } else if (instance > ks_numplaced(&wave->base)) {
866  KS_THROW("%s: Invalid instance: %d > %d", wave->description, instance, ks_numplaced(&wave->base)-1);
867  }
868 
869  wave->rtscaling.num_instances = ks_numplaced(&wave->base);
870  ks_rt_scale_log_set_state(&wave->rtscaling, instance, state);
871 #endif
872  wave->current_state[instance] = state;
873 
874 } /* ks_scan_setwavestate */
int boardinstance
Definition: KSFoundation.h:484
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:755
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
int num_instances
Definition: KSFoundation.h:476
KS_DESCRIPTION description
Definition: KSFoundation.h:745
LONG * wave_ptrs
Definition: KSFoundation.h:763
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
KS_BASE base
Definition: KSFoundation.h:744
#define KS_WAVE_MAXNSTATES
Definition: KSFoundation.h:293
WF_PULSE * wf
Definition: KSFoundation.h:485
void ks_rt_scale_log_set_state(KS_RT_SCALE_LOG *log, int instance_idx, int state)
Definition: KSFoundation_common.c:4929
int nstates
Definition: KSFoundation.h:495
int * current_state
Definition: KSFoundation.h:762
float * p_waveformstates[KS_WAVE_MAXNSTATES]
Definition: KSFoundation.h:749
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_scan_wave2hardware()

void ks_scan_wave2hardware ( KS_WAVE wave,
const KS_WAVEFORM  newwaveform,
int  state 
)

Writes over an existing waveform state in sequencer memory

scan_wave2hardware.svg
graphical description

This function copies a waveform to the iwave buffer on the sequencer associated with the specified wave state. In order to use this function multiple wave states are required, these are added using ks_pg_addwavestate. During run time, it is the responsibility of the programmer to not copy a waveform into the currently active wave state. This is because the sequencer and your psd-code are asynchronous and this function writes into the sequence immediately. If the KS_WAVE is currently playing this could trip you scanner! Note: This function affects all instructions (instances) pointing to this state.

Example

@ipgexport (HOST)
@host
cveval() {
ks_eval_wave(&mywave, "mywavedesc", res, duration, some_floatarray);
}
@pg
tmploc.pos = 10ms;
tmploc.board = XGRAD;
ks_pg_wave(&mywave, tmploc, &seqctrl); // Same wave object *can* be placed on multiple boards (but not recommended as the units differ between gradient and RF/OMEGA boards)
ks_pg_addwaveformstate(mywave, some_other_waveform, 1); // We add state 1, we will use this as our buffer later
@rsp (TGT)
scan() {
float * your_waveform = (float *) AllocNode(1024 * sizeof(float)); // allocate some memory
make_your_waveform(your_waveform, some_inputs); // create a float array
const int new_state = (mywave.current_state+1) % mywave.base.nstates; // safely fetch the inactive state (for nstate=2 -> 1010101010.. etc)
ks_scan_wave2hardware(&mywave, your_waveform, new_state); // replace the waveform at the address of <new_state> (this affects all instances pointing to this state)
ks_scan_setwavestate(&mywave, new_state, INSTRALL); // change all instances of the instruction addresses to point to the <new_state> (so it plays out on the next time the seqctrl executes)
FreeNode(your_waveform); // free the memory on the heap
}
Parameters
[in,out]wavePointer to KS_WAVE
[in]newwaveformKS_WAVEFORM to copy to hardware (if NULL, the .waveform field in KS_WAVE will be used instead)
[in]stateThe wave state to write the waveform into; this can't be equal to the currently active wavestate
876  {
877 #ifndef IPG
878  if(wave->max_amp < ks_waveform_absmax(newwaveform, wave->res)) {
879  ks_error("%s [%s]: can't add a newwaveform state with a larger amplitude than state0.", __FUNCTION__, wave->description);
880  return;
881  }
882 
883  float slew_max = ks_waveform_maxslew(newwaveform, wave->res, wave->duration, NULL);
884  /* times > 1 in case of float rounding */
885  extern float cfxfs, cfyfs, cfzfs;
886  extern int cfrmp2xfs, cfrmp2yfs, cfrmp2zfs;
887  int i;
888  float slew_limit = FMin(3, cfxfs, cfyfs, cfzfs)/IMax(3,cfrmp2xfs,cfrmp2yfs,cfrmp2zfs)* 1.00001;
889  /* float slew_limit = ks_syslimits_slewrate1(loggrd) * 1.00001; */
890  for (i = 0; i < ks_numplaced(&wave->base); i++) {
891  KS_SEQLOC loc = wave->locs[i];
892  int isGrad = (loc.board == XGRAD || loc.board == YGRAD || loc.board == ZGRAD);
893  if ((isGrad) && (slew_max > slew_limit)) {
894  KS_THROW("[%s]: state %i exceeds the least conservative gradient slew rate limit. %f > %f",
895  wave->description, state, slew_max, slew_limit);
896  return;
897  }
898  }
899  if(state > wave->base.nstates) {
900  KS_THROW("This state (%d) was not pulsegen'd", state);
901  return;
902  }
903 
904 #endif
905 
906 #ifdef IPG
907  /* wave -> short int wave for hardware use. All waveforms but THETA are autoscaled to +/- max_pg_wamp (32766)*/
908  WF_PULSE * wfpulse;
909  int board;
910  short * iwave = (short *) AllocNode(wave->res * sizeof(short));
911  int skippedboards = 0;
912  int i;
913  for (i = 0; i < ks_numplaced(&wave->base); i++) {
914  if(state == wave->current_state[i]) {
915  ks_error("Can't move a waveform to the currently active state, instance = %i!", i);
916  return;
917  }
918  }
919 
920  const int board_instance = 0;
921  for(board = 0; board < 7; board++) {
922  wfpulse = wave->wfpulse[board];
923  if (!wfpulse) {
924  skippedboards++;
925  continue;
926  }
927  float max_amp = 0.0;
928  if (board == RHO) {
929  max_amp = 1.0;
930  } else {
931  max_amp = wave->abs_max_amp;
932  }
933 
934  /* Here we adjust the iwave amplitude to achieve the correct final amplitude iamp*iwave*/
935  if (ks_waveform2iwave(iwave,
936  newwaveform,
937  wave->res,
938  board,
939  max_amp,
940  wave->fs_factor) == FAILURE)
941  return;
942  LONG wave_ptr = 0;
943  getwave(&wave_ptr, &wfpulse[0]); /* Get current ptr */
944  setwave(wave->wave_ptrs[state], &wfpulse[0], board_instance); /* Load state ptr */
945  movewaveimm(iwave, &wfpulse[0], (int) board_instance, wave->res, TOHARDWARE); /* Write to wave to state ptr */
946  setwave(wave_ptr, &wfpulse[0], board_instance); /* Restore current ptr */
947  }
948  FreeNode(iwave);
949 
950  if (skippedboards == 7) {
951  ks_error("%s [%s] -> state %d: no WF_PULSES have been allocated, something is very wrong!", __FUNCTION__, wave->description, state);
952  return;
953  }
954 
955 #endif
956 
957 } /* ks_scan_wave2hardware */
float fs_factor
Definition: KSFoundation.h:756
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
KS_SEQLOC * locs
Definition: KSFoundation.h:752
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
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
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
KS_BASE base
Definition: KSFoundation.h:744
float max_amp
Definition: KSFoundation.h:759
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
STATUS ks_waveform2iwave(KS_IWAVE iwave, const KS_WAVEFORM waveform, int res, int board, float max, float fs_factor) WARN_UNUSED_RESULT
(Internal use) Conversion of a KS_WAVEFORM to a short int array for use on hardware
Definition: KSFoundation_common.c:1698
int nstates
Definition: KSFoundation.h:495
int * current_state
Definition: KSFoundation.h:762
float ks_waveform_absmax(const KS_WAVEFORM waveform, int res)
Returns the maximum absolute value in a KS_WAVEFORM
Definition: KSFoundation_common.c:1336
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int res
Definition: KSFoundation.h:746
int duration
Definition: KSFoundation.h:747

◆ ks_scan_offsetfov_iso()

void ks_scan_offsetfov_iso ( KS_READTRAP readtrap,
int  instanceno,
SCAN_INFO  sliceinfo,
double  ky,
double  kz,
double  rcvphase 
)

Updates the frequency and phase to create a FOV shift assuming that the k-space voxels/pixels are isometric

Parameters
[in,out]readtrapPointer to KS_READTRAP
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]sliceinfoSCAN_INFO struct for the current slice to be played out
[in]kyphase offset in k-space measured in voxels/pixels
[in]kzphase offset in k-space measured in voxels/pixels
[in]rcvphaseReceiver phase in [degrees] of the acquisition window corresponding to the KS_READTRAP and instanceno
961  {
962  /* Warning: We never have more than one instance (i.e. instruction) per readtrap.echo[i] (see ks_pg_readtrap())
963  unlike KS_TRAP and KS_RF. This means that the 2nd input arg here ('instanceno') means the instanceno'th echo. */
964 
965 #ifdef IPG
966  const int numplaced = readtrap->acq.base.ngenerated;
967 #else
968  const int numplaced = readtrap->acq.base.ninst;
969 #endif
970 
971  int firstreadout, lastreadout;
972  if (instanceno == INSTRALL) {
973  firstreadout = 0;
974  lastreadout = numplaced - 1;
975  } else {
976  firstreadout = instanceno;
977  lastreadout = instanceno;
978  }
979 
980  if (numplaced == 0) {
981  return;
982  }
983 
984  if (firstreadout < 0 || lastreadout >= numplaced) {
985  ks_error("ks_scan_offsetfov(%s): readout instance (%d) out of range [0,%d]", readtrap->grad.description, instanceno, numplaced - 1);
986  return;
987  }
988 
989  int i;
990  for (i = firstreadout; i <= lastreadout; i++) {
991 #ifdef IPG
992  /* gradient amplitude for this instance -> Hz */
993  const float ampscale = readtrap->grad.wfi[i].loc.ampscale;
994  float rloc = sliceinfo.oprloc;
995 #else
996  const float ampscale = readtrap->grad.locs[i].ampscale;
997  float rloc = 1;
998 #endif
999 
1000  const double hertz_per_mm = (readtrap->grad.amp * ampscale) * GAM / 10.0; /* [Hz/mm] = amp [G/cm] * GAM [Hz/G] / 10.0 [cm->mm] */
1001 
1002  /* iphase_omega for rampsampled cases includes the entire ramp up (+acqdelay) */
1003  unsigned short iphase_omega = 0;
1004  if (readtrap->omega.duration > 0 && !areSame(ampscale, 0.0)) {
1005  iphase_omega = -ks_scan_omegawave_hz(&readtrap->omega, i, hertz_per_mm * rloc /* [Hz] */, readtrap->omega_iwave_phase_at_echo);
1006  }
1007 
1008 #ifdef IPG
1009  const int gradsign = (hertz_per_mm >= 0) ? 1 : -1;
1010  /* Frequency offsets [Hz]:
1011  - cfreceiveroffsetfreq: GE's standard frequency offset
1012  - readtrap->freqoffHz: Additional frequency offset for current KS_READTRAP. This value is multiplied with the gradient polarity sign
1013  - hertz_per_mm * sliceinfo.oprloc: Slice-dependent and gradient polarity dependent frequency offset (when omega is off) */
1014  const double freqoffHz = cfreceiveroffsetfreq
1015  + readtrap->freqoffHz * gradsign
1016  + (readtrap->omega.duration == 0) * (hertz_per_mm * rloc); /* [Hz] */
1017 
1018  /* set readout frequency offset */
1019  if (i < readtrap->acq.base.ngenerated && readtrap->acq.echo[i].tag == SSPDAB) { /* make sure it has been set up properly */
1020  setfrequency((int)(freqoffHz / TARDIS_FREQ_RES), &readtrap->acq.echo[i], 0);
1021  }
1022  /* set phase offset */
1023  if (i < readtrap->acq.base.ngenerated && readtrap->acq.echo[i].tag == SSPDAB) {
1024 
1025  /* The period of time between when the oscillator starts accumulating phase and
1026  the centre of the first ADC sample is XTRSETLNG (132 us) + XTR_TAIL (5 us). XTRSETLNG is
1027  used in the placement of the XTR, DAB and RBA messages in acqq_longdab/acqq.
1028  If the pulse placement in the acqq functions are modified from the GE defaults,
1029  this timing is no longer valid! */
1030  int freqstart2readstart = XTRSETLNG + XTR_TAIL + 2 - (int)(readtrap->acq.filt.tsp / 2.0f);
1031  int readstart2echo = readtrap->time2center - readtrap->acqdelay;
1032 
1033  const unsigned short iphase_due_to_freqoffset = ks_cycles_to_iphase(- freqoffHz * (freqstart2readstart + readstart2echo) * 1e-6);
1034  const unsigned short iphase_ky = ks_cycles_to_iphase(- ky * sliceinfo.opphasoff / readtrap->fov);
1035  const unsigned short iphase_kz = ks_cycles_to_iphase(- kz * sliceinfo.optloc / readtrap->fov);
1036  const unsigned short ircvphase = ks_degrees_to_iphase(rcvphase);
1037  unsigned short iphase = (iphase_ky + iphase_kz + ircvphase + iphase_due_to_freqoffset + iphase_omega);
1038  setiphase((long)iphase, &readtrap->acq.echo[i], 0);
1039 
1040  }
1041 #else
1042  (void)iphase_omega;
1043 #endif
1044 
1045  } /* for */
1046 } /* ks_scan_offsetfov_iso */
WF_PULSE * echo
Definition: KSFoundation.h:846
#define areSame(a, b)
Definition: KSFoundation.h:144
unsigned short ks_scan_omegawave_hz(KS_WAVE *wave, int instanceno, float Hz, int omega_iwave_phase_at_null)
Updates a KS_WAVE object on the OMEGA board to produce a frequency offset
Definition: KSFoundation_tgt.c:56
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ninst
Definition: KSFoundation.h:494
float fov
Definition: KSFoundation.h:1551
KS_WAVE omega
Definition: KSFoundation.h:1562
KS_SEQLOC * locs
Definition: KSFoundation.h:678
int cfreceiveroffsetfreq
KS_TRAP grad
Definition: KSFoundation.h:1561
float ampscale
Definition: KSFoundation.h:464
KS_BASE base
Definition: KSFoundation.h:839
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:680
int omega_iwave_phase_at_echo
Definition: KSFoundation.h:1564
KS_SEQLOC loc
Definition: KSFoundation.h:486
float amp
Definition: KSFoundation.h:669
KS_DESCRIPTION description
Definition: KSFoundation.h:668
FILTER_INFO filt
Definition: KSFoundation.h:843
unsigned short ks_cycles_to_iphase(double cycles)
Returns the integer phase (internal use)
Definition: KSFoundation_common.c:367
float freqoffHz
Definition: KSFoundation.h:1557
int ngenerated
Definition: KSFoundation.h:496
unsigned short ks_degrees_to_iphase(double degrees)
Definition: KSFoundation_common.c:379
KS_READ acq
Definition: KSFoundation.h:1549
int time2center
Definition: KSFoundation.h:1560
int acqdelay
Definition: KSFoundation.h:1555
int duration
Definition: KSFoundation.h:747

◆ ks_scan_offsetfov_iso_readwave()

void ks_scan_offsetfov_iso_readwave ( KS_READWAVE readwave,
int  instanceno,
SCAN_INFO  sliceinfo,
double  ky,
double  kz,
double  rcvphase 
)

ADDTITLEHERE

1049  {
1050  KS_READ * read = &readwave->acq;
1051  const int numplaced = ks_numplaced(&read->base);
1052 
1053  if (numplaced == 0) {
1054  return;
1055  }
1056 
1057  int firstgrad, lastgrad;
1058  if (instanceno == INSTRALL) {
1059  firstgrad = 0;
1060  lastgrad = numplaced - 1;
1061  } else {
1062  firstgrad = instanceno;
1063  lastgrad = instanceno;
1064  }
1065 
1066  if (firstgrad < 0 || lastgrad >= numplaced) {
1067  ks_error("%s: readwave gradinstance (%d) out of range [0,%d]", __FUNCTION__, instanceno, numplaced - 1);
1068  return;
1069  }
1070 
1071  int i;
1072  for (i = firstgrad; i <= lastgrad; i++) {
1073 #ifdef IPG
1074  /* gradient amplitude for this instance -> Hz */
1075  const float ampscale = readwave->grad.wfi[i].loc.ampscale;
1076  const float rloc = sliceinfo.oprloc;
1077 #else
1078  const float ampscale = readwave->grad.locs[i].ampscale;
1079  const float rloc = 1;
1080 #endif
1081 
1082  const double hertz_per_mm = readwave->omega.abs_max_amp * ampscale; /* [Hz/mm] * ampscale (to match polarity of read gradient) */
1083  unsigned short iphase_omega = 0;
1084  iphase_omega = -ks_scan_omegawave_hz(&readwave->omega, i, hertz_per_mm * rloc /* [Hz] */, readwave->omega_iwave_phase_at_echo);
1085 
1086 #ifdef IPG
1087  const int gradsign = (ampscale >= 0) ? 1 : -1;
1088 
1089  /* Frequency offsets [Hz]:
1090  - cfreceiveroffsetfreq: GE's standard frequency offset
1091  - readwave->freqoffHz: Additional frequency offset for current KS_WAVE. This value is multiplied with the gradient polarity sign */
1092  const double freqoffHz = cfreceiveroffsetfreq
1093  + readwave->freqoffHz * gradsign;
1094 
1095  /* set readout frequency offset */
1096  if (i < read->base.ngenerated && read->echo[i].tag == SSPDAB) {/* make sure it has been set up properly */
1097  setfrequency((int)(freqoffHz / TARDIS_FREQ_RES), &read->echo[i], 0);
1098  }
1099 
1100  /* set phase offset */
1101  if (i < numplaced && read->echo[i].tag == SSPDAB) {
1102 
1103  /* The period of time between when the oscillator starts accumulating phase and
1104  the centre of the first ADC sample is XTRSETLNG (132 us) + XTR_TAIL (5 us). XTRSETLNG is
1105  used in the placement of the XTR, DAB and RBA messages in acqq_longdab/acqq.
1106  If the pulse placement in the acqq functions are modified from the GE defaults,
1107  this timing is no longer valid! */
1108  int freqstart2readstart = XTRSETLNG + XTR_TAIL + 2 - (int)(readwave->acq.filt.tsp / 2.0f);
1109  int readstart2echo = readwave->time2center - readwave->acqdelay;
1110 
1111  const unsigned short iphase_due_to_freqoffset = ks_cycles_to_iphase(- freqoffHz * (freqstart2readstart + readstart2echo) * 1e-6);
1112  const unsigned short iphase_ky = ks_cycles_to_iphase(- ky * sliceinfo.opphasoff / readwave->fov);
1113  const unsigned short iphase_kz = ks_cycles_to_iphase(- kz * sliceinfo.optloc / readwave->fov);
1114  const unsigned short ircvphase = ks_degrees_to_iphase(rcvphase);
1115  unsigned short iphase = (iphase_ky + iphase_kz + ircvphase + iphase_due_to_freqoffset + iphase_omega);
1116  setiphase(iphase, &read->echo[i], 0);
1117  }
1118 #else
1119  (void)iphase_omega;
1120 #endif
1121 
1122  } /* for */
1123 } /* ks_scan_offsetfov_iso_readwave */
float fov
Definition: KSFoundation.h:1610
WF_PULSE * echo
Definition: KSFoundation.h:846
KS_SEQLOC * locs
Definition: KSFoundation.h:752
unsigned short ks_scan_omegawave_hz(KS_WAVE *wave, int instanceno, float Hz, int omega_iwave_phase_at_null)
Updates a KS_WAVE object on the OMEGA board to produce a frequency offset
Definition: KSFoundation_tgt.c:56
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
KS_WAVE omega
Definition: KSFoundation.h:1605
int time2center
Definition: KSFoundation.h:1615
int cfreceiveroffsetfreq
float freqoffHz
Definition: KSFoundation.h:1609
KS_WAVE grad
Definition: KSFoundation.h:1604
float ampscale
Definition: KSFoundation.h:464
KS_BASE base
Definition: KSFoundation.h:839
KS_WFINSTANCE * wfi
Definition: KSFoundation.h:754
float abs_max_amp
Definition: KSFoundation.h:761
KS_SEQLOC loc
Definition: KSFoundation.h:486
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
Core sequence object that handles a data acquisition window
Definition: KSFoundation.h:838
int omega_iwave_phase_at_echo
Definition: KSFoundation.h:1617
FILTER_INFO filt
Definition: KSFoundation.h:843
unsigned short ks_cycles_to_iphase(double cycles)
Returns the integer phase (internal use)
Definition: KSFoundation_common.c:367
int acqdelay
Definition: KSFoundation.h:1608
unsigned short ks_degrees_to_iphase(double degrees)
Definition: KSFoundation_common.c:379
KS_READ acq
Definition: KSFoundation.h:1606

◆ ks_scan_offsetfov()

void ks_scan_offsetfov ( KS_READTRAP readtrap,
int  instanceno,
SCAN_INFO  sliceinfo,
float  view,
float  phasefovratio,
float  rcvphase 
)

Updates the frequency and phase of one or all instances of a KS_READTRAP to create a FOV shift

This function can be used by 2D Cartesian pulse sequences to build up the phase ramp in k-space necessary to shift the image FOV. The desired image FOV shift is given by the SCAN_INFO struct passed in as 3rd argument. The view field and the phasefovratio arguments are necessary to know where in the physical k-space the acquired data is placed. Knowing this and the FOV offset in the phase encoding direction, the necessary receiver phase for the current view can be set. After this function has been called for all view numbers, the necessary phase ramp has been set up in k-space to perform the phase FOV shift in the image domain. The rcvphase is added to the receive phase required for the FOV shift. In general, the rcvphase should be the same as the phase of the RF excitation pulse.

For rampsampled acquisitions (.rampsampling = 1 in KS_READTRAP), the ks_scan_offsetfov_iso() function called will internally call ks_scan_omegatrap_hz() for FOV shifts in the readout direction. Both ks_scan_offsetfov() and ks_scan_offsetfov3D() calls the same ks_scan_offsetfov_iso() function after performing unit conversions of the input arguments.

Parameters
[in,out]readtrapPointer to KS_READTRAP
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]sliceinfoSCAN_INFO struct for the current slice to be played out
[in]viewPhase encoding line to acquire with index corresponding to a fully sampled k-space [0, res-1]
[in]phasefovratioThe ratio of FOVphase/FOVfreq (as opphasefov)
[in]rcvphaseReceiver phase in [degrees] of the acquisition window corresponding to the KS_READTRAP and instanceno
1126  {
1127  const double koffset = (double)(ky) / phasefovratio;
1128  ks_scan_offsetfov_iso(readtrap, instanceno, sliceinfo, koffset, 0, rcvphase);
1129 }
void ks_scan_offsetfov_iso(KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, double ky, double kz, double rcvphase)
Updates the frequency and phase to create a FOV shift assuming that the k-space voxels/pixels are iso...
Definition: KSFoundation_tgt.c:961

◆ ks_scan_offsetfov3D()

void ks_scan_offsetfov3D ( KS_READTRAP readtrap,
int  instanceno,
SCAN_INFO  sliceinfo,
float  kyview,
float  phasefovratio,
float  kzview,
float  zphasefovratio,
float  rcvphase 
)

Updates the frequency and phase of one or all instances of a KS_READTRAP to create a FOV shift

This function can be used by 3D Cartesian pulse sequences to build up the phase ramp in k-space necessary to shift the image FOV. The desired image FOV shift is given by the SCAN_INFO struct passed in as 3rd argument. The kyview/kzview field and the phasefovratio/zphasefovratio arguments are necessary to know where in the physical k-space the acquired data is placed. Knowing this and the FOV offset in both phase encoding directions, the necessary receiver phase for the current kyview/kzview can be set. After this function has been called for all kyview/kzview numbers, the necessary phase ramp has been set up in k-space to perform the phase FOV shift in the image domain. The rcvphase is added to the receive phase required for the FOV shift. In general, the rcvphase should be the same as the phase of the RF excitation pulse.

For rampsampled acquisitions (.rampsampling = 1 in KS_READTRAP), the ks_scan_offsetfov_iso() function called will internally call ks_scan_omegatrap_hz() for FOV shifts in the readout direction. Both ks_scan_offsetfov() and ks_scan_offsetfov3D() calls the same ks_scan_offsetfov_iso() function after performing unit conversions of the input arguments.

Parameters
[in,out]readtrapPointer to KS_READTRAP
[in]instancenoInstance of KS_RF to change (INSTRALL changes all instances)
[in]sliceinfoSCAN_INFO struct for the current slice to be played out
[in]kyviewPhase encoding line to acquire with index corresponding to a fully sampled k-space [0, res-1] (YGRAD)
[in]phasefovratioThe ratio of FOVphase/FOVfreq (as opphasefov)
[in]kzviewZ Phase encoding line to acquire with index corresponding to a fully sampled k-space [0, res-1] (ZGRAD)
[in]zphasefovratioThe ratio of FOVslice/FOVfreq (as (opslquant * opslthick) / opfov)
[in]rcvphaseReceiver phase in [degrees] of the acquisition window corresponding to the KS_READTRAP and instanceno
1134  {
1135  const double kyoffset = (double)(ky) / phasefovratio;
1136  const double kzoffset = (double)(kz) / zphasefovratio;
1137  ks_scan_offsetfov_iso(readtrap, instanceno, sliceinfo, kyoffset, kzoffset, rcvphase);
1138 }
void ks_scan_offsetfov_iso(KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, double ky, double kz, double rcvphase)
Updates the frequency and phase to create a FOV shift assuming that the k-space voxels/pixels are iso...
Definition: KSFoundation_tgt.c:961

◆ ks_scan_offsetfov_readwave()

void ks_scan_offsetfov_readwave ( KS_READWAVE readwave,
int  instanceno,
SCAN_INFO  sliceinfo,
float  ky,
float  phasefovratio,
float  rcvphase 
)

ADDTITLEHERE

1143  {
1144  const double koffset = (double)(ky) / phasefovratio;
1145  ks_scan_offsetfov_iso_readwave(readwave, instanceno, sliceinfo, koffset, 0, rcvphase);
1146 }
void ks_scan_offsetfov_iso_readwave(KS_READWAVE *readwave, int instanceno, SCAN_INFO sliceinfo, double ky, double kz, double rcvphase)
ADDTITLEHERE
Definition: KSFoundation_tgt.c:1049

◆ ks_scan_offsetfov3D_readwave()

void ks_scan_offsetfov3D_readwave ( KS_READWAVE readwave,
int  instanceno,
SCAN_INFO  sliceinfo,
float  ky,
float  phasefovratio,
float  kz,
float  zphasefovratio,
float  rcvphase 
)

ADDTITLEHERE

1151  {
1152  const double koffset = (double)(ky) / phasefovratio;
1153  const double kzoffset = (double)(kz) / zphasefovratio;
1154  ks_scan_offsetfov_iso_readwave(readwave, instanceno, sliceinfo, koffset, kzoffset, rcvphase);
1155 }
void ks_scan_offsetfov_iso_readwave(KS_READWAVE *readwave, int instanceno, SCAN_INFO sliceinfo, double ky, double kz, double rcvphase)
ADDTITLEHERE
Definition: KSFoundation_tgt.c:1049

◆ ks_scan_getrotate()

float* ks_scan_getrotate ( void  )
1160  {
1161  typedef float R_float[9];
1162  static R_float R_out = KS_MAT3x3_IDENTITY;
1163 #ifdef IPG
1164  typedef long R_long[9];
1165  R_long R_in = KS_MAT3x3_IDENTITY;
1166  getrotate(R_in, 1);
1167 
1168  unscale(&R_in, &R_out, 1, &loggrd, &phygrd, 0);
1169 
1170 #endif
1171  return &R_out[0];
1172 }
PHYS_GRAD phygrd
#define KS_MAT3x3_IDENTITY
Definition: KSFoundation.h:339
LOG_GRAD loggrd

◆ ks_scan_rotate()

void ks_scan_rotate ( SCAN_INFO  slice_pos)

Performs a rotation of the logical system on hardware (WARP)

The field .oprot (9-element array) in the SCAN_INFO struct holds the rotation matrix that should be played out

This function performs the necessary scaling of the rotation matrix using loggrd and phygrd and then calls setrotatearray(), which performs the actual rotation on hardware during the next SSI time.

See ks_scan_update_slice_location() for detail on how to create new SCAN_INFO structs in run-time

Parameters
[in]slice_posSCAN_INFO struct holding new slice information
Returns
void
1179  {
1180 #ifdef IPG
1181 
1182  /* scale to long int rotation matrix (accounting for gradient scaling) */
1183  scale(&slice_pos.oprot, &rsprot[0], 1, &loggrd, &phygrd, 0);
1184 
1185  setrotatearray(1, rsprot[0]);
1186 
1187 #endif
1188 }
PHYS_GRAD phygrd
LOG_GRAD loggrd
long rsprot[TRIG_ROT_MAX][9]
STATUS scale(FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)

◆ ks_scan_isirotate()

void ks_scan_isirotate ( KS_ISIROT isirot)

Performs an immediate rotation of the logical system on hardware (WARP)

This function needs a psd-specific wrapper function to execute (see ks_pg_isirot()) since the ISI interupt routine is calling a void function without input arguments. This psd-specific wrapper function should only contain the call to ks_scan_isirotate() with the psd-specific KS_ISIROT set up in pulsegen().

For N number of calls to ks_pg_isirot() in the sequence module's pg-function, the field isirot.numinstances will be set to N, and this many ISI interrupt with a corresponding isirot.isinumber exist in the sequence module. Valid ISI numbers are 4-7, and one available number should be linked to one specific wrapper function using ks_eval_isirot() and ks_pg_isirot().

In real-time, ks_scan_isirotate() will increment the isirot.counter field by 1 and restart at 0 after isirot->numinstances. isirot.counter is set to 0 in ks_pg_isirot(). Based on the value of the .counter field, it will assign a pre-stored SCAN_INFO struct corresponding to this counter value. Again, this connection is done by ks_pg_isirot().

ks_scan_isirotate() takes the current SCAN_INFO and converts it to long int, and then calls setrotateimm(..., WARP_UPDATE_ON_SSP_INT);

Parameters
[in]isirotPointer to the KS_ISIROT struct set up by ks_pg_isirot()
Returns
void
1193  {
1194 #ifdef IPG
1195 
1196  if (isirot == NULL || isirot->numinstances < 1)
1197  return;
1198 
1199  /* wrap around after numinstances interupts */
1200  isirot->counter = isirot->counter % isirot->numinstances;
1201 
1202  /* scale to long int rotation matrix (accounting for gradient scaling) */
1203  scale(&isirot->scan_info[isirot->counter++].oprot, &rsprot[0], 1, &loggrd, &phygrd, 0);
1204 
1205  /* rotate on SSP interrupt */
1206  setrotateimm(rsprot[0], WARP_UPDATE_ON_SSP_INT);
1207 
1208 #endif
1209 }
SCAN_INFO * scan_info
Definition: KSFoundation.h:560
PHYS_GRAD phygrd
LOG_GRAD loggrd
long rsprot[TRIG_ROT_MAX][9]
int counter
Definition: KSFoundation.h:563
STATUS scale(FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)
int numinstances
Definition: KSFoundation.h:564

◆ ks_scan_getsliceloc()

int ks_scan_getsliceloc ( const KS_SLICE_PLAN slice_plan,
int  passindx,
int  sltimeinpass 
)

Returns the spatially sorted slice index from a DATA_ACQ_ORDER struct array

This function finds the spatially sorted slice index (.slloc) in range [0, nslices-1] given the sequence's DATA_ACQ_ORDER struct array (in slice_plan.acq_order)

Parameters
[in]slice_planPointer to the slice plan (KS_SLICE_PLAN) for the sequence
[in]passindxCurrent pass index ([0, acqs-1])
[in]sltimeinpassTemporal index of the n slices acquired in each pass ([0, n-1])
Return values
sllocSpatially sorted slice index
1214  {
1215  int i;
1216  for (i = 0; i < slice_plan->nslices; i++) {
1217  if (slice_plan->acq_order[i].slpass == passindx && slice_plan->acq_order[i].sltime == sltimeinpass) {
1218  return slice_plan->acq_order[i].slloc;
1219  }
1220  }
1221 
1222  return KS_NOTSET;
1223 
1224 }
DATA_ACQ_ORDER acq_order[SLICE_FACTOR *DATA_ACQ_MAX]
Definition: KSFoundation.h:1321
#define KS_NOTSET
Definition: KSFoundation.h:115
int passindx
Definition: ksgre_tutorial_implementation.e:1046
int nslices
Definition: KSFoundation.h:1318

◆ ks_scan_getslicetime()

int ks_scan_getslicetime ( const KS_SLICE_PLAN slice_plan,
int  passindx,
int  slloc 
)

Returns the temporally sorted slice index from a DATA_ACQ_ORDER struct array

This function finds the temporally sorted slice index (.sltime) in range [0, nslices-1] given the sequence's DATA_ACQ_ORDER struct array (in slice_plan.acq_order)

Parameters
[in]slice_planPointer to the slice plan (KS_SLICE_PLAN) for the sequence
[in]passindxCurrent pass index ([0, acqs-1])
[in]sllocSpatially sorted slice index [0, nslices-1]
Return values
sltimeinpassTemporal index of the n slices acquired in each pass ([0, n-1])
1229  {
1230  int i;
1231  for (i = 0; i < slice_plan->nslices; i++) {
1232  if (slice_plan->acq_order[i].slpass == passindx && slice_plan->acq_order[i].slloc == slloc) {
1233  return slice_plan->acq_order[i].sltime;
1234  }
1235  }
1236 
1237  return KS_NOTSET;
1238 
1239 }
DATA_ACQ_ORDER acq_order[SLICE_FACTOR *DATA_ACQ_MAX]
Definition: KSFoundation.h:1321
#define KS_NOTSET
Definition: KSFoundation.h:115
int passindx
Definition: ksgre_tutorial_implementation.e:1046
int nslices
Definition: KSFoundation.h:1318

◆ ks_scan_epi_verify_phaseenc_plan()

ks_enum_epiblipsign ks_scan_epi_verify_phaseenc_plan ( KS_EPI epi,
KS_PHASEENCODING_PLAN phaseenc_plan,
int  shot 
)

ADDTITLEHERE

1244  {
1245  int i;
1246  int kystep[epi->etl];
1249 
1250  if (phaseenc_plan == NULL) {
1251  return blipsign;
1252  }
1253 
1254  /* verify phase encoding plan has equidistant ky step size */
1255  /* first store ky coords */
1256  for (i = 0; i < epi->etl; i++) {
1257  coord = ks_phaseencoding_get(phaseenc_plan, i, shot);
1258  kystep[i] = coord.ky;
1259  }
1260 
1261  for (i = 0; i < epi->etl-1; i++) {
1262  kystep[i] = kystep[i+1] - kystep[i]; /* calculate ky step */
1263  if (i > 0) {
1264  /* check that kystep is consistent */
1265  if (kystep[i] != kystep[0]) {
1266  KS_THROW("%s: KS_EPI does not support varying ky step size", phaseenc_plan->description);
1267  return KS_EPI_NOBLIPS;
1268  }
1269  }
1270  }
1271 
1272  if (kystep[0] < 0) {
1273  blipsign = KS_EPI_POSBLIPS;
1274  } else if (kystep[0] > 0) {
1275  blipsign = KS_EPI_NEGBLIPS;
1276  }
1277 
1278  return blipsign;
1279 }
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
#define KS_INIT_PHASEENCODING_COORD
Definition: KSFoundation.h:306
s16 ky
Definition: KSFoundation.h:1750
int etl
Definition: KSFoundation.h:1941
Struct holding a 3D k-space phase encoding location (ky,kz)
Definition: KSFoundation.h:1749
KS_DESCRIPTION description
Definition: KSFoundation.h:1791
Definition: KSFoundation.h:2330
ks_enum_epiblipsign
Definition: KSFoundation.h:2330
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
Definition: KSFoundation.h:2330
Definition: KSFoundation.h:2330

◆ _compute_epi_blipsign()

ks_enum_epiblipsign _compute_epi_blipsign ( KS_EPI epi,
KS_PHASEENCODING_COORD  starting_coord 
)
1285  {
1286  const double starting_kmove = ks_scan_phaser_compute_kmove(&epi->blipphaser, starting_coord.ky);
1287 
1289 
1290  /* Note that negative kmove values correspond to high kyview */
1291  if (starting_kmove < 0) {
1292  blipsign = KS_EPI_NEGBLIPS;
1293  }
1294  if (starting_kmove > 0) {
1295  blipsign = KS_EPI_POSBLIPS;
1296  }
1297 
1298  return blipsign;
1299 }
double ks_scan_phaser_compute_kmove(KS_PHASER *phaser, int view)
Definition: KSFoundation_tgt.c:444
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
s16 ky
Definition: KSFoundation.h:1750
Definition: KSFoundation.h:2330
ks_enum_epiblipsign
Definition: KSFoundation.h:2330
Definition: KSFoundation.h:2330
Definition: KSFoundation.h:2330

◆ ks_scan_epi_shotcontrol_sms()

void ks_scan_epi_shotcontrol_sms ( KS_EPI epi,
int  echo,
SCAN_INFO  sliceinfo,
KS_PHASEENCODING_COORD  starting_coord,
ks_enum_epiblipsign  blipsign,
float  rcvphase,
int  sms_factor,
float  sms_slice_gap,
int  caipi_factor,
int  sms_slice_encoding_direction 
)

Changes the gradient state of a KS_EPI object for the given slice information

This function has two different tasks. First, it controls the EPI blips and sets the EPI dephaser and rephaser amplitude given the current phaseshot and blipsign. If phaseshot is outside the valid range ([0, .blipphaser.R-1], all gradient amplitudes on the blip (phase encoding) axis will be zero. This can be useful to acquire a refscan for Nyquist ghost correction. Second, it sets up the proper frequency and phase modulation per readout lobe to produce the desired FOV offset in both the frequency and phase encoding directions

Parameters
[in,out]epiPointer to KS_EPI
[in]echoEPI echo index (up to 16 EPI trains supported)
[in]sliceinfoSCAN_INFO struct for the current slice to be played out
[in]starting_coordcoordinate in k-space from where the EPI train starts
[in]blipsignKS_EPI_POSBLIPS or KS_EPI_NEGBLIPS
[in]rcvphaseReceiver phase in degrees, for RF spoiling.
[in]sms_factorADDTEXTHERE
[in]sms_slice_gapADDTEXTHERE
[in]caipi_factorADDTEXTHERE
[in]sms_slice_encoding_directionADDTEXTHERE
Returns
void
1304  {
1305  float blipampscale = 1.0;
1306  float yfovratio, zfovratio;
1307  int i, s;
1308  int numblips = (epi->etl - 1);
1309  int readindx, blipindx, kyview, kzview;
1310  float caipi_rcvphase = 0.0;
1311 
1312  if (blipsign == KS_EPI_NOBLIPS) {
1313  starting_coord.ky = KS_NOTSET;
1314  starting_coord.kz = KS_NOTSET;
1315  }
1316 
1317  const int readfact = (epi->epi_readout_mode == KS_EPI_SPLITODDEVEN) ? 2 : 1;
1318 
1319  /* Blips-off triggers: If at least one of KS_EPI_NOBLIPS or ky = KS_NOTSET, make sure
1320  both blipdephasers and blips are off */
1321  if (blipsign == KS_EPI_NOBLIPS || starting_coord.ky == KS_NOTSET) {
1322  blipsign = KS_EPI_NOBLIPS; /* blip amp off */
1323  starting_coord.ky = KS_NOTSET; /* blipdephaser off */
1324  }
1325 
1326  /* EPI dephaser. From k-space center to this line */
1327  ks_scan_phaser_toline(&epi->blipphaser, 0 + 2 * echo, starting_coord.ky); /* KS_NOTSET => zero amplitude */
1328  if (epi->zphaser.grad.duration > 0) {
1329  /* 3D epi z dephaser(s) for even instances '2*echo' */
1330  ks_scan_phaser_toline(&epi->zphaser, 0 + 2 * echo, starting_coord.kz);
1331  }
1332 
1333  if (epi->zphaser.grad.duration > 0) {
1334  /* 3D epi z rephaser(s) for odd instances '1+2*echo' */
1335  ks_scan_phaser_fromline(&epi->zphaser, 1 + 2 * echo, starting_coord.kz);
1336  }
1337 
1338  /* EPI read & blips for current 'echo' = EPI train. */
1339  float caipi_phase = ks_calc_caipi_phase(sms_slice_gap, sms_factor, &sliceinfo, epi->caipiblip.area, sms_slice_encoding_direction);
1340  float caipi_previous = 0.0;
1341  for (i = 0; i < epi->etl; i++) {
1342  kyview = starting_coord.ky - blipsign * epi->blipphaser.R * i;
1343  kzview = starting_coord.kz;
1344 
1345  readindx = readfact * (i + echo * epi->etl); /* ETL# of readouts */
1346  blipindx = i + echo * numblips; /* (ETL-1)# of blips */
1347 
1348  if (i < numblips) {
1349  /* FUTURE: at this point, we could increase/decrease blipampscale for odd/even blips for oblique ghost correction */
1350  blipampscale = blipsign / epi->blipoversize;
1351  ks_scan_trap_ampscale(&epi->blip, blipindx, blipampscale);
1352  }
1353 
1354  /* CAIPI-blip */
1355  float caipi_target = ks_calc_caipi_scale(kyview, epi->R_ky, caipi_factor) * abs(blipsign) * 0.5; /* Get target caipi-phase with pattern linspace(-0.5, 0.5, sms_caipi_factor) */
1356  float caipi_scale = caipi_target - caipi_previous;
1357  ks_scan_trap_ampscale(&epi->caipiblip, blipindx, caipi_scale);
1358  caipi_previous = caipi_target;
1359 
1360  if (i == epi->etl-1) {
1361  /* EPI rephaser. From this line to k-space center */
1362  ks_scan_phaser_fromline(&epi->blipphaser, 1 + 2 * echo, kyview); /* KS_NOTSET => zero amplitude */
1363  /* CAIPI rephaser */
1364  ks_scan_trap_ampscale(&epi->caipiblip, blipindx+1, -caipi_previous);
1365  }
1366 
1367  /* FOV offsets (by changing freq/phase of epi.read) */
1368  float ky_centred, kz_centred;
1369  if (kyview < 0 || blipsign == KS_EPI_NOBLIPS) {
1370  ky_centred = 0.0f;
1371  } else {
1372  ky_centred = (float)kyview - ((epi->blipphaser.res - 1) / 2.0f);
1373  }
1374  yfovratio = epi->blipphaser.fov / epi->read.fov;
1375 
1376  int n_readouts_per_blip = (epi->epi_readout_mode == KS_EPI_SPLITODDEVEN ? 2 : 1);
1377  if (epi->zphaser.grad.duration > 0) {
1378  if (kzview < 0) {
1379  kz_centred = 0.0f;
1380  } else {
1381  kz_centred = (float)kzview - ((epi->zphaser.res - 1) / 2.0f);
1382  }
1383  zfovratio = epi->zphaser.fov / epi->read.fov;
1384  for (s = 0; s < n_readouts_per_blip; s++) {
1385  ks_scan_offsetfov3D(&epi->read, readindx + s, sliceinfo, ky_centred, yfovratio, kz_centred, zfovratio, rcvphase);
1386  }
1387  } else {
1388 
1389  if (caipi_factor > 1) {
1390  caipi_rcvphase = caipi_phase * caipi_target;
1391  } else {
1392  caipi_rcvphase = 0.0;
1393  }
1394 
1395  for (s = 0; s < n_readouts_per_blip; s++) {
1396  ks_scan_offsetfov(&epi->read, readindx + s, sliceinfo, ky_centred, yfovratio, rcvphase + caipi_rcvphase);
1397  }
1398  }
1399 
1400  } /* for etl */
1401 
1402 } /* ks_scan_epi_shotcontrol_sms */
float blipoversize
Definition: KSFoundation.h:1945
KS_TRAP blip
Definition: KSFoundation.h:1935
void ks_scan_phaser_toline(KS_PHASER *phaser, int instanceno, int view)
Updates the amplitude of a KS_PHASER sequence object to move from the k-space center to a desired k-s...
Definition: KSFoundation_tgt.c:460
int R
Definition: KSFoundation.h:1723
int res
Definition: KSFoundation.h:1721
void ks_scan_offsetfov3D(KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, float ky, float phasefovratio, float kz, float zphasefovratio, float rcvphase)
Updates the frequency and phase of one or all instances of a KS_READTRAP to create a FOV shift...
Definition: KSFoundation_tgt.c:1134
int R_ky
Definition: KSFoundation.h:1940
KS_TRAP grad
Definition: KSFoundation.h:1719
#define KS_NOTSET
Definition: KSFoundation.h:115
float fov
Definition: KSFoundation.h:1551
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
KS_PHASER zphaser
Definition: KSFoundation.h:1938
s16 ky
Definition: KSFoundation.h:1750
int etl
Definition: KSFoundation.h:1941
void ks_scan_offsetfov(KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, float ky, float phasefovratio, float rcvphase)
Updates the frequency and phase of one or all instances of a KS_READTRAP to create a FOV shift...
Definition: KSFoundation_tgt.c:1126
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
KS_READTRAP read
Definition: KSFoundation.h:1932
Definition: KSFoundation.h:2329
int epi_readout_mode
Definition: KSFoundation.h:1939
KS_TRAP caipiblip
Definition: KSFoundation.h:1936
float area
Definition: KSFoundation.h:670
s16 kz
Definition: KSFoundation.h:1751
void ks_scan_trap_ampscale(KS_TRAP *trp, int instanceno, float ampscale)
Updates the amplitude of one or all instances of a KS_TRAP sequence object
Definition: KSFoundation_tgt.c:306
float ks_calc_caipi_scale(const int ky, const int R, const int caipi_factor)
ADDTITLEHERE
Definition: KSFoundation_common.c:520
void ks_scan_phaser_fromline(KS_PHASER *phaser, int instanceno, int view)
Updates the amplitude of a KS_PHASER sequence object to move from a k-space line to the k-space cente...
Definition: KSFoundation_tgt.c:472
int duration
Definition: KSFoundation.h:673
Definition: KSFoundation.h:2330
float fov
Definition: KSFoundation.h:1720

◆ ks_scan_epi_shotcontrol()

void ks_scan_epi_shotcontrol ( KS_EPI epi,
int  echo,
SCAN_INFO  sliceinfo,
KS_PHASEENCODING_COORD  starting_coord,
ks_enum_epiblipsign  blipsign,
float  rcvphase 
)

Changes the gradient state of a KS_EPI object for the given slice information

This function has two different tasks. First, it controls the EPI blips and sets the EPI dephaser and rephaser amplitude given the current phaseshot and blipsign. If phaseshot is outside the valid range ([0, .blipphaser.R-1], all gradient amplitudes on the blip (phase encoding) axis will be zero. This can be useful to acquire a refscan for Nyquist ghost correction. Second, it sets up the proper frequency and phase modulation per readout lobe to produce the desired FOV offset in both the frequency and phase encoding directions

Parameters
[in,out]epiPointer to KS_EPI
[in]echoEPI echo index (up to 16 EPI trains supported)
[in]sliceinfoSCAN_INFO struct for the current slice to be played out
[in]starting_coordcoordinate in k-space from where the EPI train starts
[in]blipsignKS_EPI_POSBLIPS or KS_EPI_NEGBLIPS
[in]rcvphaseReceiver phase in degrees, for RF spoiling.
1405  {
1406 
1407  int sms_factor = 1;
1408  float sms_slice_gap = 0.0;
1409  int caipi_factor = 1;
1410  int sms_slice_encoding_direction = 1;
1411 
1412  ks_scan_epi_shotcontrol_sms(epi, echo, sliceinfo, starting_coord, blipsign, rcvphase, sms_factor, sms_slice_gap, caipi_factor, sms_slice_encoding_direction);
1413 
1414 }
void ks_scan_epi_shotcontrol_sms(KS_EPI *epi, int echo, SCAN_INFO sliceinfo, KS_PHASEENCODING_COORD starting_coord, ks_enum_epiblipsign blipsign, float rcvphase, int sms_factor, float sms_slice_gap, int caipi_factor, int sms_slice_encoding_direction)
Changes the gradient state of a KS_EPI object for the given slice information
Definition: KSFoundation_tgt.c:1304

◆ ks_scan_epi_loadecho()

void ks_scan_epi_loadecho ( KS_EPI epi,
int  echo,
int  storeecho,
int  slice,
KS_PHASEENCODING_COORD  starting_coord,
ks_enum_epiblipsign  blipsign,
KS_DYNAMIC_STATE *  dynamic 
)

Loads the data storage information to hardware for the acquisition windows in a KS_EPI sequence object

ADDTEXTHERE

Parameters
[in,out]epiPointer to KS_EPI
[in]echoEPI echo index to work on (up to 16 EPI trains supported)
[in]storeechoEPI echo index for storing (usually the same as echo)
[in]sliceSlice index where to store the data (0-based)
[in]starting_coordcoordinate in k-space from where the EPI train starts
[in]blipsignKS_EPI_POSBLIPS or KS_EPI_NEGBLIPS
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
Returns
void
1421  {
1422 
1423  int i, readindx;
1424  const int n_readouts_per_blip = (epi->epi_readout_mode == KS_EPI_SPLITODDEVEN) ? 2 : 1;
1425  const int numplaced = ks_numplaced(&epi->read.acq.base);
1426  if (numplaced == 0) {
1427  return;
1428  }
1429 
1430 
1431  /* Data routing control */
1432  TYPDAB_PACKETS dabacqctrl = dynamic->slloc >= 0 ? DABON : DABOFF;
1433  if ((dynamic->prescan || !dynamic->force_acq) && (dynamic->shot < 0 || dynamic->average < 0)) {
1434  dabacqctrl = DABOFF;
1435  }
1436  (void)dabacqctrl;
1437 
1438 
1439  if (echo < 0 || (echo + 1) * (n_readouts_per_blip * epi->etl) > numplaced) {
1440  KS_THROW("echo (%d) must be in range [0:%d]", echo, numplaced/(n_readouts_per_blip * epi->etl) - 1);
1441  return;
1442  }
1443 
1444  const int view_factor = epi->compressed_bam ? epi->R_ky : 1;
1445  (void) view_factor;
1446 
1447  for (i = 0; i < epi->etl; i++) {
1448 
1449  readindx = n_readouts_per_blip * (i + echo * epi->etl); /* N.B.: 'echo' is # of EPI trains, not EPI readout lobes (up to 16 possible, set by opnecho) */
1450 
1451  if ((readindx + (epi->epi_readout_mode == KS_EPI_SPLITODDEVEN)) >= numplaced) {
1452  KS_THROW("%s: Readout lobe index %d has not been placed in PG", epi->read.grad.description, readindx);
1453  return;
1454  }
1455 
1456 #ifdef IPG
1457  int kyview = starting_coord.ky - blipsign * epi->blipphaser.R * i;
1458  int s;
1459  int centerread = epi->time2center / epi->read.grad.duration; /* etl index corresponding to k-space center */
1460  /* 'pscR1' is the R1 receive gain made by prescan */
1461  int currentR1 = (epi->read.acq.override_R1 > 0 && epi->read.acq.override_R1 <= 11) ? epi->read.acq.override_R1 : pscR1;
1462 
1463  kyview = kyview < 0 ? kyview : kyview / view_factor;
1464 
1465  for (s = 0; s < n_readouts_per_blip; s++) {
1466 
1467  WF_PULSE_ADDR current_wf_pulse = &epi->read.acq.echo[readindx + s];
1468 
1469  if (dynamic->prescan) {
1470  /* Prescan (R1 & R2), turn on acquisition for center echo of 1st EPI train */
1471  TYPDAB_PACKETS psc_dabacqctrl = ((readindx + s) == centerread && echo == 0) ? dabacqctrl : DABOFF;
1472  loaddab(current_wf_pulse, slice, 0, DABSTORE, 0, psc_dabacqctrl, PSD_LOAD_DAB_ALL);
1473  } else {
1474  loaddab_hub_r1(current_wf_pulse, slice, n_readouts_per_blip * storeecho + s, DABSTORE, kyview + 1 /* GE's views are 1-based */, 0, currentR1, dabacqctrl, PSD_LOAD_DAB_ALL_WITH_HUB_R1);
1475  }
1476 
1477  } /* for s */
1478 #endif
1479 
1480  } /* per acq window (readout lobe) */
1481 
1482 } /* ks_scan_epi_loadecho() */
int R
Definition: KSFoundation.h:1723
WF_PULSE * echo
Definition: KSFoundation.h:846
int R_ky
Definition: KSFoundation.h:1940
LONG override_R1
Definition: KSFoundation.h:845
KS_PHASER blipphaser
Definition: KSFoundation.h:1937
s16 ky
Definition: KSFoundation.h:1750
KS_TRAP grad
Definition: KSFoundation.h:1561
KS_BASE base
Definition: KSFoundation.h:839
int etl
Definition: KSFoundation.h:1941
int pscR1
KS_READTRAP read
Definition: KSFoundation.h:1932
Definition: KSFoundation.h:2329
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
int epi_readout_mode
Definition: KSFoundation.h:1939
KS_DESCRIPTION description
Definition: KSFoundation.h:668
int time2center
Definition: KSFoundation.h:1944
int compressed_bam
Definition: KSFoundation.h:1947
KS_READ acq
Definition: KSFoundation.h:1549
int duration
Definition: KSFoundation.h:673
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ks_set_opcode()

void ks_set_opcode ( WF_PULSE_ADDR  echo,
short  opcode 
)

ADDTITLEHERE

1487  {
1488  sspload(&opcode, echo, 1, 1, (HW_DIRECTION)TOHARDWARE, (SSP_S_ATTRIB)SSPS1);
1489 }

◆ ks_loaddab_reserved()

void ks_loaddab_reserved ( WF_PULSE_ADDR  echo,
short  state,
short  resampler_index 
)

ADDTITLEHERE

Parameters
[in]echoADDTEXTHERE
[in]stateADDTEXTHERE
[in]resampler_indexADDTEXTHERE
Returns
void
1494  {
1495  #ifdef IPG
1496  sspload(&state, echo, 28, 1, (HW_DIRECTION)TOHARDWARE, (SSP_S_ATTRIB)SSPS1);
1497  sspload(&resampler_index, echo, 29, 1, (HW_DIRECTION)TOHARDWARE, (SSP_S_ATTRIB)SSPS1);
1498 #endif
1499 }

◆ ks_loaddab()

void ks_loaddab ( WF_PULSE_ADDR  echo,
const char *  dab_array 
)

ADDTITLEHERE

Parameters
[in]echoADDTEXTHERE
[in]dab_arrayADDTEXTHERE
Returns
void
1504  {
1505  int i;
1506  static const int dab_indices[KS_DABARRAY_AVAILABLE_BYTES] = {2,3,4,5,6,7,14,15,16,17,18,19,20,21,22,23,24,25,26,27}; /* 20 */
1507 
1508  if (!custom_dab_array) {
1509  return;
1510  }
1511  short dabbyte;
1512  for (i = 0; i < KS_DABARRAY_AVAILABLE_BYTES; i++) { /* KS_DABARRAY_AVAILABLE_BYTES = 20 */
1513  dabbyte = custom_dab_array[i];
1514 #ifdef IPG
1515  sspload(&dabbyte, echo, dab_indices[i], 1, (HW_DIRECTION)TOHARDWARE, (SSP_S_ATTRIB)SSPS1);
1516 #else
1517  (void) dabbyte;
1518  (void) dab_indices;
1519 #endif
1520  }
1521 
1522 } /* ks_loaddab() */
#define KS_DABARRAY_AVAILABLE_BYTES
Definition: KSFoundation.h:1839

◆ ks_loaddab_full()

void ks_loaddab_full ( WF_PULSE_ADDR  echo,
const char *  custom_dab_array 
)

ADDTITLEHERE

Parameters
[in]echoADDTEXTHERE
[in]custom_dab_arrayADDTEXTHERE
Returns
void
1527  {
1528  int i;
1529 
1530  if (!custom_dab_array) {
1531  return;
1532  }
1533  static const int dab_indices_full[KS_DABARRAY_FULL_LENGTH] = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29};
1534 
1535  for (i=0; i<KS_DABARRAY_FULL_LENGTH; i++){
1536  short dabbyte = custom_dab_array[i];
1537 #ifdef IPG
1538  sspload(&dabbyte, echo, dab_indices_full[i], 1, (HW_DIRECTION)TOHARDWARE, (SSP_S_ATTRIB)SSPS1);
1539 #else
1540  (void) dabbyte;
1541  (void) dab_indices_full;
1542 #endif
1543  }
1544 }
#define KS_DABARRAY_FULL_LENGTH
Definition: KSFoundation.h:1837

◆ ks_get_wf_pulse()

WF_PULSE_ADDR ks_get_wf_pulse ( KS_ECHOTRAIN echotrain,
const int  readout_index 
)

ADDTITLEHERE

Parameters
[in]echotrainADDTEXTHERE
[in]readout_indexADDTEXTHERE
Return values
WF_PULSE_ADDR
1549  {
1550  int object_index = echotrain->controls[readout_index].pg.object_index;
1551  int instance_index = echotrain->controls[readout_index].pg.instance_index;
1552  KS_READ_TYPE type = echotrain->controls[readout_index].pg.read_type;
1553  if (type == KS_READ_TRAP) {
1554  return &echotrain->readtraps[object_index].acq.echo[instance_index];
1555  } else {
1556  return &echotrain->readwaves[object_index].acq.echo[instance_index];
1557  }
1558 }
KS_READTRAP readtraps[KS_ECHOTRAIN_MAX_TRAPS]
Definition: KSFoundation.h:2016
KS_READWAVE readwaves[KS_ECHOTRAIN_MAX_WAVES]
Definition: KSFoundation.h:2017
WF_PULSE * echo
Definition: KSFoundation.h:846
int object_index
Definition: KSFoundation.h:1985
KS_READ_TYPE
The read object type, used in KS_READCONTROL_PULSEGEN
Definition: KSFoundation.h:1957
int instance_index
Definition: KSFoundation.h:1988
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_get_override_R1()

LONG ks_get_override_R1 ( KS_ECHOTRAIN echotrain,
const int  readout_index 
)

ADDTITLEHERE

Parameters
[in]echotrainADDTEXTHERE
[in]readout_indexADDTEXTHERE
Return values
LONG
1563  {
1564  int object_index = echotrain->controls[readout_index].pg.object_index;
1565  KS_READ_TYPE type = echotrain->controls[readout_index].pg.read_type;
1566  const int override_R1 = (type == KS_READ_TRAP) ?
1567  echotrain->readtraps[object_index].acq.override_R1 :
1568  echotrain->readwaves[object_index].acq.override_R1;
1569  return override_R1;
1570 }
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
LONG override_R1
Definition: KSFoundation.h:845
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_scan_acq_to_rtp()

void ks_scan_acq_to_rtp ( KS_READ read,
TYPDAB_PACKETS  dabacqctrl,
float  fatoffset 
)

Data routing control for RTP

Parameters
[in,out]readPointer to KS_READ
[in]dabacqctrlDABON or DABOFF
[in]fatoffsetFrequency offset in [Hz] for the current data acquisition window
Returns
void
1582  {
1583 #ifdef IPG
1584 
1585  WF_PULSE *echo_ptr;
1586  WF_PULSE *xtr_ptr;
1587  WF_PULSE *rba_ptr;
1588 
1589  int i;
1590  for (i = 0; i < acq->base.ngenerated; ++i) {
1591  echo_ptr = &acq->echo[i];
1592  setrfltrs((int) acq->filt.fslot, echo_ptr);
1593 
1594  getssppulse(&rba_ptr, echo_ptr, "rba", 0);
1595  getssppulse(&xtr_ptr, echo_ptr, "xtr", 0);
1596  acqctrl(dabacqctrl, (RECEIVER_SPEED_E)0, rba_ptr);
1597 
1598  setfreqphase((int)(fatoffset / TARDIS_FREQ_RES), /* freq ctrl */
1599  0, /* phase ctrl */
1600  xtr_ptr);
1601 
1602  /* TODO: Add r1 scaling here! */
1603  /*if (r1_scale != 1.0 && (rspent==L_SCAN)) {
1604  newR1 = ceil(pscR1 * r1_scale);
1605  if (newR1 > 13)
1606  newR1 = 13;
1607  else if (newR1 < 1)
1608  newR1 = 1;
1609 
1610  loaddab_hub_r1(echo_ptr, dabslice, dabecho, DABSTORE, dabview, 0, newR1, dabacqctrl, PSD_LOAD_DAB_ALL | PSD_LOAD_DAB_R1);
1611  }*/ /* if R1 change */
1612  routeDataFrameDab(echo_ptr, ROUTE_TO_RTP, cfcoilswitchmethod);
1613  }
1614 
1615 #endif
1616 
1617 }
WF_PULSE * echo
Definition: KSFoundation.h:846
KS_BASE base
Definition: KSFoundation.h:839
int cfcoilswitchmethod
FILTER_INFO filt
Definition: KSFoundation.h:843
int ngenerated
Definition: KSFoundation.h:496

◆ boffset()

STATUS boffset ( long *  offsets)

◆ ks_scan_switch_to_sequence()

void ks_scan_switch_to_sequence ( KS_SEQ_CONTROL ctrl)
1625  {
1626 #ifdef IPG
1627  if (ctrl->duration > 0) {
1628  if (ctrl->handle.offset == NULL) {
1629  ks_error("%s: ctrl->handle.offset is NULL. Missing calls to pg and KS_SEQLENGTH in pulsegen?", __FUNCTION__);
1630  } else {
1631  boffset(ctrl->handle.offset);
1632  }
1633  }
1634 #endif
1635 }
STATUS boffset(long *offsets)
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
long * offset
Definition: KSFoundation.h:1077
int duration
Definition: KSFoundation.h:1227
KS_SEQ_HANDLE handle
Definition: KSFoundation.h:1235

◆ setssitime()

STATUS setssitime ( long  )

◆ startseq()

STATUS startseq ( s16  ,
s16   
)

◆ ks_scan_playsequence()

int ks_scan_playsequence ( KS_SEQ_CONTROL ctrl)
1644  {
1645 
1646  if (ctrl->duration > 0) {
1647 
1648 #ifdef IPG
1649  {
1651  setssitime(ctrl->ssi_time / cfhwgut);
1652  startseq(0, (short) MAY_PAUSE); /* play out the sequence in real time */
1653  }
1654 #else
1655  /* HOST */
1656  ctrl->nseqinstances++;
1657 
1658  /* Register the playout to the seq. collection */
1659  if (ctrl->collection->numplayouts < KS_MAX_SEQUENCE_PLAYOUTS) {
1660  ctrl->collection->seqplayouts[ctrl->collection->numplayouts++] = ctrl;
1661  }
1662 
1663  /* Advance scaling logs for all objects */
1664  int i;
1665  for (i = 0; i < ctrl->gradrf.numrf; ++i) {
1667  if (ks_numplaced(&ctrl->gradrf.rfptr[i]->omegawave.base)) {
1669  }
1670  if (ks_numplaced(&ctrl->gradrf.rfptr[i]->thetawave.base)) {
1672  }
1673  }
1674  for (i = 0; i < ctrl->gradrf.numtrap; ++i) {
1676  }
1677  for (i = 0; i < ctrl->gradrf.numwave; ++i) {
1679  }
1680  for (i = 0; i < ctrl->gradrf.numwait; ++i) {
1682  }
1683 #endif
1684  } /* ctrl->duration > 0 */
1685 
1686  return ctrl->duration;
1687 }
STATUS startseq(s16, s16)
STATUS setssitime(long)
KS_RF * rfptr[KS_MAXUNIQUE_RF]
Definition: KSFoundation.h:1055
int numtrap
Definition: KSFoundation.h:1058
int cfhwgut
int duration
Definition: KSFoundation.h:1227
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:550
int nseqinstances
Definition: KSFoundation.h:1225
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:681
int numrf
Definition: KSFoundation.h:1056
KS_GRADRFCTRL gradrf
Definition: KSFoundation.h:1236
KS_RT_SCALE_LOG rtscaling
Definition: KSFoundation.h:755
void ks_rt_scale_log_next(KS_RT_SCALE_LOG *log)
Definition: KSFoundation_common.c:4969
#define KS_MAX_SEQUENCE_PLAYOUTS
Definition: KSFoundation.h:262
KS_WAVE thetawave
Definition: KSFoundation.h:1039
int numwait
Definition: KSFoundation.h:1064
KS_WAVE * waveptr[KS_MAXUNIQUE_WAVE]
Definition: KSFoundation.h:1059
KS_WAVE rfwave
Definition: KSFoundation.h:1037
int ks_numplaced(KS_BASE *base)
ADDTITLEHERE
Definition: KSFoundation_common.c:4838
KS_BASE base
Definition: KSFoundation.h:744
KS_WAIT * waitptr[KS_MAXUNIQUE_WAIT]
Definition: KSFoundation.h:1063
void ks_scan_switch_to_sequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1625
KS_TRAP * trapptr[KS_MAXUNIQUE_TRAP]
Definition: KSFoundation.h:1057
int ssi_time
Definition: KSFoundation.h:1226
int numwave
Definition: KSFoundation.h:1060
KS_WAVE omegawave
Definition: KSFoundation.h:1038
struct _seq_collection_s * collection
Definition: KSFoundation.h:1237

◆ ks_scan_loaddabwithindices_nex()

STATUS ks_scan_loaddabwithindices_nex ( WF_PULSE_ADDR  pulse,
LONG  slice,
LONG  echo,
LONG  view,
uint8_t  acq,
uint8_t  vol,
LONG  operation,
TYPDAB_PACKETS  acqon_flag 
)

loaddab() with extra arguments for current acquisition and image volume and current excitation (NEX)

Parameters
[in]pulsePointer to WF_PULSE in a KS_READ
[in]slice0-based temporal slice index (2D) or kz encoding step typically (3D)
[in]echo0-based echo in the echo train
[in]view1-based ky view number
[in]acq0-based acquisition index (always 0 if all slices fit in one TR)
[in]vol0-based volume index (always 0 if only one volume)
[in]operationDABSTORE, DABADD (for 2nd to last excitation)
[in]acqon_flagDABON or DABOFF
Return values
STATUSSUCCESS or FAILURE
1704  {
1705 
1706  union Indices idx;
1707  idx.c[0] = acq;
1708  idx.c[1] = vol;
1709  return loaddabwithangle(pulse, idx.i, slice, echo, operation, view, acqon_flag, PSD_LOAD_DAB_ALL);
1710 }
Definition: KSFoundation_tgt.c:1692
int view
Definition: GERequired.e:3728
uint8_t c[4]
Definition: KSFoundation_tgt.c:1693

◆ ks_scan_loaddabwithindices()

STATUS ks_scan_loaddabwithindices ( WF_PULSE_ADDR  pulse,
LONG  slice,
LONG  echo,
LONG  view,
uint8_t  acq,
uint8_t  vol,
TYPDAB_PACKETS  acqon_flag 
)

loaddab() with extra arguments for current acquisition and image volume

Parameters
[in]pulsePointer to WF_PULSE in a KS_READ
[in]slice0-based temporal slice index (2D) or kz encoding step typically (3D)
[in]echo0-based echo in the echo train
[in]view1-based ky view number
[in]acq0-based acquisition index (always 0 if all slices fit in one TR)
[in]vol0-based volume index (always 0 if only one volume)
[in]acqon_flagDABON or DABOFF
Return values
STATUSSUCCESS or FAILURE
1721  {
1722  return ks_scan_loaddabwithindices_nex(pulse, slice, echo, view, acq, vol, DABSTORE, acqon_flag);
1723 }
STATUS ks_scan_loaddabwithindices_nex(WF_PULSE_ADDR pulse, LONG slice, LONG echo, LONG view, uint8_t acq, uint8_t vol, LONG operation, TYPDAB_PACKETS acqon_flag)
loaddab() with extra arguments for current acquisition and image volume and current excitation (NEX)...
Definition: KSFoundation_tgt.c:1697
int view
Definition: GERequired.e:3728

◆ ks_scan_wait_for_rtp()

int ks_scan_wait_for_rtp ( void *  rtpmsg,
int  maxmsgsize,
int  maxwait,
KS_SEQ_CONTROL waitctrl 
)

play a wait sequence in a loop untill a RTP message is received.

Parameters
[out]rtpmsgpointer to memory that will be filled by the RTP message
[in]maxmsgsizesize in bytes of the memory pointed by rtpmsg
[in]maxwaittiming out period in [ms]
[in]waitctrlpointer to the KS_SEQ_CONTROL of a wait sequence. If NULL, the provided maxwait is ignored and a value of zero used instead.
Return values
sizeof the received message, zero if timed out
1728  {
1729  int maxplayouts;
1730  int nBytes = 0;
1731  int i;
1732  n32 packed = 1;
1733 #ifdef IPG
1734  setscantimestop();
1735 #endif
1736 
1737  maxplayouts = waitctrl ? maxwait / waitctrl->duration : 0;
1738  if (maxplayouts < 1) {
1739  waitctrl = NULL;
1740  maxplayouts = 0;
1741  }
1742 
1743  for (i = 0; i <= maxplayouts; i++) {
1744 
1745 #ifdef IPG
1746  if (i != 0 && waitctrl) {
1747  ks_scan_playsequence(waitctrl);
1748  }
1749 #endif
1750 
1751  nBytes = 0;
1752 
1753 #if defined(MGD_TGT) && defined(PSD_HW)
1754 
1755 
1756  nBytes = rtp_get_feedback_data(rtpmsg, maxmsgsize, &packed, 2, RTP_QUEUE_NEWEST); /*according to RTP_RESULT_PROMO=2, defined in lx/include/PromoCommon.h*/
1757 
1758 
1759 #endif
1760 
1761  if (nBytes>0 && !packed) {
1762  break;
1763  }
1764  }
1765 
1766 #ifdef IPG
1767  setscantimestart();
1768 #endif
1769 
1770  return nBytes;
1771 }
int32_t i
Definition: KSFoundation_tgt.c:1694
int duration
Definition: KSFoundation.h:1227
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1644

◆ ks_copy_and_reset_obj()

void ks_copy_and_reset_obj ( void *  pobj)

Create a copy of any sequence object with a KS_BASE as first member

Create a copy of the object pointed by pobj and insert it into the linked list in second position. finally reset the (base part of) original object.

It is required that pobj can be casted to (KS_BASE *), which is the pointed object should have a KS_BASE as first member. Note that other, object-specific, actions may need to be performed to finalize the reset. This includes calls to ks_instancereset_***() functions on each member of the current pobj

Parameters
[in]pobjPointer to a sequence object of some kind
Returns
void
1777  {
1778 
1779  KS_BASE *head = (KS_BASE*) pobj;
1780 
1781  /* create a copy */
1782  KS_BASE *copy = (KS_BASE*) AllocNode(head->size);
1783  memcpy(copy, head, head->size);
1784 
1785  /* link to the copy */
1786  head->next = copy;
1787 
1788  /* reset the count of generated instances */
1789  head->ngenerated = 0;
1790 }
void * next
Definition: KSFoundation.h:497
(Internal use) Structure being a part of various sequence object to keep count of instances on HOST a...
Definition: KSFoundation.h:493
int ngenerated
Definition: KSFoundation.h:496
int size
Definition: KSFoundation.h:498

◆ ks_tgt_reset_gradrfctrl()

void ks_tgt_reset_gradrfctrl ( KS_GRADRFCTRL gradrfctrl)

Clears KS_GRADRFCTRL on TGT. Called in ks_pg_trap, ks_pg_wave, and ks_pg_rf if the field is_cleared_on_tgt is false.

Parameters
gradrfctrl[pointer to KS_GRADRFCTRL]
1797  {
1798  int i = 0;
1799  for (i = 0; i < gradrfctrl->numrf; ++i) {
1800  gradrfctrl->rfptr[i] = NULL;
1801  }
1802  for (i = 0; i < gradrfctrl->numtrap; ++i) {
1803  gradrfctrl->trapptr[i] = NULL;
1804  }
1805  for (i = 0; i < gradrfctrl->numwave; ++i) {
1806  gradrfctrl->waveptr[i] = NULL;
1807  }
1808  for (i = 0; i < gradrfctrl->numacq; ++i) {
1809  gradrfctrl->readptr[i] = NULL;
1810  }
1811  for (i = 0; i < gradrfctrl->numwait; ++i) {
1812  gradrfctrl->waitptr[i] = NULL;
1813  }
1814  gradrfctrl->numrf = 0;
1815  gradrfctrl->numtrap = 0;
1816  gradrfctrl->numwave = 0;
1817  gradrfctrl->numacq = 0;
1818  gradrfctrl->numwait = 0;
1819  gradrfctrl->is_cleared_on_tgt = TRUE;
1820 }
KS_RF * rfptr[KS_MAXUNIQUE_RF]
Definition: KSFoundation.h:1055
int numtrap
Definition: KSFoundation.h:1058
int32_t i
Definition: KSFoundation_tgt.c:1694
int numrf
Definition: KSFoundation.h:1056
int numwait
Definition: KSFoundation.h:1064
KS_WAVE * waveptr[KS_MAXUNIQUE_WAVE]
Definition: KSFoundation.h:1059
int is_cleared_on_tgt
Definition: KSFoundation.h:1065
KS_WAIT * waitptr[KS_MAXUNIQUE_WAIT]
Definition: KSFoundation.h:1063
KS_TRAP * trapptr[KS_MAXUNIQUE_TRAP]
Definition: KSFoundation.h:1057
int numwave
Definition: KSFoundation.h:1060
KS_READ * readptr[KS_MAXUNIQUE_READ]
Definition: KSFoundation.h:1061
int numacq
Definition: KSFoundation.h:1062

◆ ks_show_clock()

void ks_show_clock ( FLOAT  scantime)

Show the clock in the UI with the remaining scan time

1829  {
1830 #ifdef IPG
1831  setscantimestop();
1832  setscantimeimm(PSD_CLOCK_NORM, (float)scantime, piviews, (float)pitslice, opslicecnt);
1833  setscantimestart();
1834 #endif
1835 }
int piviews
int opslicecnt
Definition: KSFoundation_tgt.c:1827
float pitslice

◆ 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 }

Variable Documentation

◆ cfreceiveroffsetfreq

int cfreceiveroffsetfreq

◆ rspent

int rspent

◆ pscR1

int pscR1

◆ cfcoilswitchmethod

int cfcoilswitchmethod

◆ rsprot

long rsprot[TRIG_ROT_MAX][9]

◆ cfhwgut

int cfhwgut

◆ opslicecnt

int opslicecnt

◆ piviews

int piviews

◆ pitslice

float pitslice