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