add missing noisesp.c

This commit is contained in:
Holger Vogt 2022-03-29 16:00:10 +02:00
parent 9882c3a24c
commit d961c7c91d
1 changed files with 371 additions and 0 deletions

View File

@ -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