KSFoundation  [October2024]
A platform for structured EPIC programming on GE MR systems
Feature module: Propeller (ksprop.[h,cc])

Data Structures

struct  KSPROP2_METADATA
 
struct  KSPROP_DESIGN
 
struct  KSPROP_STATE
 
struct  KSPROP_SETTINGS
 

Macros

#define KSPROP_MAXBLADES   256
 
#define GOLDEN_SECTION   1.618
 
#define KSPROP2_INIT_METADATA   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 
#define KSPROP_INIT_DESIGN   {KSPROP_LINEAR_ANGLE, KSPROP_LOOPMODE_INNER_BLADE, KSPROP_COLORED_NOISE, 1.0f, 0, 1}
 
#define KSPROP_INIT_STATE   {KS_NOTSET, KS_INITVALUE(KSPROP_MAXBLADES,0)}
 
#define KSPROP_DEFAULT_SETTINGS   {KSPROP_INIT_DESIGN, KSPROP_INIT_STATE}
 

Enumerations

enum  KSPROP_MODE { KSPROP_GOLDEN_ANGLE = 0, KSPROP_LINEAR_ANGLE = 1 }
 
enum  KSPROP_LOOPMODE { KSPROP_LOOPMODE_INNER_PASS = 0, KSPROP_LOOPMODE_INNER_BLADE = 1 }
 
enum  KSPROP_NOISEMODE { KSPROP_COLORED_NOISE = 0, KSPROP_WHITE_NOISE_RADIAL = 1, KSPROP_WHITE_NOISE_SIMPLE_RADIAL = 2, KSPROP_WHITE_NOISE_TAILORED = 3 }
 

Functions

float ksprop_bladeangle_golden (int bladeidx)
 
STATUS ksprop_eval_bladeangles (KSPROP_SETTINGS *prop)
 
int ksprop_eval_numblades (float bladefactor, int xres, int yres, const int crosscal, const unsigned int averages)
 
STATUS ksprop_eval_validatedesign (KSPROP_SETTINGS *prop, KS_KSPACE_DESIGN *kdesign)
 
STATUS ksprop_eval (KSPROP_SETTINGS *prop, KS_KSPACE_DESIGN *kdesign)
 
STATUS eval_white_prop_readwave (KS_READWAVE *readwave, const int nsamples, const KS_WAVEFORM half_acq_waveform, const float sampling_area, const KS_KSPACE_DESIGN *kdesign, const float xcrusher_area, const char *desc)
 
float get_blade_intersection (const float theta, const float kv, const float kv_max)
 
void get_blade_intersections (float *blade_intersections, const float kv, const float kv_max, const float *blade_angles, const int nblades)
 
int num_intersections_beyond_k (const float *blade_intersections, const int nblades, const float k)
 
float radial_curve (const float ku, const float ku_max, const float kv_max)
 
void get_half_wave (KS_WAVEFORM acq_waveform, const int nsamples, const float scale, const float *blade_intersections, const int nblades, const float ku_max, const float kv_max, const float slew_limit, const float amp_limit)
 
float get_area (KS_WAVEFORM waveform, const int nsamples, const float dwell)
 
void optimize (KS_WAVEFORM acq_waveform, const int nsamples, const float *blade_intersections, const int nblades, const float ku_max, const float kv_max, const float slew_limit, const float amp_limit)
 
void ksprop_init_settings (KSPROP_SETTINGS *const prop)
 
