1 changed files with 371 additions and 0 deletions
@ -0,0 +1,371 @@ |
|||||
|
/********** |
||||
|
Copyright 1990 Regents of the University of California. All rights reserved. |
||||
|
Author: 1987 Gary W. Ng |
||||
|
Modified: 2001 AlansFixes |
||||
|
**********/ |
||||
|
|
||||
|
/* Patch to noisean.c by Richard D. McRoberts. |
||||
|
* Patched with modifications from Weidong Liu (2000) |
||||
|
* Patched with modifications ftom Weidong Liu |
||||
|
* in bsim4.1.0 code |
||||
|
*/ |
||||
|
|
||||
|
#include "ngspice/ngspice.h" |
||||
|
#include "ngspice/acdefs.h" |
||||
|
#include "ngspice/cktdefs.h" |
||||
|
#include "ngspice/iferrmsg.h" |
||||
|
#include "ngspice/cpextern.h" |
||||
|
#include "ngspice/noisedef.h" |
||||
|
#include "ngspice/sperror.h" |
||||
|
#include "ngspice/sim.h" |
||||
|
#include "vsrc/vsrcdefs.h" |
||||
|
#include "isrc/isrcdefs.h" |
||||
|
|
||||
|
// fixme |
||||
|
// ugly hack to work around missing api to specify the "type" of signals |
||||
|
extern int fixme_onoise_type; |
||||
|
extern int fixme_inoise_type; |
||||
|
|
||||
|
#ifdef RFSPICE |
||||
|
|
||||
|
int |
||||
|
NOISEsp (CKTcircuit *ckt, int restart) |
||||
|
{ |
||||
|
/* variable must be static, for continuation of interrupted (Ctrl-C), |
||||
|
longer lasting noise anlysis */ |
||||
|
static Ndata *data; |
||||
|
|
||||
|
double realVal; |
||||
|
double imagVal; |
||||
|
int error; |
||||
|
int posOutNode; |
||||
|
int negOutNode; |
||||
|
int step; |
||||
|
IFuid freqUid; |
||||
|
double freqTol; /* tolerence parameter for finding final frequency; hack */ |
||||
|
int i, src_type; |
||||
|
|
||||
|
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; |
||||
|
GENinstance *inst = CKTfndDev(ckt, job->input); |
||||
|
bool frequequal = AlmostEqualUlps(job->NstartFreq, job->NstopFreq, 3); |
||||
|
|
||||
|
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); |
||||
|
} |
||||
|
} |
||||
|
/* 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); |
||||
|
return E_NOTFOUND; |
||||
|
} |
||||
|
|
||||
|
if (inst->GENmodPtr->GENmodType == CKTtypelook("Vsource")) { |
||||
|
ac_given = ((VSRCinstance *)inst) -> VSRCacGiven; |
||||
|
src_type = SV_VOLTAGE; |
||||
|
} else if(inst->GENmodPtr->GENmodType == CKTtypelook("Isource")) { |
||||
|
ac_given = ((ISRCinstance *)inst) -> ISRCacGiven; |
||||
|
src_type = SV_CURRENT; |
||||
|
} else { |
||||
|
SPfrontEnd->IFerrorf (ERR_WARNING, |
||||
|
"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); |
||||
|
return E_NOACINPUT; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if ( (job->NsavFstp == 0.0) || restart) { /* va, NsavFstp is double */ |
||||
|
switch (job->NstpType) { |
||||
|
|
||||
|
|
||||
|
case DECADE: |
||||
|
job->NfreqDelta = exp(log(10.0)/ |
||||
|
job->NnumSteps); |
||||
|
break; |
||||
|
|
||||
|
case OCTAVE: |
||||
|
job->NfreqDelta = exp(log(2.0)/ |
||||
|
job->NnumSteps); |
||||
|
break; |
||||
|
|
||||
|
case LINEAR: |
||||
|
if (job->NnumSteps == 1) |
||||
|
job->NfreqDelta = 0; |
||||
|
else |
||||
|
job->NfreqDelta = (job->NstopFreq - |
||||
|
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); |
||||
|
|
||||
|
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; |
||||
|
|
||||
|
/* the current front-end needs the namelist to be fully |
||||
|
declared before an OUTpBeginplot */ |
||||
|
|
||||
|
SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL); |
||||
|
|
||||
|
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 |
||||
|
*/ |
||||
|
|
||||
|
if (src_type == SV_VOLTAGE) |
||||
|
fixme_inoise_type = |
||||
|
data->squared ? SV_SQR_VOLTAGE_DENSITY : SV_VOLTAGE_DENSITY; |
||||
|
else |
||||
|
fixme_inoise_type = |
||||
|
data->squared ? SV_SQR_CURRENT_DENSITY : SV_CURRENT_DENSITY; |
||||
|
|
||||
|
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]); |
||||
|
|
||||
|
error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, |
||||
|
data->squared |
||||
|
? "Noise Spectral Density Curves - (V^2 or A^2)/Hz" |
||||
|
|
||||
|
: "Noise Spectral Density Curves", |
||||
|
freqUid, IF_REAL, |
||||
|
data->numPlots, data->namelist, IF_REAL, |
||||
|
&(data->NplotPtr)); |
||||
|
if (error) return(error); |
||||
|
|
||||
|
if (job->NstpType != LINEAR) { |
||||
|
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) { |
||||
|
|
||||
|
case DECADE: |
||||
|
case OCTAVE: |
||||
|
data->freq = job->NstartFreq * exp (step * |
||||
|
log (job->NfreqDelta)); |
||||
|
break; |
||||
|
|
||||
|
case LINEAR: |
||||
|
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*/ |
||||
|
error = SPfrontEnd->OUTpBeginPlot (NULL, NULL, |
||||
|
NULL, |
||||
|
NULL, 0, |
||||
|
666, NULL, 666, |
||||
|
&(data->NplotPtr)); |
||||
|
/*saj*/ |
||||
|
} |
||||
|
|
||||
|
switch (job->NstpType) { |
||||
|
case DECADE: |
||||
|
case OCTAVE: |
||||
|
freqTol = job->NfreqDelta * job->NstopFreq * ckt->CKTreltol; |
||||
|
break; |
||||
|
case LINEAR: |
||||
|
freqTol = job->NfreqDelta * ckt->CKTreltol; |
||||
|
break; |
||||
|
default: |
||||
|
return(E_BADPARM); |
||||
|
} |
||||
|
|
||||
|
data->lstFreq = data->freq; |
||||
|
|
||||
|
/* do the noise analysis over all frequencies */ |
||||
|
|
||||
|
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); |
||||
|
} |
||||
|
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; |
||||
|
} else { |
||||
|
data->prtSummary = FALSE; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
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) |
||||
|
*/ |
||||
|
|
||||
|
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 |
||||
|
*/ |
||||
|
|
||||
|
error = CKTnoise(ckt,N_DENS,N_CALC,data); |
||||
|
if (error) return(error); |
||||
|
data->lstFreq = data->freq; |
||||
|
|
||||
|
/* update the frequency */ |
||||
|
|
||||
|
switch (job->NstpType) { |
||||
|
|
||||
|
case DECADE: |
||||
|
case OCTAVE: |
||||
|
data->freq *= job->NfreqDelta; |
||||
|
break; |
||||
|
|
||||
|
case LINEAR: |
||||
|
data->freq += job->NfreqDelta; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
return(E_INTERN); |
||||
|
} |
||||
|
step++; |
||||
|
|
||||
|
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); |
||||
|
|
||||
|
if (error) return(error); |
||||
|
|
||||
|
if (src_type == SV_VOLTAGE) |
||||
|
fixme_inoise_type = |
||||
|
data->squared ? SV_SQR_VOLTAGE : SV_VOLTAGE; |
||||
|
else |
||||
|
fixme_inoise_type = |
||||
|
data->squared ? SV_SQR_CURRENT : SV_CURRENT; |
||||
|
|
||||
|
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]); |
||||
|
|
||||
|
SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, |
||||
|
data->squared |
||||
|
? "Integrated Noise - V^2 or A^2" |
||||
|
: "Integrated Noise", |
||||
|
NULL, 0, |
||||
|
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_CLOSE,data); |
||||
|
if (error) return(error); |
||||
|
} |
||||
|
|
||||
|
FREE(data); |
||||
|
return(OK); |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue