|
|
|
@ -30,10 +30,10 @@ extern int fixme_inoise_type; |
|
|
|
int |
|
|
|
NOISEan (CKTcircuit *ckt, int restart) |
|
|
|
{ |
|
|
|
static Ndata *data; /* va, must be static, for continuation of |
|
|
|
* interrupted(Ctrl-C), longer lasting noise |
|
|
|
* analysis |
|
|
|
*/ |
|
|
|
/* variable must be static, for continuation of interrupted (Ctrl-C), |
|
|
|
longer lasting noise anlysis */ |
|
|
|
static Ndata *data; |
|
|
|
|
|
|
|
double realVal; |
|
|
|
double imagVal; |
|
|
|
int error; |
|
|
|
@ -51,37 +51,35 @@ NOISEan (CKTcircuit *ckt, int restart) |
|
|
|
posOutNode = (job->output) -> number; |
|
|
|
negOutNode = (job->outputRef) -> number; |
|
|
|
|
|
|
|
if (job->NnumSteps < 1) { |
|
|
|
SPfrontEnd->IFerrorf(ERR_WARNING, |
|
|
|
"Number of steps for noise measurement has to be larger than 0,\n but currently is %d\n", |
|
|
|
job->NnumSteps); |
|
|
|
return(E_PARMVAL); |
|
|
|
} |
|
|
|
else if ((job->NnumSteps == 1) && (job->NstpType == LINEAR)) { |
|
|
|
if (!frequequal) { |
|
|
|
job->NstopFreq = job->NstartFreq; |
|
|
|
SPfrontEnd->IFerrorf(ERR_WARNING, |
|
|
|
"Noise measurement at a single frequency %g only!\n", |
|
|
|
job->NstartFreq); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if (frequequal) { |
|
|
|
job->NstopFreq = job->NstartFreq; |
|
|
|
job->NnumSteps = 1; |
|
|
|
SPfrontEnd->IFerrorf(ERR_WARNING, |
|
|
|
"Noise measurement at a single frequency %g only!\n", |
|
|
|
job->NstartFreq); |
|
|
|
} |
|
|
|
} |
|
|
|
if (job->NnumSteps < 1) { |
|
|
|
SPfrontEnd->IFerrorf(ERR_WARNING, |
|
|
|
"Number of steps for noise measurement has to be larger than 0,\n but currently is %d\n", |
|
|
|
job->NnumSteps); |
|
|
|
return(E_PARMVAL); |
|
|
|
} else if ((job->NnumSteps == 1) && (job->NstpType == LINEAR)) { |
|
|
|
if (!frequequal) { |
|
|
|
job->NstopFreq = job->NstartFreq; |
|
|
|
SPfrontEnd->IFerrorf(ERR_WARNING, |
|
|
|
"Noise measurement at a single frequency %g only!\n", |
|
|
|
job->NstartFreq); |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (frequequal) { |
|
|
|
job->NstopFreq = job->NstartFreq; |
|
|
|
job->NnumSteps = 1; |
|
|
|
SPfrontEnd->IFerrorf(ERR_WARNING, |
|
|
|
"Noise measurement at a single frequency %g only!\n", |
|
|
|
job->NstartFreq); |
|
|
|
} |
|
|
|
} |
|
|
|
/* see if the source specified is AC */ |
|
|
|
{ |
|
|
|
bool ac_given = FALSE; |
|
|
|
|
|
|
|
if (!inst || inst->GENmodPtr->GENmodType < 0) { |
|
|
|
SPfrontEnd->IFerrorf (ERR_WARNING, |
|
|
|
"Noise input source %s not in circuit", |
|
|
|
job->input); |
|
|
|
"Noise input source %s not in circuit", |
|
|
|
job->input); |
|
|
|
return E_NOTFOUND; |
|
|
|
} |
|
|
|
|
|
|
|
@ -93,93 +91,93 @@ NOISEan (CKTcircuit *ckt, int restart) |
|
|
|
src_type = SV_CURRENT; |
|
|
|
} else { |
|
|
|
SPfrontEnd->IFerrorf (ERR_WARNING, |
|
|
|
"Noise input source %s is not of proper type", |
|
|
|
job->input); |
|
|
|
"Noise input source %s is not of proper type", |
|
|
|
job->input); |
|
|
|
return E_NOTFOUND; |
|
|
|
} |
|
|
|
|
|
|
|
if (!ac_given) { |
|
|
|
SPfrontEnd->IFerrorf (ERR_WARNING, |
|
|
|
"Noise input source %s has no AC value", |
|
|
|
job->input); |
|
|
|
"Noise input source %s has no AC value", |
|
|
|
job->input); |
|
|
|
return E_NOACINPUT; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if ( (job->NsavFstp == 0.0) || restart) { /* va, NsavFstp is double */ |
|
|
|
switch (job->NstpType) { |
|
|
|
switch (job->NstpType) { |
|
|
|
|
|
|
|
|
|
|
|
case DECADE: |
|
|
|
job->NfreqDelta = exp(log(10.0)/ |
|
|
|
job->NnumSteps); |
|
|
|
job->NnumSteps); |
|
|
|
break; |
|
|
|
|
|
|
|
case OCTAVE: |
|
|
|
job->NfreqDelta = exp(log(2.0)/ |
|
|
|
job->NnumSteps); |
|
|
|
job->NnumSteps); |
|
|
|
break; |
|
|
|
|
|
|
|
case LINEAR: |
|
|
|
if (job->NnumSteps == 1) |
|
|
|
job->NfreqDelta = 0; |
|
|
|
else |
|
|
|
if (job->NnumSteps == 1) |
|
|
|
job->NfreqDelta = 0; |
|
|
|
else |
|
|
|
job->NfreqDelta = (job->NstopFreq - |
|
|
|
job->NstartFreq) / (job->NnumSteps - 1); |
|
|
|
job->NstartFreq) / (job->NnumSteps - 1); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return(E_BADPARM); |
|
|
|
} |
|
|
|
|
|
|
|
/* error = DCop(ckt); */ |
|
|
|
error = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, |
|
|
|
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, |
|
|
|
ckt->CKTdcMaxIter); |
|
|
|
/* error = DCop(ckt); */ |
|
|
|
error = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, |
|
|
|
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, |
|
|
|
ckt->CKTdcMaxIter); |
|
|
|
|
|
|
|
if (error) return(error); |
|
|
|
|
|
|
|
if (error) return(error); |
|
|
|
/* Patch to noisean.c by Richard D. McRoberts. */ |
|
|
|
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; |
|
|
|
error = CKTload(ckt); |
|
|
|
if(error) return(error); |
|
|
|
|
|
|
|
/* Patch to noisean.c by Richard D. McRoberts. */ |
|
|
|
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; |
|
|
|
error = CKTload(ckt); |
|
|
|
if(error) return(error); |
|
|
|
|
|
|
|
data = TMALLOC(Ndata, 1); |
|
|
|
step = 0; |
|
|
|
data->freq = job->NstartFreq; |
|
|
|
data->outNoiz = 0.0; |
|
|
|
data->inNoise = 0.0; |
|
|
|
data->squared = cp_getvar("sqrnoise", CP_BOOL, NULL, 0) ? 1 : 0; |
|
|
|
data = TMALLOC(Ndata, 1); |
|
|
|
step = 0; |
|
|
|
data->freq = job->NstartFreq; |
|
|
|
data->outNoiz = 0.0; |
|
|
|
data->inNoise = 0.0; |
|
|
|
data->squared = cp_getvar("sqrnoise", CP_BOOL, NULL, 0) ? 1 : 0; |
|
|
|
|
|
|
|
/* the current front-end needs the namelist to be fully |
|
|
|
declared before an OUTpBeginplot */ |
|
|
|
/* the current front-end needs the namelist to be fully |
|
|
|
declared before an OUTpBeginplot */ |
|
|
|
|
|
|
|
SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL); |
|
|
|
SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL); |
|
|
|
|
|
|
|
data->numPlots = 0; /* we don't have any plots yet */ |
|
|
|
data->numPlots = 0; /* we don't have any plots yet */ |
|
|
|
error = CKTnoise(ckt,N_DENS,N_OPEN,data); |
|
|
|
if (error) return(error); |
|
|
|
|
|
|
|
/* |
|
|
|
* all names in the namelist have been declared. now start the |
|
|
|
* plot |
|
|
|
*/ |
|
|
|
/* |
|
|
|
* all names in the namelist have been declared. now start the |
|
|
|
* plot |
|
|
|
*/ |
|
|
|
|
|
|
|
if (src_type == SV_VOLTAGE) |
|
|
|
fixme_inoise_type = |
|
|
|
if (src_type == SV_VOLTAGE) |
|
|
|
fixme_inoise_type = |
|
|
|
data->squared ? SV_SQR_VOLTAGE_DENSITY : SV_VOLTAGE_DENSITY; |
|
|
|
else |
|
|
|
fixme_inoise_type = |
|
|
|
else |
|
|
|
fixme_inoise_type = |
|
|
|
data->squared ? SV_SQR_CURRENT_DENSITY : SV_CURRENT_DENSITY; |
|
|
|
|
|
|
|
fixme_onoise_type = |
|
|
|
fixme_onoise_type = |
|
|
|
data->squared ? SV_SQR_VOLTAGE_DENSITY : SV_VOLTAGE_DENSITY; |
|
|
|
|
|
|
|
if (!data->squared) |
|
|
|
for (i = 0; i < data->numPlots; i++) |
|
|
|
data->squared_value[i] = |
|
|
|
ciprefix("inoise", data->namelist[i]) || |
|
|
|
ciprefix("onoise", data->namelist[i]); |
|
|
|
if (!data->squared) |
|
|
|
for (i = 0; i < data->numPlots; i++) |
|
|
|
data->squared_value[i] = |
|
|
|
ciprefix("inoise", data->namelist[i]) || |
|
|
|
ciprefix("onoise", data->namelist[i]); |
|
|
|
|
|
|
|
error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, |
|
|
|
data->squared |
|
|
|
@ -189,41 +187,41 @@ NOISEan (CKTcircuit *ckt, int restart) |
|
|
|
freqUid, IF_REAL, |
|
|
|
data->numPlots, data->namelist, IF_REAL, |
|
|
|
&(data->NplotPtr)); |
|
|
|
if (error) return(error); |
|
|
|
if (error) return(error); |
|
|
|
|
|
|
|
if (job->NstpType != LINEAR) { |
|
|
|
SPfrontEnd->OUTattributes (data->NplotPtr, NULL, OUT_SCALE_LOG, NULL); |
|
|
|
} |
|
|
|
SPfrontEnd->OUTattributes (data->NplotPtr, NULL, OUT_SCALE_LOG, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
} else { /* we must have paused before. pick up where we left off */ |
|
|
|
step = (int)(job->NsavFstp); |
|
|
|
switch (job->NstpType) { |
|
|
|
step = (int)(job->NsavFstp); |
|
|
|
switch (job->NstpType) { |
|
|
|
|
|
|
|
case DECADE: |
|
|
|
case DECADE: |
|
|
|
case OCTAVE: |
|
|
|
data->freq = job->NstartFreq * exp (step * |
|
|
|
log (job->NfreqDelta)); |
|
|
|
data->freq = job->NstartFreq * exp (step * |
|
|
|
log (job->NfreqDelta)); |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case LINEAR: |
|
|
|
data->freq = job->NstartFreq + step * |
|
|
|
job->NfreqDelta; |
|
|
|
data->freq = job->NstartFreq + step * |
|
|
|
job->NfreqDelta; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return(E_BADPARM); |
|
|
|
|
|
|
|
} |
|
|
|
job->NsavFstp = 0; |
|
|
|
data->outNoiz = job->NsavOnoise; |
|
|
|
data->inNoise = job->NsavInoise; |
|
|
|
/* saj resume rawfile fix*/ |
|
|
|
job->NsavFstp = 0; |
|
|
|
data->outNoiz = job->NsavOnoise; |
|
|
|
data->inNoise = job->NsavInoise; |
|
|
|
/* saj resume rawfile fix*/ |
|
|
|
error = SPfrontEnd->OUTpBeginPlot (NULL, NULL, |
|
|
|
NULL, |
|
|
|
NULL, 0, |
|
|
|
666, NULL, 666, |
|
|
|
&(data->NplotPtr)); |
|
|
|
/*saj*/ |
|
|
|
/*saj*/ |
|
|
|
} |
|
|
|
|
|
|
|
switch (job->NstpType) { |
|
|
|
@ -244,111 +242,111 @@ NOISEan (CKTcircuit *ckt, int restart) |
|
|
|
|
|
|
|
while (data->freq <= job->NstopFreq + freqTol) { |
|
|
|
if(SPfrontEnd->IFpauseTest()) { |
|
|
|
job->NsavFstp = step; /* save our results */ |
|
|
|
job->NsavOnoise = data->outNoiz; /* up until now */ |
|
|
|
job->NsavInoise = data->inNoise; |
|
|
|
return (E_PAUSE); |
|
|
|
job->NsavFstp = step; /* save our results */ |
|
|
|
job->NsavOnoise = data->outNoiz; /* up until now */ |
|
|
|
job->NsavInoise = data->inNoise; |
|
|
|
return (E_PAUSE); |
|
|
|
} |
|
|
|
ckt->CKTomega = 2.0 * M_PI * data->freq; |
|
|
|
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEAC | MODEACNOISE; |
|
|
|
ckt->noise_input = inst; |
|
|
|
|
|
|
|
/* |
|
|
|
* solve the original AC system to get the transfer |
|
|
|
* function between the input and output |
|
|
|
*/ |
|
|
|
|
|
|
|
NIacIter(ckt); |
|
|
|
realVal = ckt->CKTrhsOld [posOutNode] |
|
|
|
- ckt->CKTrhsOld [negOutNode]; |
|
|
|
imagVal = ckt->CKTirhsOld [posOutNode] |
|
|
|
- ckt->CKTirhsOld [negOutNode]; |
|
|
|
data->GainSqInv = 1.0 / MAX(((realVal*realVal) |
|
|
|
+ (imagVal*imagVal)),N_MINGAIN); |
|
|
|
data->lnGainInv = log(data->GainSqInv); |
|
|
|
|
|
|
|
/* set up a block of "common" data so we don't have to |
|
|
|
* recalculate it for every device |
|
|
|
*/ |
|
|
|
|
|
|
|
data->delFreq = data->freq - data->lstFreq; |
|
|
|
data->lnFreq = log(MAX(data->freq,N_MINLOG)); |
|
|
|
data->lnLastFreq = log(MAX(data->lstFreq,N_MINLOG)); |
|
|
|
ckt->CKTomega = 2.0 * M_PI * data->freq; |
|
|
|
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEAC | MODEACNOISE; |
|
|
|
ckt->noise_input = inst; |
|
|
|
|
|
|
|
/* |
|
|
|
* solve the original AC system to get the transfer |
|
|
|
* function between the input and output |
|
|
|
*/ |
|
|
|
|
|
|
|
NIacIter(ckt); |
|
|
|
realVal = ckt->CKTrhsOld [posOutNode] |
|
|
|
- ckt->CKTrhsOld [negOutNode]; |
|
|
|
imagVal = ckt->CKTirhsOld [posOutNode] |
|
|
|
- ckt->CKTirhsOld [negOutNode]; |
|
|
|
data->GainSqInv = 1.0 / MAX(((realVal*realVal) |
|
|
|
+ (imagVal*imagVal)),N_MINGAIN); |
|
|
|
data->lnGainInv = log(data->GainSqInv); |
|
|
|
|
|
|
|
/* set up a block of "common" data so we don't have to |
|
|
|
* recalculate it for every device |
|
|
|
*/ |
|
|
|
|
|
|
|
data->delFreq = data->freq - data->lstFreq; |
|
|
|
data->lnFreq = log(MAX(data->freq,N_MINLOG)); |
|
|
|
data->lnLastFreq = log(MAX(data->lstFreq,N_MINLOG)); |
|
|
|
data->delLnFreq = data->lnFreq - data->lnLastFreq; |
|
|
|
|
|
|
|
if ((job->NStpsSm != 0) && ((step % (job->NStpsSm)) == 0)) { |
|
|
|
data->prtSummary = TRUE; |
|
|
|
if ((job->NStpsSm != 0) && ((step % (job->NStpsSm)) == 0)) { |
|
|
|
data->prtSummary = TRUE; |
|
|
|
} else { |
|
|
|
data->prtSummary = FALSE; |
|
|
|
data->prtSummary = FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
data->outNumber = 1; |
|
|
|
*/ |
|
|
|
/* |
|
|
|
data->outNumber = 1; |
|
|
|
*/ |
|
|
|
|
|
|
|
data->outNumber = 0; |
|
|
|
/* the frequency will NOT be stored in array[0] as before; instead, |
|
|
|
* it will be given in refVal.rValue (see later) |
|
|
|
*/ |
|
|
|
data->outNumber = 0; |
|
|
|
/* the frequency will NOT be stored in array[0] as before; instead, |
|
|
|
* it will be given in refVal.rValue (see later) |
|
|
|
*/ |
|
|
|
|
|
|
|
NInzIter(ckt,posOutNode,negOutNode); /* solve the adjoint system */ |
|
|
|
NInzIter(ckt,posOutNode,negOutNode); /* solve the adjoint system */ |
|
|
|
|
|
|
|
/* now we use the adjoint system to calculate the noise |
|
|
|
* contributions of each generator in the circuit |
|
|
|
*/ |
|
|
|
/* now we use the adjoint system to calculate the noise |
|
|
|
* contributions of each generator in the circuit |
|
|
|
*/ |
|
|
|
|
|
|
|
error = CKTnoise(ckt,N_DENS,N_CALC,data); |
|
|
|
if (error) return(error); |
|
|
|
data->lstFreq = data->freq; |
|
|
|
error = CKTnoise(ckt,N_DENS,N_CALC,data); |
|
|
|
if (error) return(error); |
|
|
|
data->lstFreq = data->freq; |
|
|
|
|
|
|
|
/* update the frequency */ |
|
|
|
/* update the frequency */ |
|
|
|
|
|
|
|
switch (job->NstpType) { |
|
|
|
switch (job->NstpType) { |
|
|
|
|
|
|
|
case DECADE: |
|
|
|
case OCTAVE: |
|
|
|
data->freq *= job->NfreqDelta; |
|
|
|
break; |
|
|
|
case DECADE: |
|
|
|
case OCTAVE: |
|
|
|
data->freq *= job->NfreqDelta; |
|
|
|
break; |
|
|
|
|
|
|
|
case LINEAR: |
|
|
|
data->freq += job->NfreqDelta; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return(E_INTERN); |
|
|
|
data->freq += job->NfreqDelta; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return(E_INTERN); |
|
|
|
} |
|
|
|
step++; |
|
|
|
step++; |
|
|
|
|
|
|
|
if ((job->NnumSteps == 1) && (job->NstpType == LINEAR)) |
|
|
|
break; |
|
|
|
if ((job->NnumSteps == 1) && (job->NstpType == LINEAR)) |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
error = CKTnoise(ckt,N_DENS,N_CLOSE,data); |
|
|
|
if (error) return(error); |
|
|
|
|
|
|
|
|
|
|
|
data->numPlots = 0; |
|
|
|
data->outNumber = 0; |
|
|
|
|
|
|
|
if (job->NstartFreq != job->NstopFreq) { |
|
|
|
error = CKTnoise(ckt,INT_NOIZ,N_OPEN,data); |
|
|
|
error = CKTnoise(ckt,INT_NOIZ,N_OPEN,data); |
|
|
|
|
|
|
|
if (error) return(error); |
|
|
|
if (error) return(error); |
|
|
|
|
|
|
|
if (src_type == SV_VOLTAGE) |
|
|
|
fixme_inoise_type = |
|
|
|
if (src_type == SV_VOLTAGE) |
|
|
|
fixme_inoise_type = |
|
|
|
data->squared ? SV_SQR_VOLTAGE : SV_VOLTAGE; |
|
|
|
else |
|
|
|
fixme_inoise_type = |
|
|
|
else |
|
|
|
fixme_inoise_type = |
|
|
|
data->squared ? SV_SQR_CURRENT : SV_CURRENT; |
|
|
|
|
|
|
|
fixme_onoise_type = |
|
|
|
data->squared ? SV_SQR_VOLTAGE : SV_VOLTAGE; |
|
|
|
fixme_onoise_type = |
|
|
|
data->squared ? SV_SQR_VOLTAGE : SV_VOLTAGE; |
|
|
|
|
|
|
|
if (!data->squared) |
|
|
|
for (i = 0; i < data->numPlots; i++) |
|
|
|
data->squared_value[i] = |
|
|
|
ciprefix("inoise", data->namelist[i]) || |
|
|
|
ciprefix("onoise", data->namelist[i]); |
|
|
|
if (!data->squared) |
|
|
|
for (i = 0; i < data->numPlots; i++) |
|
|
|
data->squared_value[i] = |
|
|
|
ciprefix("inoise", data->namelist[i]) || |
|
|
|
ciprefix("onoise", data->namelist[i]); |
|
|
|
|
|
|
|
SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, |
|
|
|
data->squared |
|
|
|
@ -358,11 +356,11 @@ NOISEan (CKTcircuit *ckt, int restart) |
|
|
|
data->numPlots, data->namelist, IF_REAL, |
|
|
|
&(data->NplotPtr)); |
|
|
|
|
|
|
|
error = CKTnoise(ckt,INT_NOIZ,N_CALC,data); |
|
|
|
if (error) return(error); |
|
|
|
error = CKTnoise(ckt,INT_NOIZ,N_CALC,data); |
|
|
|
if (error) return(error); |
|
|
|
|
|
|
|
error = CKTnoise(ckt,INT_NOIZ,N_CLOSE,data); |
|
|
|
if (error) return(error); |
|
|
|
error = CKTnoise(ckt,INT_NOIZ,N_CLOSE,data); |
|
|
|
if (error) return(error); |
|
|
|
} |
|
|
|
|
|
|
|
FREE(data); |
|
|
|
|