Пример #1
0
void calc_grad_duty(double time)
   {
   double  gradenergy[3],gradduty[3];
   double  mult=1.0;
   double  currentlimit,RMScurrentlimit;
   double  sglduty,dutylimit;
   int     checksilent,r,nrcvrs,arraydim,error=0;
   char    rcvrs[MAXSTR];

   currentlimit = getval("currentlimit");
   RMScurrentlimit = getval("RMScurrentlimit");
   getRealSetDefault(GLOBAL, "sglduty", &sglduty,0.0);
   dutylimit = RMScurrentlimit/currentlimit;
   checksilent = option_check("checksilent");

   /* Adjust array dimenstion for multiple receivers */
   nrcvrs = 0;
   getstr("rcvrs",rcvrs);
   arraydim = getvalnwarn("arraydim");
   for (r = 0; r < strlen(rcvrs); r++) {
     if (rcvrs[r] == 'y') nrcvrs++;
   }
   arraydim /= nrcvrs;

   if (seqcon[2] == 'c')
     mult *= nv;
   if (seqcon[3] == 'c')
     mult *= nv2;

   if (!checkflag)
     mult *= arraydim;

   getgradpowerintegral(gradenergy);
   gradduty[0] = sqrt(gradenergy[0]/(mult*time));
   gradduty[1] = sqrt(gradenergy[1]/(mult*time));
   gradduty[2] = sqrt(gradenergy[2]/(mult*time));

   if (sglduty && ((checkflag && !checksilent) || (!checksilent && ix == arraydim))) {
     text_message("Grad energy X: %.3g    Grad energy Y: %.3g    Grad energy Z: %.3g",gradenergy[0],gradenergy[1],gradenergy[2]);
     text_message("Grad duty X: %.3g%%    Grad duty Y: %.3g%%    Grad duty Z: %.3g%%",100*gradduty[0],100*gradduty[1],100*gradduty[2]);
   }

   if ((gradduty[0] > dutylimit) && ((checkflag && !checksilent) || (!checksilent && ix == arraydim))) {
     text_message("%s: X gradient duty cycle %5.1f%% exceeds allowed limit of %5.1f%%",seqfil,100*gradduty[0],100*dutylimit);
     error = 1;
   }
   if ((gradduty[1] > dutylimit) && ((checkflag && !checksilent) || (!checksilent && ix == arraydim))) {
     text_message("%s: Y gradient duty cycle %5.1f%% exceeds allowed limit of %5.1f%%",seqfil,100*gradduty[1],100*dutylimit);
     error = 1;
   }
   if ((gradduty[2] > dutylimit) && ((checkflag && !checksilent) || (!checksilent && ix == arraydim))) {
     text_message("%s: Z gradient duty cycle %5.1f%% exceeds allowed limit of %5.1f%%",seqfil,100*gradduty[2],100*dutylimit);
     error = 1;
   }
   if (error) {
     if (sglduty)
       warn_message("%s: Duty cycle exceeds allowed limit",seqfil);
     else
       abort_message("%s: Duty cycle exceeds allowed limit",seqfil);
   }
   }