s64 ksprop_scan_singlepass (const KSPROP_SETTINGS *prop, KSSCAN_LOOP_CONTROL *loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
s64 ksprop_scan_singlepass_inv (const KSPROP_SETTINGS *prop, KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
s64 ksprop_scan_scanloop (const KSPROP_SETTINGS *prop, KSSCAN_LOOP_CONTROL *loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
s64 ksprop_scan_scanloop_inv (const KSPROP_SETTINGS *prop, KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
void ksprop_attach_metadata (WF_PULSE_ADDR echo, const KS_DYNAMIC_STATE *dynamic, const char *custom)
 

Detailed Description

Macro Definition Documentation

◆ KSPROP_MAXBLADES

#define KSPROP_MAXBLADES   256

◆ GOLDEN_SECTION

#define GOLDEN_SECTION   1.618

◆ KSPROP2_INIT_METADATA

#define KSPROP2_INIT_METADATA   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

◆ KSPROP_INIT_DESIGN

#define KSPROP_INIT_DESIGN   {KSPROP_LINEAR_ANGLE, KSPROP_LOOPMODE_INNER_BLADE, KSPROP_COLORED_NOISE, 1.0f, 0, 1}

◆ KSPROP_INIT_STATE

#define KSPROP_INIT_STATE   {KS_NOTSET, KS_INITVALUE(KSPROP_MAXBLADES,0)}

◆ KSPROP_DEFAULT_SETTINGS

#define KSPROP_DEFAULT_SETTINGS   {KSPROP_INIT_DESIGN, KSPROP_INIT_STATE}

Enumeration Type Documentation

◆ KSPROP_MODE

Enumerator
KSPROP_GOLDEN_ANGLE 
KSPROP_LINEAR_ANGLE 
59 } KSPROP_MODE;
Definition: ksprop.h:58
Definition: ksprop.h:57
KSPROP_MODE
Definition: ksprop.h:57

◆ KSPROP_LOOPMODE

Enumerator
KSPROP_LOOPMODE_INNER_PASS 
KSPROP_LOOPMODE_INNER_BLADE 
Definition: ksprop.h:61
Definition: ksprop.h:62
KSPROP_LOOPMODE
Definition: ksprop.h:61

◆ KSPROP_NOISEMODE

Enumerator
KSPROP_COLORED_NOISE 
KSPROP_WHITE_NOISE_RADIAL 
KSPROP_WHITE_NOISE_SIMPLE_RADIAL 
KSPROP_WHITE_NOISE_TAILORED 
Definition: ksprop.h:67
Definition: ksprop.h:65
Definition: ksprop.h:68
Definition: ksprop.h:66
KSPROP_NOISEMODE
Definition: ksprop.h:65

Function Documentation

◆ ksprop_bladeangle_golden()

float ksprop_bladeangle_golden ( int  bladeidx)
30  {
31  /* golden angle with crosscal */
32 
33  /* for each pair of blades the first will follow increments of the golden section of 90°
34  the second will be at +90° from the first to allow cross calibration.
35  */
36  int pairidx = bladeidx/2;
37 
38  /* it seems VxWorks implementation of fmod is broken... */
39  float linear_angle = 90.0f*pairidx/GOLDEN_SECTION;
40  int num_quadrants = ((int)linear_angle) / 90;
41  float base_angle = linear_angle - 90.0f*num_quadrants;
42 
43  return base_angle + (bladeidx%2 ? 90.0f : 0);
44 
45 } /* ksprop_bladeangle_golden() */
#define GOLDEN_SECTION
Definition: ksprop.h:25

◆ ksprop_eval_bladeangles()

STATUS ksprop_eval_bladeangles ( KSPROP_SETTINGS prop)
50  {
51 
52  const unsigned int n_averages = prop->design.averages;
53  const unsigned int n_unique_blades = prop->state.nblades / n_averages;
54  if (n_unique_blades == 0) {
55  return KS_THROW("Requested 0 blades");
56  }
57  if (n_averages * n_unique_blades > KSPROP_MAXBLADES) {
58  return KS_THROW("Request too many blades (%d > %d)", n_averages * n_unique_blades, KSPROP_MAXBLADES);
59  }
60 
61  const float delta_theta = 180.0f / n_unique_blades;
62  unsigned int avg, bladeidx;
63 
64  for (bladeidx = 0; bladeidx < n_unique_blades; bladeidx++) {
65  switch (prop->design.mode) {
67  for (avg = 0; avg < n_averages; avg++) {
68  prop->state.angle[bladeidx*n_averages + avg] = ksprop_bladeangle_golden(bladeidx);
69  }
70  break;
72  if (prop->design.crosscal) {
73  const float base_angle = delta_theta/2.0f * bladeidx;
74  for (avg = 0; avg < n_averages; avg++) {
75  prop->state.angle[bladeidx*n_averages + avg] = base_angle;
76  }
77  bladeidx++;
78  for (avg = 0; avg < n_averages; avg++) {
79  prop->state.angle[bladeidx*n_averages + avg] = base_angle + 90.0f;
80  }
81  } else {
82  for (avg = 0; avg < n_averages; avg++) {
83  prop->state.angle[bladeidx*n_averages + avg] = delta_theta * bladeidx;
84  }
85  }
86  break;
87  default:
88  break;
89  }
90  }
91  return SUCCESS;
92 
93 } /* ksprop_eval_bladeangles() */
KSPROP_STATE state
Definition: ksprop.h:91
KSPROP_MODE mode
Definition: ksprop.h:72
Definition: ksprop.h:58
#define KSPROP_MAXBLADES
Definition: ksprop.h:23
float ksprop_bladeangle_golden(int bladeidx)
Definition: ksprop.cc:30
Definition: ksprop.h:57
int crosscal
Definition: ksprop.h:76
unsigned int averages
Definition: ksprop.h:77
KSPROP_DESIGN design
Definition: ksprop.h:90
int nblades
Definition: ksprop.h:83
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
float angle[KSPROP_MAXBLADES]
Definition: ksprop.h:84

◆ ksprop_eval_numblades()

int ksprop_eval_numblades ( float  bladefactor,
int  xres,
int  yres,
const int  crosscal,
const unsigned int  averages 
)
98  {
99 
100  float nyquistblades = (float) (xres) * PI / (2 * yres);
101  if (xres == yres)
102  nyquistblades = 1;
103  else if ((float) xres / 1.5 < yres)
104  nyquistblades = 2;
105  else if ((float) xres / 2 < yres)
106  nyquistblades = 3;
107 
108  int numblades = (int) (bladefactor * nyquistblades + 0.5); /* round up*/
109  if ((crosscal == TRUE) && (numblades % 2)) {
110  numblades++;
111  }
112 
113  numblades *= averages;
114 
115  return numblades > 0 ? numblades : 1;
116 
117 } /* ksprop_eval_numblades() */

◆ ksprop_eval_validatedesign()

STATUS ksprop_eval_validatedesign ( KSPROP_SETTINGS prop,
KS_KSPACE_DESIGN kdesign 
)
122  {
123  /* This check is disabled for now to allow SMS with ksneuromix.
124 
125  if (!areSame(kdesign->fov[XGRAD], kdesign->fov[YGRAD])) {
126  return KS_THROW("Rectangular FOV is not compatible with PROPELLER");
127  }
128  */
129 
130  if ((prop->design.mode == KSPROP_GOLDEN_ANGLE) && (prop->design.crosscal == FALSE)) {
131  return KS_THROW("KSPROP_DESIGN Golden angle ordering must be used in combination with crosscal");
132  }
133 
134  if (prop->design.averages <= 0) {
135  return KS_THROW("KSPROP_DESIGN averages is %d", prop->design.averages);
136  }
137 
138  return SUCCESS;
139 
140 } /* ksprop_eval_validatedesign() */
KSPROP_MODE mode
Definition: ksprop.h:72
Definition: ksprop.h:57
int crosscal
Definition: ksprop.h:76
unsigned int averages
Definition: ksprop.h:77
KSPROP_DESIGN design
Definition: ksprop.h:90
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksprop_eval()

STATUS ksprop_eval ( KSPROP_SETTINGS prop,
KS_KSPACE_DESIGN kdesign 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
propADDTEXTHERE
kdesignADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
145  {
146  STATUS status;
147  status = ksprop_eval_validatedesign(prop, kdesign);
148  KS_RAISE(status);
149 
151  kdesign->res[XGRAD],
152  kdesign->res[YGRAD],
153  prop->design.crosscal,
154  prop->design.averages);
155  status = ksprop_eval_bladeangles(prop);
156  KS_RAISE(status);
157 
158  return SUCCESS;
159 
160 } /* ksprop_eval() */
KSPROP_STATE state
Definition: ksprop.h:91
STATUS ksprop_eval_bladeangles(KSPROP_SETTINGS *prop)
Definition: ksprop.cc:50
int ksprop_eval_numblades(float bladefactor, int xres, int yres, const int crosscal, const unsigned int averages)
Definition: ksprop.cc:98
int crosscal
Definition: ksprop.h:76
#define KS_RAISE(status)
Definition: KSFoundation.h:190
unsigned int averages
Definition: ksprop.h:77
STATUS ksprop_eval_validatedesign(KSPROP_SETTINGS *prop, KS_KSPACE_DESIGN *kdesign)
Definition: ksprop.cc:122
KSPROP_DESIGN design
Definition: ksprop.h:90
int nblades
Definition: ksprop.h:83
float bladefactor
Definition: ksprop.h:75
int res[3]
Definition: ksdesign.h:80

◆ eval_white_prop_readwave()

STATUS eval_white_prop_readwave ( KS_READWAVE readwave,
const int  nsamples,
const KS_WAVEFORM  half_acq_waveform,
const float  sampling_area,
const KS_KSPACE_DESIGN kdesign,
const float  xcrusher_area,
const char *  desc 
)
165  {
166  STATUS status;
167 
168  /* eval waveform to wave */
169  KS_WAVE acq_wave;
170  status = ks_eval_wave(&acq_wave, desc, nsamples, GRAD_UPDATE_TIME * nsamples, half_acq_waveform);
171  KS_RAISE(status);
172 
173  /* Scale amplitude to get prescribed area */
174  ks_wave_multiplyval(&acq_wave, sampling_area / acq_wave.area);
175 
176  /* mirror and append half wave */
177  KS_WAVE rightside = acq_wave;
178  status = ks_eval_mirrorwave(&acq_wave);
179  KS_RAISE(status);
180  status = ks_eval_append_two_waves(&acq_wave, &rightside);
181  KS_RAISE(status);
182 
183  readwave->res = kdesign->res[XGRAD];
184  readwave->fov = kdesign->fov[XGRAD];
185  readwave->nover = kdesign->nover[XGRAD];
186  status = ks_eval_readwave(readwave, &acq_wave, xcrusher_area, xcrusher_area, 1, KS_CRUSHER_STRATEGY_FASTEST, KS_CRUSHER_STRATEGY_FASTEST);
187  KS_RAISE(status);
188 
189  return SUCCESS;
190 
191 } /* eval_white_prop_readwave() */
STATUS ks_eval_readwave(KS_READWAVE *readwave, KS_WAVE *acq_wave, float pre_crusher_area, float post_crusher_area, int flag_symmetric_padding, ks_enum_crusher_strategy pre_strategy, ks_enum_crusher_strategy post_strategy)
A wrapper of ks_eval_readwave_constrained
Definition: KSFoundation_host.c:1725
float fov
Definition: KSFoundation.h:1610
STATUS ks_eval_append_two_waves(KS_WAVE *first_wave, KS_WAVE *second_wave) WARN_UNUSED_RESULT
Definition: KSFoundation_host.c:4438
int nover[3]
Definition: ksdesign.h:82
Core sequence object making arbitrary waveforms on any board (using float data format)
Definition: KSFoundation.h:743
STATUS ks_eval_mirrorwave(KS_WAVE *wave)
Flips the contents of the KS_WAVEFORM in a KS_WAVE object
Definition: KSFoundation_host.c:2140
float area
Definition: KSFoundation.h:757
#define KS_RAISE(status)
Definition: KSFoundation.h:190
Definition: KSFoundation.h:2362
STATUS ks_eval_wave(KS_WAVE *wave, const char *const desc, const int res, const int duration, const KS_WAVEFORM waveform) WARN_UNUSED_RESULT
Sets up a KS_WAVE object based on a waveform (KS_WAVEFORM) in memory
Definition: KSFoundation_host.c:2029
int res
Definition: KSFoundation.h:1611
void ks_wave_multiplyval(KS_WAVE *wave, float val)
In-place scalar multiplication of a KS_WAVE
Definition: KSFoundation_common.c:1653
int res[3]
Definition: ksdesign.h:80
float fov[3]
Definition: ksdesign.h:79
int nover
Definition: KSFoundation.h:1612

◆ get_blade_intersection()

float get_blade_intersection ( const float  theta,
const float  kv,
const float  kv_max 
)
196  {
197  if areSameRelative(theta, M_PI / 2.0, 1e-4) { /* orthogonal blade */
198  return kv_max;
199  }
200  return fabs((kv_max + kv * cos(theta)) / sin(theta));
201 
202 } /* get_blade_intersection() */
#define areSameRelative(a, b, r)
Definition: KSFoundation.h:159

◆ get_blade_intersections()

void get_blade_intersections ( float *  blade_intersections,
const float  kv,
const float  kv_max,
const float *  blade_angles,
const int  nblades 
)
207  {
208  int blade;
209  for (blade = 1; blade < nblades; blade++) {
210  float theta = (blade_angles[blade] - blade_angles[0]) * M_PI / 180.0; /* [radians] */
211  blade_intersections[blade-1] = get_blade_intersection(theta, kv, kv_max);
212  }
213  qsort(blade_intersections, nblades-1, sizeof(float), ks_compare_float);
214 
215 } /* get_blade_intersections() */
int ks_compare_float(const void *v1, const void *v2)
Compares two floats
Definition: KSFoundation_common.c:4201
float get_blade_intersection(const float theta, const float kv, const float kv_max)
Definition: ksprop.cc:196

◆ num_intersections_beyond_k()

int num_intersections_beyond_k ( const float *  blade_intersections,
const int  nblades,
const float  k 
)
220  {
221  int res = 1;
222  int intersection;
223  for (intersection=0; intersection < nblades-1; intersection++) {
224  if (blade_intersections[intersection] > k) {
225  res++;
226  }
227  }
228  return res;
229 
230 } /* num_intersections_beyond_k() */

◆ radial_curve()

float radial_curve ( const float  ku,
const float  ku_max,
const float  kv_max 
)
236  {
237  if (fabs(ku) > kv_max) {
238  return ku_max / kv_max * asin(kv_max / fabs(ku));
239  } else {
240  return ku_max / kv_max * (M_PI / 2.0);
241  }
242 
243 } /* radial_curve() */

◆ get_half_wave()

void get_half_wave ( KS_WAVEFORM  acq_waveform,
const int  nsamples,
const float  scale,
const float *  blade_intersections,
const int  nblades,
const float  ku_max,
const float  kv_max,
const float  slew_limit,
const float  amp_limit 
)
248  {
249  float dGmax = slew_limit * GRAD_UPDATE_TIME; /* [G/cm] */
250  float ku = ku_max;
251  float G;
252  int sample;
253  for (sample = (nsamples-1); sample >= 0; sample--) { /* Go k-space edge->center (conservative approach) */
254  if (ku > kv_max) { /* spoke */
255  if (blade_intersections == NULL) {
256  G = scale * radial_curve(ku, ku_max, kv_max); /* radial waveform */
257  } else {
258  G = scale * num_intersections_beyond_k(blade_intersections, nblades, ku); /* tailored waveform */
259  }
260  G = FMin(2, G, amp_limit); /* respect amplitude limit */
261  if (sample < (nsamples-1)) {
262  G = FMin(2, G, acq_waveform[sample+1] + dGmax); /* respect slew limit */
263  }
264  } else { /* hub */
265  G = acq_waveform[sample+1];
266  }
267  acq_waveform[sample] = G;
268  ku -= GAM * G * GRAD_UPDATE_TIME * 1e-4; /* [1/m] = [Hz/G] * [G/cm] * [us] * [1e-4] */
269  }
270 
271 } /* get_half_wave() */
int num_intersections_beyond_k(const float *blade_intersections, const int nblades, const float k)
Definition: ksprop.cc:220
float radial_curve(const float ku, const float ku_max, const float kv_max)
Definition: ksprop.cc:236
STATUS scale(FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)

◆ get_area()

float get_area ( KS_WAVEFORM  waveform,
const int  nsamples,
const float  dwell 
)
277  {
278  float area = 0.0;
279  int sample;
280  for (sample=0; sample<nsamples; sample++) {
281  area += waveform[sample];
282  }
283  return area * dwell;
284 
285 } /* get_area() */

◆ optimize()

void optimize ( KS_WAVEFORM  acq_waveform,
const int  nsamples,
const float *  blade_intersections,
const int  nblades,
const float  ku_max,
const float  kv_max,
const float  slew_limit,
const float  amp_limit 
)
291  {
292  float prev_scale = ku_max / (GAM * 2 * nsamples * GRAD_UPDATE_TIME * 1e-4); /* [G/cm] = [1/m] / ([Hz/G] * [us] * [1e-4]) */
293  get_half_wave(acq_waveform, nsamples, prev_scale, blade_intersections, nblades, ku_max, kv_max, slew_limit, amp_limit);
294  float area = get_area(acq_waveform, nsamples, (float) GRAD_UPDATE_TIME); /* [G/cm*us] */
295  float target_area = ku_max / (GAM * 1e-4); /* [1/m] / ([Hz/G] * [1e-4]) = [G/cm*us] */
296  float err = area - target_area;
297  float scale = prev_scale * 0.99;
298  int i = 0;
299  int max_iter = 20;
300  float tol = 1e-5;
301  while ((i < max_iter) && (fabs(scale-prev_scale)>tol)) {
302  get_half_wave(acq_waveform, nsamples, scale, blade_intersections, nblades, ku_max, kv_max, slew_limit, amp_limit);
303  area = get_area(acq_waveform, nsamples, (float) GRAD_UPDATE_TIME); /* [G/cm*us] */
304  float prev_err = err;
305  err = area - target_area;
306  float err_dev = (err-prev_err) / (scale-prev_scale); /* derivative of error */
307  prev_scale = scale;
308  scale -= err/err_dev;
309  i++;
310  }
311 
312 } /* optimize() */
float get_area(KS_WAVEFORM waveform, const int nsamples, const float dwell)
Definition: ksprop.cc:277
STATUS scale(FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)
void get_half_wave(KS_WAVEFORM acq_waveform, const int nsamples, const float scale, const float *blade_intersections, const int nblades, const float ku_max, const float kv_max, const float slew_limit, const float amp_limit)
Definition: ksprop.cc:248

◆ ksprop_init_settings()

void ksprop_init_settings ( KSPROP_SETTINGS *const  prop)

ADDTITLEHERE

ADDDESCHERE

Parameters
propADDTEXTHERE
Returns
void
457  {
458  KSPROP_SETTINGS default_settings = KSPROP_DEFAULT_SETTINGS;
459  *prop = default_settings;
460 
461 } /* ksprop_init_settings() */
Definition: ksprop.h:89
#define KSPROP_DEFAULT_SETTINGS
Definition: ksprop.h:94

◆ ksprop_scan_singlepass()

s64 ksprop_scan_singlepass ( const KSPROP_SETTINGS prop,
KSSCAN_LOOP_CONTROL loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
propADDTEXTHERE
loopctrlADDTEXTHERE
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceKS_CORESLICETIME playing one or more sequence modules for a single playout
Return values
timeDuration in [us] to play out the scope of the function in real time
474  {
475  s64 time = 0;
476 
477  const int dda = loopctrl->dda;
478 
479  for (dynamic->vol = 0; dynamic->vol < prop->state.nblades; dynamic->vol++) {
480 
481  ks_mat4_setgeometry(dynamic->Mlogical, 0, 0, 0, 0, 0, -prop->state.angle[dynamic->vol]);
482 
483  time += ksscan_acqloop(loopctrl, dynamic, coreslice);
484 
485  /* Play dummies only once */
486  loopctrl->dda = 0;
487 
488  /* TODO: put this here or in scanloop? */
489  if (loopctrl->play_endofpass) {
490  time += GEReq_endofpass();
491  }
492 
493  }
494 
495  /* restore #dummies */
496  loopctrl->dda = dda;
497 
498  return time; /* in [us] */
499 
500 } /* ksprop_scan_singlepass() */
KSPROP_STATE state
Definition: ksprop.h:91
int play_endofpass
Definition: ksscan.h:188
void ks_mat4_setgeometry(KS_MAT4x4 lhs, float x, float y, float z, float xr, float yr, float zr)
Set geometry for KS_MAT4x4
Definition: KSFoundation_common.c:3800
s64 ksscan_acqloop(const KSSCAN_LOOP_CONTROL *loop_control, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
Executes all loops for a single pass/acquisition
Definition: ksscan.cc:504
int dda
Definition: ksscan.h:185
int nblades
Definition: ksprop.h:83
int GEReq_endofpass()
Sets SSP word in sequence off_GEpass() to trigger data (Pfile) writing and reconstruction
Definition: GERequired.e:3621
float angle[KSPROP_MAXBLADES]
Definition: ksprop.h:84

◆ ksprop_scan_singlepass_inv()

s64 ksprop_scan_singlepass_inv ( const KSPROP_SETTINGS prop,
KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
propADDTEXTHERE
inv_loopctrlADDTEXTHERE
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceKS_CORESLICETIME playing one or more sequence modules for a single playout
[in]irsliceKS_CORESLICETIME playing an inversion (and optionally more) modules for a single inversion slice playout
Return values
timeDuration in [us] to play out the scope of the function in real time
509  {
510  s64 time = 0;
511 
512 #ifndef IPG
513  if (inv_loopctrl == NULL) {
514  KS_THROW("KSINV_LOOP_CONTROL (2nd arg) is NULL");
515  return KS_NOTSET;
516  }
517  if (inv_loopctrl->irmode == 0) {
518  KS_THROW("KSINV_LOOP_CONTROL (2nd arg) .irmode is 0");
519  return KS_NOTSET;
520  }
521 #endif
522 
523  const int dda = inv_loopctrl->loopctrl.dda;
524 
525  for (dynamic->vol = 0; dynamic->vol < prop->state.nblades; dynamic->vol++) {
526 
527  ks_mat4_setgeometry(dynamic->Mlogical, 0, 0, 0, 0, 0, -prop->state.angle[dynamic->vol]);
528 
529  const int inv_rampup = dynamic->vol == 0;
530  const int inv_rampdown = dynamic->vol == prop->state.nblades-1;
531  time += ksinv_scan_acqloop(inv_loopctrl, dynamic,
532  coreslice, irslice,
533  inv_rampup, inv_rampdown);
534 
535  /* Play dummies only once */
536  inv_loopctrl->loopctrl.dda = 0;
537 
538  /* TODO: put this here or in scanloop? */
539  if (inv_loopctrl->loopctrl.play_endofpass) {
540  time += GEReq_endofpass();
541  }
542 
543  }
544 
545  /* restore #dummies */
546  inv_loopctrl->loopctrl.dda = dda;
547 
548  return time; /* in [us] */
549 
550 } /* ksprop_scan_singlepass_inv() */
KSPROP_STATE state
Definition: ksprop.h:91
#define KS_NOTSET
Definition: KSFoundation.h:115
int irmode
Definition: ksinversion.h:103
int play_endofpass
Definition: ksscan.h:188
void ks_mat4_setgeometry(KS_MAT4x4 lhs, float x, float y, float z, float xr, float yr, float zr)
Set geometry for KS_MAT4x4
Definition: KSFoundation_common.c:3800
int dda
Definition: ksscan.h:185
int nblades
Definition: ksprop.h:83
s64 ksinv_scan_acqloop(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), const int inv_rampup, const int inv_rampdown)
Plays out one pass/acquisition for an inversion scan
Definition: ksinversion.cc:1197
int GEReq_endofpass()
Sets SSP word in sequence off_GEpass() to trigger data (Pfile) writing and reconstruction
Definition: GERequired.e:3621
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
float angle[KSPROP_MAXBLADES]
Definition: ksprop.h:84

◆ ksprop_scan_scanloop()

s64 ksprop_scan_scanloop ( const KSPROP_SETTINGS prop,
KSSCAN_LOOP_CONTROL loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
propADDTEXTHERE
loopctrlADDTEXTHERE
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceKS_CORESLICETIME playing one or more sequence modules for a single playout
Return values
timeDuration in [us] to play out the scope of the function in real time
558  {
559  s64 time = 0;
560 
561  KS_DYNAMIC_STATE default_dynamic = KS_INIT_DYNAMIC_STATE;
562 
563  if (!dynamic) {
564  dynamic = &default_dynamic;
565  }
566 
567  /* TODO: Restore this option? */
568  /* (prop->design.loop_mode == KSPROP_LOOPMODE_INNER_PASS) */
569 
570  /* Inner loop over blades */
571  for (dynamic->pass = 0; dynamic->pass < loopctrl->slicetiming.slice_plan.npasses; dynamic->pass++) {
572 
573  time += ksprop_scan_singlepass(prop, loopctrl, dynamic, coreslice);
574 
575  /* TODO: put this here or in passloop? */
577 
578  } /* pass loop */
579 
580  return time; /* in [us] */
581 
582 } /* ksprop_scan_scanloop() */
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int npasses
Definition: KSFoundation.h:1319
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
void ks_plot_slicetime_endofpass(KS_PLOT_PASS_MODE pass_mode)
ADDTITLEHERE
Definition: KSFoundation_common.c:4286
Definition: KSFoundation.h:409
s64 ksprop_scan_singlepass(const KSPROP_SETTINGS *prop, KSSCAN_LOOP_CONTROL *loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
ADDTITLEHERE
Definition: ksprop.cc:471
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42

◆ ksprop_scan_scanloop_inv()

s64 ksprop_scan_scanloop_inv ( const KSPROP_SETTINGS prop,
KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
propADDTEXTHERE
inv_loopctrlADDTEXTHERE
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceKS_CORESLICETIME playing one or more sequence modules for a single playout
[in]irsliceKS_CORESLICETIME playing an inversion (and optionally more) modules for a single inversion slice playout. Can be NULL
Return values
timeDuration in [us] to play out the scope of the function in real time
591  {
592  s64 time = 0;
593 
594  KS_DYNAMIC_STATE default_dynamic = KS_INIT_DYNAMIC_STATE;
595 
596  if (!dynamic) {
597  dynamic = &default_dynamic;
598  }
599 
600  /* TODO: Restore this option? */
601  /* (prop->design.loop_mode == KSPROP_LOOPMODE_INNER_PASS) */
602 
603  /* Inner loop over blades */
604  for (dynamic->pass = 0; dynamic->pass < inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses; dynamic->pass++) {
605 
606  time += ksprop_scan_singlepass_inv(prop, inv_loopctrl, dynamic, coreslice, irslice);
607 
608  /* TODO: put this here or in passloop? */
610 
611  } /* pass loop */
612 
613  return time; /* in [us] */
614 
615 } /* ksprop_scan_scanloop_inv() */
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int npasses
Definition: KSFoundation.h:1319
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
s64 ksprop_scan_singlepass_inv(const KSPROP_SETTINGS *prop, KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
ADDTITLEHERE
Definition: ksprop.cc:505
void ks_plot_slicetime_endofpass(KS_PLOT_PASS_MODE pass_mode)
ADDTITLEHERE
Definition: KSFoundation_common.c:4286
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
Definition: KSFoundation.h:409
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42

◆ ksprop_attach_metadata()

void ksprop_attach_metadata ( WF_PULSE_ADDR  echo,
const KS_DYNAMIC_STATE *  dynamic,
const char *  custom 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
[in]echoADDTEXTHERE
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
customADDTEXTHERE
Returns
void