void init_generic(GENERIC_GRADIENT_T *grad, char name[], double amp, double time) { if ((ix > 1) && !sglarray) return; initGeneric(grad); /* initialize generic gradient with defaults */ grad->amp = amp; /* assign gradient amplitude */ grad->duration = time; /* assign gradient duration */ grad->maxGrad = gmax; /* assign maximum allowed gradient */ strcpy(grad->name,name); /* assign waveform name */ }
void trapezoid(GENERIC_GRADIENT_T *grad, char name[], double amp, double time, double moment, int write_flag) { /* check is input values for moment, amplitude, time are set */ if ((amp == 0) && (time == 0) && (moment == 0)) { sgl_abort_message("ERROR gradient %s: All input values to <trapezoid> function are zero",name); return; } initGeneric(grad); /* initialize generic gradient with defaults */ grad->amp = amp; /* assign amplitude */ grad->duration = time; /* assign duration */ grad->m0 = moment; /* assign moment0 */ grad->maxGrad = gmax; /* assign maximum allowed gradient */ grad->writeToDisk = write_flag; /* set writeToDisk flag */ strcpy(grad->name,name); /* assign waveform name */ /* check amplitude */ if (amp > glim*gmax) { sgl_abort_message("ERROR gradient %s: amp too large (%f), reduced to glim*gmax (%f)", name, amp, glim*gmax); } /* evaluate imputs and set correct calcFlag */ if ((amp != 0) && (time != 0) && (moment == 0)) { grad->calcFlag = MOMENT_FROM_DURATION_AMPLITUDE; } else if ((amp == 0) && (time != 0) && (moment != 0)) { grad->calcFlag = AMPLITUDE_FROM_MOMENT_DURATION; } else if ((amp != 0) && (time == 0) && (moment != 0)) { grad->calcFlag = DURATION_FROM_MOMENT_AMPLITUDE; } calcGeneric(grad); }
void calc_readout_rampsamp(READOUT_GRADIENT_T *grad, double *dwell, double *minskip, int *npr) { double this_gro, skip, skip_m0, dwint, dw, dwflat; double ramp_t, ramp_m0, flat_t, flat_m0, dwell_sum, rt; int npro, np_ramp, np_flat; int pt, pt2; GENERIC_GRADIENT_T gg; /* Calculate gradient amplitude based on FOV and sw */ this_gro = sw/grad->gamma/lro; grad->amp = this_gro; /* Nominal dwell time is 1/sw */ dw = granularity(1/sw,1/epi_grad.ddrsr); dwflat = dw; /* we may later end up with different dw on flat part */ dwint = dw*grad->amp; /* Gradient Integral per point */ npro = (int) np/2; /* Calculate the area that is skipped for phase encoding blip */ skip = *minskip; if (skip == 0) skip = dw + getval("aqtm")-at; /* Need at least a dwell time at the end */ skip_m0 = skip*(skip*grad->slewRate)/2; /* Area of that skipped part */ /* Calculate the ramp time */ grad->tramp = granularity(grad->amp/grad->slewRate,grad->resolution); grad->slewRate = grad->amp/grad->tramp; ramp_m0 = grad->tramp*grad->amp/2; np_ramp = (int) ((ramp_m0 - skip_m0)/dwint); /* Check that we even need points on the flat part */ if (np_ramp >= npro/2) { np_ramp = npro/2 - 1; /* Center two points considered "flat part" */ /* We may not need to go all the way to full gradient in order to fit all points on ramp; adjust amplitude */ ramp_m0 = np_ramp*dwint + skip_m0; grad->tramp = granularity(sqrt(2*ramp_m0/grad->slewRate),grad->resolution); grad->amp = grad->tramp * grad->slewRate; /* recalculate ramp area and np_ramp */ ramp_m0 = grad->tramp*grad->amp/2; /* Now adjust the dwell time necessary on flat part with this amplitude */ dwflat = granularity(dwint/grad->amp,1/epi_grad.ddrsr); } np_flat = npro - 2*np_ramp; /* How long must the flat part be? */ grad->duration = granularity((np_flat-1)*dwflat,grad->resolution); /* Due to rounding of gradient duration, we may be able to fit more points on flat part */ while (grad->duration - (np_flat-1)*dwflat >= 2*dwflat) { np_flat += 2; np_ramp -= 1; } /* Now add the ramp times to the total duration */ grad->duration += 2*grad->tramp; /* Use a generic to calculate the actual shape, ie fill in dataPoints */ initGeneric(&gg); gg.amp = grad->amp; gg.duration = grad->duration; gg.tramp = grad->tramp; gg.slewRate = grad->slewRate; gg.calcFlag = MOMENT_FROM_DURATION_AMPLITUDE_RAMP; gg.writeToDisk = FALSE; calcGeneric(&gg); if (gg.error != ERR_NO_ERROR) { printf("Temporary generic gradient: \n"); displayGeneric(&gg); abort_message("Problem calculating RO gradient with ramp sampling"); } grad->m0 = gg.m0; grad->m1 = gg.m1; grad->m0ref = grad->m0/2; grad->numPoints = gg.numPoints; free(grad->dataPoints); // release original array grad->dataPoints = gg.dataPoints; /* Recalculate the skipped part with new gradient integral */ skip_m0 = (grad->m0 - dwint*(np/2-1))/2; skip = sqrt(2*skip_m0/grad->slewRate); /* Skip rampsampling if gradient is longer than necessary */ if ((grad->m0-ramp_m0*2) > npro*dwint) { warn_message("The gradient is too long, no ramp sampling"); for (pt = 0; pt < npro; pt++) { dwell[pt] = dwflat; } *minskip = grad->tramp; return; } /* Calculate where we start acquisition on the ramp */ /* Do we have extra integral on flat part? */ flat_m0 = (grad->m0 - 2*ramp_m0) - ((np_flat-1)*dwflat*grad->amp); /* if yes, then what is the duration of this? */ if (flat_m0 > 0) flat_t = (grad->duration - 2*grad->tramp) / ((np_flat - 1)*dwflat); else flat_t = 0; /* Double-check that gradient is long enough */ if (flat_m0 < -1e-9) abort_message("Gradient integral too small %f vs %f (%f) G/cm*us", (grad->m0-2*ramp_m0)*1e6,(np_flat-1)*dwint*1e6,flat_m0*1e9); /* If extra integral > 2*dwint, we could move a point from each ramp up to the flat */ if (flat_m0 > 2*dwint) warn_message("Gradient flat part longer than necessary with ramp sampling, check gradient calculation\n"); /**************************************************************************/ /* Calculate dwell times */ /**************************************************************************/ dwell_sum = 0; /* Start at top of ramp and walk down ramp */ pt = np_ramp - 1; rt = grad->tramp; /* Top point on ramp first, it may use a bit of time from the flat part */ if (flat_m0 > 0) { ramp_m0 -= (dwint - flat_m0/2); /* area at ramp at previous point */ flat_t = (grad->duration - 2*grad->tramp) - ((np_flat - 1)*dwflat); /* extra duration at top */ flat_t /= 2; /* divide evenly between both ramps */ } else { ramp_m0 -= dwint; /* area at ramp at previous point */ flat_t = 0; } ramp_t = sqrt(2*ramp_m0/grad->slewRate); /* time at ramp at previous point */ dwell[pt] = granularity(flat_t + (rt-ramp_t), 1/epi_grad.ddrsr); dwell_sum += dwell[pt]; ramp_t = rt - (dwell[pt] - flat_t); /* correct for rounding of dwell */ /* Do all the rest of the points on the ramp */ for(pt = np_ramp-2; pt >= 0; pt--) { rt = ramp_t; /* remember current time */ ramp_m0 -= dwint; /* total area of ramp at previous point */ if (ramp_m0 <= 0) { if (fabs(ramp_m0) > dwint*0.01) abort_message("problem: ramp_m0 negative %f\n",ramp_m0*1000); ramp_t = 0; } else ramp_t = sqrt(2*ramp_m0/grad->slewRate); /* time at previous point */ dwell[pt] = granularity(rt-ramp_t,1/epi_grad.ddrsr); dwell_sum += dwell[pt]; ramp_t = rt - dwell[pt]; } skip = ramp_t; dwell_sum += skip; for (pt = np_ramp; pt < np_ramp+np_flat-1; pt++) { /* Flat part */ dwell[pt] = dwflat; dwell_sum += dwflat; } pt2 = np_ramp-1; for (pt = np_ramp+np_flat-1; pt < np_ramp*2 + np_flat - 1; pt++) { dwell[pt] = dwell[pt2--]; dwell_sum += dwell[pt]; } /* Very last point, just set dwell = 1/sw */ pt = np_ramp*2 + np_flat - 1; dwell[pt] = dw; dwell_sum += skip; if (fabs(dwell_sum - grad->duration) > 12.5e-9) warn_message("Mismatch in sum of dwells (%.3fus) vs. gradient duration (%.3fus)", dwell_sum*1e6,grad->duration*1e6); /* Return values */ *minskip = skip; *npr = np_ramp; if (sgldisplay) { printf("============== DEBUG DWELL (%d, %d, %d) ===============\n",np_ramp,np_flat,np_ramp); dwell_sum = skip; for (pt = 0; pt < npro-1; pt++) { printf("[%3d] %3.6f\t%3.3f\t%3.6f\n",pt+1,dwell_sum*1e6,dwell[pt]*1e6,(dwell[pt]+dwell_sum)*1e6); dwell_sum += dwell[pt]; } printf("[%3d] %3.6f\t%3.3f\t%3.6f\n",(pt+1),dwell_sum*1e6,0.0,dwell_sum*1e6);pt++; printf("[%3d] %3.6f\t%3.3f\t%3.6f\n",pt+1,dwell_sum*1e6,skip*1e6,(skip+dwell_sum)*1e6); dwell_sum += skip; printf("Did we get a full gradient's worth? %.6f, %.6f\n",grad->duration*1e6,dwell_sum*1e6); printf("=======================================================\n"); } }