Пример #2
0
void calc_readout_rampsamp(READOUT_GRADIENT_T *grad, double *dwell, double *minskip, int *npr) {
  double this_gro, skip, skip_m0, dwint, dw, dwflat;
  double ramp_t, ramp_m0, flat_t, flat_m0, dwell_sum, rt;
  int    npro, np_ramp, np_flat;
  int    pt, pt2;
  GENERIC_GRADIENT_T gg;
  
  /* Calculate gradient amplitude based on FOV and sw */
  this_gro       = sw/grad->gamma/lro;
  grad->amp      = this_gro;

  /* Nominal dwell time is 1/sw */
  dw    = granularity(1/sw,1/epi_grad.ddrsr);
  dwflat = dw;  /* we may later end up with different dw on flat part */
  dwint = dw*grad->amp;   /* Gradient Integral per point */
  npro  = (int) np/2;

  /* Calculate the area that is skipped for phase encoding blip */
  skip    = *minskip;
  if (skip == 0)
    skip = dw + getval("aqtm")-at;                /* Need at least a dwell time at the end */

  skip_m0 = skip*(skip*grad->slewRate)/2;         /* Area of that skipped part */

  /* Calculate the ramp time */
  grad->tramp     = granularity(grad->amp/grad->slewRate,grad->resolution);
  grad->slewRate  = grad->amp/grad->tramp;

  ramp_m0 = grad->tramp*grad->amp/2;
  np_ramp = (int) ((ramp_m0 - skip_m0)/dwint);
  
  /* Check that we even need points on the flat part */
  if (np_ramp >= npro/2) {
    np_ramp = npro/2 - 1;  /* Center two points considered "flat part" */
    
    /* We may not need to go all the way to full gradient
       in order to fit all points on ramp; adjust amplitude */
    ramp_m0 = np_ramp*dwint + skip_m0;
    grad->tramp = granularity(sqrt(2*ramp_m0/grad->slewRate),grad->resolution);
    grad->amp   = grad->tramp * grad->slewRate;

    /* recalculate ramp area and np_ramp */
    ramp_m0 = grad->tramp*grad->amp/2;
    
    /* Now adjust the dwell time necessary on flat part with this amplitude */
    dwflat = granularity(dwint/grad->amp,1/epi_grad.ddrsr);
  }

  np_flat = npro - 2*np_ramp;

  /* How long must the flat part be? */
  grad->duration = granularity((np_flat-1)*dwflat,grad->resolution); 

  /* Due to rounding of gradient duration, 
     we may be able to fit more points on flat part */
  while (grad->duration - (np_flat-1)*dwflat >= 2*dwflat) {
    np_flat += 2;
    np_ramp -= 1;
  }

  /* Now add the ramp times to the total duration */
  grad->duration += 2*grad->tramp; 
  
  /* Use a generic to calculate the actual shape, ie fill in dataPoints */
  initGeneric(&gg);
  gg.amp         = grad->amp;
  gg.duration    = grad->duration;
  gg.tramp       = grad->tramp;
  gg.slewRate    = grad->slewRate;
  gg.calcFlag    = MOMENT_FROM_DURATION_AMPLITUDE_RAMP;
  gg.writeToDisk = FALSE;

  calcGeneric(&gg);

  if (gg.error != ERR_NO_ERROR) {
    printf("Temporary generic gradient: \n");
    displayGeneric(&gg);
    abort_message("Problem calculating RO gradient with ramp sampling");
  }

  grad->m0         = gg.m0;
  grad->m1         = gg.m1;
  grad->m0ref      = grad->m0/2;
  grad->numPoints  = gg.numPoints;
  free(grad->dataPoints); // release original array
  grad->dataPoints = gg.dataPoints;

  /* Recalculate the skipped part with new gradient integral */
  skip_m0 = (grad->m0 - dwint*(np/2-1))/2;
  skip = sqrt(2*skip_m0/grad->slewRate);

  /* Skip rampsampling if gradient is longer than necessary */
  if ((grad->m0-ramp_m0*2) > npro*dwint) {
    warn_message("The gradient is too long, no ramp sampling");
    for (pt = 0; pt < npro; pt++) {
      dwell[pt]  = dwflat;
    }
    *minskip = grad->tramp;
    return;
  }

  /* Calculate where we start acquisition on the ramp */
  /* Do we have extra integral on flat part? */
  flat_m0 = (grad->m0 - 2*ramp_m0) - ((np_flat-1)*dwflat*grad->amp);
  
  /* if yes, then what is the duration of this? */
  if (flat_m0 > 0)
    flat_t = (grad->duration - 2*grad->tramp) / ((np_flat - 1)*dwflat);
  else
    flat_t = 0;

  /* Double-check that gradient is long enough */
  if (flat_m0 < -1e-9)
    abort_message("Gradient integral too small %f vs %f (%f) G/cm*us", 
                   (grad->m0-2*ramp_m0)*1e6,(np_flat-1)*dwint*1e6,flat_m0*1e9);

  /* If extra integral > 2*dwint, we could move a point from each ramp up to the flat */
  if (flat_m0 > 2*dwint)
    warn_message("Gradient flat part longer than necessary with ramp sampling, check gradient calculation\n");


  /**************************************************************************/
  /* Calculate dwell times */
  /**************************************************************************/
  dwell_sum = 0;
  /* Start at top of ramp and walk down ramp */
  pt = np_ramp - 1;
  rt = grad->tramp;  

  /* Top point on ramp first, it may use a bit of time from the flat part */
  if (flat_m0 > 0) {
    ramp_m0 -= (dwint - flat_m0/2);  /* area at ramp at previous point */
    flat_t = (grad->duration - 2*grad->tramp) - ((np_flat - 1)*dwflat); /* extra duration at top */
    flat_t /= 2;  /* divide evenly between both ramps */
  }
  else {
    ramp_m0 -= dwint;  /* area at ramp at previous point */
    flat_t = 0;
  }
  ramp_t    = sqrt(2*ramp_m0/grad->slewRate); /* time at ramp at previous point */
  dwell[pt] = granularity(flat_t + (rt-ramp_t), 1/epi_grad.ddrsr);
  dwell_sum += dwell[pt];

  ramp_t = rt - (dwell[pt] - flat_t); /* correct for rounding of dwell */
  /* Do all the rest of the points on the ramp */
  for(pt = np_ramp-2; pt >= 0; pt--) {  
    rt = ramp_t;       /* remember current time */
    ramp_m0 -= dwint;  /* total area of ramp at previous point */
    if (ramp_m0 <= 0) {
      if (fabs(ramp_m0) > dwint*0.01) abort_message("problem: ramp_m0 negative %f\n",ramp_m0*1000);
      ramp_t = 0;
    }
    else ramp_t  = sqrt(2*ramp_m0/grad->slewRate);  /* time at previous point */
    dwell[pt]  = granularity(rt-ramp_t,1/epi_grad.ddrsr);
    dwell_sum += dwell[pt];

    ramp_t = rt - dwell[pt];
  }       

  skip = ramp_t;
  dwell_sum += skip;

  for (pt = np_ramp; pt < np_ramp+np_flat-1; pt++) {  /* Flat part */
    dwell[pt]  = dwflat;
    dwell_sum += dwflat;
  }

  pt2 = np_ramp-1;
  for (pt = np_ramp+np_flat-1; pt < np_ramp*2 + np_flat - 1; pt++) {
    dwell[pt] = dwell[pt2--];
    dwell_sum += dwell[pt];
  }
  /* Very last point, just set dwell = 1/sw */
  pt = np_ramp*2 + np_flat - 1;
  dwell[pt] = dw;
  dwell_sum += skip;
  
  if (fabs(dwell_sum - grad->duration) > 12.5e-9)
    warn_message("Mismatch in sum of dwells (%.3fus) vs. gradient duration (%.3fus)",
                 dwell_sum*1e6,grad->duration*1e6);


  /* Return values */
  *minskip = skip;
  *npr     = np_ramp;

  if (sgldisplay) {    
    printf("============== DEBUG DWELL  (%d, %d, %d) ===============\n",np_ramp,np_flat,np_ramp);
    dwell_sum = skip;
    for (pt = 0; pt < npro-1; pt++) {
      printf("[%3d] %3.6f\t%3.3f\t%3.6f\n",pt+1,dwell_sum*1e6,dwell[pt]*1e6,(dwell[pt]+dwell_sum)*1e6);
      dwell_sum += dwell[pt];  
    }
    printf("[%3d] %3.6f\t%3.3f\t%3.6f\n",(pt+1),dwell_sum*1e6,0.0,dwell_sum*1e6);pt++;
    printf("[%3d] %3.6f\t%3.3f\t%3.6f\n",pt+1,dwell_sum*1e6,skip*1e6,(skip+dwell_sum)*1e6);
    dwell_sum += skip;

    printf("Did we get a full gradient's worth? %.6f, %.6f\n",grad->duration*1e6,dwell_sum*1e6);
    printf("=======================================================\n");
  }
  
}
Пример #3
0
pulsesequence()
{
  /* Internal variable declarations *************************/
  double  freq90[MAXNSLICE],freq180[MAXNSLICE],freqIR[MAXNSLICE];
  int     shape90=0, shape180=0, shapeIR=0;
  double  te_delay1, te_delay2, tr_delay, ti_delay = 0;
  double  del1=0, del2=0, del3=0, del4=0;
  double  tau1=0, tau2=0, difftime=0, tetime=0;
  int     table=0;

  /* Diffusion parameters */
#define MAXDIR 1024           /* Will anybody do more than 1024 directions or b-values? */
  double roarr[MAXDIR], pearr[MAXDIR], slarr[MAXDIR];
  int    nbval,               /* Total number of bvalues*directions */
         nbro, nbpe, nbsl,
	 i;    
  double bro[MAXDIR], bpe[MAXDIR], bsl[MAXDIR], /* b-values along RO, PE, SL */
         brs[MAXDIR], brp[MAXDIR], bsp[MAXDIR], /* and the cross-terms */
	 btrace[MAXDIR],                        /* and the trace */
	 max_bval=0,
         dcrush, dgss2,       /* "delta" for crusher and gss2 gradients */
         Dro, Dcrush, Dgss2;  /* "DELTA" for readout, crusher and gss2 gradients */

  /* Real-time variables ************************************/
  int  vpe_steps  = v1;
  int  vpe_ctr    = v2;
  int  vms_slices = v3;
  int  vms_ctr    = v4;
  int  vpe_offset = v5;
  int  vpe_index  = v6;
  int  vph180     = v7;  // Phase of 180 pulse
  int  vph2       = v8;  // alternate phase of 180 on odd transients

  /*  Initialize paramaters *********************************/
  init_mri();

  /*  Check for external PE table ***************************/
  if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) {
    loadtable(petable);
    table = 1;
  }
  if ((diff[0] == 'y') && (gcrush < 4))
    warn_message("Advisory: set gcrush to higher value to avoid image artifacts");

  /* Initialize gradient structures *************************/
  init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2);
  init_rf(&p2_rf,p2pat,p2,flip2,rof2,rof2);
  init_slice(&ss_grad,"ss",thk);
  init_slice_butterfly(&ss2_grad,"ss2",thk*1.1,gcrush,tcrush);
  init_slice_refocus(&ssr_grad,"ssr");
  init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro);
  init_readout_refocus(&ror_grad,"ror");
  init_phase(&pe_grad,"pe",lpe,nv);

  /* RF Calculations ****************************************/
  calc_rf(&p1_rf,"tpwr1","tpwr1f");
  calc_rf(&p2_rf,"tpwr2","tpwr2f");
  if (p2_rf.header.rfFraction != 0.5)
    abort_message("RF pulse for refocusing (%s) must be symmetric",p2pat);

  /* Gradient calculations **********************************/
  calc_slice(&ss_grad,&p1_rf,WRITE,"gss");
  calc_slice(&ss2_grad,&p2_rf,WRITE,"gss2");
    
  calc_slice_refocus(&ssr_grad, &ss_grad, NOWRITE,"gssr");
  calc_readout(&ro_grad, WRITE, "gro","sw","at");
  ro_grad.m0ref *= grof;
  calc_readout_refocus(&ror_grad, &ro_grad, NOWRITE, "gror");

  calc_phase(&pe_grad, NOWRITE, "gpe","tpe");

  /* Equalize refocus and PE gradient durations *************/
  calc_sim_gradient(&ror_grad, &pe_grad, &ssr_grad,0,WRITE);

  /* Set up diffusion gradient */
  if (diff[0] == 'y') {
    init_generic(&diff_grad,"diff",gdiff,tdelta);
    calc_generic(&diff_grad,NOWRITE,"","");
    /* adjust duration, so tdelta is from start ramp up to start ramp down */    
    if (ix == 1) diff_grad.duration += diff_grad.tramp; 
    calc_generic(&diff_grad,WRITE,"","");
  }

  /* Min TE *************************************************/
  tau1 = ss_grad.rfCenterBack + pe_grad.duration + 4e-6 + ss2_grad.rfCenterFront;
  tau2 = ss2_grad.rfCenterBack + ror_grad.duration + ro_grad.timeToEcho + alfa;

  temin = 2*(MAX(tau1,tau2) + 2*4e-6);  /* have at least 4us between gradient events */

  /* Calculate te_delays with the current TE, then later see how diffusion fits */
  if ((minte[0] == 'y') || (te < temin)) {
    te_delay1 = temin/2 - tau1;
    te_delay2 = temin/2 - tau2;
  }
  else {
    te_delay1 = te/2 - tau1;
    te_delay2 = te/2 - tau2;
  }

  if (diff[0] =='y') {
    /* Is tDELTA long enough for RF refocusing gradient? */
    if (tDELTA < diff_grad.duration + ss2_grad.duration)
      abort_message("DELTA too short, increase to %.2fms",
        (diff_grad.duration + ss2_grad.duration)*1000+0.005);

    /* Is tDELTA too long for TE dead time? */
    difftime = tDELTA + diff_grad.duration;    // tDELTA + front & back half diff_grad
    tetime = ss2_grad.duration + te_delay1 + te_delay2;
    if (difftime > tetime) {
      temin += (difftime - tetime);
    }
  }

  /* We now know the minimum TE incl. diffusion */
  if (minte[0] == 'y') {
    te = temin;
    putvalue("te",ceil(te*1e6)*1e-6); /* round up to nearest us */
  }
  if (te < temin) {
    if (diff[0] == 'n') {
      abort_message("TE too short.  Minimum TE = %.2fms\n",temin*1000);   
    }
    else {
      abort_message("TE too short, increase to %.2fms or reduce DELTA to %.2fms",
        temin*1000,(tetime-diff_grad.duration)*1000);
    }
  }
  te_delay1 = te/2 - tau1;
  te_delay2 = te/2 - tau2;

  /* Set up delays around diffusion gradients */
  /* RF1 - del1 - diff - del2 - RF2 - del3 - diff - del4 - ACQ */
  if (diff[0] == 'y') {
    del1 = (tetime - difftime)/2;
    del4 = del1;
    del2 = te_delay1 - diff_grad.duration;
    del3 = te_delay2 - diff_grad.duration;

    if (del3 < 0.0) {             // shift diff block to right
      del1 += del3;
      del2 -= del3;
      del4 -= del3;
      del3 = 0;
    } else if (del2 < 0.0) {      // shift diff block to left
      del1 -= del2;
      del3 -= del2;
      del4 += del2;
      del2 = 0;
    }
  }
  else {  /* No diffusion */
    del1 = 0;
    del3 = 0;
    del2 = te_delay1;
    del4 = te_delay2;
  }

  /* Min TR *************************************************/   	
  trmin = (ss_grad.duration - ss_grad.rfCenterBack) + te + ro_grad.timeFromEcho;
  if (navigator[0] == 'y')
    trmin += (pe_grad.duration + ro_grad.duration);
  
  /* Optional prepulse calculations *************************/
  if (sat[0] == 'y') {
    create_satbands();
    trmin += satTime;
  }
  
  if (fsat[0] == 'y') {
    create_fatsat();
    trmin += fsatTime;
  }

  if (mt[0] == 'y') {
    create_mtc();
    trmin += mtTime;
  }

  if (ir[0] == 'y') {
    init_rf(&ir_rf,pipat,pi,flipir,rof2,rof2); 
    calc_rf(&ir_rf,"tpwri","tpwrif");
    init_slice_butterfly(&ssi_grad,"ssi",thk,gcrushir,tcrushir);
    calc_slice(&ssi_grad,&ir_rf,WRITE,"gssi");

    tau1 = ss_grad.duration - ss_grad.rfCenterBack; /* duration of ss_grad before RF center */
    ti_delay = ti - (ssi_grad.rfCenterBack + tau1);

    if (ti_delay < 0) {
      abort_message("TI too short, Minimum TI = %.2fms\n",(ti-ti_delay)*1000);
    }

    irTime = ti + ssi_grad.duration - ssi_grad.rfCenterBack;  /* time to add to TR */
    trmin += irTime;
    trmin -= tau1;  /* but subtract out ss_grad which was already included in TR */
  }

  trmin *= ns;
  if (mintr[0] == 'y'){
    tr = trmin + ns*4e-6;
    putvalue("tr",tr);
  }
  if (tr < trmin) {
    abort_message("TR too short.  Minimum TR= %.2fms\n",trmin*1000);   
  }
  tr_delay = (tr - trmin)/ns > 4e-6 ? (tr - trmin)/ns : 4e-6;


  /***************************************************/
  /* CALCULATE B VALUES ******************************/
  if (diff[0] == 'y') {
    /* Get multiplication factors and make sure they have same # elements */
    /* All this is only necessary because putCmd only work for ix==1      */
    nbro = (int) getarray("dro",roarr);  nbval = nbro;
    nbpe = (int) getarray("dpe",pearr);  if (nbpe > nbval) nbval = nbpe;
    nbsl = (int) getarray("dsl",slarr);  if (nbsl > nbval) nbval = nbsl;
    if ((nbro != nbval) && (nbro != 1))
      abort_message("%s: Number of directions/b-values must be the same for all axes (readout)",seqfil);
    if ((nbpe != nbval) && (nbpe != 1))
      abort_message("%s: Number of directions/b-values must be the same for all axes (phase)",seqfil);
    if ((nbsl != nbval) && (nbsl != 1))
      abort_message("%s: Number of directions/b-values must be the same for all axes (slice)",seqfil);


    if (nbro == 1) for (i = 1; i < nbval; i++) roarr[i] = roarr[0];
    if (nbpe == 1) for (i = 1; i < nbval; i++) pearr[i] = pearr[0];
    if (nbsl == 1) for (i = 1; i < nbval; i++) slarr[i] = slarr[0];

  }
  else {
    nbval = 1;
    roarr[0] = 0;
    pearr[0] = 0;
    slarr[0] = 0;
  }


  for (i = 0; i < nbval; i++)  {
    /* Readout */
    Dro     = ror_grad.duration;
    bro[i]  = bval(gdiff*roarr[i],tdelta,tDELTA);
    bro[i] += bval(ro_grad.amp,ro_grad.timeToEcho,Dro);

    /* Slice */
    dgss2   = Dgss2 = ss_grad.rfCenterFront;
    dcrush  = tcrush;                      //"delta" for crusher part of butterfly 
    Dcrush  = dcrush + ss_grad.rfDuration; //"DELTA" for crusher
    bsl[i]  = bval(gdiff*slarr[i],tdelta,tDELTA);
    bsl[i] += bval(gcrush,dcrush,Dcrush);
    bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2);
    bsl[i] += bval_nested(gdiff*slarr[i],tdelta,tDELTA,gcrush,dcrush,Dcrush);
    bsl[i] += bval_nested(gdiff*slarr[i],tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2);
    bsl[i] += bval_nested(gcrush,dcrush,Dcrush,ss2_grad.ssamp,dgss2,Dgss2);

    /* Phase */
    bpe[i] = bval(gdiff*pearr[i],tdelta,tDELTA);

    /* Readout/Slice Cross-terms */
    brs[i]  = bval2(gdiff*roarr[i],gdiff*slarr[i],tdelta,tDELTA);
    brs[i] += bval_cross(gdiff*roarr[i],tdelta,tDELTA,gcrush,dcrush,Dcrush);
    brs[i] += bval_cross(gdiff*roarr[i],tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2);

    /* Readout/Phase Cross-terms */
    brp[i]  = bval2(gdiff*roarr[i],gdiff*pearr[i],tdelta,tDELTA);

    /* Slice/Phase Cross-terms */
    bsp[i]  = bval2(gdiff*slarr[i],gdiff*pearr[i],tdelta,tDELTA);
    bsp[i] += bval_cross(gdiff*pearr[i],tdelta,tDELTA,gcrush,dcrush,Dcrush);
    bsp[i] += bval_cross(gdiff*pearr[i],tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2);

    btrace[i] = (bro[i]+bsl[i]+bpe[i]);

    if (max_bval < btrace[i]) {
      max_bval = (bro[i]+bsl[i]+bpe[i]);
    }
  }  /* End for-all-directions */

  putarray("bvalrr",bro,nbval);
  putarray("bvalpp",bpe,nbval);
  putarray("bvalss",bsl,nbval);
  putarray("bvalrp",brp,nbval);
  putarray("bvalrs",brs,nbval);
  putarray("bvalsp",bsp,nbval);
  putarray("bvalue",btrace,nbval);
  putvalue("max_bval",max_bval);



  /* Generate phase-ramped pulses: 90, 180, and IR */
  offsetlist(pss,ss_grad.ssamp,0,freq90,ns,seqcon[1]);
  shape90 = shapelist(p1pat,ss_grad.rfDuration,freq90,ns,0,seqcon[1]);

  offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]);
  shape180 = shapelist(p2pat,ss2_grad.rfDuration,freq180,ns,0,seqcon[1]);

  if (ir[0] == 'y') {
    offsetlist(pss,ssi_grad.ssamp,0,freqIR,ns,seqcon[1]);
    shapeIR = shapelist(pipat,ssi_grad.rfDuration,freqIR,ns,0,seqcon[1]);
  }

  /* Set pe_steps for profile or full image **********/   	
  pe_steps = prep_profile(profile[0],nv,&pe_grad,&null_grad);
  initval(pe_steps/2.0,vpe_offset);

  sgl_error_check(sglerror);


  /* Return parameters to VnmrJ */
  putvalue("rgss",ss_grad.tramp);  //90  slice ramp
  if (ss2_grad.enableButterfly) {   //180 slice ramps
    putvalue("rcrush",ss2_grad.crusher1RampToCrusherDuration);
    putvalue("rgss2",ss2_grad.crusher1RampToSsDuration);
  }
  else {
    putvalue("rgss2",ss2_grad.tramp);
  }
  if (ro_grad.enableButterfly) {
    putvalue("rgro",ro_grad.crusher1RampToSsDuration);
  }
  else {   
    putvalue("rgro",ro_grad.tramp);      //RO ramp
  }
  putvalue("tror",ror_grad.duration);  //ROR duration
  putvalue("rgror",ror_grad.tramp);    //ROR ramp
  putvalue("gpe",pe_grad.peamp);         //PE max amp
  putvalue("gss",ss_grad.ssamp);
  putvalue("gro",ro_grad.roamp);


  g_setExpTime(tr*(nt*pe_steps*arraydim + ssc));


  /* PULSE SEQUENCE *************************************/
  rotate();
  obsoffset(resto);
  roff = -poffset(pro,ro_grad.roamp);
  delay(4e-6);

  /* Begin phase-encode loop ****************************/       
  peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr);

    /* Read external kspace table if set ******************/       
    if (table)
      getelem(t1,vpe_ctr,vpe_index);
    else
      sub(vpe_ctr,vpe_offset,vpe_index);

    settable(t2,2,ph180);        // initialize phase tables and variables
    getelem(t2,vpe_ctr,vph180);
    add(oph,vph180,vph180);      // 180 deg pulse phase alternates +/- 90 from receiver
    mod2(ct,vph2);
    dbl(vph2,vph2);
    add(vph180,vph2,vph180);     // Alternate phase for 180 on odd transients

    /* Begin multislice loop ******************************/       
    msloop(seqcon[1],ns,vms_slices,vms_ctr);
      if (ticks) {
        xgate(ticks);
        grad_advance(gpropdelay);
      }
      /* TTL scope trigger **********************************/       
       sp1on(); delay(5e-6); sp1off();

      /* Prepulses ******************************************/       
      if (sat[0]  == 'y') satbands();
      if (fsat[0] == 'y') fatsat();
      if (mt[0]   == 'y') mtc();

      /* Optional IR pulse **********************************/ 
      if (ir[0] == 'y') {
	obspower(ir_rf.powerCoarse);
	obspwrf(ir_rf.powerFine);
	delay(4e-6);
	obl_shapedgradient(ssi_grad.name,ssi_grad.duration,0,0,ssi_grad.amp,NOWAIT);
	delay(ssi_grad.rfDelayFront);
	shapedpulselist(shapeIR,ssi_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr);
	delay(ssi_grad.rfDelayBack);
	delay(ti_delay);
      }

      /* Slice select RF pulse ******************************/ 
      obspower(p1_rf.powerCoarse);
      obspwrf(p1_rf.powerFine);
      delay(4e-6);
      obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT);
      delay(ss_grad.rfDelayFront);
      shapedpulselist(shape90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr);
      delay(ss_grad.rfDelayBack);

      /* Phase encode, refocus, and dephase gradient ********/
      pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,-ssr_grad.amp,
          pe_grad.increment,vpe_index,WAIT);

      delay(del1);           // delay to start of first diffusion gradient
      if (diff[0] == 'y') {
        obl_shapedgradient(diff_grad.name,diff_grad.duration,
          diff_grad.amp*dro,diff_grad.amp*dpe,diff_grad.amp*dsl,WAIT);
      }
      delay(del2);           // delay from end of diffusion to slice refocusing

      /* Refocusing RF pulse ********************************/ 
      obspower(p2_rf.powerCoarse);
      obspwrf(p2_rf.powerFine);
      delay(4e-6);
      obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT);
      delay(ss2_grad.rfDelayFront);
      shapedpulselist(shape180,ss2_grad.rfDuration,vph180,rof2,rof2,seqcon[1],vms_ctr);
      delay(ss2_grad.rfDelayBack);

      delay(del3);           // delay from slice refocusing to second diffusion gradient
      if (diff[0] == 'y') {
        obl_shapedgradient(diff_grad.name,diff_grad.duration,
          diff_grad.amp*dro,diff_grad.amp*dpe,diff_grad.amp*dsl,WAIT);
      }
      delay(del4);           // delay from end of diffusion gradient to readout event

      /* Readout gradient and acquisition ********************/
      roff = -poffset(pro,ro_grad.roamp);
      obl_shapedgradient(ror_grad.name,ror_grad.duration,-ror_grad.amp,0,0,WAIT);
      obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT);
      delay(ro_grad.atDelayFront);
      startacq(alfa);
      acquire(np,1.0/sw);
      delay(ro_grad.atDelayBack);
      endacq();

      /* Rewind Phase encoding ******************************/
      pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,
          pe_grad.increment,vpe_index,WAIT);

      if (navigator[0] == 'y') {
  roff = -poffset(pro,-ro_grad.roamp);
	obl_shapedgradient(ro_grad.name,ro_grad.duration,-ro_grad.amp,0,0,NOWAIT);
	delay(ro_grad.atDelayFront);
	startacq(alfa);
	acquire(np,1.0/sw);
	delay(ro_grad.atDelayBack);
	endacq();
      }

      /* Relaxation delay ***********************************/       
      delay(tr_delay);

    endmsloop(seqcon[1],vms_ctr);
  endpeloop(seqcon[2],vpe_ctr);
}
Пример #4
0
void calc_epi(EPI_GRADIENT_T          *epi_grad, 
              READOUT_GRADIENT_T      *ro_grad,
              PHASE_ENCODE_GRADIENT_T *pe_grad,
              REFOCUS_GRADIENT_T      *ror_grad,
              PHASE_ENCODE_GRADIENT_T *per_grad,
              READOUT_GRADIENT_T      *nav_grad,
              int write_flag) {

  /* Variables for generating gradient shapes */
  double dwint,blipint,skip,dw;
  int    np_ramp, np_flat, npro;
  double *dwell, *dac;
  double pos, neg;
  int    pt, pts, inx=0, lobe, lobes, blippts, zeropts;
    
  /* Variables for generating tables */
  int  n, seg, steps;
  char order_str[MAXSTR],gpe_tab[MAXSTR],tab_file[MAXSTR];
  FILE *fp;

  /********************************************************************************/
  /* Error Checks */
  /********************************************************************************/
  /* make sure that the combination of nseg, ky_order and fract_ky make sense */
  if (ky_order[0] == 'c') {
    /* Can't do just one segment with centric */
    if (nseg == 1) {
      if (ix == 1) {
        warn_message("WARNING %s: ky_order set to 'l'\n",seqfil);
        warn_message("            Only linear ordering allowed with single-shot acquisition\n");
      }
      ky_order[0] = 'l';
    }
    /* Must have even number of shots with centric ordering */
    if (((int) nseg % 2) == 1)
      abort_message("ERROR %s: Must do even number of shots with centric ordering\n",seqfil);

    /* Can't do fractional ky with centric acquisition */
    if (fract_ky != pe_grad->steps/2)
      abort_message("ERROR %s: fract_ky must be = nv/2 (%d) for centric acquisition\n",seqfil,(int) (pe_grad->steps/2));
  }

  if (fract_ky > pe_grad->steps/2)
    abort_message("ERROR %s: fract_ky must be <= nv/2 (%d)\n",seqfil,(int) (pe_grad->steps/2));


  /* calculate etl */
  switch(ky_order[0]) {
    case 'l': 
      epi_grad->etl = (pe_grad->steps/2 + fract_ky)/nseg; 
      epi_grad->center_echo = fract_ky/nseg - 1;

      if (epi_grad->etl - ((int) epi_grad->etl) > 0.005)
        abort_message("%s: Echo train length ((%d/2+%d)/%d = %.2f) not an integer\n",
	  seqfil,(int)pe_grad->steps,(int) fract_ky, (int) nseg,epi_grad->etl);

      break;
    case 'c': 
      epi_grad->etl = pe_grad->steps/nseg; 
      epi_grad->center_echo = 0;
      if (epi_grad->etl - ((int) epi_grad->etl) > 0.005)
        abort_message("%s: Echo train length (%d/%d) not an integer\n",
	  seqfil,(int)pe_grad->steps,(int) nseg);

      break;
    default:
      abort_message("%s: ky_order %s not recognized, use 'l' (linear) or 'c' (centric)\n",
                     seqfil, ky_order);
      break;
  }	    
  epi_grad->center_echo += ssepi*2;


  /********************************************************************************/
  /* Generate a single phase encoding blip and the dephaser                       */
  /********************************************************************************/
  blipint = 1/(pe_grad->fov/10*nuc_gamma()); /* base step in PE dimension */
  switch(ky_order[0]) {
    case 'l': /* each blip will jump nseg lines in ky: */
      pe_grad->m0     = blipint*nseg;
      per_grad->steps = pe_grad->steps;   /* each increment is = one blip unit */
      per_grad->m0    = blipint*per_grad->steps/2; /* start at nv/2, step 1 */
      break;
    case 'c': /* each blip will jump nseg/2 lines in ky: */
      pe_grad->m0     = blipint*nseg/2;
      per_grad->steps = nseg; 
      per_grad->m0    = blipint*per_grad->steps/2;  /* start at nseg/2, step 1 */
      break;
    default:  
      abort_message("ky_order %s not recognized, use 'l' (linear) or 'c' (centric)\n",ky_order);
      break;
  }

  /* Phase encoding blip */
  pe_grad->calcFlag  = SHORTEST_DURATION_FROM_MOMENT;
  pe_grad->writeToDisk = FALSE;
  calcPhase(pe_grad);
 
  if ((pe_grad->duration < epi_grad->tblip) || (pe_grad->amp/pe_grad->tramp > pe_grad->slewRate)) {
    pe_grad->tramp    = granularity(MAX(epi_grad->tblip/2,pe_grad->amp/pe_grad->slewRate),pe_grad->resolution);
    pe_grad->duration = 2*pe_grad->tramp;
    pe_grad->calcFlag = AMPLITUDE_FROM_MOMENT_DURATION_RAMP;
    calcPhase(pe_grad);
  }

  /* Phase encoding dephaser */
  per_grad->calcFlag = SHORTEST_DURATION_FROM_MOMENT;
  per_grad->maxGrad *= glim;
  per_grad->writeToDisk = write_flag;
  calcPhase(per_grad);
  
  /* Now adjust the initial dephaser for fractional k-space */
  per_grad->amp *= (fract_ky/(pe_grad->steps/2));

  /* Create an array for dwell times */
  npro = ro_grad->numPointsFreq; 
  if ((dwell = (double *)malloc(sizeof(double)*npro)) == NULL) {
    abort_message("Can't allocate memory for dwell");
  }

  /********************************************************************************/
  /* Generate a single readout lobe */  
  /********************************************************************************/
  ro_grad->writeToDisk = nav_grad->writeToDisk = FALSE;
  calcReadout(ro_grad);

  dw    = granularity(1/sw,1/epi_grad->ddrsr);
  dwint = dw*ro_grad->amp;

  skip  = getval("skip");              /* User specified min delay between acquisitions */
  skip  = MAX(skip,pe_grad->duration); /* Is PE blip longer? Then use that */
  skip /= 2;  /* in further calculations, skip is the skipped part on either ramp */

  /* If RO ramp - skip isn't at least one dwell, then we can't do ramp sampling */
  if (ro_grad->tramp - (skip + dw + getval("aqtm") - at) < dw) {
    if (rampsamp[0] == 'y') {
      printf("Blip duration or Min echo spacing is long (%.2fus), ramp sampling turned off",2*skip*1e6);
      rampsamp[0] = 'n';
    }
    /* set ramp time and recalculate */
    ro_grad->tramp = skip + (dw + getval("aqtm") - at); 
    calcReadout(ro_grad);
  }
    
  /********************************************************************************/
  if (rampsamp[0] == 'n') {  /* No rampsampling, just use simple RO shape */
  /********************************************************************************/
    np_ramp = 0; 
    np_flat = npro;
    
    skip = (ro_grad->atDelayFront + ro_grad->atDelayBack)/2;

    /* Set dwell array */
    for (pt = 0; pt < npro; pt++) 
      dwell[pt] = dw;
    dwell[npro-1] = 2*dw;  /* gradient duration is actually dw too long */

  }
  /********************************************************************************/
  else {  /* rampsampling */
  /********************************************************************************/
    calc_readout_rampsamp(ro_grad,dwell,&skip,&np_ramp);
    np_flat = npro - 2*np_ramp;

  }  /* end if rampsampling = 'y' */

  switch (ro_grad->error) {
    case ERR_NO_ERROR:
      break;
    case ERR_AMPLITUDE:
      abort_message("Readout gradient too large, increase FOV to %.2fmm",
        ro_grad->bandwidth/(ro_grad->gamma * ro_grad->maxGrad * MM_TO_CM));
      break;
    default:
      abort_message("Error in calculation of readout gradient (error %d)",
        (int)ro_grad->error);
      break;
      
  }


  /* We now have a single lobe, keep that for the navigator echo */
  nav_grad->amp        = ro_grad->amp; 
  nav_grad->duration   = ro_grad->duration; 
  nav_grad->tramp      = ro_grad->tramp; 
  nav_grad->m0         = ro_grad->m0;
  nav_grad->m0ref      = ro_grad->m0ref;
  nav_grad->dataPoints = ro_grad->dataPoints;
  nav_grad->numPoints  = ro_grad->numPoints;
  nav_grad->slewRate   = ro_grad->slewRate;


  /********************************************************************************/
  /* Readout dephaser */
  /********************************************************************************/
  ror_grad->balancingMoment0  = nav_grad->m0ref; /* ideal moment */
  /* adjust with grora tweaker */
  if (grora == 0) {
    warn_message("grora tweaker is 0, probably using old protocol - changed to 1.0");
    grora = 1.0;
  }
  ror_grad->balancingMoment0 *= grora;
  ror_grad->writeToDisk       = write_flag;
  
  calcRefocus(ror_grad);

  /********************************************************************************/
  /* Expand gradient shapes to full echo train                                    */
  /********************************************************************************/
  /* Readout - The navigator shape holds a single lobe                            */
  /********************************************************************************/
  /* Does positive or negative lobe need to be adjusted for tweaker? */
  pos = neg = 1;
  if (groa >= 0)  /* Adjust negative downwards, since positive is already at max */
    neg = (1 - groa/nav_grad->amp);
  else /* groa < 0, Adjust positive downwards */
    pos = (1 + groa/nav_grad->amp);

  /* Increase the size of ro shape to hold full shape */
  /* free(ro_grad->dataPoints); Don't free this, it's now assigned to the navigator echo */
  lobes = (epi_grad->etl + ssepi*2);
  ro_grad->numPoints *= lobes;
  
  if ((ro_grad->dataPoints = (double *)malloc(ro_grad->numPoints*sizeof(double))) == NULL) 
    abort_message("%s: Problem allocating memory for EPI readout gradient",seqfil);
  ro_grad->duration *= lobes;

  /* Concatenate positive and negative lobes        */
  /* until we have a full echo train (plus ssepi)  */
  pts = nav_grad->numPoints;
  inx = 0;
  for (lobe = 0; lobe < lobes/2; lobe++) {
    for (pt = 0; pt < pts; pt++)
      ro_grad->dataPoints[inx++] =  nav_grad->dataPoints[pt] * pos;
    for (pt = 0; pt < pts; pt++)
      ro_grad->dataPoints[inx++] = -nav_grad->dataPoints[pt] * neg;
  }


  /********************************************************************************/
  /* Phase encoding  */
  /********************************************************************************/
  /* Keep blip */
  blippts = pe_grad->numPoints;
  if ((dac = (double *)malloc(blippts*sizeof(double))) == NULL) 
    abort_message("%s: Problem allocating memory for EPI blip",seqfil);

  for (pt = 0; pt < blippts; pt++)
    dac[pt] = pe_grad->dataPoints[pt];

  /* Increase the size of pe shape to hold full shape */
  free(pe_grad->dataPoints);
  if ((pe_grad->dataPoints = (double *)malloc(ro_grad->numPoints*sizeof(double))) == NULL) 
    abort_message("%s: Problem allocating memory for EPI phase encoding gradient",seqfil);

  /* Pad front of shape - including ssepi time - with zeros */
  inx = 0;
  lobes = ssepi*2;
  zeropts = nav_grad->numPoints;
  for (lobe = 0; lobe < lobes; lobe++) {
    for (pt = 0; pt < zeropts; pt++) {
      pe_grad->dataPoints[inx++] = 0;
    }
  }
  zeropts = nav_grad->numPoints - blippts/2;
  for (pt = 0; pt < zeropts; pt++)
    pe_grad->dataPoints[inx++] = 0;

  lobes = epi_grad->etl-1;
  zeropts = nav_grad->numPoints - blippts;
  for (lobe=0; lobe < lobes; lobe++) {
    for (pt = 0; pt < blippts; pt++)    
      pe_grad->dataPoints[inx++] = dac[pt];
    for (pt = 0; pt < zeropts; pt++)
      pe_grad->dataPoints[inx++] = 0;
  }
  
  /* Add a few zeros, half the duration of the blip + one lobe, at the very end */
  zeropts = blippts/2 + nav_grad->numPoints;
  zeropts = blippts/2;
  for (pt = 0; pt < zeropts; pt++)
    pe_grad->dataPoints[inx++] = 0;

  pe_grad->numPoints = ro_grad->numPoints;
  pe_grad->duration  = ro_grad->duration;
  
  /********************************************************************************/
  /* Keep some parameters in EPI struct */
  /********************************************************************************/
  epi_grad->skip      = skip;
  epi_grad->np_flat   = np_flat;
  epi_grad->np_ramp   = np_ramp;
  epi_grad->dwell     = dwell;
  epi_grad->duration  = ro_grad->duration;
  epi_grad->numPoints = ro_grad->numPoints;
  epi_grad->amppos    =  nav_grad->amp*pos;
  epi_grad->ampneg    = -nav_grad->amp*neg;
  epi_grad->amppe     =  pe_grad->amp;

  
  /********************************************************************************/
  /* Write shapes to disk */
  /********************************************************************************/
  if (writeToDisk(ro_grad->dataPoints, ro_grad->numPoints, 0, 
                  ro_grad->resolution, TRUE /* rollout */,
                  ro_grad->name) != ERR_NO_ERROR)
    abort_message("Problem writing shape %s (%d points) to disk",
                  ro_grad->name,(int) ro_grad->numPoints);

  if (writeToDisk(nav_grad->dataPoints, nav_grad->numPoints, 0, 
                  nav_grad->resolution, TRUE /* rollout */,
                  nav_grad->name) != ERR_NO_ERROR)
    abort_message("Problem writing shape %s (%d points) to disk",
                  nav_grad->name,(int) nav_grad->numPoints);

  if (writeToDisk(pe_grad->dataPoints, pe_grad->numPoints, 0, 
                  pe_grad->resolution, TRUE /* rollout */, 
                  pe_grad->name) != ERR_NO_ERROR)
    abort_message("Problem writing shape %s (%d points) to disk",
                  pe_grad->name,(int) pe_grad->numPoints);
 

  /********************************************************************************/
  /* Create EPI tables */
  /********************************************************************************/
  /* Generates two tables:  */ 
  /* t1 that specifies the k-space ordering, used by recon_all */
  /* t2 that specifies which direction in k-space to go in a given shot */
  /*     1 = positive blips, and -1 = negative blips */
  if ((epi_grad->table1 = (int *)malloc(pe_grad->steps*sizeof(int))) == NULL) 
    abort_message("%s: Problem allocating memory for EPI table1",seqfil);
  if ((epi_grad->table2 = (int *)malloc(nseg*sizeof(int))) == NULL) 
    abort_message("%s: Problem allocating memory for EPI table2",seqfil);
  
  switch(ky_order[0]) {
    case 'l':
      inx = 0;
      for (seg = 0; seg < nseg; seg++) {
        epi_grad->table1[inx++] = -fract_ky + seg;
        for (n = 0; n < epi_grad->etl-1; n++) {
          epi_grad->table1[inx] = (int) (epi_grad->table1[inx-1]+nseg);
          inx++;
        }
      }
      for (seg = 0; seg < nseg; seg++) 
        epi_grad->table2[seg] = 1;
      break;
 
    case 'c':
      inx = 0;
      for (seg = 0; seg < nseg; seg++) {
        epi_grad->table1[inx++] = -(nseg/2 - seg);
        for (n = 0; n < epi_grad->etl-1; n++) {
          if (epi_grad->table1[inx-1] >= 0)
            epi_grad->table1[inx] = (int) (epi_grad->table1[inx-1] + nseg/2);
          else
            epi_grad->table1[inx] = (int) (epi_grad->table1[inx-1] - nseg/2);
          inx++;
        }
      }
      for (seg = 0; seg < nseg; seg++)
        epi_grad->table2[seg] = ((nseg/2 - 1 - seg >= 0) ? -1 : 1);
      break;

      default:  /* This should have been caught earlier */
        break;
  }
  steps = inx;

  /* Print table t1 to file in tablib */
  switch(ky_order[0]) {
    case 'l': sprintf(order_str,"lin"); break;
    case 'c': sprintf(order_str,"cen"); break;
    default:  
      abort_message("%s: ky_order %s not recognized, use 'l' (linear) or 'c' (centric)\n",
                     seqfil,ky_order);
  } 

  if (ky_order[1] == 'r')  /* not reversed */
    sprintf(gpe_tab,"%s_nv%d_f%d_%s%d_rev",seqfil,
       (int)pe_grad->steps,(int)fract_ky,order_str,(int)nseg);
  else
    sprintf(gpe_tab,"%s_nv%d_f%d_%s%d",seqfil,
       (int)pe_grad->steps,(int)fract_ky,order_str,(int)nseg);
  sprintf(tab_file,"%s/tablib/%s",userdir,gpe_tab);

  if ((fp = fopen(tab_file,"w")) == NULL) {
    abort_message("Error opening file %s\n",gpe_tab);
  }

  fprintf(fp,"t1 = ");
  for (inx = 0; inx < steps; inx++) {
    if (ky_order[1] == 'r')
      fprintf(fp,"%d ", epi_grad->table1[inx]);
    else
      fprintf(fp,"%d ", -epi_grad->table1[inx]);
  }
  fprintf(fp,"\n"); 
  fclose(fp);
  strcpy(petable,gpe_tab);
  putstring("petable",gpe_tab);

  /* Return values in VnmrJ parameter pe_table */
  putCmd("exists('pe_table','parameter'):$ex\n");
  putCmd("if ($ex > 0) then\n");
  putCmd("  pe_table = 0\n"); //reset pe_table array
  for (inx = 0; inx < steps; inx++) {
    putCmd("  pe_table[%d] = %d\n",inx+1,
      ((ky_order[1] == 'r') ? 1 : -1)*epi_grad->table1[inx]);
  }
  putCmd("endif\n");
}
Пример #5
0
void shapedgradient(char *name,double width,double amp,char which,
     int loops,int wait4me)
{
   cPatternEntry *tmp;
   int axisCode = 0;
   long long extra;
   double value;
   char buffer[4];
   int divs, duration;

   buffer[0] = which;
   buffer[1] = '\0';
   value = width;
   switch (buffer[0])
   {
     case 'x': case 'X': axisCode = 1; break;
     case 'y': case 'Y': axisCode = 2; break;
     case 'z': case 'Z': axisCode = 3; break;
     default:
       abort_message("invalid gradient axis in shapedgradient. abort!\n");
   }

   GradientBase *gC = P2TheConsole->getConfiguredGradient();

   if (gC->isNoWaitMode())
      abort_message("gradient event requested too soon after previous one in NOWAIT mode. abort!\n");

   tmp = gC->resolveOblShpGrdPattern(name,axisCode,"shapedgradient",1);

   P2TheConsole->newEvent();
   gC->clearSmallTicker();
   if (wait4me)
     gC->setActive();
   else
     gC->setNOWAITMode();

   divs = tmp->getNumberStates();
   duration = gC->calcTicksPerState(value,divs,4,0.1,"Shaped Gradient",0);
   if (duration < 320)   // 4 us is lower limit.
      abort_message("gradient duration too short for shapedgradient. abort!\n");


   // This should work for all imaging, micro imaging & Z axis and Triax PFG
   gC->setGradScale("X",0x4000);
   gC->setGradScale("Y",0x4000);
   gC->setGradScale("Z",0x4000);

   int fifobuffer[5];
   fifobuffer[0] = tmp->getReferenceID();

   if (axisCode == 1)
   {
       fifobuffer[1] = XGRADKEY;
   }
   else if (axisCode == 2)
   {
       fifobuffer[1] = YGRADKEY;
   }
   else
   {
       fifobuffer[1] = ZGRADKEY;
   }

   int daclimit = gC->getDACLimit();

   if (daclimit == 0x7ff)
   {
     if ( (amp > 2047.5) || (amp < -2047.5 ) )
       abort_message("gradient amplitude value %g is outside valid dac range in shapedgradient. abort!\n", amp);
     amp *= 16.0;
   }

   int dacvalue = ((int) floor(amp));

   if (dacvalue < -32767)
   {
     warn_message("advisory: gradient amplitude value %d outside valid dac range clipped to -32767\n",dacvalue);
     dacvalue = -32767;
   }
   else if (dacvalue > 32767)
   {
     warn_message("advisory: gradient amplitude value +%d outside valid dac range clipped to +32767\n",dacvalue);
     dacvalue = 32767;
   }

   fifobuffer[2] = dacvalue;
   fifobuffer[3] = duration;
   fifobuffer[4] = 1;           // Loops
   gC->outputACode(SHAPEDGRD, 5, fifobuffer);

   gC->noteDelay(duration*divs);            // maybe plus 1..
   extra = gC->getSmallTicker();
   if (wait4me)
      P2TheConsole->update4Sync(extra);
   else
      gC->incr_NOWAIT_eventTicker(extra);

   grad_flag = TRUE;
   return;
}