void calc_generic(GENERIC_GRADIENT_T *grad, int write_flag, char VJparam_g[], char VJparam_t[]) { double gradamp; if ((ix > 1) && !sglarray) return; grad->writeToDisk = write_flag; /* assign writeToDisk flag */ strcpy(grad->param1,VJparam_g); /* Assign VNMRJ paramter 1 */ strcpy(grad->param2,VJparam_t); /* Assign VNMRJ paramter 2 */ if (grad->amp > grad->maxGrad) { sgl_abort_message("ERROR gradient %s: Crusher amplitude (%.2f) exceeds maximum (%.2f)", grad->name,grad->amp,grad->maxGrad); } if (grad->duration == 0) { if (strcmp(grad->param2, "")) /* The name of the duration is supplied */ sgl_abort_message("ERROR gradient %s: Duration (%s) is zero",grad->name,grad->param2); else sgl_abort_message("ERROR gradient %s: Duration is zero",grad->name); return; } gradamp = grad->amp; if (grad->amp == 0) { /* temporarily set it to a non-zero value in order to calculate a shape */ grad->amp = 1.0/32767.0*gmax; } calcGeneric(grad); /* calculate and create generic gradient */ /* reset gradient amplitude */ if (gradamp == 0) { grad->amp = 0; grad->m0 = 0; } if (strcmp(grad->param1, "")) putvalue(grad->param1, grad->amp); if (strcmp(grad->param2, "")) putvalue(grad->param2, grad->duration); }
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); }
/*********************************************************************** * Function Name: calc_sim_gradient * Example: calc_sim_gradient (GENERIC_GRADIENT_T *grad0, * GENERIC_GRADIENT_T *grad1, * GENERIC_GRADIENT_T *grad2, * double min_tpe, * int write_flag) * Purpose: Blocks up to three gradient * Input * Formal: *grad0 - pointer to generic structure * *grad0 - pointer to generic structure * *grad0 - pointer to generic structure * min_tpe - minimum duration * write_flag - write to disk flag * Private: none * Public: * Output * Return: double - duration of blocked greadients * Formal: none * Private: none * Public: none * Notes: ONLY works for trapezoidal gradients ***********************************************************************/ double calc_sim_gradient(GENERIC_GRADIENT_T *grad0, GENERIC_GRADIENT_T *grad1, GENERIC_GRADIENT_T *grad2, double min_tpe, int write_flag) { int i; /* loop counter */ int typesum = 0; /* check for gradient type */ double time = 0.0; /* longest duration of gradient */ double tramp = 0.0; /* longest ramp time */ double duration0, duration1, duration2; /* gradient durations */ double tramp0, tramp1,tramp2; /* gradient ramp time */ double amp0, amp1, amp2; GENERIC_GRADIENT_T* grad[3]; /* internal array of structs to allow indexing */ if ((ix > 1) && !sglarray) return(grad0->duration); /* assign input structs to internal array to allow use in for loop ***/ grad[0] = grad0; grad[1] = grad1; grad[2] = grad2; /* check for shape -> all gradients need to be trapezoidal */ for (i=0; i<3; i++) { if (grad[i]->shape != TRAPEZOID) { displayGeneric(grad[i]); sgl_abort_message("ERROR calc_sim_gradient: Gradient %d ('%s') must be trapezoidal",i,grad[i]->name); } } /* find longest gradient duration */ duration0 = grad[0]->duration - grad[0]->tramp; /* duration of a square gradient with same integral & amplitude */ duration1 = grad[1]->duration - grad[1]->tramp; duration2 = grad[2]->duration - grad[2]->tramp; time = MAX(MAX(duration0,duration1),duration2); /* should already be granulated */ if( trampfixed > 0.0 ) { tramp = grad[0]->tramp; } else { amp0 = (fabs(grad[0]->m0) + fabs(grad[0]->areaOffset))/time; /* amplitude of square gradient with same integral and duration "time" */ amp1 = (fabs(grad[1]->m0) + fabs(grad[1]->areaOffset))/time; amp2 = (fabs(grad[2]->m0) + fabs(grad[2]->areaOffset))/time; tramp0 = amp0/grad[0]->slewRate; /* ramp time with new amplitude */ tramp1 = amp1/grad[1]->slewRate; tramp2 = amp2/grad[2]->slewRate; tramp = MAX(MAX(tramp0,tramp1),tramp2); tramp = granularity(tramp,grad[0]->resolution); } /* But use min_tpe as duration, if it is longer */ time = MAX(time+tramp,granularity(min_tpe,grad[0]->resolution)); /* assign new duration, ramp time, calc flag, and write flag to all 3 */ grad[0]->duration = grad[1]->duration = grad[2]->duration = time; grad[0]->tramp = grad[1]->tramp = grad[2]->tramp = tramp; grad[0]->calcFlag = grad[1]->calcFlag = grad[2]->calcFlag = AMPLITUDE_FROM_MOMENT_DURATION_RAMP; /* set writeToDisk flag */ grad[0]->writeToDisk = grad[1]->writeToDisk = grad[2]->writeToDisk = write_flag; /* Re-calculate gradients */ for (i=0; i<3; i++) { switch(grad[i]->type) { case REFOCUS_GRADIENT_TYPE: calcRefocus(grad[i]); if (strcmp(grad[i]->param1, "")) putvalue(grad[i]->param1, grad[i]->amp); break; case DEPHASE_GRADIENT_TYPE: calcDephase(grad[i]); if (strcmp(grad[i]->param1, "")) putvalue(grad[i]->param1, grad[i]->amp); break; case PHASE_GRADIENT_TYPE: calcPhase(grad[i]); if (strcmp(grad[i]->param1, "")) putvalue(grad[i]->param1, grad[i]->amp); if (strcmp(grad[i]->param2, "")) putvalue(grad[i]->param2, grad[i]->duration); break; case GENERIC_GRADIENT_TYPE: calcGeneric(grad[i]); if (strcmp(grad[i]->param1, "")) putvalue(grad[i]->param1, grad[i]->amp); break; default: typesum += 1; } } if (typesum >=2) { sgl_abort_message("ERROR calc_sim_gradient: 2 or more unspecified gradients as arguments"); } /* return longest duration */ return(time); }
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"); } }