pulsesequence() { /* declaration of SGL kernel structures */ SGL_KERNEL_INFO_T read, phase, slice, ss_pre, ss_post; /* declaration of internal variables */ double freqlist[MAXNSLICE]; double pe_steps; int shapelist1, table; double xtime, grad_duration, ror_pad,rod_pad; double temp_tr; double readAmp, phaseAmp, sliceAmp; double tepad, tepad2, temin2, htrmin, delayToRF, delayRFToAcq, delayAcqToRF; double rof_pad, delRof; double sliceRephTrim, sliceDephTrim; double readRephTrim, readDephTrim; int rfPhase[2] = {0,2}; /* declaration of realtime 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 vss = v7; int vssc = v8; int vacquire = v9; int vphase = v10; settable(t2,2,rfPhase); /* setup phase encoding order */ table = set_pe_order(); init_mri(); if( (sliceRephTrim = getvalnwarn("sliceRephTrim")) == 0.0 ) { sliceRephTrim = 1.0; } if( (sliceDephTrim = getvalnwarn("sliceDephTrim")) == 0.0 ) { sliceDephTrim = 1.0; } if( (readRephTrim = getvalnwarn("readRephTrim")) == 0.0 ) { readRephTrim = 1.0; } if( (readDephTrim = getvalnwarn("readDephTrim")) == 0.0 ) { readDephTrim = 1.0; } shape_rf( &p1_rf, "p1", p1pat, p1, flip1, rof1, rof2 ); // excitation pulse init_slice( &ss_grad, "ss", thk ); // slice gradient init_slice_refocus( &ssr_grad, "ssr" ); // slice refocus init_slice_refocus( &ssd_grad, "ssd" ); // slice refocus init_readout( &ro_grad, "ro", lro, np, sw ); // read gradient init_readout_refocus( &ror_grad, "ror" ); // read dephase init_readout_refocus( &rod_grad, "ror" ); // read dephase init_phase( &pe_grad, "pe", lpe, nv ); // phase gradient ss_grad.maxGrad = gmax * 0.57; ssr_grad.maxGrad = gmax * 0.57; ssd_grad.maxGrad = gmax * 0.57; ro_grad.maxGrad = gmax * 0.57; ror_grad.maxGrad = gmax * 0.57; rod_grad.maxGrad = gmax * 0.57; pe_grad.maxGrad = glimpe < 0.57? gmax*glimpe : gmax * 0.57; /* calculate the RF pulses, gradient pulses and their interdependencies */ calc_rf( &p1_rf, "tpwr1", "tpwr1f" ); calc_slice( &ss_grad, &p1_rf, NOWRITE, "gss" ); ssr_grad.amp = ss_grad.amp; ssr_grad.gmult = sliceRephTrim; ssr_grad.calcFlag = DURATION_FROM_MOMENT_AMPLITUDE; calc_slice_refocus( &ssr_grad, &ss_grad, NOWRITE, "gssr" ); ssd_grad.amp = ss_grad.amp; ssd_grad.gmult = sliceDephTrim; ssd_grad.calcFlag = DURATION_FROM_MOMENT_AMPLITUDE; calc_slice_dephase( &ssd_grad, &ss_grad, NOWRITE, "gssd" ); calc_readout( &ro_grad, NOWRITE, "gro", "sw", "at" ); ror_grad.amp = ro_grad.amp; ror_grad.calcFlag = DURATION_FROM_MOMENT_AMPLITUDE; rod_grad.amp = ro_grad.amp; rod_grad.calcFlag = DURATION_FROM_MOMENT_AMPLITUDE; ror_grad.gmult = readRephTrim; calc_readout_refocus( &ror_grad, &ro_grad, NOWRITE, "gror" ); rod_grad.gmult = readDephTrim; calc_readout_rephase( &rod_grad, &ro_grad, NOWRITE, "grod" ); calc_phase( &pe_grad, NOWRITE, "gpe", "tpe" ); /* work out the position of the markers */ /* markerA */ /* ss_grad.rfDelayFront indicates the starting point of the RF pulse measured from the start of the slice gradient ( rof1:pulse length:rof2 ) */ double granulatedRFDelayFront = granularity( ss_grad.rfDelayFront, GRADIENT_RES ); if( granulatedRFDelayFront > ss_grad.rfDelayFront ) { granulatedRFDelayFront -= GRADIENT_RES; } /* ss_grad.rfDelayBack indicates the end point of the RF pulse measured to the end of the slice gradient ( rof1:pulse length:rof2 ) */ double granulatedRFDelayBack = granularity( ss_grad.rfDelayBack, GRADIENT_RES ); if( granulatedRFDelayBack > ss_grad.rfDelayBack ) { granulatedRFDelayBack -= GRADIENT_RES; } double granulatedRFDelay = granulatedRFDelayFront < granulatedRFDelayBack ? granulatedRFDelayFront : granulatedRFDelayBack; double markerADelay = granulatedRFDelay; /* read and phase gradients can overlap the start or end of the slice gradient by max of granulatedRFDElay */ double granulatedATDelayFront = granularity(ro_grad.atDelayFront, GRADIENT_RES); if( granulatedATDelayFront > ro_grad.atDelayFront ) { granulatedATDelayFront -= GRADIENT_RES; } double granulatedATDelayBack = granularity(ro_grad.atDelayBack, GRADIENT_RES); if( granulatedATDelayBack > ro_grad.atDelayBack ) { granulatedATDelayBack -= GRADIENT_RES; } double granulatedATDelay = granulatedATDelayFront < granulatedATDelayBack ? granulatedATDelayFront : granulatedATDelayBack; /* longest gradient between RF pulse and acquire dominates */ xtime = ssr_grad.duration + granulatedRFDelay; xtime = xtime > ssd_grad.duration + granulatedRFDelay ? xtime : ssd_grad.duration + granulatedRFDelay; xtime = xtime > ror_grad.duration + granulatedATDelay ? xtime : ror_grad.duration + granulatedATDelay; xtime = xtime > rod_grad.duration + granulatedATDelay ? xtime : rod_grad.duration + granulatedATDelay; xtime = xtime > pe_grad.duration ? xtime : pe_grad.duration; ror_pad = xtime - ror_grad.duration - granulatedATDelay; rod_pad = xtime - rod_grad.duration - granulatedATDelay; /* make a gradient list */ start_kernel( &sk ); add_gradient( (void*)&ss_grad, "slice", SLICE, START_TIME, "", 0.0, PRESERVE ); add_gradient( (void*)&ssr_grad, "sliceReph", SLICE, BEHIND, "slice", 0.0, INVERT ); add_gradient( (void*)&ror_grad, "readDeph", READ, BEHIND, "slice", -granulatedRFDelay + ror_pad, INVERT ); add_gradient( (void*)&ro_grad, "read", READ, BEHIND, "readDeph", 0.0, PRESERVE ); add_gradient( (void*)&pe_grad, "phase", PHASE, SAME_START, "readDeph", 0.0, PRESERVE ); add_gradient( (void*)&rod_grad, "readReph", READ, BEHIND, "read", 0.0, INVERT ); add_gradient( (void*)&pe_grad, "rewind", PHASE, SAME_END, "readReph", 0.0, INVERT ); add_gradient( (void*)&ss_grad, "nextSlice", SLICE, BEHIND, "readReph", rod_pad - granulatedRFDelay, PRESERVE ); add_gradient( (void*)&ssd_grad, "sliceDeph", SLICE, BEFORE, "nextSlice", 0, INVERT ); add_marker( "markerA", SAME_START, "slice", granulatedRFDelay ); add_marker( "markerB", SAME_START, "nextSlice", granulatedRFDelay ); /* get the minimum echo time */ temin = get_timing( FROM_RF_CENTER_OF, "slice", TO_ECHO_OF, "read" ); temin2 = get_timing( FROM_ECHO_OF, "read", TO_RF_CENTER_OF, "nextSlice" ); htrmin = MAX( temin, temin2 ); if( minte[0] == 'y' ){ te = htrmin; } tepad = granularity( te - temin, GRADIENT_RES ); tepad2 = granularity( te - temin2, GRADIENT_RES ); te = temin + tepad; putCmd("setvalue('te', %f, 'current')\n", te ); if( tepad>0.0 ) change_timing( "readDeph", tepad ); if( tepad2>0.0 ) change_timing( "nextSlice", tepad2 ); tr = get_timing( FROM_START_OF, "slice", TO_START_OF, "nextSlice" ); putvalue("tr", tr ); delayRFToAcq = get_timing( FROM_RF_PULSE_OF, "slice", TO_ACQ_OF, "read" ); delayAcqToRF = get_timing( FROM_ACQ_OF, "read", TO_RF_PULSE_OF, "nextSlice" ); set_comp_info( &ss_pre, "ss_pre" ); write_comp_grads_snippet( NULL, NULL, &ss_pre, "START_OF_KERNEL", "markerA" ); set_comp_info( &read, "ro" ); set_comp_info( &phase, "pe" ); set_comp_info( &slice, "ss" ); write_comp_grads_snippet( &read, &phase, &slice, "markerA", "markerB" ); set_comp_info( &ss_post, "ss_post" ); write_comp_grads_snippet( NULL, NULL, &ss_post, "markerB", "END_OF_KERNEL" ); /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.ssamp,0,freqlist,ns,seqcon[1]); shapelist1 = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freqlist,ns,ss_grad.rfFraction, seqcon[1]); /* Set pe_steps for profile or full image **********/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&pe_grad);/* profile[0] is n y or r */ F_initval(pe_steps/2.0,vpe_offset); g_setExpTime(trmean*(ntmean*pe_steps*arraydim + (1+fabs(ssc))*arraydim)); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* PULSE SEQUENCE */ status( A ); rotate(); triggerSelect(trigger); obsoffset( resto ); delay( GRADIENT_RES ); initval( 1+fabs( ssc ), vss ); obspower( p1_rf.powerCoarse ); obspwrf( p1_rf.powerFine ); delay( GRADIENT_RES ); assign(one,vacquire); // real-time acquire flag setacqvar(vacquire); // Turn on acquire when vacquire is zero obl_shapedgradient(ss_pre.name,ss_pre.dur,0,0,ss_pre.amp,NOWAIT); sp1on(); delay(GRADIENT_RES); sp1off(); delay(ss_pre.dur-GRADIENT_RES ); msloop( seqcon[1], ns, vms_slices, vms_ctr ); assign(vss,vssc); peloop( seqcon[2], pe_steps, vpe_steps, vpe_ctr ); sub(vpe_ctr,vssc,vpe_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's') assign(zero,vacquire); // Always acquire for non-compressed loop else { ifzero(vpe_ctr); assign(zero,vacquire); // Start acquiring when vpe_ctr reaches zero endif(vpe_ctr); } if (table) getelem(t1,vpe_ctr,vpe_index); else { ifzero(vacquire); sub(vpe_ctr,vpe_offset,vpe_index); elsenz(vacquire); sub(zero,vpe_offset,vpe_index); endif(vacquire); } pe_shaped3gradient( read.name, phase.name, slice.name, read.dur, read.amp, 0, slice.amp, -pe_grad.increment, vpe_index, NOWAIT ); delay(ss_grad.rfDelayFront - granulatedRFDelay); shapedpulselist( shapelist1, ss_grad.rfDuration, oph, rof1, rof2, seqcon[1], vms_ctr ); delay( delayRFToAcq - alfa ); startacq(alfa); acquire( np, 1/ro_grad.bandwidth ); endacq(); delay( delayAcqToRF - ss_grad.rfDelayFront + granulatedRFDelay - GRADIENT_RES ); sp1on(); delay(GRADIENT_RES); sp1off(); endpeloop( seqcon[2], vpe_ctr ); endmsloop( seqcon[1], vms_ctr ); obl_shapedgradient(ss_post.name,ss_post.dur,0,0,ss_post.amp,WAIT); }
pulsesequence() { /* Internal variable declarations *************************/ int shapelist90,shapelist180,shapelistIR; double nseg; double seqtime,tau1,tau2,tau3, te1_delay,te2_delay,te3_delay, iti_delay, ti_delay, tr_delay; double kzero; double freq90[MAXNSLICE], freq180[MAXNSLICE], freqIR[MAXNSLICE]; /* Real-time variables used in this sequence **************/ int vpe_ctr = v2; // PE loop counter int vpe_mult = v3; // PE multiplier, ranges from -PE/2 to PE/2 int vms_slices = v4; // Number of slices int vms_ctr = v5; // Slice loop counter int vseg = v6; // Number of ETL segments int vseg_ctr = v7; // Segment counter int vetl = v8; // Echo train length int vetl_ctr = v9; // Echo train loop counter int vssc = v10; // Compressed steady-states int vtrimage = v11; // Counts down from nt, trimage delay when 0 int vacquire = v12; // Argument for setacqvar, to skip steady state acquires int vphase180 = v13; // phase of 180 degree refocusing pulse /* Initialize paramaters **********************************/ init_mri(); /* Load external PE table ********************************/ if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); } else { abort_message("petable undefined"); } seqtime = 0.0; espmin = 0.0; kzero = getval("kzero"); /* RF Power & Bandwidth Calculations **********************/ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2); init_rf(&p2_rf,p2pat,p2,flip2,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Initialize gradient structures *************************/ init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_slice(&ss_grad,"ss",thk); /* NOTE assume same band widths for p1 and p2 */ init_slice_butterfly(&ss2_grad,"ss2",thk,gcrush,tcrush); init_slice_refocus(&ssr_grad,"ssr"); /* Gradient calculations **********************************/ calc_readout(&ro_grad,WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); calc_phase(&pe_grad,WRITE,"gpe","tpe"); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p1_rf,WRITE,""); calc_slice_refocus(&ssr_grad,&ss_grad,NOWRITE,"gssr"); /* Equalize refocus and PE gradient durations *************/ calc_sim_gradient(&ror_grad,&null_grad,&ssr_grad,0.0,WRITE); /* Create optional prepulse events ************************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); if (mt[0] == 'y') create_mtc(); if (ir[0] == 'y') { init_rf(&ir_rf,pipat,pi,flipir,rof1,rof2); calc_rf(&ir_rf,"tpwri","tpwrif"); init_slice_butterfly(&ssi_grad,"ssi",thk,gcrushir,tcrushir); calc_slice(&ssi_grad,&ir_rf,WRITE,"gssi"); } /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.ssamp, 0,freq90, ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); offsetlist(pss,ssi_grad.ssamp,0,freqIR, ns,seqcon[1]); shapelist90 = shapelist(p1pat,ss_grad.rfDuration, freq90, ns,0,seqcon[1]); shapelist180 = shapelist(p2pat,ss2_grad.rfDuration,freq180,ns,0,seqcon[1]); shapelistIR = shapelist(pipat,ssi_grad.rfDuration,freqIR, ns,0,seqcon[1]); /* same slice selection gradient and RF pattern used */ if (ss_grad.rfFraction != 0.5) abort_message("ERROR %s: RF pulse must be symmetric (RF fraction = %.2f)", seqfil,ss_grad.rfFraction); if (ro_grad.echoFraction != 1) abort_message("ERROR %s: Echo Fraction must be 1",seqfil); /* Find sum of all events in each half-echo period ********/ tau1 = ss_grad.rfCenterBack + ssr_grad.duration + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + pe_grad.duration + ro_grad.timeToEcho; tau3 = ro_grad.timeFromEcho + pe_grad.duration + ss2_grad.rfCenterFront; espmin = 2*MAX(MAX(tau1,tau2),tau3); // Minimum echo spacing if (minesp[0] == 'y') { esp = espmin + 8e-6; // ensure at least 4us delays in both TE periods putvalue("esp",esp); } else if (((espmin+8e-6)-esp) > 12.5e-9) { abort_message("ERROR %s: Echo spacing too small, minimum is %.2fms\n",seqfil,(espmin+8e-6)*1000); } te1_delay = esp/2.0 - tau1; // Intra-esp delays te2_delay = esp/2.0 - tau2; te3_delay = esp/2.0 - tau3; te = kzero*esp; // Return effective TE putvalue("te",te); /* Minimum TR **************************************/ /* seqtime is total time per slice */ seqtime = 2*4e-6 + ss_grad.rfCenterFront + etl*esp + ro_grad.timeFromEcho + pe_grad.duration + te3_delay; /* Increase TR if any options are selected****************/ if (sat[0] == 'y') seqtime += ns*satTime; if (fsat[0] == 'y') seqtime += ns*fsatTime; if (mt[0] == 'y') seqtime += ns*mtTime; if (ir[0] == 'y') { /* Inter-IR delay */ if (ns > 1) iti_delay = seqtime - ssi_grad.duration; /* it is probably safe to assume that seqtime is always > the pulse widths */ else iti_delay = 0; /* Inversion Recovery */ timin = ssi_grad.rfCenterBack + ss_grad.rfCenterFront; timin += 8e-6; // from sp1on/off and after 90 pulse power setting timin += seqtime*(ns-1) + iti_delay; if (ti < timin + 4e-6) // ensure at least a 4us delay abort_message("%s: ti too short, minimum is %.2fms",seqfil,timin*1000); /* Delay after the last IR pulse */ ti_delay = ti - timin; /* force all slices to be acquired back-to-back, with a single TR delay at end */ trtype = 1; } else { iti_delay = ti_delay = 0; } trmin = ns*(seqtime + 4e-6); if (ir[0] == 'y') { trmin += (4e-6 + ssi_grad.rfCenterFront + ti); } if (mintr[0] == 'y'){ tr = trmin; putvalue("tr",tr); } if ((trmin-tr) > 12.5e-9) { abort_message("TR too short. Minimum TR = %.2fms\n",trmin*1000); } tr_delay = (tr - trmin)/ns; /* Set number of segments for profile or full image **********/ nseg = prep_profile(profile[0],nv/etl,&pe_grad,&per_grad); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Calculate total acquisition time */ g_setExpTime(tr*(nt*nseg*getval("arraydim") + ssc) + trimage*getval("arraydim")); /* 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); /* PULSE SEQUENCE *************************************/ initval(fabs(ssc),vssc); // Compressed steady-state counter assign(one,vacquire); // real-time acquire flag /* Phase cycle: Alternate 180 phase to cancel residual FID */ mod2(ct,vphase180); // 0101 dbl(vphase180,vphase180); // 0202 add(vphase180,one,vphase180); // 1313 Phase difference from 90 add(vphase180,oph,vphase180); obsoffset(resto); delay(4e-6); initval(nseg,vseg); loop(vseg,vseg_ctr); /* TTL scope trigger **********************************/ sp1on(); delay(4e-6); sp1off(); /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vseg_ctr,vssc,vseg_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); ifzero(vseg_ctr); assign(zero,vacquire); // Start acquiring when vseg_ctr reaches zero endif(vseg_ctr); setacqvar(vacquire); // Turn on acquire when vacquire is zero if (ticks) { xgate(ticks); grad_advance(gpropdelay); delay(4e-6); } if(ir[0] == 'y') { /* IR for all slices prior to data acquisition */ obspower(ir_rf.powerCoarse); obspwrf(ir_rf.powerFine); delay(4e-6); msloop(seqcon[1],ns,vms_slices,vms_ctr); obl_shapedgradient(ssi_grad.name,ssi_grad.duration,0,0,ssi_grad.amp,NOWAIT); delay(ssi_grad.rfDelayFront); shapedpulselist(shapelistIR,ssi_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ssi_grad.rfDelayBack); delay(iti_delay); endmsloop(seqcon[1],vms_ctr); delay(ti_delay); } msloop(seqcon[1],ns,vms_slices,vms_ctr); /* Prepulse options ***********************************/ if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* 90 degree pulse ************************************/ rotate(); 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(shapelist90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Read dephase and Slice refocus *********************/ obl_shapedgradient(ssr_grad.name,ssr_grad.duration,ror_grad.amp,0.0,-ssr_grad.amp,WAIT); /* First half-TE delay ********************************/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(te1_delay); peloop(seqcon[2],etl,vetl,vetl_ctr); mult(vseg_ctr,vetl,vpe_ctr); add(vpe_ctr,vetl_ctr,vpe_ctr); getelem(t1,vpe_ctr,vpe_mult); /* 180 degree pulse *******************************/ /* Note, ss2_grad.amp is max gradient for butterfly shape; flat top = _.ssamp */ obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shapelist180,ss2_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); /* Phase-encode gradient ******************************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,-pe_grad.increment,vpe_mult,WAIT); /* Second half-TE period ******************************/ delay(te2_delay); /* Readout gradient ************************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront); /* Acquire data ****************************************/ startacq(alfa); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode gradient ********************/ /* Phase encode, refocus, and dephase gradient ******************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,pe_grad.increment,vpe_mult,WAIT); /* Second half-TE delay *******************************/ delay(te3_delay); endpeloop(seqcon[2],vetl_ctr); /* Relaxation delay ***********************************/ if (!trtype) delay(tr_delay); endmsloop(seqcon[1],vms_ctr); if (trtype) delay(ns*tr_delay); endloop(vseg_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }
pulsesequence() { /* Internal variable declarations *************************/ double freqEx[MAXNSLICE]; double maxgradtime,spoilMoment,perTime,tau1,te_delay,tr_delay; double te2=0.0,te3=0.0,te2min,te3min,tau2,tau3,te2_delay,te3_delay=0; char minte2[MAXSTR],minte3[MAXSTR],spoilflag[MAXSTR]; int sepSliceRephase,sepReadRephase=0,readrev,table,shapeEx; int i; /* Real-time variables used in this sequence **************/ int vpe_steps = v1; // Number of PE steps int vpe_ctr = v2; // PE loop counter int vms_slices = v3; // Number of slices int vms_ctr = v4; // Slice loop counter int vpe_offset = v5; // PE/2 for non-table offset int vpe_mult = v6; // PE multiplier, ranges from -PE/2 to PE/2 int vper_mult = v7; // PE rewinder multiplier; turn off rewinder when 0 int vssc = v8; // Compressed steady-states int vacquire = v9; // Argument for setacqvar, to skip steady state acquires int vrfspoil_ctr = v10; // RF spoil counter int vrfspoil = v11; // RF spoil multiplier int vtrimage = v12; // Counts down from nt, trimage delay when 0 int vne = v13; // Number of echoes int vne_ctr = v14; // Echo loop counter int vneindex = v15; // Echo index, odd or even int vnelast = v16; // Check for last echo int vtrigblock = v17; // Number of slices per trigger block /* Initialize paramaters **********************************/ init_mri(); getstr("spoilflag",spoilflag); te2=getval("te2"); te3=getval("te3"); getstr("minte2",minte2); getstr("minte3",minte3); readrev=(int)getval("readrev"); /* Check for external PE table ***************************/ table = 0; if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); table = 1; } /* Set Rcvr/Xmtr phase increments for RF Spoiling ********/ /* Ref: Zur, Y., Magn. Res. Med., 21, 251, (1991) *******/ if (rfspoil[0] == 'y') { rcvrstepsize(rfphase); obsstepsize(rfphase); } /* Initialize gradient structures *************************/ shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2 ); // excitation pulse init_slice(&ss_grad,"ss",thk); // slice select gradient init_slice_refocus(&ssr_grad,"ssr"); // slice refocus gradient init_readout(&ro_grad,"ro",lro,np,sw); // readout gradient ro_grad.pad1=alfa; ro_grad.pad2=alfa; init_readout_refocus(&ror_grad,"ror"); // dephase gradient init_phase(&pe_grad,"pe",lpe,nv); // phase encode gradient init_dephase(&spoil_grad,"spoil"); // optimized spoiler init_dephase(&ref_grad,"ref"); // readout rephase /* RF Calculations ****************************************/ calc_rf(&p1_rf,"tpwr1","tpwr1f"); /* Gradient calculations **********************************/ calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice_refocus(&ssr_grad, &ss_grad,WRITE,"gssr"); calc_readout(&ro_grad, WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); calc_phase(&pe_grad, NOWRITE,"gpe","tpe"); calc_dephase(&ref_grad,WRITE,ro_grad.m0,"",""); spoilMoment = ro_grad.acqTime*ro_grad.roamp; // Optimal spoiling is at*gro for 2pi per pixel spoilMoment -= ro_grad.m0def; // Subtract partial spoiling from back half of readout calc_dephase(&spoil_grad,WRITE,spoilMoment,"gspoil","tspoil"); /* Is TE long enough for separate slice refocus? ******/ maxgradtime = MAX(ror_grad.duration,pe_grad.duration); if (spoilflag[0] == 'y') maxgradtime = MAX(maxgradtime,spoil_grad.duration); tau1 = ss_grad.rfCenterBack + ssr_grad.duration + maxgradtime + ro_grad.timeToEcho + GRADIENT_RES; /* Equalize refocus and PE gradient durations *********/ if ((te >= tau1) && (minte[0] != 'y')) { sepSliceRephase = 1; // Set flag for separate slice rephase calc_sim_gradient(&ror_grad,&pe_grad,&spoil_grad,tpemin,WRITE); } else { sepSliceRephase = 0; calc_sim_gradient(&ror_grad,&pe_grad,&ssr_grad,tpemin,WRITE); calc_sim_gradient(&ror_grad,&spoil_grad,&null_grad,tpemin,NOWRITE); } perTime = 0.0; if ((perewind[0] == 'y') || (spoilflag[0] == 'y')) perTime = spoil_grad.duration; if (spoilflag[0] == 'n') spoil_grad.amp = 0.0; /* Create optional prepulse events ************************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); if (mt[0] == 'y') create_mtc(); if (ir[0] == 'y') create_inversion_recovery(); /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.ssamp,0,freqEx,ns,seqcon[1]); shapeEx = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freqEx,ns,ss_grad.rfFraction,seqcon[1]); /* Check that all Gradient calculations are ok ************/ sgl_error_check(sglerror); /* Min TE ******************************************/ tau1 = ss_grad.rfCenterBack + pe_grad.duration + ro_grad.timeToEcho; tau1 += (sepSliceRephase) ? ssr_grad.duration : 0.0; // Add slice refocusing if separate event temin = tau1 + GRADIENT_RES; /* ensure that te_delay is at least GRADIENT_RES */ te = granularity(te,GRADIENT_RES); if (minte[0] == 'y') { te = temin; putvalue("te",te); } if (FP_LT(te,temin)) { abort_message("TE too short. Minimum TE= %.3fms\n",temin*1000); } te_delay = te - tau1; /* Min TE2 *****************************************/ tau2 = (readrev) ? 2*ro_grad.timeFromEcho : ro_grad.duration+ref_grad.duration; te2min = tau2 + GRADIENT_RES; te2 = granularity(te2,GRADIENT_RES); if (minte2[0] == 'y') { te2 = te2min; putvalue("te2",te2); } if (FP_LT(te2,te2min)) { abort_message("TE2 too short. Minimum TE2= %.3fms\n",te2min*1000); } if (readrev) te2_delay = te2 - tau2; else { tau2 = ro_grad.duration + 3*ror_grad.duration; if (te2 >= tau2) { sepReadRephase = 1; // Set flag for separate read rephase te2_delay = te2 - ro_grad.duration - 2*ror_grad.duration; } else { sepReadRephase = 0; if (te2 > te2min+GRADIENT_RES) { ref_grad.duration = granularity(te2-ro_grad.duration-2*GRADIENT_RES,GRADIENT_RES); ref_grad.calcFlag = AMPLITUDE_FROM_MOMENT_DURATION; calc_dephase(&ref_grad,WRITE,ro_grad.m0,"",""); } te2_delay = te2 - ro_grad.duration - ref_grad.duration; } } /* Min TE3 *****************************************/ if (readrev) { tau3 = 2*ro_grad.timeToEcho; te3min = tau3 + GRADIENT_RES; te3 = granularity(te3,GRADIENT_RES); if (minte3[0] == 'y') { te3 = te3min; putvalue("te3",te3); } if (FP_LT(te3,te3min)) { abort_message("TE3 too short. Minimum TE3= %.3fms\n",te3min*1000); } te3_delay = te3 - tau3; } /* Now set the TE array accordingly */ putCmd("TE = 0"); /* Re-initialize TE */ putCmd("TE[1] = %f",te*1000); if (readrev) { for (i=1;i<ne;i++) { if (i%2 == 0) putCmd("TE[%d] = TE[%d]+%f",i+1,i,te3*1000); else putCmd("TE[%d] = TE[%d]+%f",i+1,i,te2*1000); } } else { for (i=1;i<ne;i++) putCmd("TE[%d] = TE[%d]+%f",i+1,i,te2*1000); } /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* Min TR ******************************************/ trmin = ss_grad.duration + te_delay + pe_grad.duration + ne*ro_grad.duration + perTime + 2*GRADIENT_RES; trmin += (sepSliceRephase) ? ssr_grad.duration : 0.0; // Add slice refocusing if separate event if (readrev) trmin += (ne/2)*te2_delay + ((ne-1)/2)*te3_delay; else trmin += (sepReadRephase) ? (ne-1)*(te2_delay+2*ror_grad.duration) : (ne-1)*(te2_delay+ref_grad.duration); /* Increase TR if any options are selected *********/ if (sat[0] == 'y') trmin += satTime; if (fsat[0] == 'y') trmin += fsatTime; if (mt[0] == 'y') trmin += mtTime; if (ticks > 0) trmin += GRADIENT_RES; /* Adjust for all slices ***************************/ trmin *= ns; /* Inversion recovery *********************************/ if (ir[0] == 'y') { /* tauti is the additional time beyond IR component to be included in ti */ /* satTime, fsatTime and mtTime all included as those modules will be after IR */ tauti = satTime + fsatTime + mtTime + GRADIENT_RES + ss_grad.rfCenterFront; /* calc_irTime checks ti and returns the time of all IR components */ trmin += calc_irTime(tauti,trmin,mintr[0],tr,&trtype); } if (mintr[0] == 'y') { tr = trmin; putvalue("tr",tr); } if (FP_LT(tr,trmin)) { abort_message("TR too short. Minimum TR = %.3fms\n",trmin*1000); } /* Calculate tr delay */ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Set pe_steps for profile or full image **********/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&per_grad); F_initval(pe_steps/2.0,vpe_offset); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Adjust experiment time for VnmrJ *********************/ if (ssc<0) { if (seqcon[2] == 'c') g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*arraydim)); else g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*pe_steps*arraydim)); } else g_setExpTime(trmean*ntmean*pe_steps*arraydim + tr*ssc); /* PULSE SEQUENCE ***************************************/ status(A); rotate(); triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); delay(GRADIENT_RES); initval(fabs(ssc),vssc); // Compressed steady-state counter if (seqcon[2]=='s') assign(zero,vssc); // Zero for standard peloop assign(zero,vrfspoil_ctr); // RF spoil phase counter assign(zero,vrfspoil); // RF spoil multiplier assign(one,vacquire); // real-time acquire flag setacqvar(vacquire); // Turn on acquire when vacquire is zero /* trigger */ if (ticks > 0) F_initval((double)nsblock,vtrigblock); /* Begin phase-encode loop ****************************/ peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr); if (trtype) delay(ns*tr_delay); // relaxation delay /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vpe_ctr,vssc,vpe_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's') assign(zero,vacquire); // Always acquire for non-compressed loop else { ifzero(vpe_ctr); assign(zero,vacquire); // Start acquiring when vpe_ctr reaches zero endif(vpe_ctr); } /* Set rcvr/xmtr phase for RF spoiling *******************/ if (rfspoil[0] == 'y') { incr(vrfspoil_ctr); // vrfspoil_ctr = 1 2 3 4 5 6 add(vrfspoil,vrfspoil_ctr,vrfspoil); // vrfspoil = 1 3 6 10 15 21 xmtrphase(vrfspoil); rcvrphase(vrfspoil); } /* Read external kspace table if set ******************/ if (table) getelem(t1,vpe_ctr,vpe_mult); else { ifzero(vacquire); sub(vpe_ctr,vpe_offset,vpe_mult); elsenz(vacquire); sub(zero,vpe_offset,vpe_mult); // Hold PE mult at initial value for steady states endif(vacquire); } /* PE rewinder follows PE table; zero if turned off ***/ if (perewind[0] == 'y') assign(vpe_mult,vper_mult); else assign(zero,vper_mult); /* Begin multislice loop ******************************/ msloop(seqcon[1],ns,vms_slices,vms_ctr); if (!trtype) delay(tr_delay); // Relaxation delay if (ticks > 0) { modn(vms_ctr,vtrigblock,vtest); ifzero(vtest); // if the beginning of an trigger block xgate(ticks); grad_advance(gpropdelay); delay(GRADIENT_RES); elsenz(vtest); delay(GRADIENT_RES); endif(vtest); } /* TTL scope trigger **********************************/ sp1on(); delay(GRADIENT_RES); sp1off(); /* Prepulse options ***********************************/ if (ir[0] == 'y') inversion_recovery(); if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* Slice select RF pulse ******************************/ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(GRADIENT_RES); obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shapeEx,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Phase encode, refocus, and dephase gradient ********/ if (sepSliceRephase) { // separate slice refocus gradient obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0,0,-ssr_grad.amp,WAIT); delay(te_delay); // delay between slab refocus and pe pe_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp,0,0, -pe_grad.increment,vpe_mult,WAIT); } else { pe_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp,0,-ssr_grad.amp, -pe_grad.increment,vpe_mult,WAIT); delay(te_delay); // delay after refocus/pe } F_initval(ne,vne); loop(vne,vne_ctr); if (readrev) { mod2(vne_ctr,vneindex); ifzero(vneindex); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Readout gradient ********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquisition ***************************************/ startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); sub(vne,vne_ctr,vnelast); sub(vnelast,one,vnelast); ifzero(vnelast); elsenz(vnelast); delay(te2_delay); endif(vnelast); elsenz(vneindex); /* Shift DDR for pro *******************************/ roff = -poffset(pro,-ro_grad.roamp); /* Readout gradient ********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,-ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquisition ***************************************/ startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); sub(vne,vne_ctr,vnelast); sub(vnelast,one,vnelast); ifzero(vnelast); elsenz(vnelast); delay(te3_delay); endif(vnelast); endif(vneindex); } else { /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Readout gradient ********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquisition ***************************************/ startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); sub(vne,vne_ctr,vnelast); sub(vnelast,one,vnelast); ifzero(vnelast); elsenz(vnelast); if (sepReadRephase) { obl_shapedgradient(ror_grad.name,ror_grad.duration,-ror_grad.amp,0,0,WAIT); delay(te2_delay); obl_shapedgradient(ror_grad.name,ror_grad.duration,-ror_grad.amp,0,0,WAIT); } else { obl_shapedgradient(ref_grad.name,ref_grad.duration,-ref_grad.amp,0,0,WAIT); delay(te2_delay); } endif(vnelast); } endloop(vne_ctr); /* Rewind / spoiler gradient **************************/ if ((perewind[0] == 'y') || (spoilflag[0] == 'y')) { pe_shapedgradient(pe_grad.name,pe_grad.duration,spoil_grad.amp,0,0,pe_grad.increment,vper_mult,WAIT); } endmsloop(seqcon[1],vms_ctr); endpeloop(seqcon[2],vpe_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }
pulsesequence() { /* Internal variable declarations *********************/ double freq90[MAXNSLICE],freq180[MAXNSLICE]; double te_delay1,te_delay2,tr_delay,tau1,tau2,thk2fact,te_delay3=0.0,te_delay4=0.0,navTime=0.0; double crushm0,pem0,gcrushr,gcrushp,gcrushs,pecrush; double refsign=1,crushsign=1,navsign=1; int shape90,shape180,table=0,sepRefocus; char slprofile[MAXSTR]; /* sequence dependent diffusion variables */ double Gro,Gss; // "gdiff" for readout/readout refocus and slice/slice refocus double dgro,dgss; // "delta" for readout/readout refocus and slice/slice refocus double Dgro,Dgss; // "DELTA" for readout/readout refocus and slice/slice refocus double dcrush,dgss2; // "delta" for crusher and gss2 gradients double Dcrush,Dgss2; // "DELTA" for crusher and gss2 gradients int i; /* Real-time variables used in this sequence **********/ int vpe_steps = v1; // Number of PE steps int vpe_ctr = v2; // PE loop counter int vms_slices = v3; // Number of slices int vms_ctr = v4; // Slice loop counter int vpe_offset = v5; // PE/2 for non-table offset int vpe_mult = v6; // PE multiplier, ranges from -PE/2 to PE/2 int vph180 = v7; // Phase of 180 pulse int vph2 = v8; // alternate phase of 180 on odd transients int vssc = v9; // Compressed steady-states int vtrimage = v10; // Counts down from nt, trimage delay when 0 int vacquire = v11; // Argument for setacqvar, to skip steady state acquires int vtrigblock = v12; // Number of slices per trigger block /* Initialize paramaters *****************************/ init_mri(); thk2fact=getval("thk2fact"); pecrush=getval("pecrush"); sepRefocus=getvalnwarn("sepRefocus"); getstrnwarn("slprofile",slprofile); /* Check for external PE table ***********************/ init_tablepar("pelist"); // Initialize pelist parameter if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); writetabletopar(t1,"pelist"); // Write t1 table to pelist parameter table = 1; } /* RF Power & Bandwidth Calculations ******************/ shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2); shape_rf(&p2_rf,"p2",p2pat,p2,flip2,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Initialize gradient structures *********************/ init_slice(&ss_grad,"ss",thk); init_slice(&ss2_grad,"ss2",thk*thk2fact); init_dephase(&crush_grad,"crush"); init_slice_refocus(&ssr_grad,"ssr"); if (FP_LT(tcrushro,alfa)) tcrushro=alfa; init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_generic(&spoil_grad,"spoil",gspoil,tspoil); /* Gradient calculations ******************************/ 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"); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p2_rf,WRITE,"gss2"); calc_slice_refocus(&ssr_grad,&ss_grad,WRITE,"gssr"); calc_generic(&spoil_grad,WRITE,"",""); /* Make sure crushing in PE dimension does not refocus signal from 180 */ crushm0=fabs(gcrush*tcrush); pem0=0.0; gcrushp=0.0; if (pecrush) pem0=pe_grad.m0; calc_dephase(&crush_grad,WRITE,crushm0+pem0,"",""); gcrushr = crush_grad.amp*crushm0/crush_grad.m0; if (pecrush) gcrushp = crush_grad.amp; gcrushs = crush_grad.amp*crushm0/crush_grad.m0; /* Allow phase encode and read dephase to be separated from slice refocus */ if (sepRefocus) { /* Equalize read dephase and PE gradient durations */ calc_sim_gradient(&ror_grad,&pe_grad,&null_grad,0,WRITE); crushsign=-1; } else { if (slprofile[0] == 'y') { /* Combined slice refocusing and read dephasing, reverse gradient sign if ror > ssr integral */ refsign = (ss_grad.m0ref > ro_grad.m0ref) ? 1.0 : -1.0; ss_grad.m0ref -= ro_grad.m0ref; calc_slice_refocus(&ssr_grad,&ss_grad,NOWRITE,"gssr"); } /* Equalize both refocus and PE gradient durations */ calc_sim_gradient(&ror_grad,&pe_grad,&ssr_grad,0,WRITE); } /* Create optional prepulse events ********************/ if (fsat[0] == 'y') create_fatsat(); if (sat[0] == 'y') create_satbands(); if (mt[0] == 'y') create_mtc(); if (ir[0] == 'y') create_inversion_recovery(); if (diff[0] == 'y') init_diffusion(&diffusion,&diff_grad,"diff",gdiff,tdelta); sgl_error_check(sglerror); /* Min TE *********************************************/ te = granularity(te,2*GRADIENT_RES); /* tau1, tau2 are the sum of events in each half echo period */ /* tau1, tau2 include a GRADIENT_RES as this is minimum delay time */ tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront + 2*GRADIENT_RES; tau2 = ss2_grad.rfCenterBack + crush_grad.duration + ro_grad.timeToEcho + GRADIENT_RES; if (sepRefocus) tau2 += ror_grad.duration; temin = 2*MAX(tau1,tau2); /* Diffusion ******************************************/ if (diff[0] == 'y') { /* granulate tDELTA */ tDELTA = granularity(tDELTA,GRADIENT_RES); /* taudiff is the duration of events between diffusion gradients */ taudiff = ss2_grad.duration + 2*crush_grad.duration + GRADIENT_RES; /* set minimum diffusion structure requirements for gradient echo: taudiff, tDELTA, te and minte[0] */ set_diffusion(&diffusion,taudiff,tDELTA,te,minte[0]); /* set additional diffusion structure requirements for spin echo: tau1 and tau2 */ set_diffusion_se(&diffusion,tau1,tau2); /* calculate the diffusion structure delays. address &temin is required in order to update temin accordingly */ calc_diffTime(&diffusion,&temin); } /* TE delays ******************************************/ if (minte[0] == 'y') { te = temin; putvalue("te",te); } if (FP_LT(te,temin)) { abort_message("TE too short, minimum TE = %.3f ms\n",temin*1000); } te_delay1 = te/2 - tau1 + GRADIENT_RES; te_delay2 = te/2 - tau2 + GRADIENT_RES; if (navigator[0] == 'y') { /* tau1, tau2 are the sum of events in each half echo period */ tau1 = ro_grad.timeFromEcho + pe_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + crush_grad.duration + ro_grad.timeToEcho; if (FP_GT(tau1,tau2)) { te_delay3 = GRADIENT_RES; te_delay4 = tau1-tau2+GRADIENT_RES; } else { te_delay3 = tau2-tau1+GRADIENT_RES; te_delay4 = GRADIENT_RES; } navTime = te_delay3 + ss2_grad.duration + 2*crush_grad.duration + ro_grad.duration + te_delay4 + 2*GRADIENT_RES; } /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* Min TR *********************************************/ trmin = ss_grad.rfCenterFront + te + ro_grad.timeFromEcho + pe_grad.duration + 2*GRADIENT_RES; /* Increase TR if any options are selected ************/ if (spoilflag[0] == 'y') trmin += spoil_grad.duration; if (navigator[0] == 'y') trmin += navTime; if (sat[0] == 'y') trmin += satTime; if (fsat[0] == 'y') trmin += fsatTime; if (mt[0] == 'y') trmin += mtTime; if (ticks > 0) trmin += GRADIENT_RES; /* Adjust for all slices ******************************/ trmin *= ns; /* Inversion recovery *********************************/ if (ir[0] == 'y') { /* tauti is the additional time beyond IR component to be included in ti */ /* satTime, fsatTime and mtTime all included as those modules will be after IR */ tauti = satTime + fsatTime + mtTime + GRADIENT_RES + ss_grad.rfCenterFront; /* calc_irTime checks ti and returns the time of all IR components */ trmin += calc_irTime(tauti,trmin,mintr[0],tr,&trtype); } if (mintr[0] == 'y') { tr = trmin; putvalue("tr",tr); } if (FP_LT(tr,trmin)) { abort_message("TR too short, minimum TR = %.3f ms\n",trmin*1000); } /* TR delay *******************************************/ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Calculate B values *********************************/ if (ix == 1) { /* Calculate bvalues according to main diffusion gradients */ calc_bvalues(&diffusion,"dro","dpe","dsl"); /* Add components from additional diffusion encoding imaging gradients peculiar to this sequence */ /* Initialize variables */ dgro = 0.5*(ror_grad.duration+ro_grad.timeToEcho); Gro = ro_grad.m0ref/dgro; Dgro = dgro; if (!sepRefocus) Dgro = te-ss_grad.rfCenterBack-ro_grad.timeToEcho; dgss = 0.5*(ss_grad.rfCenterBack+ssr_grad.duration); Gss = ss_grad.m0ref/dgss; Dgss = dgss; dgss2 = ss2_grad.duration/2; Dgss2 = dgss2; dcrush = crush_grad.duration-crush_grad.tramp; Dcrush = crush_grad.duration+ss2_grad.duration; for (i = 0; i < diffusion.nbval; i++) { /* set droval, dpeval and dslval */ set_dvalues(&diffusion,&droval,&dpeval,&dslval,i); /* Readout */ diffusion.bro[i] += bval(Gro,dgro,Dgro); diffusion.bro[i] += bval(crushsign*gcrushr,dcrush,Dcrush); diffusion.bro[i] += bval_nested(gdiff*droval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); if (!sepRefocus) { diffusion.bro[i] += bval_nested(Gro,dgro,Dgro,gdiff*droval,tdelta,tDELTA); diffusion.bro[i] += bval_nested(Gro,dgro,Dgro,crushsign*gcrushr,dcrush,Dcrush); } /* Phase */ if (pecrush) { diffusion.bpe[i] += bval(gcrushp,dcrush,Dcrush); diffusion.bpe[i] += bval_nested(gdiff*dpeval,tdelta,tDELTA,gcrushp,dcrush,Dcrush); } /* Slice */ diffusion.bsl[i] += bval(Gss,dgss,Dgss); diffusion.bsl[i] += bval(gcrushs,dcrush,Dcrush); diffusion.bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2); diffusion.bsl[i] += bval_nested(gdiff*dslval,tdelta,tDELTA,gcrushs,dcrush,Dcrush); diffusion.bsl[i] += bval_nested(gdiff*dslval,tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); diffusion.bsl[i] += bval_nested(gcrushs,dcrush,Dcrush,ss2_grad.ssamp,dgss2,Dgss2); /* Readout/Phase Cross-terms */ diffusion.brp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); diffusion.brp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); if (pecrush) diffusion.brp[i] += bval_cross(gdiff*droval,tdelta,tDELTA,gcrushp,dcrush,Dcrush); if (!sepRefocus) { diffusion.brp[i] += bval_cross(Gro,dgro,Dgro,gdiff*dpeval,tdelta,tDELTA); if (pecrush) diffusion.brp[i] += bval_cross(Gro,dgro,Dgro,gcrushp,dcrush,Dcrush); } /* Readout/Slice Cross-terms */ diffusion.brs[i] += bval2(crushsign*gcrushr,gcrushs,dcrush,Dcrush); diffusion.brs[i] += bval_cross(gdiff*droval,tdelta,tDELTA,gcrushs,dcrush,Dcrush); diffusion.brs[i] += bval_cross(gdiff*dslval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); diffusion.brs[i] += bval_cross(gdiff*droval,tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); if (!sepRefocus) { diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,gdiff*dslval,tdelta,tDELTA); diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,gcrushs,dcrush,Dcrush); diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,ss2_grad.ssamp,dgss2,Dgss2); } /* Slice/Phase Cross-terms */ diffusion.bsp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,gcrushs,dcrush,Dcrush); diffusion.bsp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); if (pecrush) { diffusion.bsp[i] += bval2(gcrushs,gcrushp,dcrush,Dcrush); diffusion.bsp[i] += bval_cross(gdiff*dslval,tdelta,tDELTA,gcrushp,dcrush,Dcrush); diffusion.bsp[i] += bval_cross(gcrushp,dcrush,Dcrush,ss2_grad.ssamp,dgss2,Dgss2); } } /* End for-all-directions */ /* Write the values */ write_bvalues(&diffusion,"bval","bvalue","max_bval"); } /* Generate phase-ramped pulses ***********************/ offsetlist(pss,ss_grad.ssamp,0,freq90,ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shape90 = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freq90,ns,ss_grad.rfFraction,seqcon[1]); shape180 = shapelist(p2_rf.pulseName,ss2_grad.rfDuration,freq180,ns,ss2_grad.rfFraction,seqcon[1]); /* Set pe_steps for profile or full image *************/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&null_grad); F_initval(pe_steps/2.0,vpe_offset); /* Shift DDR for pro **********************************/ roff = -poffset(pro,ro_grad.roamp); /* Adjust experiment time for VnmrJ *******************/ if (ssc<0) { if (seqcon[2] == 'c') g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*arraydim)); else g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*pe_steps*arraydim)); } else g_setExpTime(trmean*ntmean*pe_steps*arraydim + tr*ssc); /* Slice profile **************************************/ if (slprofile[0] == 'y' && !sepRefocus) ror_grad.amp = 0; /* Set phase cycle table ******************************/ if (sepRefocus) settable(t2,1,ph180); // Phase encode is just before readout else settable(t2,2,ph180); /* PULSE SEQUENCE *************************************/ status(A); // Set status A rotate(); // Set gradient rotation according to psi, phi and theta triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); // Set spectrometer frequency delay(GRADIENT_RES); // Delay for frequency setting initval(fabs(ssc),vssc); // Compressed steady-state counter if (seqcon[2]=='s') assign(zero,vssc); // Zero for standard peloop assign(one,vacquire); // real-time acquire flag setacqvar(vacquire); // Turn on acquire when vacquire is zero /* trigger */ if (ticks > 0) F_initval((double)nsblock,vtrigblock); /* Begin phase-encode loop ****************************/ peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr); if (trtype) delay(ns*tr_delay); // relaxation delay /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vpe_ctr,vssc,vpe_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's') assign(zero,vacquire); // Always acquire for non-compressed loop else { ifzero(vpe_ctr); assign(zero,vacquire); // Start acquiring when vpe_ctr reaches zero endif(vpe_ctr); } /* Read external kspace table if set ******************/ if (table) getelem(t1,vpe_ctr,vpe_mult); else { ifzero(vacquire); sub(vpe_ctr,vpe_offset,vpe_mult); elsenz(vacquire); sub(zero,vpe_offset,vpe_mult); // Hold PE mult at initial value for steady states endif(vacquire); } /* Phase cycle ****************************************/ getelem(t2,vpe_ctr,vph180); // For phase encoding with slice rephase 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 (!trtype) delay(tr_delay); // Relaxation delay if (ticks > 0) { modn(vms_ctr,vtrigblock,vtest); ifzero(vtest); // if the beginning of an trigger block xgate(ticks); grad_advance(gpropdelay); delay(GRADIENT_RES); elsenz(vtest); delay(GRADIENT_RES); endif(vtest); } sp1on(); delay(GRADIENT_RES); sp1off(); // Scope trigger /* Prepulse options ***********************************/ if (ir[0] == 'y') inversion_recovery(); if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* Slice select RF pulse ******************************/ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(GRADIENT_RES); 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); /* Slice refocus gradient *****************************/ if (sepRefocus) obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0,0,-ssr_grad.amp,WAIT); else /* Include phase encode and readout dephase gradient if refocus gradients not separated */ pe_shapedgradient(pe_grad.name,pe_grad.duration,ror_grad.amp,0,-ssr_grad.amp*refsign,pe_grad.increment,vpe_mult,WAIT); if (diff[0] == 'y') { delay(diffusion.d1); diffusion_dephase(&diffusion,dro,dpe,dsl); delay(diffusion.d2); } else delay(te_delay1); /* Refocusing RF pulse ********************************/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(GRADIENT_RES); obl_shapedgradient(crush_grad.name,crush_grad.duration,crushsign*gcrushr,gcrushp,gcrushs,WAIT); 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); obl_shapedgradient(crush_grad.name,crush_grad.duration,crushsign*gcrushr,gcrushp,gcrushs,WAIT); if (diff[0] == 'y') { delay(diffusion.d3); diffusion_rephase(&diffusion,dro,dpe,dsl); delay(diffusion.d4); } else delay(te_delay2); /* Readout dephase, phase encode & readout gradients **/ roff = -poffset(pro,ro_grad.roamp); // incase inverted navigator is acquired if (slprofile[0] == 'y') { /* Readout gradient only if refocus gradients not separated */ if (sepRefocus) obl_shapedgradient(ror_grad.name,ror_grad.duration,0,0,-ror_grad.amp,WAIT); obl_shapedgradient(ro_grad.name,ro_grad.duration,0,0,ro_grad.amp,NOWAIT); } else { /* Readout gradient only if refocus gradients not separated */ if (sepRefocus) pe_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp,0,0,-pe_grad.increment,vpe_mult,WAIT); obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); } /* Acquisition ****************************************/ delay(ro_grad.atDelayFront-alfa); 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_mult,WAIT); /* Navigator acquisition ******************************/ if (navigator[0] == 'y') { delay(te_delay3); obl_shapedgradient(crush_grad.name,crush_grad.duration,-crushsign*gcrushr,0,-gcrushs,WAIT); 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); obl_shapedgradient(crush_grad.name,crush_grad.duration,-crushsign*gcrushr,0,-gcrushs,WAIT); delay(te_delay4); obl_shapedgradient(ro_grad.name,ro_grad.duration,navsign*ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); } if (spoilflag[0] == 'y') { obl_shapedgradient(spoil_grad.name,spoil_grad.duration,navsign*spoil_grad.amp,0,spoil_grad.amp,WAIT); } endmsloop(seqcon[1],vms_ctr); endpeloop(seqcon[2],vpe_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); /* Duty cycle *****************************************/ calc_grad_duty(tr); }
pulsesequence() { /* Internal variable declarations *************************/ double freqEx[MAXNSLICE], freqIR[MAXNSLICE]; double pe_steps,pespoil_amp; double perTime, seqtime, tau1, tauIR=0, te_delay, tr_delay, ti_delay=0; int table, shapeEx, shapeIR=0; char spoilflag[MAXSTR],per_name[MAXSTR]; /* Real-time variables used in this sequence **************/ int vpe_steps = v1; // Number of PE steps int vpe_ctr = v2; // PE loop counter int vms_slices = v3; // Number of slices int vms_ctr = v4; // Slice loop counter int vpe_offset = v5; // PE/2 for non-table offset int vpe_mult = v6; // PE multiplier, ranges from -PE/2 to PE/2 int vper_mult = v7; // PE rewinder multiplier; turn off rewinder when 0 int vssc = v8; // Compressed steady-states int vacquire = v9; // Argument for setacqvar, to skip steady state acquires int vrfspoil_ctr = v10; // RF spoil counter int vrfspoil = v11; // RF spoil multiplier int vtrimage = v12; // Counts down from nt, trimage delay when 0 /* Initialize paramaters **********************************/ get_parameters(); get_ovsparameters(); getstr("spoilflag",spoilflag); /* Check for external PE table ***************************/ table = 0; if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); table = 1; } /* Set Rcvr/Xmtr phase increments for RF Spoiling ********/ /* Ref: Zur, Y., Magn. Res. Med., 21, 251, (1991) *******/ if (rfspoil[0] == 'y') { rcvrstepsize(rfphase); obsstepsize(rfphase); } /* Initialize gradient structures *************************/ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2 ); // excitation pulse init_slice(&ss_grad,"ss",thk); // slice select gradient init_slice_refocus(&ssr_grad,"ssr"); // slice refocus gradient init_readout(&ro_grad,"ro",lro,np,sw); // readout gradient init_readout_refocus(&ror_grad,"ror"); // dephase gradient init_phase(&pe_grad,"pe",lpe,nv); // phase encode gradient init_phase(&per_grad,"per",lpe,nv); // phase encode gradient init_generic(&spoil_grad,"spoil",gspoil,tspoil); // spoiler gradient /* RF Calculations ****************************************/ calc_rf(&p1_rf,"tpwr1","tpwr1f"); /* Gradient calculations **********************************/ calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice_refocus(&ssr_grad, &ss_grad, NOWRITE,"gssr"); calc_readout(&ro_grad, WRITE, "gro","sw","at"); 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,tpemin, WRITE); /* Calculate phase-rewind & spoiler gradients *************/ pespoil_amp = 0.0; perTime = 0.0; if ((perewind[0] == 'y') && (spoilflag[0] == 'n')) { // Rewinder, no spoiler calc_phase(&per_grad,WRITE,"",""); strcpy(per_name,per_grad.name); perTime = per_grad.duration; spoil_grad.amp = 0.0; } else if ((perewind[0] == 'n') && (spoilflag[0] == 'y')) { // Spoiler, no rewinder calc_generic(&spoil_grad,WRITE,"",""); strcpy(per_name,spoil_grad.name); perTime = spoil_grad.duration; pespoil_amp = spoil_grad.amp; // Apply spoiler on PE axis if no rewinder } else if ((perewind[0] == 'y') && (spoilflag[0] == 'y')) { // Rewinder and spoiler calc_phase(&per_grad,NOWRITE,"",""); calc_generic(&spoil_grad,NOWRITE,"",""); calc_sim_gradient(&per_grad,&spoil_grad,&null_grad,0.0,WRITE); strcpy(per_name,per_grad.name); perTime = per_grad.duration; } /* Create optional prepulse events ************************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); if (mt[0] == 'y') create_mtc(); if (ovs[0] == 'y') { /* Must set up a few voxel specific parameters for create_ovsbands() to function */ vox1_grad.thickness = vox1; vox2_grad.thickness = vox2; vox3_grad.thickness = vox3; vox1_grad.rfBandwidth = vox2_grad.rfBandwidth = vox3_grad.rfBandwidth = p1_rf.bandwidth; create_ovsbands(); } 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,gcrush,tcrush); calc_slice(&ssi_grad,&ir_rf,WRITE,"gssi"); tauIR = ss_grad.duration - ss_grad.rfCenterBack; // Duration of ss_grad before RF center ti_delay = ti - (ssi_grad.rfCenterFront + tauIR); if (ti_delay < 0) { abort_message("TI too short, Minimum TI = %.2fms\n",(ti-ti_delay)*1000); } irTime = 4e-6 + ti + ssi_grad.duration - ssi_grad.rfCenterBack; // Time to add to TR } /* Check that all Gradient calculations are ok ************/ sgl_error_check(sglerror); /* Min TE ******************************************/ tau1 = ss_grad.rfCenterBack + pe_grad.duration + alfa + ro_grad.timeToEcho; temin = tau1 + 4e-6; /* ensure that te_delay is at least 4us */ if (minte[0] == 'y') { te = temin; putvalue("te",te); } if (te < temin) { abort_message("TE too short. Minimum TE= %.2fms\n",temin*1000+0.005); } te_delay = te - tau1; /* Min TR ******************************************/ seqtime = ss_grad.duration + te_delay + pe_grad.duration + ro_grad.duration + perTime + tep + alfa; /* Increase TR if any options are selected ****************/ if (sat[0] == 'y') seqtime += satTime; if (fsat[0] == 'y') seqtime += fsatTime; if (mt[0] == 'y') seqtime += mtTime; if (ovs[0] == 'y') seqtime += ovsTime; if (ir[0] == 'y') { seqtime += irTime; seqtime -= tauIR; /* subtract out ss_grad which was already included in TR */ } trmin = seqtime + 4e-6; /* ensure that tr_delay is at least 4us */ trmin *= ns; if (mintr[0] == 'y') { tr = trmin; putvalue("tr",tr); } if (tr < trmin) { abort_message("TR too short. Minimum TR= %.2fms\n",trmin*1000+0.005); } tr_delay = (tr - seqtime*ns)/ns; /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.ssamp,0,freqEx,ns,seqcon[1]); shapeEx = shapelist(p1pat,ss_grad.rfDuration,freqEx,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,&per_grad); initval(pe_steps/2.0,vpe_offset); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); g_setExpTime(tr*(nt*pe_steps*arraydim + ssc)); /* PULSE SEQUENCE *************************************/ status(A); rotate(); obsoffset(resto); delay(4e-6); initval(fabs(ssc),vssc); // Compressed steady-state counter assign(zero,vrfspoil_ctr); // RF spoil phase counter assign(zero,vrfspoil); // RF spoil multiplier assign(one,vacquire); // real-time acquire flag setacqvar(vacquire); // Turn on acquire when vacquire is zero /* Delay all channels except gradient *****************/ sub(ssval,ssctr,v30); add(v30,ct,v30); if (ix == 1) { ifzero(v30); grad_advance(tep); endif(v30); } /* Begin phase-encode loop ****************************/ peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr); /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vpe_ctr,vssc,vpe_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's') assign(zero,vacquire); // Always acquire for non-compressed loop else { ifzero(vpe_ctr); assign(zero,vacquire); // Start acquiring when vpe_ctr reaches zero endif(vpe_ctr); } /* Set rcvr/xmtr phase for RF spoiling *******************/ if (rfspoil[0] == 'y') { incr(vrfspoil_ctr); // vrfspoil_ctr = 1 2 3 4 5 6 add(vrfspoil,vrfspoil_ctr,vrfspoil); // vrfspoil = 1 3 6 10 15 21 xmtrphase(vrfspoil); rcvrphase(vrfspoil); } /* Read external kspace table if set ******************/ if (table) getelem(t1,vpe_ctr,vpe_mult); else { ifzero(vacquire); sub(vpe_ctr,vpe_offset,vpe_mult); elsenz(vacquire); sub(zero,vpe_offset,vpe_mult); // Hold PE mult at initial value for steady states endif(vacquire); } /* PE rewinder follows PE table; zero if turned off ***/ if (perewind[0] == 'y') assign(vpe_mult,vper_mult); else assign(zero,vper_mult); /* Begin multislice loop ******************************/ msloop(seqcon[1],ns,vms_slices,vms_ctr); triggerSelect(trigger); // Selectable trigger input delay(4e-6); if (ticks) { xgate(ticks); grad_advance(tep); // Gradient propagation delay } /* TTL scope trigger **********************************/ sp1on(); delay(4e-6); sp1off(); /* Prepulse options ***********************************/ if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); if (ovs[0] == 'y') {ovsbands(); rotate();} /* 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,rof2,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(shapeEx,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,-ror_grad.amp,0,-ssr_grad.amp, -pe_grad.increment,vpe_mult,WAIT); /* TE delay *******************************************/ delay(te_delay); /* Readout gradient and acquisition ********************/ 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 / spoiler gradient *********************************/ if ((perewind[0] == 'y') || (spoilflag[0] == 'y')) { pe_shapedgradient(per_name,perTime,spoil_grad.amp,pespoil_amp,spoil_grad.amp, per_grad.increment,vper_mult,WAIT); } /* Relaxation delay ***********************************/ if (!trtype) delay(tr_delay); endmsloop(seqcon[1],vms_ctr); if (trtype) delay(ns*tr_delay); endpeloop(seqcon[2],vpe_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }
pulsesequence() { /* Acquisition variables */ double dw; /* nominal dwell time, = 1/sw */ double aqtm = getval("aqtm"); /* Delay variables */ double tref, te_delay1, te_delay2, tr_delay, ti_delay, del1, del2, del3, del4, del5, /* before and after diffusion gradients */ busy1, busy2, /* time spent on rf pulses etc. in TE periods */ seqtime, invTime; int use_minte; /* RF and receiver frequency variables */ double freq90[MAXNSLICE],freq180[MAXNSLICE],freqIR[MAXNSLICE]; /* frequencies for multi-slice */ int shape90=0, shape180=0, shapeIR=0; /* List ID for RF shapes */ double roff1, roff2, roffn; /* Receiver offsets when FOV is offset along readout */ /* Gradient amplitudes, may vary depending on "image" parameter */ double peramp, perinc, peamp, roamp, roramp; /* diffusion variables */ #define MAXDIR 1024 /* Will anybody do more than 1024 directions or b-values? */ int diff_in_one = 0; double tmp, tmp_ss2; double roarr[MAXDIR], pearr[MAXDIR], slarr[MAXDIR]; int nbval, /* Total number of bvalues*directions */ nbro, nbpe, nbsl; /* bvalues*directions along RO, PE, and SL */ double bro[MAXDIR], bpe[MAXDIR], bsl[MAXDIR], /* b-values along RO, PE, SL */ brs[MAXDIR], brp[MAXDIR], bsp[MAXDIR], /* 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 */ /* loop variable */ int i; /* Real-time variables used in this sequence **************/ int vms_slices = v3; // Number of slices int vms_ctr = v4; // Slice loop counter int vnseg = v5; // Number of segments int vnseg_ctr = v6; // Segment loop counter int vetl = v7; // Number of choes in readout train int vetl_ctr = v8; // etl loop counter int vblip = v9; // Sign on blips in multi-shot experiment int vssepi = v10; // Number of Gradient Steady States lobes int vssepi_ctr = v11; // Steady State counter int vacquire = v12; // Argument for setacqvar, to skip steady states /******************************************************/ /* VARIABLE INITIALIZATIONS ***************************/ /******************************************************/ get_parameters(); euler_test(); if (tep < 0) { // adjust by reducing gpropdelay by that amount gpropdelay += tep; tep = 0; } setacqmode(WACQ|NZ); // Necessary for variable rate sampling use_minte = (minte[0] == 'y'); /******************************************************/ /* CALCULATIONS ***************************************/ /******************************************************/ if (ix == 1) { /* Calculate RF pulse */ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); /* Calculate gradients: */ init_slice(&ss_grad,"ss",thk); calc_slice(&ss_grad, &p1_rf,WRITE,"gss"); init_slice_refocus(&ssr_grad,"ssr"); calc_slice_refocus(&ssr_grad, &ss_grad, WRITE,"gssr"); if (spinecho[0] == 'y') { init_rf(&p2_rf,p2pat,p2,flip2,rof1,rof1); calc_rf(&p2_rf,"tpwr2","tpwr2f"); init_slice_butterfly(&ss2_grad,"ss2",thk,gcrush,tcrush); calc_slice(&ss2_grad,&p2_rf,WRITE,"gss2"); } else ss2_grad.duration = 0; /* used for diffusion calculations */ init_readout(&epiro_grad,"epiro",lro,np,sw); init_readout_refocus(&ror_grad,"ror"); init_phase(&epipe_grad, "epipe",lpe,nv); init_phase(&per_grad,"per",lpe,nv); init_readout(&nav_grad,"nav",lro,np,sw); init_epi(&epi_grad); if (!strcmp(orient,"oblique")) { if ((phi != 90) || (psi != 90) || (theta != 90)) { /* oblique slice - this should take care of most cases */ epiro_grad.slewRate /= 3; /* = gmax/trise */ epipe_grad.slewRate /= 3; } } calc_epi(&epi_grad,&epiro_grad,&epipe_grad,&ror_grad,&per_grad,&nav_grad,NOWRITE); /* Make sure the slice refocus, readout refocus, and phase dephaser fit in the same duration */ tref = calc_sim_gradient(&ror_grad, &per_grad, &null_grad, getval("tpe"), WRITE); if (sgldisplay) displayEPI(&epi_grad); /* calc_sim_gradient recalculates per_grad, so reset its base amplitude for centric ordering or fractional k-space*/ switch(ky_order[0]) { case 'l': per_grad.amp *= (fract_ky/(epipe_grad.steps/2)); break; case 'c': per_grad.amp = (nseg/2-1)*per_grad.increment; break; } if (ir[0] == 'y') { init_rf(&ir_rf,pipat,pi,flipir,rof1,rof1); calc_rf(&ir_rf,"tpwri","tpwrif"); init_slice_butterfly(&ssi_grad,"ssi",thk,gcrush,tcrush); calc_slice(&ssi_grad,&ir_rf,WRITE,"gssi"); } if (fsat[0] == 'y') { create_fatsat(); } if (diff[0] == 'y') { init_generic(&diff_grad,"diff",gdiff,tdelta); diff_grad.maxGrad = gmax; 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,"",""); } } /* Acquire top-down or bottom-up ? */ if (ky_order[1] == 'r') { epipe_grad.amp *= -1; per_grad.amp *= -1; per_grad.increment *= -1; } } /* end gradient setup if ix == 1 */ /* Load table used to determine multi-shot direction */ settable(t2,(int) nseg,epi_grad.table2); /* What is happening in the 2 TE/2 periods (except for diffusion)? */ busy1 = ss_grad.rfCenterBack + ssr_grad.duration; busy2 = tep + nav_grad.duration*(epi_grad.center_echo + 0.5); if (navigator[0] == 'y') busy2 += (tep + nav_grad.duration + per_grad.duration); /* How much extra time do we have in each TE/2 period? */ if (spinecho[0] == 'y') { busy1 += (GDELAY + ss2_grad.rfCenterFront); busy2 += ss2_grad.rfCenterBack; temin = MAX(busy1,busy2)*2; if (use_minte) te = temin; te_delay1 = te/2 - busy1; te_delay2 = te/2 - busy2; if (temin > te) { /* Use min TE and try and catch further violations of min TE */ te_delay1 = temin/2 - busy1; te_delay2 = temin/2 - busy2; } } else { /* Gradient echo */ temin = (busy1 + busy2); if (use_minte) te = temin; te_delay1 = te - temin; te_delay2 = 0; if (temin > te) te_delay1 = 0; } /* Now fill in the diffusion delays: del1 = between 90 and 1st diffusion gradient del2 = after 1st diffusion gradient del3 = before 2nd diffusion gradient when both in same TE/2 period del4 = before 2nd diffusion gradient when in different TE/2 period del5 = before acquisition Ie, the order is: 90 - del1 - diff - del2 - (diff - del3) - 180 - (del4 - diff) - del5 - acq where one and only one of the two options (diff - del3) or (del4 - diff) is used */ if (diff[0] == 'y') { tmp_ss2 = GDELAY + ss2_grad.duration; /* ss2 grad + 4us delay */ del1 = del2 = del3 = del4 = del5 = 0; if (tDELTA < (diff_grad.duration + tmp_ss2)) /* Minimum DELTA */ abort_message("ERROR %s: tDELTA is too short, minimum is %.2fms\n", seqfil,(diff_grad.duration + tmp_ss2)*1000+0.005); if (tDELTA + diff_grad.duration > te_delay1 + tmp_ss2 + te_delay2) { if (!use_minte) { abort_message("ERROR %s: Maximum tDELTA is %.2fms", seqfil,te_delay1 + ss2_grad.duration + te_delay2 - diff_grad.duration); } else { tmp = (tDELTA + diff_grad.duration) - (te_delay1 + tmp_ss2 + te_delay2); if (spinecho[0] == 'y') { te_delay1 += (tmp/2); te_delay2 += (tmp/2); } else te_delay1 += tmp; temin += tmp; } } if (spinecho[0] == 'y') { if (te_delay1 >= (tDELTA + diff_grad.duration)) { /* Put them both in 1st TE/2 period, */ diff_in_one = (diff[0] == 'y'); /* no need to increase temin */ del2 = tDELTA - diff_grad.duration; /* time between diffusion gradients */ del3 = te_delay1 - (tDELTA+diff_grad.duration); /* time after diffusion gradients */ del5 = te_delay2; /* delay in second TE/2 period */ } else { /* put them on each side of the 180 */ diff_in_one = 0; busy1 += diff_grad.duration; busy2 += diff_grad.duration; temin = 2*MAX(busy1,busy2); /* Optimally, the 2nd diff grad is right after the 180 */ del2 = tDELTA - diff_grad.duration - tmp_ss2; /* This is always > 0, or we would have aborted above */ del1 = te_delay1 - (diff_grad.duration + del2); if (del1 < 0) { del1 = 0; /* Place the 1st right after the 90 and push the 2nd out */ del4 = tDELTA - te_delay1 - ss2_grad.duration; } del5 = te_delay2 - (del4 + diff_grad.duration); /* del5 could still be < 0, when te_delay2 < diff_grad.duration */ if (del5 < 0) { del1 += fabs(del5); /* Increase each TE/2 period by abs(del5) */ del5 = 0; } } } else { /* gradient echo */ diff_in_one = (diff[0] == 'y'); del1 = 0; del2 = tDELTA - diff_grad.duration; /* time between diffusion gradients */ del3 = 0; del4 = 0; if (!use_minte) /* user defined TE */ del5 = te_delay1 - (tDELTA + diff_grad.duration); } } /* End of Diffusion block */ else { del1 = te_delay1; del5 = te_delay2; del2 = del3 = del4 = 0; } if (sgldisplay) { text_message("busy1/2, temin = %f, %f, %f",busy1*1e3, busy2*1e3, temin*1e3); text_message("te_delay1/2 = %f, %f",te_delay1*1e3, te_delay2*1e3); text_message("delays 1-5: %.2f, %.2f, %.2f, %.2f, %.2fms\n",del1*1000,del2*1000,del3*1000,del4*1000,del5*1000); } /* Check if TE is long enough */ temin = ceil(temin*1e6)/1e6; /* round to nearest us */ if (use_minte) { te = temin; putvalue("te",te); } else if (temin > te) { abort_message("TE too short, minimum is %.2f ms\n",temin*1000); } if (ir[0] == 'y') { ti_delay = ti - (pi*ssi_grad.rfFraction + rof2 + ssi_grad.rfDelayBack) - (ss_grad.rfDelayFront + rof1 + p1*(1-ss_grad.rfFraction)); if (ti_delay < 0) { abort_message("TI too short, minimum is %.2f ms\n",(ti-ti_delay)*1000); } } else ti_delay = 0; invTime = GDELAY + ssi_grad.duration + ti_delay; /* Minimum TR per slice, w/o options */ seqtime = GDELAY + ss_grad.rfCenterFront // Before TE + te + (epiro_grad.duration - nav_grad.duration*(epi_grad.center_echo+0.5)); // After TE /* Add in time for options outside of TE */ if (ir[0] == 'y') seqtime += invTime; if (fsat[0] == 'y') seqtime += fsatTime; trmin = seqtime + 4e-6; /* ensure a minimum of 4us in tr_delay */ trmin *= ns; if (tr - trmin < 0.0) { abort_message("%s: Requested tr too short. Min tr = %.2f ms\n", seqfil,ceil(trmin*100000)/100.00); } /* spread out multi-slice acquisition over total TR */ tr_delay = (tr - ns*seqtime)/ns; /******************************************************/ /* Return gradient values to VnmrJ interface */ /******************************************************/ putvalue("etl",epi_grad.etl+2*ssepi); putvalue("gro",epiro_grad.amp); putvalue("rgro",epiro_grad.tramp); putvalue("gror",ror_grad.amp); putvalue("tror",ror_grad.duration); putvalue("rgror",ror_grad.tramp); putvalue("gpe",epipe_grad.amp); putvalue("rgpe",epipe_grad.tramp); putvalue("gped",per_grad.amp); putvalue("tped",per_grad.duration); putvalue("rgped",per_grad.tramp); putvalue("gss",ss_grad.amp); putvalue("gss2",ss2_grad.ssamp); putvalue("rgss",ss_grad.tramp); putvalue("gssr",ssr_grad.amp); putvalue("tssr",ssr_grad.duration); putvalue("rgssr",ssr_grad.tramp); putvalue("rgss2",ss2_grad.crusher1RampToSsDuration); putvalue("rgssi",ssi_grad.crusher1RampToSsDuration); putvalue("rgcrush",ssi_grad.crusher1RampToCrusherDuration); putvalue("at_full",epi_grad.duration); putvalue("at_one",nav_grad.duration); putvalue("rcrush",ss2_grad.crusher1RampToCrusherDuration); putvalue("np_ramp",epi_grad.np_ramp); putvalue("np_flat",epi_grad.np_flat); if (diff[0] == 'y') { /* CALCULATE B VALUES */ /* 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++) { /* We need to worry about slice gradients & crushers for slice gradients */ /* Everything else is outside diffusion gradients, and thus constant */ /* for all b-values/directions */ /* Readout */ bro[i] = bval(gdiff*roarr[i],tdelta,tDELTA); /* Phase */ bpe[i] = bval(gdiff*pearr[i],tdelta,tDELTA); /* Slice */ dgss2 = p2/2; Dgss2 = dgss2; dcrush = tcrush; Dcrush = dcrush + p2; bsl[i] = bval(gdiff*slarr[i],tdelta,tDELTA); if (spinecho[0] == 'y') { bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2); bsl[i] += bval(gcrush,dcrush,Dcrush); bsl[i] += bval_nested(gcrush,dcrush,Dcrush,ss2_grad.ssamp,dgss2,Dgss2); } if (!diff_in_one) { 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); } /* Readout/Slice Cross-terms */ brs[i] = bval2(gdiff*roarr[i],gdiff*slarr[i],tdelta,tDELTA); if (spinecho[0] == 'y') { 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); /* Set all gradients depending on whether we do */ /* Use separate variables, because we only initialize & calculate gradients for ix==1 */ peamp = epipe_grad.amp; perinc = per_grad.increment; peramp = per_grad.amp; roamp = epiro_grad.amp; roramp = ror_grad.amp; switch ((int)image) { case 1: /* Real image scan, don't change anything */ break; case 0: /* Normal reference scan */ peamp = 0; perinc = 0; peramp = 0; roamp = epiro_grad.amp; roramp = ror_grad.amp; break; case -1: /* Inverted image scan */ roamp = -epiro_grad.amp; roramp = -ror_grad.amp; break; case -2: /* Inverted reference scan */ peamp = 0; perinc = 0; peramp = 0; roamp = -epiro_grad.amp; roramp = -ror_grad.amp; break; default: break; } /* 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]); if (spinecho[0] == 'y') { 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]); } sgl_error_check(sglerror); roff1 = -poffset(pro,epi_grad.amppos); roff2 = -poffset(pro,epi_grad.ampneg); roffn = -poffset(pro,nav_grad.amp); roff1 = -poffset(pro,epi_grad.amppos*roamp/epiro_grad.amp); roff2 = -poffset(pro,epi_grad.ampneg*roamp/epiro_grad.amp); roffn = -poffset(pro,nav_grad.amp); dw = granularity(1/sw,1/epi_grad.ddrsr); /* Total Scan Time */ g_setExpTime(tr*nt*nseg*arraydim); /******************************************************/ /* PULSE SEQUENCE *************************************/ /******************************************************/ rotate(); F_initval(epi_grad.etl/2, vetl); /* vetl is the loop counter in the acquisition loop */ /* that includes both a positive and negative readout lobe */ F_initval(nseg, vnseg); /* NB. F_initval(-ssepi,vssepi); currently gives errors */ initval(-ssepi,vssepi); /* gradient steady state lobes */ obsoffset(resto); delay(GDELAY); ifzero(rtonce); grad_advance(gpropdelay); endif(rtonce); loop(vnseg,vnseg_ctr); /* Loop through segments in segmented EPI */ msloop(seqcon[1],ns,vms_slices,vms_ctr); /* Multislice loop */ assign(vssepi,vssepi_ctr); sp1on(); delay(4e-6); sp1off(); /* Output trigger to look at scope */ if (ticks) { xgate(ticks); grad_advance(gpropdelay); delay(4e-6); } getelem(t2,vnseg_ctr,vblip); /* vblip = t2[vnseg_ctr]; either 1 or -1 for pos/neg blip */ /* Optional FAT SAT */ if (fsat[0] == 'y') { fatsat(); } /* Optional IR + TI delay */ if (ir[0] == 'y') { obspower(ir_rf.powerCoarse); obspwrf(ir_rf.powerFine); delay(GDELAY); obl_shapedgradient(ssi_grad.name,ssi_grad.duration,0.0,0.0,ssi_grad.amp,NOWAIT); delay(ssi_grad.rfDelayBack); shapedpulselist(shapeIR,ssi_grad.rfDuration,oph,rof1,rof1,seqcon[1],vms_ctr); delay(ssi_grad.rfDelayBack); delay(ti_delay); } /* 90 ss degree pulse */ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(GDELAY); obl_shapedgradient(ss_grad.name,ss_grad.duration,0.0,0.0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shape90,p1_rf.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Slice refocus */ obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0,0,-ssr_grad.amp,WAIT); delay(del1); 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); if (diff_in_one) obl_shapedgradient(diff_grad.name,diff_grad.duration, -diff_grad.amp*dro,-diff_grad.amp*dpe,-diff_grad.amp*dsl,WAIT); delay(del3); /* Optional 180 ss degree pulse with crushers */ if (spinecho[0] == 'y') { obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(GDELAY); obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0.0,0.0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shape180,ss2_grad.rfDuration,oph,rof1,rof1,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); } delay(del4); if ((diff[0] == 'y') && !diff_in_one) obl_shapedgradient(diff_grad.name,diff_grad.duration, diff_grad.amp*dro,diff_grad.amp*dpe,diff_grad.amp*dsl,WAIT); delay(del5); /* Optional navigator echo */ if (navigator[0] == 'y') { obl_shapedgradient(ror_grad.name,ror_grad.duration,roramp,0,0,WAIT); obl_shapedgradient(nav_grad.name,nav_grad.duration, -nav_grad.amp,0,0,NOWAIT); delay(tep); roff = roffn; /* Set receiver offset for navigator gradient */ delay(epi_grad.skip-alfa); /* ramp up */ startacq(alfa); for(i=0;i<np/2;i++){ sample(dw); delay((epi_grad.dwell[i] - dw)); } sample(aqtm-at); endacq(); delay(epi_grad.skip - dw - (aqtm-at)); /* Phase encode dephaser here if navigator echo was acquired */ var_shapedgradient(per_grad.name,per_grad.duration,0,-peramp,0,perinc,vnseg_ctr,WAIT); } else { var_shapedgradient(per_grad.name,per_grad.duration, -roramp,-peramp,0,perinc,vnseg_ctr,WAIT); } /* Start readout and phase encode gradient waveforms, NOWAIT */ /* If alternating ky-ordering, get polarity on blips from table */ var_shaped3gradient(epiro_grad.name,epipe_grad.name,"", /* patterns */ epiro_grad.duration, /* duration */ roamp,0,0, /* amplitudes */ peamp,vblip, /* step and multiplier */ NOWAIT); /* Don't wait */ delay(tep); /* Acquisition loop */ assign(one,vacquire); // real-time acquire flag nowait_loop(epi_grad.etl/2 + ssepi,vetl,vetl_ctr); ifzero(vssepi_ctr); //vssepi_ctr = -ssepi, -ssepi+1, ..., 0, 1,2,... assign(zero,vacquire); // turn on acquisition after all ss lobes endif(vssepi_ctr); incr(vssepi_ctr); setacqvar(vacquire); // Set acquire flag roff = roff1; /* Set receiver offset for positive gradient */ delay(epi_grad.skip-alfa); /* ramp up */ startacq(alfa); for(i=0;i<np/2;i++){ sample(dw); //dw = 1/sw delay((epi_grad.dwell[i] - dw)); } if (aqtm > at) sample(aqtm-at); endacq(); delay(epi_grad.skip - dw - (aqtm-at)); roff = roff2; /* Set receiver offset for negative gradient */ delay(epi_grad.skip-alfa); startacq(alfa); for(i=0;i<np/2;i++){ sample(dw); delay((epi_grad.dwell[i] - dw)); } if (aqtm > at) sample(aqtm-at); endacq(); delay(epi_grad.skip - dw - (aqtm-at)); nowait_endloop(vetl_ctr); delay(tr_delay); endmsloop(seqcon[1],vms_ctr); /* end multislice loop */ endloop(vnseg_ctr); /* end segments loop */ } /* end pulsesequence */
void pulsesequence() { /* Internal variable declarations *********************/ int shapelist90,shapelist180,shapelistte=0; double kzero,thk2fact,thk3fact; double te1=0.0,te1_delay,te2_delay,te3_delay,tr_delay,te_delay1=0.0,te_delay2=0.0; double crushm0,pem0,gcrushr,gcrushp,gcrushs; double freq90[MAXNSLICE],freq180[MAXNSLICE],freqte[MAXNSLICE]; char autocrush[MAXSTR]; /* Phase encode variables */ FILE *fp; int tab[4096],petab[4096],odd,seg0,tabscheme; char tabname[MAXSTR],tabfile[MAXSTR]; int i,j,k; /* Diffusion variables */ double Gro,Gss; // "gdiff" for readout/readout refocus and slice/slice refocus double dgro,Dgro; // delta and DELTA for readout dephase & readout double dgss,Dgss; // delta and DELTA for excitation ss double dgss3,Dgss3; // delta and DELTA for spin echo prep ss double dcrush3,Dcrush3; // delta and DELTA for spin echo prep crusher double dgss2,Dgss2; // delta and DELTA for refocus ss double dcrush2,Dcrush2; // delta and DELTA for refocus crusher /* Real-time variables used in this sequence **********/ int vpe_ctr = v2; // PE loop counter int vpe_mult = v3; // PE multiplier, ranges from -PE/2 to PE/2 int vms_slices = v4; // Number of slices int vms_ctr = v5; // Slice loop counter int vseg = v6; // Number of ETL segments int vseg_ctr = v7; // Segment counter int vetl = v8; // Echo train length int vetl_ctr = v9; // Echo train loop counter int vpe2_steps = v10; // Number of PE2 steps int vpe2_ctr = v11; // PE2 loop counter int vpe2_mult = v12; // PE2 multiplier int vpe2_offset = v13; // PE2/2 for non-table offset int vssc = v14; // Compressed steady-states int vtrimage = v15; // Counts down from nt, trimage delay when 0 int vacquire = v16; // Argument for setacqvar, to skip steady state acquires int vphase180 = v17; // phase of 180 degree refocusing pulse int vtrigblock = v18; // Number of slices per trigger block /* Initialize paramaters ******************************/ init_mri(); kzero = getval("kzero"); getstr("autocrush",autocrush); tabscheme = getval("tabscheme"); getstr("spoilflag",spoilflag); /* Allow ROxPE2 projection ****************************/ if (profile[0] == 'y' && profile[1] == 'n') { etl=1; kzero=1; nv=nv2; } else { /* Check kzero is valid *****************************/ if (kzero<1) kzero=1; if (kzero>etl) kzero=etl; putCmd("kzero = %d",(int)kzero); } /* Set petable name and full path *********************/ sprintf(tabname,"fse%d_%d_%d",(int)nv,(int)etl,(int)kzero); putCmd("petable = '%s'",tabname); strcpy(tabfile,userdir); strcat(tabfile,"/tablib/"); strcat(tabfile,tabname); /* Generate phase encode table ************************/ if (tabscheme) { /* New scheme */ /* Calculate PE table for kzero=1 */ seg0=nseg/2; for (j=0;j<seg0;j++) { for (i=0;i<etl/2;i++) tab[j*(int)etl+i] = i*nseg+seg0-j; for (i=1;i<=etl/2;i++) tab[(j+1)*(int)etl-i] = tab[j*(int)etl]-i*nseg; } for (j=seg0;j<nseg;j++) { for (i=0;i<=etl/2;i++) tab[j*(int)etl+i] = i*nseg+seg0-j; for (i=1;i<etl/2;i++) tab[(j+1)*(int)etl-i] = tab[j*(int)etl]-i*nseg; } /* Adjust for kzero */ for (i=0;i<nseg;i++) { k=i*etl; for (j=0;j<kzero-1;j++) petab[k+j]=tab[k+(int)etl-(int)kzero+j+1]; for (j=kzero-1;j<etl;j++) petab[k+j]=tab[k+j-(int)kzero+1]; } } else { /* Original scheme */ /* Calculate PE table for kzero=1 */ odd=(int)nseg%2; seg0=nseg/2+odd; k=0; for (i=0;i<etl;i++) for (j=seg0-odd*i%2-1;j>=0;j--) tab[j*(int)etl+i] = k--; k=1; for (i=0;i<etl;i++) for (j=seg0-odd*i%2;j<nseg;j++) tab[j*(int)etl+i] = k++; /* Adjust for kzero */ for (i=0;i<nseg;i++) { k=i*etl; for (j=0;j<kzero-1;j++) petab[k+j]=tab[k+(int)etl-j-1]; for (j=kzero-1;j<etl;j++) petab[k+j]=tab[k+j-(int)kzero+1]; } } /* Set petable name and full path *********************/ sprintf(tabname,"fse%d_%d_%d",(int)nv,(int)etl,(int)kzero); putCmd("petable = '%s'",tabname); strcpy(tabfile,userdir); strcat(tabfile,"/tablib/"); strcat(tabfile,tabname); /* Write to tabfile ***********************************/ fp=fopen(tabfile,"w"); fprintf(fp,"t1 ="); for (i=0;i<nseg;i++) { fprintf(fp,"\n"); for (j=0;j<etl;j++) fprintf(fp,"%3d\t",petab[i*(int)etl+j]); } fclose(fp); /* Set pelist to contain table order ******************/ putCmd("pelist = 0"); /* Re-initialize pelist */ for (i=0;i<nseg*etl;i++) putCmd("pelist[%d] = %d",i+1,petab[i]); /* Avoid gradient slew rate errors */ for (i=0;i<nseg*etl;i++) if (abs(petab[i]) > nv/2) petab[i]=0; /* Set phase encode table *****************************/ settable(t1,(int)etl*nseg,petab); /* RF Power & Bandwidth Calculations ******************/ shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2); shape_rf(&p2_rf,"p2",p2pat,p2,flip2,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Calculate thk2fact to ensure gss=gss2 for the choice of p1 and p2 so that the sequence remains robust in the absence of correct balancing of slice select and slice refocus gradients */ thk2fact=p2_rf.bandwidth/p1_rf.bandwidth; putvalue("thk2fact",thk2fact); /* Initialize gradient structures *********************/ init_readout(&ro_grad,"ro",lro,np,sw); ro_grad.pad1=alfa; ro_grad.pad2=alfa; init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_phase(&pe2_grad,"pe2",lpe2,nv2); init_slice(&ss_grad,"ss",thk); init_slice(&ss2_grad,"ss2",thk*thk2fact); init_slice_refocus(&ssr_grad,"ssr"); init_dephase(&crush_grad,"crush"); /* Gradient calculations ******************************/ calc_readout(&ro_grad,WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,WRITE,"gror"); calc_phase(&pe_grad,NOWRITE,"",""); calc_phase(&pe2_grad,NOWRITE,"",""); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p2_rf,WRITE,""); calc_slice_refocus(&ssr_grad,&ss_grad,WRITE,"gssr"); /* Equalize refocus gradient durations ****************/ calc_sim_gradient(&ror_grad,&null_grad,&ssr_grad,0.0,WRITE); /* Equalize PE gradient durations *********************/ calc_sim_gradient(&pe_grad,&pe2_grad,&null_grad,0.0,WRITE); /* Set crushing gradient moment ***********************/ crushm0=fabs(gcrush*tcrush); if (spoilflag[0] == 'y') { init_generic(&spoil_grad,"spoil",gspoil,tspoil); calc_generic(&spoil_grad,WRITE,"gspoil","tspoil"); } /* Create optional prepulse events ********************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); if (mt[0] == 'y') create_mtc(); if (ir[0] == 'y') create_inversion_recovery(); if (diff[0] == 'y') init_diffusion(&diffusion,&diff_grad,"diff",gdiff,tdelta); if (diff[0] == 'y') { /* Diffusion encoding is during spin echo preparation */ spinecho[0]='y'; putCmd("spinecho='y'"); } if (spinecho[0] == 'y') { /* spin echo preparation */ shape_rf(&p3_rf,"p3",p3pat,p3,flip3,rof1,rof2); calc_rf(&p3_rf,"tpwr3","tpwr3f"); /* Calculate thk3fact to ensure gss=gss2=gss3 for the choice of p1, p2 and p3 so that the sequence remains robust in the absence of correct balancing of slice select and slice refocus gradients */ thk3fact=p3_rf.bandwidth/p1_rf.bandwidth; putvalue("thk3fact",thk3fact); init_slice(&ss3_grad,"ss3",thk*thk3fact); calc_slice(&ss3_grad,&p3_rf,WRITE,""); putvalue("gss3",ss3_grad.ssamp); offsetlist(pss,ss3_grad.ssamp,0,freqte,ns,seqcon[1]); shapelistte = shapelist(p3_rf.pulseName,ss3_grad.rfDuration,freqte,ns,ss3_grad.rfFraction,seqcon[1]); /* Automatically set crushers to avoid unwanted echoes */ if (autocrush[0] == 'y') { if (crushm0 < 0.6*ro_grad.m0) crushm0=0.6*ro_grad.m0; } } /* Make sure crushing in PE dimensions does not refocus signal from 180 */ pem0 = (pe_grad.m0 > pe2_grad.m0) ? pe_grad.m0 : pe2_grad.m0; calc_dephase(&crush_grad,WRITE,crushm0+pem0,"",""); gcrushr = crush_grad.amp*crushm0/crush_grad.m0; gcrushp = crush_grad.amp*(crushm0+pe_grad.m0)/crush_grad.m0; gcrushs = crush_grad.amp*(crushm0+pe2_grad.m0)/crush_grad.m0; sgl_error_check(sglerror); /* Set up frequency offset pulse shape list ***********/ offsetlist(pss,ss_grad.amp,0,freq90,ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shapelist90 = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freq90,ns,ss_grad.rfFraction,seqcon[1]); shapelist180 = shapelist(p2_rf.pulseName,ss2_grad.rfDuration,freq180,ns,ss2_grad.rfFraction,seqcon[1]); /* To ensure proper overlap spin and stimulated echoes ensure that the middle of the refocusing RF pulse is the centre of the pulse and that echoes are formed in the centre of the acquisition window */ if (ss2_grad.rfFraction != 0.5) abort_message( "ERROR %s: Refocusing RF pulse must be symmetric (RF fraction = %.2f)", seqfil,ss2_grad.rfFraction); if (ro_grad.echoFraction != 1) abort_message("ERROR %s: Echo Fraction must be 1",seqfil); /* Find sum of all events in each half-echo period ****/ esp = granularity(esp,2*GRADIENT_RES); tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront + GRADIENT_RES; tau2 = ss2_grad.rfCenterBack + crush_grad.duration + pe_grad.duration + ro_grad.timeToEcho + GRADIENT_RES; tau3 = ro_grad.timeFromEcho + pe_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront + GRADIENT_RES; espmin = 2*MAX(MAX(tau1,tau2),tau3); // Minimum echo spacing if (minesp[0] == 'y') { esp = espmin; putvalue("esp",esp); } if (FP_LT(esp,espmin)) { abort_message("ERROR %s: Echo spacing too small, minimum is %.3fms\n",seqfil,espmin*1000); } te1_delay = esp/2.0 - tau1 + GRADIENT_RES; // Intra-esp delays te2_delay = esp/2.0 - tau2 + GRADIENT_RES; te3_delay = esp/2.0 - tau3 + GRADIENT_RES; /* Spin echo preparation ******************************/ if (spinecho[0] == 'y') { te = granularity(te,2*GRADIENT_RES); te1 = te-kzero*esp; tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss3_grad.duration/2.0 + GRADIENT_RES; tau2 = ss3_grad.duration/2.0 + crush_grad.duration + GRADIENT_RES; temin = 2*MAX(tau1,tau2); /* Diffusion */ if (diff[0] == 'y') { /* granulate tDELTA */ tDELTA = granularity(tDELTA,GRADIENT_RES); /* taudiff is the duration of events between diffusion gradients */ taudiff = ss3_grad.duration + 2*crush_grad.duration; /* set minimum diffusion structure requirements for gradient echo: taudiff, tDELTA, te and minte[0] */ set_diffusion(&diffusion,taudiff,tDELTA,te1,minte[0]); /* set additional diffusion structure requirements for spin echo: tau1 and tau2 */ set_diffusion_se(&diffusion,tau1,tau2); /* calculate the diffusion structure delays. address &temin is required in order to update temin accordingly */ calc_diffTime(&diffusion,&temin); } /* TE delays */ if (minte[0] == 'y') { te1 = temin; te = te1+kzero*esp; putvalue("te",te); } te_delay1 = te1/2 - tau1 + GRADIENT_RES; te_delay2 = te1/2 - tau2 + GRADIENT_RES; if (FP_LT(te,temin+kzero*esp)) { abort_message("ERROR %s: TE too short, minimum TE = %.3f ms\n",seqfil,temin*1000); } } else putvalue("te",kzero*esp); // Return effective TE /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* Calculate B values *********************************/ if (ix==1) { /* Calculate bvalues according to main diffusion gradients */ calc_bvalues(&diffusion,"dro","dpe","dsl"); /* Add components from additional diffusion encoding imaging gradients peculiar to this sequence */ /* Initialize variables */ dgro = 0.5*(ror_grad.duration+ro_grad.timeToEcho); // readout dephase & readout delta Gro = ro_grad.m0ref/dgro; // readout dephase & readout gradient strength Dgro = dgro+2*crush_grad.duration+ss2_grad.duration+te2_delay+pe_grad.duration; // readout dephase & readout DELTA dgss = 0.5*(ss_grad.rfCenterBack+ssr_grad.duration); // slice & slice refocus delta Gss = ss_grad.m0ref/dgss; // slice & slice refocus gradient strength Dgss = dgss; // slice & slice refocus DELTA dgss2 = (ss2_grad.duration-ss2_grad.tramp)/2.0; // refocus slice select delta Dgss2 = dgss2; // refocus slice select DELTA dcrush2 = crush_grad.duration-crush_grad.tramp; // refocus crusher delta Dcrush2 = crush_grad.duration+ss2_grad.duration; // refocus crusher DELTA dcrush3 = crush_grad.duration-crush_grad.tramp; // spin echo prep crusher delta Dcrush3 = crush_grad.duration+ss3_grad.duration; // spin echo prep crusher DELTA dgss3 = (ss3_grad.duration-ss3_grad.tramp)/2.0; // spin echo prep slice select delta Dgss3 = dgss3; // spin echo prep slice select DELTA for (i = 0; i < diffusion.nbval; i++) { /* set droval, dpeval and dslval */ set_dvalues(&diffusion,&droval,&dpeval,&dslval,i); /* Readout */ diffusion.bro[i] += bval(Gro,dgro,Dgro); diffusion.bro[i] += bval(gcrushr,dcrush2,Dcrush2); diffusion.bro[i] += bval_nested(Gro,dgro,Dgro,gcrushr,dcrush2,Dcrush2); /* Phase */ diffusion.bpe[i] += bval(gcrushp,dcrush2,Dcrush2); /* Slice */ diffusion.bsl[i] += bval(Gss,dgss,Dgss); diffusion.bsl[i] += bval(gcrushs,dcrush2,Dcrush2); diffusion.bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2); diffusion.bsl[i] += bval_nested(gcrushs,dcrush2,Dcrush2,ss2_grad.ssamp,dgss2,Dgss2); /* Readout/Phase Cross-terms */ diffusion.brp[i] += bval2(gcrushr,gcrushp,dcrush2,Dcrush2); /* Readout/Slice Cross-terms */ diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,gcrushs,dcrush2,Dcrush2); diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,ss2_grad.ssamp,dgss2,Dgss2); diffusion.brs[i] += bval2(gcrushr,gcrushs,dcrush2,Dcrush2); diffusion.brs[i] += bval_cross(gcrushr,dcrush2,Dcrush2,ss2_grad.ssamp,dgss2,Dgss2); /* Slice/Phase Cross-terms */ diffusion.bsp[i] += bval2(gcrushs,gcrushp,dcrush2,Dcrush2); diffusion.bsp[i] += bval_cross(gcrushp,dcrush2,Dcrush2,ss2_grad.ssamp,dgss2,Dgss2); if (spinecho[0] == 'y') { /* Readout */ diffusion.bro[i] += bval(crush_grad.amp,dcrush3,Dcrush3); diffusion.bro[i] += bval_nested(gdiff*droval,tdelta,tDELTA,crush_grad.amp,dcrush3,Dcrush3); /* Slice */ diffusion.bsl[i] += bval(ss3_grad.amp,dgss3,Dgss3); diffusion.bsl[i] += bval_nested(gdiff*dslval,tdelta,tDELTA,ss3_grad.ssamp,dgss3,Dgss3); /* Readout/Slice Cross-terms */ diffusion.brs[i] += bval_cross(gdiff*dslval,tdelta,tDELTA,crush_grad.amp,dcrush3,Dcrush3); diffusion.brs[i] += bval_cross(gdiff*droval,tdelta,tDELTA,ss3_grad.amp,dgss3,Dgss3); diffusion.brs[i] += bval_cross(crush_grad.amp,dcrush3,Dcrush3,ss3_grad.amp,dgss3,Dgss3); /* Readout/Phase Cross-terms */ diffusion.brp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,crush_grad.amp,dcrush3,Dcrush3); /* Slice/Phase Cross-terms */ diffusion.bsp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,ss3_grad.amp,dgss3,Dgss3); } } /* End for-all-directions */ /* Write the values */ write_bvalues(&diffusion,"bval","bvalue","max_bval"); } /* Minimum TR *****************************************/ trmin = ss_grad.rfCenterFront + etl*esp + ro_grad.timeFromEcho + pe_grad.duration + te3_delay + 2*GRADIENT_RES; if (spoilflag[0] == 'y') trmin += spoil_grad.duration; /* Increase TR if any options are selected ************/ if (sat[0] == 'y') trmin += satTime; if (fsat[0] == 'y') trmin += fsatTime; if (mt[0] == 'y') trmin += mtTime; if (spinecho[0] == 'y') trmin += te1; if (ticks > 0) trmin += GRADIENT_RES; /* Adjust for all slices ******************************/ trmin *= ns; /* Inversion recovery *********************************/ if (ir[0] == 'y') { /* tauti is the additional time beyond IR component to be included in ti */ /* satTime, fsatTime and mtTime all included as those modules will be after IR */ tauti = satTime + fsatTime + mtTime + GRADIENT_RES + ss_grad.rfCenterFront; /* calc_irTime checks ti and returns the time of all IR components */ trmin += calc_irTime(tauti,trmin,mintr[0],tr,&trtype); } if (mintr[0] == 'y') { tr = trmin; putvalue("tr",tr); } if (FP_LT(tr,trmin)) { abort_message("ERROR %s: TR too short, minimum TR = %.3fms\n",seqfil,trmin*1000); } /* Calculate tr delay *********************************/ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Set number of segments for profile or full image ***/ nseg = prep_profile(profile[0],nseg,&pe_grad,&null_grad); pe2_steps = prep_profile(profile[1],nv2,&pe2_grad,&null_grad); F_initval(pe2_steps/2.0,vpe2_offset); /* Shift DDR for pro **********************************/ roff = -poffset(pro,ro_grad.roamp); /* Adjust experiment time for VnmrJ *******************/ if (ssc<0) { if (seqcon[2] == 's' && seqcon[3]=='s') g_setExpTime(trmean*ntmean*arraydim - ssc*arraydim); else if (seqcon[2]=='s') g_setExpTime(trmean*nseg*(ntmean*pe2_steps*arraydim - ssc*arraydim)); else if (seqcon[3]=='s') g_setExpTime(trmean*pe2_steps*(ntmean*nseg*arraydim - ssc*arraydim)); else g_setExpTime(trmean*(ntmean*pe_steps*pe2_steps*arraydim - ssc*arraydim)); } else g_setExpTime(trmean*ntmean*nseg*pe2_steps*arraydim + tr*ssc); /* PULSE SEQUENCE *************************************/ status(A); // Set status A rotate(); // Set gradient rotation according to psi, phi and theta triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); // Set spectrometer frequency delay(GRADIENT_RES); // Delay for frequency setting initval(fabs(ssc),vssc); // Compressed steady-state counter if (seqcon[2]=='s' && seqcon[3]=='s') assign(zero,vssc); // Zero for standard peloop and pe2loop assign(one,vacquire); // real-time acquire flag /* Phase cycle: Alternate 180 phase to cancel residual FID */ mod2(ct,vphase180); // 0101 dbl(vphase180,vphase180); // 0202 add(vphase180,one,vphase180); // 1313 Phase difference from 90 add(vphase180,oph,vphase180); /* trigger */ if (ticks > 0) F_initval((double)nsblock,vtrigblock); /* Begin phase-encode loop ****************************/ peloop2(seqcon[3],pe2_steps,vpe2_steps,vpe2_ctr); /* Begin phase-encode loop ****************************/ peloop(seqcon[2],nseg,vseg,vseg_ctr); if (trtype) delay(ns*tr_delay); // relaxation delay /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); if (seqcon[2] == 'c') sub(vseg_ctr,vssc,vseg_ctr); // vseg_ctr counts up from -ssc else if (seqcon[3] == 'c') sub(vpe2_ctr,vssc,vpe2_ctr); // vpe2_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's' && seqcon[3]=='s') assign(zero,vacquire); // Always acquire for non-compressed loop else { if (seqcon[2] == 'c') { ifzero(vseg_ctr); assign(zero,vacquire); // Start acquiring when vseg_ctr reaches zero endif(vseg_ctr); } else if (seqcon[3] == 'c') { ifzero(vpe2_ctr); assign(zero,vacquire); // Start acquiring when vpe2_ctr reaches zero endif(vpe2_ctr); } } setacqvar(vacquire); // Turn on acquire when vacquire is zero /* Use standard encoding order for 2nd PE dimension */ ifzero(vacquire); sub(vpe2_ctr,vpe2_offset,vpe2_mult); elsenz(vacquire); sub(zero,vpe2_offset,vpe2_mult); endif(vacquire); msloop(seqcon[1],ns,vms_slices,vms_ctr); if (!trtype) delay(tr_delay); // Relaxation delay if (ticks > 0) { modn(vms_ctr,vtrigblock,vtest); ifzero(vtest); // if the beginning of an trigger block xgate(ticks); grad_advance(gpropdelay); delay(GRADIENT_RES); elsenz(vtest); delay(GRADIENT_RES); endif(vtest); } sp1on(); delay(GRADIENT_RES); sp1off(); // Scope trigger /* Prepulse options ***********************************/ if (ir[0] == 'y') inversion_recovery(); if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* 90 degree pulse ************************************/ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(GRADIENT_RES); obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shapelist90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Spin echo preparation ******************************/ if (spinecho[0] == 'y') { obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0.0,0.0,-ssr_grad.amp,WAIT); if (diff[0] == 'y') { delay(diffusion.d1); diffusion_dephase(&diffusion,dro,dpe,dsl); delay(diffusion.d2); } else delay(te_delay1); obspower(p3_rf.powerCoarse); obspwrf(p3_rf.powerFine); obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0.0,0.0,WAIT); obl_shapedgradient(ss3_grad.name,ss3_grad.duration,0,0,ss3_grad.amp,NOWAIT); delay(ss3_grad.rfDelayFront); shapedpulselist(shapelistte,ss3_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss3_grad.rfDelayBack); obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0.0,0.0,WAIT); if (diff[0] == 'y') { delay(diffusion.d3); diffusion_rephase(&diffusion,dro,dpe,dsl); delay(diffusion.d4); } else delay(te_delay2); delay(ss_grad.duration/2.0); delay(te1_delay); obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); obl_shapedgradient(ror_grad.name,ror_grad.duration,ror_grad.amp,0.0,0.0,WAIT); } else { /* Read dephase and Slice refocus */ obl_shapedgradient(ssr_grad.name,ssr_grad.duration,ror_grad.amp,0.0,-ssr_grad.amp,WAIT); /* First half-TE delay */ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(te1_delay); } F_initval(etl,vetl); loop(vetl,vetl_ctr); mult(vseg_ctr,vetl,vpe_ctr); add(vpe_ctr,vetl_ctr,vpe_ctr); getelem(t1,vpe_ctr,vpe_mult); /* 180 degree pulse *********************************/ obl_shapedgradient(crush_grad.name,crush_grad.duration,gcrushr,gcrushp,gcrushs,WAIT); obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shapelist180,ss2_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); obl_shapedgradient(crush_grad.name,crush_grad.duration,gcrushr,gcrushp,gcrushs,WAIT); /* Second half-TE period ****************************/ delay(te2_delay); /* Phase-encode gradient ****************************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,-pe_grad.increment,-pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Readout gradient *********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.roamp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquire data *************************************/ startacq(alfa); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode gradient ******************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,pe_grad.increment,pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Second half-TE delay *****************************/ delay(te3_delay); endloop(vetl_ctr); if (spoilflag[0] == 'y') obl_shapedgradient(spoil_grad.name,spoil_grad.duration,spoil_grad.amp,spoil_grad.amp,spoil_grad.amp,WAIT); endmsloop(seqcon[1],vms_ctr); endpeloop(seqcon[2],vseg_ctr); endpeloop(seqcon[3],vpe2_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }
void pulsesequence() { /* Internal variable declarations *************************/ int shapelist90,shapelist180; double seqtime,tau1,tau2,tau3,te1_delay,te2_delay,te3_delay,tr_delay; double freq90[MAXNSLICE], freq180[MAXNSLICE]; /* Diffusion variables */ double te1, te1min, del1, del2, del3, del4; double te_diff1, te_diff2, tmp1, tmp2; double diffamp; char diffpat[MAXSTR]; /* Navigator variables */ double etlnav; /* Variable crushers */ double cscale; double vcrush; // flag /* 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 used in this sequence **************/ int vpe_ctr = v1; // PE loop counter int vpe_mult = v2; // PE multiplier, ranges from -PE/2 to PE/2 int vpe2_ctr = v3; // PE loop counter int vpe2_mult = v4; // PE multiplier, ranges from -PE/2 to PE/2 int vpe2_offset = v5; int vpe2_steps = v6; int vms_slices = v7; // Number of slices int vms_ctr = v8; // Slice loop counter int vseg = v9; // Number of ETL segments int vseg_ctr = v10; // Segment counter int vetl = v11; // Echo train length int vetl_ctr = v12; // Echo train loop counter int vssc = v13; // Compressed steady-states int vtrimage = v14; // Counts down from nt, trimage delay when 0 int vacquire = v15; // Argument for setacqvar, to skip steady state acquires int vphase180 = v16; // phase of 180 degree refocusing pulse int vetl_loop = v17; // Echo train length MINUS ONE, used on etl loop int vnav = v18; // Echo train length int vcr_ctr = v19; // variable crusher, index into table int vcr1 = v20; // multiplier along RO int vcr2 = v21; // multiplier along PE int vcr3 = v22; // multiplier along SL int vetl1 = v23; // = etl-1, determine navigator echo location in echo loop int vcr_reset = v24; // check for navigator echoes, reset crushers /* Initialize paramaters **********************************/ get_parameters(); te1 = getval("te1"); /* te1 is the echo time for the first echo */ cscale = getval("cscale"); /* Scaling factor on first 180 crushers */ vcrush = getval("vcrush"); /* Variable crusher or set amplitude? */ getstr("diffpat",diffpat); /* Load external PE table ********************************/ if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); } else { abort_message("petable undefined"); } /* Hold variable crushers in tables 5, 6, 7 */ settable(t5,8,crro); settable(t6,8,crpe); settable(t7,8,crss); seqtime = 0.0; espmin = 0.0; /* RF Power & Bandwidth Calculations **********************/ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2); init_rf(&p2_rf,p2pat,p2,flip2,rof1,rof2); // shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2); // shape_rf(&p2_rf,"p2",p2pat,p2,flip2,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Initialize gradient structures *************************/ init_readout(&ro_grad,"ro",lro,np,sw); init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_phase(&pe2_grad,"pe2",lpe2,nv2); init_slice(&ss_grad,"ss",thk); /* NOTE assume same band widths for p1 and p2 */ init_slice(&ss2_grad,"ss2",thk); /* not butterfly, want to scale crushers w/ echo */ init_slice_refocus(&ssr_grad,"ssr"); /* Gradient calculations **********************************/ calc_readout(&ro_grad,WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); calc_phase(&pe_grad,NOWRITE,"gpe","tpe"); calc_phase(&pe2_grad,NOWRITE,"gpe2","tpe2"); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p1_rf,WRITE,""); calc_slice_refocus(&ssr_grad,&ss_grad,WRITE,"gssr"); /* Equalize refocus and PE gradient durations *************/ calc_sim_gradient(&ror_grad,&pe_grad,&pe2_grad,0.0,WRITE); /* Variable crusher */ init_generic(&crush_grad,"crush",gcrush,tcrush); calc_generic(&crush_grad,WRITE,"",""); /* Create optional prepulse events ************************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); if (mt[0] == 'y') create_mtc(); /* Optional Diffusion gradient */ if (diff[0] == 'y') { init_generic(&diff_grad,"diff",gdiff,tdelta); if (!strcmp("sine",diffpat)) { diff_grad.shape = SINE; diffamp = gdiff*1; } /* adjust duration, so tdelta is from start ramp up to start ramp down */ if ((ix == 1) && (diff_grad.shape == TRAPEZOID)) { calc_generic(&diff_grad,NOWRITE,"",""); diff_grad.duration += diff_grad.tramp; } calc_generic(&diff_grad,WRITE,"",""); } /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.amp,0,freq90,ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shapelist90 = shapelist(p1_rf.pulseName,ss_grad.rfDuration, freq90, ns,0,seqcon[1]); shapelist180 = shapelist(p2_rf.pulseName,ss2_grad.rfDuration,freq180,ns,0,seqcon[1]); /* same slice selection gradient and RF pattern used */ if (ss_grad.rfFraction != 0.5) abort_message("RF pulse must be symmetric (RF fraction = %.2f)",ss_grad.rfFraction); if (ro_grad.echoFraction != 1) abort_message("Echo Fraction must be 1"); /*****************************************************/ /* TIMING FOR ECHOES *********************************/ /*****************************************************/ /* First echo time, without diffusion */ tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + crush_grad.duration + pe_grad.duration + ro_grad.timeToEcho; te1min = 2*MAX(tau1,tau2); if (te1 < te1min + 2*4e-6) { abort_message("First echo time too small, minimum is %.2fms\n",(te1min+2*4e-6)*1000); } /* Each half-echo period in the ETL loop ********/ tau3 = ro_grad.timeFromEcho + pe_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront; espmin = 2*MAX(tau2,tau3); // Minimum echo spacing if (minesp[0] == 'y') { esp = espmin + 2*4e-6; putvalue("esp",esp); } if (esp - (espmin + 2*4e-6) < -12.5e-9) { abort_message("Echo spacing too small, minimum is %.2fms\n",(espmin+2*4e-6)*1000); } te1_delay = te1/2.0 - tau1; te2_delay = esp/2.0 - tau2; te3_delay = esp/2.0 - tau3; /*****************************************************/ /* TIMING FOR DIFFUSION ******************************/ /*****************************************************/ del1 = te1/2.0 - tau1; del2 = 0; del3 = te1/2.0 - tau2; del4 = 0; if (diff[0] == 'y') { tau1 += diff_grad.duration; tau2 += diff_grad.duration; te1min = 2*MAX(tau1,tau2); if (te1 < te1min + 4*4e-6) { /* te1 is split into 4 delays, each of which must be >= 4us */ abort_message("ERROR %s: First echo time too small, minimum is %.2fms\n",seqfil,te1min*1000); } /* te1 is the echo time for the first echo */ te_diff1 = te1/2 - tau1; /* Available time in first half of first echo */ te_diff2 = te1/2 - tau2; /* Available time in second half of first echo */ tmp1 = ss2_grad.duration + 2*crush_grad.duration; /* duration of 180 block */ /* Is tDELTA long enough? */ if (tDELTA < diff_grad.duration + tmp1) abort_message("DELTA too short, increase to %.2fms", (diff_grad.duration + tmp1)*1000); /* Is tDELTA too long? */ tmp2 = diff_grad.duration + te_diff1 + tmp1 + te_diff2; if (tDELTA > tmp2) { abort_message("DELTA too long, increase te1 to %.2fms", (te1 + (tDELTA-tmp2))*1000); } /* First attempt to put lobes right after slice select, ie del1 = 0 */ del1 = 4e-6; /* At least 4us after setting power for 180 */ del2 = te_diff1 - del1; del3 = tDELTA - (diff_grad.duration + del2 + tmp1); if (del3 < 4e-6) { /* shift diffusion block towards acquisition */ del3 = 4e-6; del2 = tDELTA - (diff_grad.duration + tmp1 + del3); } del1 = te_diff1 - del2; del4 = te_diff2 - del3; if (fabs(del4) < 12.5e-9) del4 = 0; } te = te1 + (kzero-1)*esp; // Return effective TE putvalue("te",te); /* How many echoes in the echo loop, including navigators? */ etlnav = (etl-1)+(navigator[0]=='y')*2.0; /* Minimum TR **************************************/ seqtime = 4e-6 + 2*nseg*ns*4e-6; /* count all the 4us delays */ seqtime += ns*(ss_grad.duration/2 + te1 + (etlnav)*esp + ro_grad.timeFromEcho + pe_grad.duration + te3_delay); /* Increase TR if any options are selected****************/ if (sat[0] == 'y') seqtime += ns*satTime; if (fsat[0] == 'y') seqtime += ns*fsatTime; if (mt[0] == 'y') seqtime += ns*mtTime; trmin = seqtime + ns*4e-6; /* Add 4us to ensure that tr_delay is always >= 4us */ if (mintr[0] == 'y'){ tr = trmin; putvalue("tr",tr+1e-6); } if (tr < trmin) { abort_message("TR too short. Minimum TR = %.2fms\n",trmin*1000); } tr_delay = (tr - seqtime)/ns; /* Set number of segments for profile or full image **********/ nseg = prep_profile(profile[0],nv/etl,&pe_grad,&per_grad); pe2_steps = prep_profile(profile[1],nv2,&pe2_grad,&pe2r_grad); /* Calculate total scan time */ g_setExpTime(tr*(nt*nseg*pe2_steps*arraydim + ssc)); /***************************************************/ /* 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++) { dcrush = crush_grad.duration; //"delta" for crusher Dcrush = dcrush + ss_grad.duration; //"DELTA" for crusher /* Readout */ Dro = ror_grad.duration; bro[i] = bval(gdiff*roarr[i],tdelta,tDELTA); bro[i] += bval(ro_grad.amp,ro_grad.timeToEcho,Dro); bro[i] += bval(crush_grad.amp,dcrush,Dcrush); bro[i] += bval_nested(gdiff*roarr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); /* Slice */ dgss2 = Dgss2 = ss_grad.rfCenterFront; bsl[i] = bval(gdiff*slarr[i],tdelta,tDELTA); bsl[i] += bval(crush_grad.amp,dcrush,Dcrush); bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2); bsl[i] += bval_nested(gdiff*slarr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); bsl[i] += bval_nested(gdiff*slarr[i],tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); bsl[i] += bval_nested(ss2_grad.ssamp,dgss2,Dgss2, crush_grad.amp,dcrush,Dcrush); /* Phase */ bpe[i] = bval(gdiff*pearr[i],tdelta,tDELTA); bpe[i] += bval(crush_grad.amp,dcrush,Dcrush); bpe[i] += bval_nested(gdiff*pearr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); /* Readout/Slice Cross-terms */ brs[i] = bval2(gdiff*roarr[i],gdiff*slarr[i],tdelta,tDELTA); brs[i] += bval2(crush_grad.amp, crush_grad.amp,dcrush,Dcrush); brs[i] += bval_cross(gdiff*roarr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); brs[i] += bval_cross(gdiff*slarr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); brs[i] += bval_cross(gdiff*roarr[i],tdelta,tDELTA, ss2_grad.ssamp,dgss2,Dgss2); brs[i] += bval_cross(crush_grad.amp,dcrush,Dcrush, ss2_grad.ssamp,dgss2,Dgss2); /* Readout/Phase Cross-terms */ brp[i] = bval2(gdiff*roarr[i],gdiff*pearr[i],tdelta,tDELTA); brp[i] += bval2(crush_grad.amp, crush_grad.amp,dcrush,Dcrush); brp[i] += bval_cross(gdiff*roarr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); brp[i] += bval_cross(gdiff*pearr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); /* Slice/Phase Cross-terms */ bsp[i] = bval2(gdiff*pearr[i],gdiff*slarr[i],tdelta,tDELTA); bsp[i] += bval2(crush_grad.amp, crush_grad.amp,dcrush,Dcrush); bsp[i] += bval_cross(gdiff*pearr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); bsp[i] += bval_cross(gdiff*slarr[i],tdelta,tDELTA, crush_grad.amp,dcrush,Dcrush); bsp[i] += bval_cross(gdiff*pearr[i],tdelta,tDELTA, ss2_grad.ssamp,dgss2,Dgss2); bsp[i] += bval_cross(crush_grad.amp,dcrush,Dcrush, 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); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* PULSE SEQUENCE *************************************/ if (ix == 1) grad_advance(tep); initval(fabs(ssc),vssc); // Compressed steady-state counter setacqvar(vacquire); // Control acquisition through vacquire assign(one,vacquire); // Turn on acquire when vacquire is zero /* Phase cycle: Alternate 180 phase to cancel residual FID */ mod2(ct,vphase180); // 0101 dbl(vphase180,vphase180); // 0202 add(vphase180,one,vphase180); // 1313 Phase difference from 90 add(vphase180,oph,vphase180); obsoffset(resto); delay(4e-6); initval(nseg,vseg); initval(pe2_steps/2.0,vpe2_offset); initval(etl,vetl); initval(etl-1,vetl1); peloop2(seqcon[3],pe2_steps,vpe2_steps,vpe2_ctr); /* Use standard encoding order for 2nd PE dimension */ sub(vpe2_ctr,vpe2_offset,vpe2_mult); loop(vseg,vseg_ctr); /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vseg_ctr,vssc,vseg_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); ifzero(vseg_ctr); assign(zero,vacquire); // Start acquiring when vseg_ctr reaches zero endif(vseg_ctr); msloop(seqcon[1],ns,vms_slices,vms_ctr); if (ticks) { xgate(ticks); grad_advance(tep); } sp1on(); delay(4e-6); sp1off(); // Scope trigger /* Prepulse options ***********************************/ if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* 90 degree pulse ************************************/ rotate(); 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(shapelist90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Read dephase and Slice refocus *********************/ obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0.0,0.0,-ssr_grad.amp,WAIT); /* First half-TE delay ********************************/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(del1); /* 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); /*****************************************************/ /* FIRST ECHO OUTSIDE LOOP ***************************/ /*****************************************************/ ifzero(vacquire); // real acquisition, get PE multiplier from table mult(vseg_ctr,vetl,vpe_ctr); getelem(t1,vpe_ctr,vpe_mult); elsenz(vacquire); // steady state scan assign(zero,vpe_mult); endif(vacquire); /* Variable crusher */ assign(zero,vcr_ctr); getelem(t5,vcr_ctr,vcr1); getelem(t6,vcr_ctr,vcr2); getelem(t7,vcr_ctr,vcr3); if(vcrush) phase_encode3_oblshapedgradient(crush_grad.name,crush_grad.name,crush_grad.name, crush_grad.duration, (double)0,(double)0,(double)0, // base levels crush_grad.amp*cscale,crush_grad.amp*cscale,crush_grad.amp*cscale, // step size vcr1,vcr2,vcr3, // multipliers (double)1.0,(double)1.0,(double)1.0, // upper limit on multipliers 1,WAIT,0); else obl_shapedgradient(crush_grad.name,crush_grad.duration, crush_grad.amp,crush_grad.amp,crush_grad.amp,WAIT); /* 180 degree pulse *******************************/ obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shapelist180,ss2_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); if (vcrush) phase_encode3_oblshapedgradient(crush_grad.name,crush_grad.name,crush_grad.name, crush_grad.duration, (double)0,(double)0,(double)0, // base levels crush_grad.amp*cscale,crush_grad.amp*cscale,crush_grad.amp*cscale, // step size vcr1,vcr2,vcr3, // multipliers (double)1.0,(double)1.0,(double)1.0, // upper limit on multipliers 1,WAIT,0); else obl_shapedgradient(crush_grad.name,crush_grad.duration, crush_grad.amp,crush_grad.amp,crush_grad.amp,WAIT); delay(del3); /* 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); /* Phase-encode gradient ******************************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp,0,0, -pe_grad.increment,-pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Readout gradient ************************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.roamp,0,0,NOWAIT); delay(ro_grad.atDelayFront); /* Acquire data ****************************************/ startacq(10e-6); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode gradient ********************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0, pe_grad.increment,pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Second half-TE delay *******************************/ delay(te3_delay); /*****************************************************/ /* LOOP THROUGH THE REST OF ETL **********************/ /*****************************************************/ peloop(seqcon[2],etlnav,vetl_loop,vetl_ctr); ifzero(vacquire); // real acquisition, get PE multiplier from table mult(vseg_ctr,vetl,vpe_ctr); add(vpe_ctr,vetl_ctr,vpe_ctr); add(vpe_ctr,one,vpe_ctr); getelem(t1,vpe_ctr,vpe_mult); elsenz(vacquire); // steady state scan assign(zero,vpe_mult); endif(vacquire); /* But don't phase encode navigator echoes */ ifrtGE(vetl_ctr,vetl1,vnav); assign(zero,vpe_mult); endif(vnav); /* Variable crusher */ incr(vcr_ctr); /* Get next crusher level */ /* Except if we're doing navigators, start over */ sub(vetl1,vetl_ctr,vcr_reset); ifzero(vcr_reset); assign(zero,vcr_ctr); endif(vcr_reset); getelem(t5,vcr_ctr,vcr1); getelem(t6,vcr_ctr,vcr2); getelem(t7,vcr_ctr,vcr3); phase_encode3_oblshapedgradient(crush_grad.name,crush_grad.name,crush_grad.name, crush_grad.duration, (double)0,(double)0,(double)0, // base levels crush_grad.amp,crush_grad.amp,crush_grad.amp, // step size vcr1,vcr2,vcr3, // multipliers (double)1.0,(double)1.0,(double)1.0, // upper limit on multipliers 1,WAIT,0); /* 180 degree pulse *******************************/ obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shapelist180,ss2_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); /* Variable crusher */ phase_encode3_oblshapedgradient(crush_grad.name,crush_grad.name,crush_grad.name, crush_grad.duration, (double)0,(double)0,(double)0, // base levels crush_grad.amp,crush_grad.amp,crush_grad.amp, // step size vcr1,vcr2,vcr3, // multipliers (double)1.0,(double)1.0,(double)1.0, // upper limit on multipliers 1,WAIT,0); /* Phase-encode gradient ******************************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0, -pe_grad.increment,-pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Second half-TE period ******************************/ delay(te2_delay); /* Readout gradient ************************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.roamp,0,0,NOWAIT); delay(ro_grad.atDelayFront); startacq(10e-6); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode gradient ********************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0, pe_grad.increment,pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Second half-TE delay *******************************/ delay(te3_delay); endpeloop(seqcon[2],vetl_ctr); /* Relaxation delay ***********************************/ if (!trtype) delay(tr_delay); endmsloop(seqcon[1],vms_ctr); if (trtype) delay(ns*tr_delay); endloop(vseg_ctr); endpeloop(seqcon[3],vpe2_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }
pulsesequence() { /* Internal variable declarations *************************/ int shapelist90,shapelist180; int table = 0; double tau1,tau2,tau3,te1_delay,te2_delay,te3_delay,tr_delay; double freq90[MAXNSLICE],freq180[MAXNSLICE]; double thk2fact,crush_step,neby2,crush_ind; int suppressSTE,*crushtab; char crushmod[MAXSTR]; int i; /* Real-time variables used in this sequence **************/ int vpe_steps = v1; // Number of PE steps int vpe_ctr = v2; // PE loop counter int vpe_mult = v3; // PE multiplier, ranges from -PE/2 to PE/2 int vpe_offset = v4; // PE/2 for non-table offset int vms_slices = v5; // Number of slices int vms_ctr = v6; // Slice loop counter int vne = v7; // Number of echoes int vne_ctr = v8; // Echo loop counter int vssc = v9; // Compressed steady-states int vtrimage = v10; // Counts down from nt, trimage delay when 0 int vacquire = v11; // Argument for setacqvar, to skip steady state acquires int vphase90 = v12; // Phase of 90 degree excitation pulse int vphase180 = v13; // Phase of 180 degree refocusing pulse int vphindex = v14; // Phase cycle index int vneindex = v15; // Echo index, odd or even int vcrush = v16; // Crusher modulation int vtrigblock = v17; // Number of slices per trigger block /* Initialize paramaters **********************************/ init_mri(); getstr("crushmod",crushmod); suppressSTE=getval("suppressSTE"); /* Load external PE table ********************************/ if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); table = 1; } /* RF Power & Bandwidth Calculations **********************/ shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2); shape_rf(&p2_rf,"p2",p2pat,p2,flip2,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Calculate thk2fact to ensure gss=gss2 for the choice of p1 and p2 so that the sequence remains robust in the absence of correct balancing of slice select and slice refocus gradients */ thk2fact=p2_rf.bandwidth/p1_rf.bandwidth; putvalue("thk2fact",thk2fact); /* Initialize gradient structures *************************/ init_readout(&ro_grad,"ro",lro,np,sw); ro_grad.pad1=alfa; ro_grad.pad2=alfa; init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_slice(&ss_grad,"ss",thk); init_slice(&ss2_grad,"ss2",thk*thk2fact); init_slice_refocus(&ssr_grad,"ssr"); init_generic(&crush_grad,"crush",gcrush,tcrush); /* Gradient calculations **********************************/ calc_readout(&ro_grad,WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); calc_phase(&pe_grad,WRITE,"gpe","tpe"); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p2_rf,WRITE,""); calc_slice_refocus(&ssr_grad,&ss_grad,NOWRITE,"gssr"); calc_generic(&crush_grad,WRITE,"",""); /* Equalize slice refocus and PE gradient durations *******/ calc_sim_gradient(&ror_grad,&null_grad,&ssr_grad,0.0,WRITE); /* Create optional prepulse events ************************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); if (mt[0] == 'y') create_mtc(); if (ir[0] == 'y') create_inversion_recovery(); sgl_error_check(sglerror); /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.amp,0,freq90,ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shapelist90 = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freq90,ns,ss_grad.rfFraction,seqcon[1]); shapelist180 = shapelist(p2_rf.pulseName,ss2_grad.rfDuration,freq180,ns,ss2_grad.rfFraction,seqcon[1]); /* To ensure proper overlap spin and stimulated echoes ensure that the middle of the refocusing RF pulse is the centre of the pulse and that echoes are formed in the centre of the acquisition window */ if (ss2_grad.rfFraction != 0.5) abort_message("ERROR %s: Refocusing RF pulse must be symmetric (RF fraction = %.2f)", seqfil,ss2_grad.rfFraction); if (ro_grad.echoFraction != 1) abort_message("ERROR %s: Echo Fraction must be 1",seqfil); /* Find sum of all events in each half-echo period ********/ tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + pe_grad.duration + crush_grad.duration + ro_grad.timeToEcho; tau3 = ro_grad.timeFromEcho + pe_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront; espmin = 2*MAX(MAX(tau1,tau2),tau3); // Minimum echo spacing espmin += 2*GRADIENT_RES; // Ensure that each delay is at least GRADIENT_RES te = granularity(te,2*GRADIENT_RES); if (minesp[0] == 'y') { te = espmin; putvalue("te",te); } if (FP_LT(te,espmin)) { abort_message("ERROR %s: Echo time too small, minimum is %.3fms\n",seqfil,espmin*1000); } te1_delay = te/2.0 - tau1; // Intra-esp delays te2_delay = te/2.0 - tau2; te3_delay = te/2.0 - tau3; /* Now set the TE processing array accordingly */ putCmd("TE = 0"); /* Re-initialize TE */ for (i=0;i<ne;i++) putCmd("TE[%d] = %f",i+1,te*1000*(i+1)); /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* Minimum TR **************************************/ trmin = ss_grad.rfCenterFront + ne*te + ro_grad.timeFromEcho + pe_grad.duration + te3_delay + 2*GRADIENT_RES; /* Increase TR if any options are selected *********/ if (sat[0] == 'y') trmin += satTime; if (fsat[0] == 'y') trmin += fsatTime; if (mt[0] == 'y') trmin += mtTime; if (ticks > 0) trmin += GRADIENT_RES; /* Adjust for all slices ***************************/ trmin *= ns; /* Inversion recovery *********************************/ if (ir[0] == 'y') { /* tauti is the additional time beyond IR component to be included in ti */ /* satTime, fsatTime and mtTime all included as those modules will be after IR */ tauti = satTime + fsatTime + mtTime + GRADIENT_RES + ss_grad.rfCenterFront; /* calc_irTime checks ti and returns the time of all IR components */ trmin += calc_irTime(tauti,trmin,mintr[0],tr,&trtype); } if (mintr[0] == 'y') { tr = trmin; putvalue("tr",tr); } if (FP_LT(tr,trmin)) { abort_message("ERROR %s: TR too short, minimum TR is %.3fms\n",seqfil,trmin*1000); } /* Calculate tr delay */ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Set pe_steps for profile or full image **********/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&per_grad); F_initval(pe_steps/2.0,vpe_offset); /* Shift DDR for pro ************************************/ roff = -poffset(pro,ro_grad.roamp); /* Adjust experiment time for VnmrJ *********************/ if (ssc<0) { if (seqcon[2] == 'c') g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*arraydim)); else g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*pe_steps*arraydim)); } else g_setExpTime(trmean*ntmean*pe_steps*arraydim + tr*ssc); /* Set phase cycle tables */ if (suppressSTE) { if ((int)nt%2 == 1) abort_message("STE suppression requires a 2 step phase cycle. Set nt as a multiple of 2\n"); settable(t2,4,phref1s); settable(t3,4,phref2s); settable(t4,4,phrec1s); settable(t5,4,phrec2s); } else { settable(t2,4,phref1); settable(t3,4,phref2); settable(t4,4,phrec1); settable(t5,4,phrec2); } /* Set crusher table */ crushtab=malloc((int)ne*sizeof(int)); neby2=ceil(ne/2.0 - US); // US to handle precision errors crush_step=gcrush/neby2; for (i=0; i<ne; i++) { crush_ind = (1.0-2.0*(i%2))*(neby2-floor(i/2)); crushtab[i] = (int)(crush_ind); } settable(t6,(int)ne,crushtab); /* PULSE SEQUENCE ***************************************/ status(A); rotate(); triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); delay(GRADIENT_RES); initval(fabs(ssc),vssc); // Compressed steady-state counter if (seqcon[2]=='s') assign(zero,vssc); // Zero for standard peloop assign(one,vacquire); // real-time acquire flag setacqvar(vacquire); // Turn on acquire when vacquire is zero /* Phase for excitation pulse */ assign(zero,vphase90); /* trigger */ if (ticks > 0) F_initval((double)nsblock,vtrigblock); /* Begin phase-encode loop ****************************/ peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr); if (trtype) delay(ns*tr_delay); // relaxation delay /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vpe_ctr,vssc,vpe_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's') assign(zero,vacquire); // Always acquire for non-compressed loop else { ifzero(vpe_ctr); assign(zero,vacquire); // Start acquiring when vpe_ctr reaches zero endif(vpe_ctr); } /* Read external kspace table if set ******************/ if (table) getelem(t1,vpe_ctr,vpe_mult); else { ifzero(vacquire); sub(vpe_ctr,vpe_offset,vpe_mult); elsenz(vacquire); sub(zero,vpe_offset,vpe_mult); // Hold PE mult at initial value for steady states endif(vacquire); } msloop(seqcon[1],ns,vms_slices,vms_ctr); if (!trtype) delay(tr_delay); // Relaxation delay if (ticks > 0) { modn(vms_ctr,vtrigblock,vtest); ifzero(vtest); // if the beginning of an trigger block xgate(ticks); grad_advance(gpropdelay); delay(GRADIENT_RES); elsenz(vtest); delay(GRADIENT_RES); endif(vtest); } sp1on(); delay(GRADIENT_RES); sp1off(); // Scope trigger /* Prepulse options ***********************************/ if (ir[0] == 'y') inversion_recovery(); if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* 90 degree pulse ************************************/ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(GRADIENT_RES); obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shapelist90,ss_grad.rfDuration,vphase90,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Slice refocus **************************************/ obl_shapedgradient(ssr_grad.name,ssr_grad.duration,ror_grad.amp,0.0,-ssr_grad.amp,WAIT); /* First half-TE delay ********************************/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(te1_delay); F_initval(ne,vne); loop(vne,vne_ctr); /* Phase cycle for refocusing pulse and receiver */ mod4(ct,vphindex); mod2(vne_ctr,vneindex); ifzero(vneindex); getelem(t2,vphindex,vphase180); getelem(t4,vphindex,oph); elsenz(vneindex); getelem(t3,vphindex,vphase180); getelem(t5,vphindex,oph); endif(vneindex); /* Crusher gradient modulation */ assign(one,vcrush); if (crushmod[0] == 'y') { assign(zero,vcrush); ifzero(vneindex); add(vcrush,one,vcrush); elsenz(vneindex); sub(vcrush,one,vcrush); endif(vneindex); } if (crushmod[0] == 'p') { getelem(t6,vne_ctr,vcrush); crush_grad.amp=crush_step; } /* 180 degree pulse *******************************/ if (crushmod[0] == 'y' || crushmod[0] == 'p') var3_shapedgradient(crush_grad.name,crush_grad.duration,0.0,0.0,0.0,0.0,0.0,crush_grad.amp,zero,zero,vcrush,WAIT); else obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0,crush_grad.amp,WAIT); obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shapelist180,ss2_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); if (crushmod[0] == 'y' || crushmod[0] == 'p') var3_shapedgradient(crush_grad.name,crush_grad.duration,0.0,0.0,0.0,0.0,0.0,crush_grad.amp,zero,zero,vcrush,WAIT); else obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0,crush_grad.amp,WAIT); /* Second half-TE period ******************************/ delay(te2_delay); /* Phase-encode gradient ******************************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,-pe_grad.increment,vpe_mult,WAIT); /* Readout gradient ************************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.roamp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquire data ****************************************/ startacq(alfa); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode gradient ********************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,pe_grad.increment,vpe_mult,WAIT); /* Second half-TE delay *******************************/ delay(te3_delay); endloop(vne_ctr); endmsloop(seqcon[1],vms_ctr); endpeloop(seqcon[2],vpe_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }