Merge branch 'pre-master-42' into bt_dev
This commit is contained in:
commit
dee0500140
|
|
@ -0,0 +1,33 @@
|
||||||
|
A simple bipolar circuit
|
||||||
|
* Tadej Tuma, Árpád Burmen "Circuit Simulation with SPICE OPUS: Theory and Practice"
|
||||||
|
* Boston 2009
|
||||||
|
|
||||||
|
v1 1 0 dc=5
|
||||||
|
r1 1 2 r=1k
|
||||||
|
q1 2 3 0 t2n2222
|
||||||
|
r2 3 4 r=1k
|
||||||
|
vin 4 0 dc=0.68 ac 1
|
||||||
|
|
||||||
|
.model t2n2222 npn
|
||||||
|
+ is=19f bf=150 vaf=100 ikf=0.18 ise=50p
|
||||||
|
+ ne=2.5 br=7.5 var=6.4 ikr=12m isc=8.7p
|
||||||
|
+ nc=1.2 rb=50 re=0.4 rc=0.3 cje=26p tf=0.5n
|
||||||
|
+ cjc=11p tr=7n xtb=1.5 kf=0.032f af=1
|
||||||
|
|
||||||
|
.control
|
||||||
|
noise v(2) vin dec 10 0.5 100meg 1
|
||||||
|
setplot noise1
|
||||||
|
set xbrushwidth=3
|
||||||
|
plot loglog
|
||||||
|
+ onoise_q1_1overf
|
||||||
|
+ onoise_q1_ib onoise_q1_ic
|
||||||
|
+ onoise_q1_rb onoise_q1_rc onoise_q1_re
|
||||||
|
+ onoise_q1
|
||||||
|
|
||||||
|
plot loglog onoise_q1 onoise_r1 onoise_r2 onoise_spectrum
|
||||||
|
|
||||||
|
plot loglog onoise_spectrum inoise_spectrum
|
||||||
|
|
||||||
|
.endc
|
||||||
|
|
||||||
|
.end
|
||||||
|
|
@ -17,7 +17,7 @@ R22 22 0 10k
|
||||||
C22 22 0 1u
|
C22 22 0 1u
|
||||||
|
|
||||||
.control
|
.control
|
||||||
noise v(2) V1 dec 10 1 100k
|
noise v(2) V1 dec 10 1 100k 1
|
||||||
echo **resistive divider**
|
echo **resistive divider**
|
||||||
print onoise_total inoise_total
|
print onoise_total inoise_total
|
||||||
setplot noise1
|
setplot noise1
|
||||||
|
|
|
||||||
|
|
@ -1353,8 +1353,14 @@ inp_dodeck(
|
||||||
|
|
||||||
if (p == dd->error) {
|
if (p == dd->error) {
|
||||||
if (strstr(dd->line, ".model"))
|
if (strstr(dd->line, ".model"))
|
||||||
fprintf(stderr, "Warning: Model issue on line %d :\n %.*s ...\n%s\n",
|
if (dd->linenum_orig == 0) { /* new line, e.g. in subcircuit */
|
||||||
dd->linenum_orig, 72, dd->line, dd->error);
|
fprintf(stderr, "Warning: Model issue on line:\n %.*s ...\n%s\n",
|
||||||
|
72, dd->line, dd->error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Warning: Model issue on line %d :\n %.*s ...\n%s\n",
|
||||||
|
dd->linenum_orig, 72, dd->line, dd->error);
|
||||||
|
}
|
||||||
else if (dd->linenum_orig == 0) {
|
else if (dd->linenum_orig == 0) {
|
||||||
fprintf(stderr, "Error on line:\n %s\n%s\n",
|
fprintf(stderr, "Error on line:\n %s\n%s\n",
|
||||||
dd->line, dd->error);
|
dd->line, dd->error);
|
||||||
|
|
|
||||||
|
|
@ -2306,7 +2306,7 @@ getisrcval(double time, char *iname)
|
||||||
delmin minimum delta CKTdelmin
|
delmin minimum delta CKTdelmin
|
||||||
redostep if 0, converged,
|
redostep if 0, converged,
|
||||||
if 1, either no convergence, need to redo with new ckt->CKTdelta
|
if 1, either no convergence, need to redo with new ckt->CKTdelta
|
||||||
or ckt->CKTdelta has been reduced by tuncation errors too large.
|
or ckt->CKTdelta has been reduced by truncation errors too large.
|
||||||
rejected pointer to ckt->CKTstat->STATrejected, counts rejected time points.
|
rejected pointer to ckt->CKTstat->STATrejected, counts rejected time points.
|
||||||
loc location of function call in dctran.c: 0: after breakpoint handling, 1: at end of for loop
|
loc location of function call in dctran.c: 0: after breakpoint handling, 1: at end of for loop
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ Author: 1987 Gary W. Ng
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
CKTnoise (CKTcircuit *ckt, int mode, int operation, Ndata *data)
|
CKTnoise(CKTcircuit* ckt, int mode, int operation, Ndata* data)
|
||||||
{
|
{
|
||||||
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob;
|
NOISEAN* job = (NOISEAN*)ckt->CKTcurJob;
|
||||||
|
|
||||||
double outNdens;
|
double outNdens;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -35,10 +35,10 @@ CKTnoise (CKTcircuit *ckt, int mode, int operation, Ndata *data)
|
||||||
|
|
||||||
/* let each device decide how many and what type of noise sources it has */
|
/* let each device decide how many and what type of noise sources it has */
|
||||||
|
|
||||||
for (i=0; i < DEVmaxnum; i++) {
|
for (i = 0; i < DEVmaxnum; i++) {
|
||||||
if ( DEVices[i] && DEVices[i]->DEVnoise && ckt->CKThead[i] ) {
|
if (DEVices[i] && DEVices[i]->DEVnoise && ckt->CKThead[i]) {
|
||||||
error = DEVices[i]->DEVnoise (mode, operation, ckt->CKThead[i],
|
error = DEVices[i]->DEVnoise(mode, operation, ckt->CKThead[i],
|
||||||
ckt,data, &outNdens);
|
ckt, data, &outNdens);
|
||||||
if (error) return (error);
|
if (error) return (error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -47,102 +47,102 @@ CKTnoise (CKTcircuit *ckt, int mode, int operation, Ndata *data)
|
||||||
|
|
||||||
case N_OPEN:
|
case N_OPEN:
|
||||||
|
|
||||||
/* take care of the noise for the circuit as a whole */
|
/* take care of the noise for the circuit as a whole */
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
|
||||||
case N_DENS:
|
case N_DENS:
|
||||||
|
|
||||||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
||||||
|
|
||||||
SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]),
|
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]),
|
||||||
NULL, "onoise_spectrum", UID_OTHER, NULL);
|
NULL, "onoise_spectrum", UID_OTHER, NULL);
|
||||||
|
|
||||||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
||||||
|
|
||||||
SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]),
|
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]),
|
||||||
NULL, "inoise_spectrum", UID_OTHER, NULL);
|
NULL, "inoise_spectrum", UID_OTHER, NULL);
|
||||||
|
|
||||||
/* we've added two more plots */
|
/* we've added two more plots */
|
||||||
|
|
||||||
data->outpVector =
|
data->outpVector =
|
||||||
TMALLOC(double, data->numPlots);
|
TMALLOC(double, data->numPlots);
|
||||||
data->squared_value =
|
data->squared_value =
|
||||||
data->squared ? NULL : TMALLOC(char, data->numPlots);
|
data->squared ? NULL : TMALLOC(char, data->numPlots);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INT_NOIZ:
|
case INT_NOIZ:
|
||||||
|
|
||||||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
||||||
SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]),
|
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]),
|
||||||
NULL, "onoise_total", UID_OTHER, NULL);
|
NULL, "onoise_total", UID_OTHER, NULL);
|
||||||
|
|
||||||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1);
|
||||||
SPfrontEnd->IFnewUid (ckt, &(data->namelist[data->numPlots++]),
|
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]),
|
||||||
NULL, "inoise_total", UID_OTHER, NULL);
|
NULL, "inoise_total", UID_OTHER, NULL);
|
||||||
/* we've added two more plots */
|
/* we've added two more plots */
|
||||||
|
|
||||||
data->outpVector =
|
data->outpVector =
|
||||||
TMALLOC(double, data->numPlots);
|
TMALLOC(double, data->numPlots);
|
||||||
data->squared_value =
|
data->squared_value =
|
||||||
data->squared ? NULL : TMALLOC(char, data->numPlots);
|
data->squared ? NULL : TMALLOC(char, data->numPlots);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (E_INTERN);
|
return (E_INTERN);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case N_CALC:
|
case N_CALC:
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
|
||||||
case N_DENS:
|
case N_DENS:
|
||||||
if ((job->NStpsSm == 0)
|
if ((job->NStpsSm == 0)
|
||||||
|| data->prtSummary)
|
|| data->prtSummary)
|
||||||
{
|
{
|
||||||
data->outpVector[data->outNumber++] = outNdens;
|
data->outpVector[data->outNumber++] = outNdens;
|
||||||
data->outpVector[data->outNumber++] =
|
data->outpVector[data->outNumber++] =
|
||||||
(outNdens * data->GainSqInv);
|
(outNdens * data->GainSqInv);
|
||||||
|
|
||||||
refVal.rValue = data->freq; /* the reference is the freq */
|
refVal.rValue = data->freq; /* the reference is the freq */
|
||||||
if (!data->squared)
|
if (!data->squared)
|
||||||
for (i = 0; i < data->outNumber; i++)
|
for (i = 0; i < data->outNumber; i++)
|
||||||
if (data->squared_value[i])
|
if (data->squared_value[i])
|
||||||
data->outpVector[i] = sqrt(data->outpVector[i]);
|
data->outpVector[i] = sqrt(data->outpVector[i]);
|
||||||
outData.v.numValue = data->outNumber; /* vector number */
|
outData.v.numValue = data->outNumber; /* vector number */
|
||||||
outData.v.vec.rVec = data->outpVector; /* vector of outputs */
|
outData.v.vec.rVec = data->outpVector; /* vector of outputs */
|
||||||
SPfrontEnd->OUTpData (data->NplotPtr, &refVal, &outData);
|
SPfrontEnd->OUTpData(data->NplotPtr, &refVal, &outData);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INT_NOIZ:
|
case INT_NOIZ:
|
||||||
data->outpVector[data->outNumber++] = data->outNoiz;
|
data->outpVector[data->outNumber++] = data->outNoiz;
|
||||||
data->outpVector[data->outNumber++] = data->inNoise;
|
data->outpVector[data->outNumber++] = data->inNoise;
|
||||||
if (!data->squared)
|
if (!data->squared)
|
||||||
for (i = 0; i < data->outNumber; i++)
|
for (i = 0; i < data->outNumber; i++)
|
||||||
if (data->squared_value[i])
|
if (data->squared_value[i])
|
||||||
data->outpVector[i] = sqrt(data->outpVector[i]);
|
data->outpVector[i] = sqrt(data->outpVector[i]);
|
||||||
outData.v.vec.rVec = data->outpVector; /* vector of outputs */
|
outData.v.vec.rVec = data->outpVector; /* vector of outputs */
|
||||||
outData.v.numValue = data->outNumber; /* vector number */
|
outData.v.numValue = data->outNumber; /* vector number */
|
||||||
SPfrontEnd->OUTpData (data->NplotPtr, &refVal, &outData);
|
SPfrontEnd->OUTpData(data->NplotPtr, &refVal, &outData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (E_INTERN);
|
return (E_INTERN);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case N_CLOSE:
|
case N_CLOSE:
|
||||||
SPfrontEnd->OUTendPlot (data->NplotPtr);
|
SPfrontEnd->OUTendPlot(data->NplotPtr);
|
||||||
FREE(data->namelist);
|
FREE(data->namelist);
|
||||||
FREE(data->outpVector);
|
FREE(data->outpVector);
|
||||||
FREE(data->squared_value);
|
FREE(data->squared_value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (E_INTERN);
|
return (E_INTERN);
|
||||||
}
|
}
|
||||||
return (OK);
|
return (OK);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||||
Author: 1985 Thomas L. Quarles
|
Author: 1985 Thomas L. Quarles
|
||||||
Modified: 2000 AlansFixes
|
Modified: 2000 AlansFixes
|
||||||
|
Modified: 2023 XSPICE breakpoint fix for shared ngspice by Vyacheslav Shevchuk
|
||||||
**********/
|
**********/
|
||||||
|
|
||||||
/* subroutine to do DC TRANSIENT analysis
|
/* subroutine to do DC TRANSIENT analysis
|
||||||
|
|
@ -106,6 +107,25 @@ DCtran(CKTcircuit *ckt,
|
||||||
double ipc_last_time = 0.0;
|
double ipc_last_time = 0.0;
|
||||||
double ipc_last_delta = 0.0;
|
double ipc_last_delta = 0.0;
|
||||||
/* gtri - end - wbk - 12/19/90 - Add IPC stuff */
|
/* gtri - end - wbk - 12/19/90 - Add IPC stuff */
|
||||||
|
|
||||||
|
// Fix for sharedsync olddelta: When DCTran processes
|
||||||
|
// either analog or XSPICE breakpoint, then it subtracts delta from
|
||||||
|
// ckt->CKTtime. It sends 0 as olddelta after analog breakpoint
|
||||||
|
// processing. Still, for XSPICE breakpoints it subtracts delta (see code
|
||||||
|
// 'else if(g_mif_info.breakpoint.current < ckt->CKTtime)' branch) and
|
||||||
|
// then sends non zero olddelta to sharedsync at the end of the function
|
||||||
|
// (see chkStep: label). Thus olddelta is subtracted twice. Then
|
||||||
|
// ckt->CKTtime becomes less than last_accepted_time.
|
||||||
|
// xspice_breakpoints_processed 0:
|
||||||
|
// XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime].
|
||||||
|
// xspice_breakpoints_processed 1:
|
||||||
|
// convergence criteria are satisfied but XSPICE breakpoint(s) is in the
|
||||||
|
// time interval [last_accepted_time, CKTtime].
|
||||||
|
int xspice_breakpoints_processed = 0;
|
||||||
|
|
||||||
|
#ifdef SHARED_MODULE
|
||||||
|
double olddelta_for_shared_sync = 0.0;
|
||||||
|
#endif // SHARED_MODULE
|
||||||
#endif
|
#endif
|
||||||
#if defined CLUSTER || defined SHARED_MODULE
|
#if defined CLUSTER || defined SHARED_MODULE
|
||||||
int redostep;
|
int redostep;
|
||||||
|
|
@ -680,7 +700,7 @@ resume:
|
||||||
} /* end if there are event instances */
|
} /* end if there are event instances */
|
||||||
|
|
||||||
/* gtri - end - wbk - Do event solution */
|
/* gtri - end - wbk - Do event solution */
|
||||||
#else
|
#else /* no XSPICE */
|
||||||
|
|
||||||
#ifdef CLUSTER
|
#ifdef CLUSTER
|
||||||
if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) {
|
if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) {
|
||||||
|
|
@ -697,7 +717,7 @@ resume:
|
||||||
ckt->CKTdelmin, 0, &ckt->CKTstat->STATrejected, 0);
|
ckt->CKTdelmin, 0, &ckt->CKTstat->STATrejected, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif /* no XSPICE */
|
||||||
for(i=5; i>=0; i--)
|
for(i=5; i>=0; i--)
|
||||||
ckt->CKTdeltaOld[i+1] = ckt->CKTdeltaOld[i];
|
ckt->CKTdeltaOld[i+1] = ckt->CKTdeltaOld[i];
|
||||||
ckt->CKTdeltaOld[0] = ckt->CKTdelta;
|
ckt->CKTdeltaOld[0] = ckt->CKTdelta;
|
||||||
|
|
@ -722,6 +742,7 @@ resume:
|
||||||
ckt->CKTcurrentAnalysis = DOING_TRAN;
|
ckt->CKTcurrentAnalysis = DOING_TRAN;
|
||||||
|
|
||||||
/* gtri - end - wbk - 4/17/91 - Fix Berkeley bug */
|
/* gtri - end - wbk - 4/17/91 - Fix Berkeley bug */
|
||||||
|
xspice_breakpoints_processed = 0;
|
||||||
#endif
|
#endif
|
||||||
olddelta=ckt->CKTdelta;
|
olddelta=ckt->CKTdelta;
|
||||||
/* time abort? */
|
/* time abort? */
|
||||||
|
|
@ -815,6 +836,7 @@ resume:
|
||||||
ckt->CKTtime -= ckt->CKTdelta;
|
ckt->CKTtime -= ckt->CKTdelta;
|
||||||
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
||||||
g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta;
|
g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta;
|
||||||
|
xspice_breakpoints_processed = 1;
|
||||||
|
|
||||||
if(firsttime) {
|
if(firsttime) {
|
||||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN;
|
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN;
|
||||||
|
|
@ -945,8 +967,24 @@ resume:
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* gtri - begin - wbk - Do event backup */
|
/* gtri - begin - wbk - Do event backup */
|
||||||
|
|
||||||
if(ckt->evt->counts.num_insts > 0)
|
if(ckt->evt->counts.num_insts > 0) {
|
||||||
|
#ifdef SHARED_MODULE
|
||||||
|
double discard_start_time = ckt->CKTtime + ckt->CKTdelta;
|
||||||
|
// ngspice in executable mode subtracts olddelta from the time
|
||||||
|
// before new delta calculation, but it keeps delta in CKTtime and
|
||||||
|
// postpones subtraction in library mode. Delayed subtraction leads
|
||||||
|
// to incorrect points dropping because ckt->CKTdelta is almost always
|
||||||
|
// less than olddelta if there are convergence issues, and EVTbackup
|
||||||
|
// may drop valid events that need to be processed within
|
||||||
|
// [last_accepted_time, last_accepted_time + ckt->CKTdelta] range
|
||||||
|
// after delta adjustment.
|
||||||
|
if (redostep && xspice_breakpoints_processed == 0)
|
||||||
|
discard_start_time -= olddelta;
|
||||||
|
EVTbackup(ckt, discard_start_time);
|
||||||
|
#else
|
||||||
EVTbackup(ckt, ckt->CKTtime + ckt->CKTdelta);
|
EVTbackup(ckt, ckt->CKTtime + ckt->CKTdelta);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* gtri - end - wbk - Do event backup */
|
/* gtri - end - wbk - Do event backup */
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -973,10 +1011,25 @@ resume:
|
||||||
function.
|
function.
|
||||||
*/
|
*/
|
||||||
chkStep:
|
chkStep:
|
||||||
|
#ifdef XSPICE
|
||||||
|
// There is no need to subtract olddelta from ckt->CKTtime one more time
|
||||||
|
// if it has been subtracted during XSPICE breakpoint processing.
|
||||||
|
// olddelta will be reinitialized on
|
||||||
|
// the new iteration, so it reassigning here should be safe. It can't be
|
||||||
|
// zeroed during breakpoint processing because it takes part in the
|
||||||
|
// "timestep too small" check.
|
||||||
|
olddelta_for_shared_sync = olddelta;
|
||||||
|
if (xspice_breakpoints_processed)
|
||||||
|
olddelta_for_shared_sync = 0.0;
|
||||||
|
if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta_for_shared_sync, ckt->CKTfinalTime,
|
||||||
|
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0)
|
||||||
|
goto nextTime;
|
||||||
|
#else
|
||||||
if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta, ckt->CKTfinalTime,
|
if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta, ckt->CKTfinalTime,
|
||||||
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0)
|
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0)
|
||||||
goto nextTime;
|
goto nextTime;
|
||||||
#endif
|
#endif // XSPICE
|
||||||
|
#endif // SHARED_MODULE
|
||||||
|
|
||||||
}
|
}
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
|
|
||||||
|
|
@ -1,477 +1,214 @@
|
||||||
/*.......1.........2.........3.........4.........5.........6.........7.........8
|
/* XSPICE code model for the Controlled PWM Oscillator.
|
||||||
================================================================================
|
* This is a complete redesign of the original version,
|
||||||
|
* according to the d_osc model provided by G. Atkinson
|
||||||
|
*/
|
||||||
|
|
||||||
FILE d_pwm/cfunc.mod
|
|
||||||
|
|
||||||
Public Domain
|
|
||||||
|
|
||||||
Georgia Tech Research Corporation
|
|
||||||
Atlanta, Georgia 30332
|
|
||||||
PROJECT A-8503-405
|
|
||||||
The ngspice team
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
24 Jul 1991 Jeffrey P. Murray
|
|
||||||
02 Mar 2022 Holger Vogt
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
23 Aug 1991 Jeffrey P. Murray
|
|
||||||
30 Sep 1991 Jeffrey P. Murray
|
|
||||||
06 Oct 2022 Holger Vogt
|
|
||||||
05 Jan 2023 Robert Turnbull
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
This file contains the model-specific routines used to
|
|
||||||
functionally describe the d_pwm code model.
|
|
||||||
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
FILE ROUTINE CALLED
|
|
||||||
|
|
||||||
CMmacros.h cm_message_send();
|
|
||||||
|
|
||||||
CM.c void *cm_analog_alloc()
|
|
||||||
void *cm_analog_get_ptr()
|
|
||||||
|
|
||||||
CMevt.c void cm_event_queue()
|
|
||||||
|
|
||||||
|
|
||||||
REFERENCED FILES
|
|
||||||
|
|
||||||
Inputs from and outputs to ARGS structure.
|
|
||||||
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
===============================================================================*/
|
|
||||||
|
|
||||||
/*=== INCLUDE FILES ====================*/
|
|
||||||
|
|
||||||
#include "d_pwm.h" /* ...contains macros & type defns.
|
|
||||||
for this model. 7/24/91 - JPM */
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define FACTOR 0.75 // Controls timing of next scheduled call. */
|
||||||
|
|
||||||
|
/* PWL table entry. */
|
||||||
|
|
||||||
/*=== CONSTANTS ========================*/
|
struct pwl {
|
||||||
|
double ctl, dc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Called at end to free memory. */
|
||||||
|
|
||||||
|
static void cm_d_pwm_callback(ARGS, Mif_Callback_Reason_t reason)
|
||||||
|
|
||||||
/*=== MACROS ===========================*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
double *x;
|
|
||||||
double *y;
|
|
||||||
} Local_Data_t;
|
|
||||||
|
|
||||||
|
|
||||||
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*==============================================================================
|
|
||||||
|
|
||||||
FUNCTION cm_d_pwm()
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
24 Jul 1991 Jeffrey P. Murray
|
|
||||||
02 Mar 2022 Holger Vogt
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
30 Sep 1991 Jeffrey P. Murray
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
This function implements the d_pwm code model.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
FILE ROUTINE CALLED
|
|
||||||
|
|
||||||
CMmacros.h cm_message_send();
|
|
||||||
|
|
||||||
CM.c void *cm_analog_alloc()
|
|
||||||
void *cm_analog_get_ptr()
|
|
||||||
|
|
||||||
CMevt.c void cm_event_queue()
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
Returns inputs and outputs via ARGS structure.
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
==============================================================================*/
|
|
||||||
|
|
||||||
static void cm_d_pwm_callback(ARGS,
|
|
||||||
Mif_Callback_Reason_t reason)
|
|
||||||
{
|
{
|
||||||
switch (reason) {
|
if (reason == MIF_CB_DESTROY) {
|
||||||
case MIF_CB_DESTROY: {
|
struct pwl *table = STATIC_VAR(locdata);
|
||||||
Local_Data_t *loc = STATIC_VAR(locdata);
|
|
||||||
if (loc) {
|
|
||||||
if (loc->x)
|
|
||||||
free(loc->x);
|
|
||||||
if(loc->y)
|
|
||||||
free(loc->y);
|
|
||||||
free(loc);
|
|
||||||
STATIC_VAR(locdata) = loc = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} /* end of case MIF_CB_DESTROY */
|
|
||||||
} /* end of switch over reason being called */
|
|
||||||
} /* end of function cm_d_pwm_callback */
|
|
||||||
|
|
||||||
|
if (table)
|
||||||
|
free(table);
|
||||||
/*=== CM_D_PWM ROUTINE ===*/
|
STATIC_VAR(locdata) = NULL;
|
||||||
|
|
||||||
/*************************************************************
|
|
||||||
* The following is the model for a duty cycle controlled *
|
|
||||||
* digital oscillator, derived from the controlled digital *
|
|
||||||
* oscillator d_osc. *
|
|
||||||
* *
|
|
||||||
* Created 3/02/2022 H. Vogt *
|
|
||||||
*************************************************************/
|
|
||||||
|
|
||||||
/*************************************************************
|
|
||||||
* *
|
|
||||||
* *
|
|
||||||
* <-----duty_cycle-----> *
|
|
||||||
* I *
|
|
||||||
* I t2 t3 *
|
|
||||||
* I \______________/_____ *
|
|
||||||
* I | | *
|
|
||||||
* I | | | | *
|
|
||||||
* I | | *
|
|
||||||
* I | | | | *
|
|
||||||
* I | | *
|
|
||||||
* I | | | | *
|
|
||||||
* I-----------------*-----* - - - - - - - - - -*--------- *
|
|
||||||
* t1 t4 *
|
|
||||||
* *
|
|
||||||
* *
|
|
||||||
* t2 = t1 + rise_delay *
|
|
||||||
* t4 = t3 + fall_delay *
|
|
||||||
* *
|
|
||||||
* Note that for the digital model, unlike for the *
|
|
||||||
* analog "square" model, t1 and t3 are stored and *
|
|
||||||
* adjusted values, but t2 & t4 are implied by the *
|
|
||||||
* rise and fall delays of the model, but are otherwise *
|
|
||||||
* not stored values. JPM *
|
|
||||||
* *
|
|
||||||
*************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
void cm_d_pwm(ARGS)
|
|
||||||
{
|
|
||||||
|
|
||||||
double *x, /* analog input value control array */
|
|
||||||
*y, /* frequency array */
|
|
||||||
cntl_input, /* control input value */
|
|
||||||
*phase, /* instantaneous phase of the model */
|
|
||||||
*phase_old, /* previous phase of the model */
|
|
||||||
*t1, /* pointer to t1 value */
|
|
||||||
*t3, /* pointer to t3 value */
|
|
||||||
/*time1,*/ /* variable for calculating new time1 value */
|
|
||||||
/*time3,*/ /* variable for calculating new time3 value */
|
|
||||||
dc = 0.5, /* instantaneous duty cycle value */
|
|
||||||
dphase, /* fractional part into cycle */
|
|
||||||
frequency, /* frequency value */
|
|
||||||
test_double, /* testing variable */
|
|
||||||
slope; /* slope value...used to extrapolate
|
|
||||||
freq values past endpoints. */
|
|
||||||
|
|
||||||
int i, /* generic loop counter index */
|
|
||||||
cntl_size, /* control array size */
|
|
||||||
dc_size; /* duty cycle array size */
|
|
||||||
|
|
||||||
Local_Data_t *loc; /* Pointer to local static data, not to be included
|
|
||||||
in the state vector (save memory!) */
|
|
||||||
|
|
||||||
/**** Retrieve frequently used parameters... ****/
|
|
||||||
|
|
||||||
cntl_size = PARAM_SIZE(cntl_array);
|
|
||||||
dc_size = PARAM_SIZE(dc_array);
|
|
||||||
frequency = PARAM(frequency);
|
|
||||||
|
|
||||||
/* check and make sure that the control array is the
|
|
||||||
same size as the frequency array */
|
|
||||||
|
|
||||||
if(cntl_size != dc_size){
|
|
||||||
cm_message_send(d_pwm_array_error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/
|
|
||||||
|
|
||||||
/* Allocate storage for internal variables */
|
|
||||||
cm_analog_alloc(0, sizeof(double));
|
|
||||||
cm_analog_alloc(1, sizeof(double));
|
|
||||||
cm_analog_alloc(2, sizeof(double));
|
|
||||||
|
|
||||||
/* assign internal variables */
|
|
||||||
phase = phase_old = (double *) cm_analog_get_ptr(0,0);
|
|
||||||
|
|
||||||
t1 = (double *) cm_analog_get_ptr(1,0);
|
|
||||||
|
|
||||||
t3 = (double *) cm_analog_get_ptr(2,0);
|
|
||||||
|
|
||||||
/*** allocate static storage for *loc ***/
|
|
||||||
STATIC_VAR (locdata) = calloc (1 , sizeof ( Local_Data_t ));
|
|
||||||
loc = STATIC_VAR (locdata);
|
|
||||||
CALLBACK = cm_d_pwm_callback;
|
|
||||||
|
|
||||||
x = loc->x = (double *) calloc((size_t) cntl_size, sizeof(double));
|
|
||||||
if (!x) {
|
|
||||||
cm_message_send(d_pwm_allocation_error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
y = loc->y = (double *) calloc((size_t) cntl_size, sizeof(double));
|
|
||||||
if (!y) {
|
|
||||||
cm_message_send(d_pwm_allocation_error);
|
|
||||||
if(x)
|
|
||||||
free(x);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Retrieve x and y values. */
|
|
||||||
for (i=0; i<cntl_size; i++) {
|
|
||||||
x[i] = PARAM(cntl_array[i]);
|
|
||||||
y[i] = PARAM(dc_array[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else { /*** This is not an initialization pass...retrieve storage
|
|
||||||
addresses and calculate new outputs, if required. ***/
|
|
||||||
|
|
||||||
/** Retrieve previous values... **/
|
|
||||||
|
|
||||||
/* assign internal variables */
|
|
||||||
phase = (double *) cm_analog_get_ptr(0,0);
|
|
||||||
phase_old = (double *) cm_analog_get_ptr(0,1);
|
|
||||||
|
|
||||||
t1 = (double *) cm_analog_get_ptr(1,0);
|
|
||||||
|
|
||||||
t3 = (double *) cm_analog_get_ptr(2,0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (CALL_TYPE) {
|
|
||||||
|
|
||||||
case ANALOG: /** analog call **/
|
|
||||||
|
|
||||||
test_double = TIME;
|
|
||||||
|
|
||||||
if ( AC == ANALYSIS ) { /* this model does not function
|
|
||||||
in AC analysis mode. */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
if ( 0.0 == TIME ) { /* DC analysis */
|
|
||||||
|
|
||||||
/* retrieve & normalize phase value */
|
|
||||||
*phase = PARAM(init_phase);
|
|
||||||
if ( 0 > *phase ) {
|
|
||||||
*phase = *phase + 360.0;
|
|
||||||
}
|
|
||||||
*phase = *phase / 360.0;
|
|
||||||
|
|
||||||
/* set phase value to init_phase */
|
|
||||||
*phase_old = *phase;
|
|
||||||
|
|
||||||
/* preset time values to harmless values... */
|
|
||||||
*t1 = -1;
|
|
||||||
*t3 = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = STATIC_VAR (locdata);
|
|
||||||
x = loc->x;
|
|
||||||
y = loc->y;
|
|
||||||
|
|
||||||
/* Retrieve cntl_input value. */
|
|
||||||
cntl_input = INPUT(cntl_in);
|
|
||||||
|
|
||||||
/* Determine segment boundaries within which cntl_input resides */
|
|
||||||
/*** cntl_input below lowest cntl_voltage ***/
|
|
||||||
if (cntl_input <= x[0]) {
|
|
||||||
|
|
||||||
slope = (y[1] - y[0])/(x[1] - x[0]);
|
|
||||||
dc = y[0] + (cntl_input - x[0]) * slope;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/*** cntl_input above highest cntl_voltage ***/
|
|
||||||
|
|
||||||
if (cntl_input >= x[cntl_size-1]) {
|
|
||||||
|
|
||||||
slope = (y[cntl_size-1] - y[cntl_size-2]) /
|
|
||||||
(x[cntl_size-1] - x[cntl_size-2]);
|
|
||||||
dc = y[cntl_size-1] + (cntl_input - x[cntl_size-1]) * slope;
|
|
||||||
|
|
||||||
}
|
|
||||||
else { /*** cntl_input within bounds of end midpoints...
|
|
||||||
must determine position progressively & then
|
|
||||||
calculate required output. ***/
|
|
||||||
|
|
||||||
for (i=0; i<cntl_size-1; i++) {
|
|
||||||
|
|
||||||
if ( (cntl_input < x[i+1]) && (cntl_input >= x[i]) ) {
|
|
||||||
|
|
||||||
/* Interpolate to the correct duty cycle value */
|
|
||||||
|
|
||||||
dc = ( (cntl_input - x[i]) / (x[i+1] - x[i]) ) *
|
|
||||||
( y[i+1]-y[i] ) + y[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** If dc < 0.0, clamp to 0 & issue a warning ***/
|
|
||||||
if ( 0.0 > dc ) {
|
|
||||||
dc = 0;
|
|
||||||
// cm_message_send(d_pwm_negative_dc_error);
|
|
||||||
}
|
|
||||||
/*** If dc > 1.0, clamp to 1 & issue a warning ***/
|
|
||||||
if ( 1.0 < dc ) {
|
|
||||||
dc = 1;
|
|
||||||
// cm_message_send(d_pwm_positive_dc_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate the instantaneous phase */
|
|
||||||
*phase = *phase_old + frequency * (TIME - T(1));
|
|
||||||
|
|
||||||
/* dphase is the percent into the cycle for
|
|
||||||
the period */
|
|
||||||
dphase = *phase_old - floor(*phase_old);
|
|
||||||
|
|
||||||
/* Calculate the time variables and the output value
|
|
||||||
for this iteration */
|
|
||||||
|
|
||||||
if((*t1 <= TIME) && (TIME <= *t3)) { /* output high */
|
|
||||||
|
|
||||||
*t3 = T(1) + (1 - dphase)/frequency;
|
|
||||||
|
|
||||||
if(TIME < *t3) {
|
|
||||||
cm_event_queue(*t3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
|
|
||||||
if((*t3 <= TIME) && (TIME <= *t1)) { /* output low */
|
|
||||||
|
|
||||||
if(dphase > (1.0 - dc) ) {
|
|
||||||
dphase = dphase - 1.0;
|
|
||||||
}
|
|
||||||
*t1 = T(1) + ( (1.0 - dc) - dphase)/frequency;
|
|
||||||
|
|
||||||
if(TIME < *t1) {
|
|
||||||
|
|
||||||
cm_event_queue(*t1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
if(dphase > (1.0 - dc) ) {
|
|
||||||
dphase = dphase - 1.0;
|
|
||||||
}
|
|
||||||
*t1 = T(1) + ( (1.0 - dc) - dphase )/frequency;
|
|
||||||
|
|
||||||
if((TIME < *t1) || (T(1) == 0)) {
|
|
||||||
cm_event_queue(*t1);
|
|
||||||
}
|
|
||||||
|
|
||||||
*t3 = T(1) + (1 - dphase)/frequency;
|
|
||||||
}
|
|
||||||
cm_analog_set_temp_bkpt(*t1);
|
|
||||||
cm_analog_set_temp_bkpt(*t3);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EVENT: /** discrete call...lots to do **/
|
|
||||||
|
|
||||||
test_double = TIME;
|
|
||||||
|
|
||||||
if ( 0.0 == TIME ) { /* DC analysis...preset values,
|
|
||||||
as appropriate.... */
|
|
||||||
|
|
||||||
/* retrieve & normalize phase value */
|
|
||||||
*phase = PARAM(init_phase);
|
|
||||||
if ( 0 > *phase ) {
|
|
||||||
*phase = *phase + 360.0;
|
|
||||||
}
|
|
||||||
*phase = *phase / 360.0;
|
|
||||||
|
|
||||||
/* set phase value to init_phase */
|
|
||||||
*phase_old = *phase;
|
|
||||||
|
|
||||||
/* preset time values to harmless values... */
|
|
||||||
*t1 = -1;
|
|
||||||
*t3 = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate the time variables and the output value
|
|
||||||
for this iteration */
|
|
||||||
|
|
||||||
/* Output is always set to STRONG */
|
|
||||||
OUTPUT_STRENGTH(out) = STRONG;
|
|
||||||
|
|
||||||
if( *t1 == TIME ) { /* rising edge */
|
|
||||||
|
|
||||||
OUTPUT_STATE(out) = ONE;
|
|
||||||
OUTPUT_DELAY(out) = PARAM(rise_delay);
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
if ( *t3 == TIME ) { /* falling edge */
|
|
||||||
|
|
||||||
OUTPUT_STATE(out) = ZERO;
|
|
||||||
OUTPUT_DELAY(out) = PARAM(fall_delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
else { /* no change in output */
|
|
||||||
|
|
||||||
if ( TIME != 0.0 ) {
|
|
||||||
OUTPUT_CHANGED(out) = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (*t1 < TIME) && (TIME < *t3) ) {
|
|
||||||
OUTPUT_STATE(out) = ONE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OUTPUT_STATE(out) = ZERO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the current duty cycle. */
|
||||||
|
|
||||||
|
static double get_dc(double ctl, struct pwl *table, int csize)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < csize; ++i) {
|
||||||
|
if (table[i].ctl > ctl)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interpolation outside input range continues slope. */
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
if (i == csize)
|
||||||
|
i -= 2;
|
||||||
|
else
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
d = table[i].dc +
|
||||||
|
(ctl - table[i].ctl) * ((table[i + 1].dc - table[i].dc) /
|
||||||
|
(table[i + 1].ctl - table[i].ctl));
|
||||||
|
|
||||||
|
/* limit duty cycle d to 0.01 <= d <= 0.99 */
|
||||||
|
if (d > 0.99)
|
||||||
|
d = 0.99;
|
||||||
|
else if (d < 0.01)
|
||||||
|
d = 0.01;
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The state data. */
|
||||||
|
|
||||||
|
struct state {
|
||||||
|
double last_time; // Time of last output change.
|
||||||
|
Digital_State_t last; // Last value output.
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The code-model function. */
|
||||||
|
|
||||||
|
void cm_d_pwm(ARGS)
|
||||||
|
{
|
||||||
|
struct pwl *table;
|
||||||
|
struct state *state;
|
||||||
|
double ctl, delta, when, ddc;
|
||||||
|
int csize, i;
|
||||||
|
|
||||||
|
CALLBACK = cm_d_pwm_callback;
|
||||||
|
|
||||||
|
csize = PARAM_SIZE(cntl_array);
|
||||||
|
delta = 1.0 / PARAM(frequency);
|
||||||
|
|
||||||
|
if (INIT) {
|
||||||
|
|
||||||
|
/* Validate PWL table. */
|
||||||
|
|
||||||
|
for (i = 0; i < csize - 1; ++i) {
|
||||||
|
if (PARAM(cntl_array[i]) >= PARAM(cntl_array[i + 1]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < csize - 1 || csize != PARAM_SIZE(dc_array)) {
|
||||||
|
cm_message_send("Badly-formed control table");
|
||||||
|
STATIC_VAR(locdata) = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate PWL table. */
|
||||||
|
|
||||||
|
table = malloc(csize * sizeof (struct pwl));
|
||||||
|
STATIC_VAR(locdata) = table;
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < csize; ++i) {
|
||||||
|
table[i].ctl = PARAM(cntl_array[i]);
|
||||||
|
table[i].dc = PARAM(dc_array[i]);
|
||||||
|
if (table[i].dc <= 0) {
|
||||||
|
cm_message_printf("Error: duty cycle %g is not positve, "
|
||||||
|
"value replaced by 0.01.",
|
||||||
|
table[i].dc);
|
||||||
|
table[i].dc = 0.01;
|
||||||
|
}
|
||||||
|
else if (table[i].dc >= 1) {
|
||||||
|
cm_message_printf("Error: duty cycle %g is 1 or larger, "
|
||||||
|
"value replaced by 0.99.",
|
||||||
|
table[i].dc);
|
||||||
|
table[i].dc = 0.99;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate state data. */
|
||||||
|
|
||||||
|
cm_event_alloc(0, sizeof (struct state));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
table = STATIC_VAR(locdata);
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
state = (struct state *)cm_event_get_ptr(0, 0);
|
||||||
|
|
||||||
|
if (CALL_TYPE != EVENT) {
|
||||||
|
if (TIME == 0.0) {
|
||||||
|
double phase;
|
||||||
|
|
||||||
|
/* Set initial output and state data. */
|
||||||
|
|
||||||
|
ctl = INPUT(cntl_in);
|
||||||
|
ddc = get_dc(ctl, table, csize);
|
||||||
|
|
||||||
|
phase = PARAM(init_phase);
|
||||||
|
phase /= 360.0;
|
||||||
|
if (phase < 0.0)
|
||||||
|
phase += 1.0;
|
||||||
|
|
||||||
|
/* When would a hypothetical previous transition have been? */
|
||||||
|
|
||||||
|
state->last_time = delta * (1.0 - ddc - phase);
|
||||||
|
if (state->last_time < 0.0) {
|
||||||
|
state->last = ONE;
|
||||||
|
} else {
|
||||||
|
state->last = ZERO;
|
||||||
|
state->last_time = -delta * phase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event call; either one requested previously or just before
|
||||||
|
* a time-step is accepted.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (TIME == 0.0) {
|
||||||
|
OUTPUT_STATE(out) = state->last;
|
||||||
|
OUTPUT_STRENGTH(out) = STRONG;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When is the next transition due? */
|
||||||
|
|
||||||
|
ctl = INPUT(cntl_in);
|
||||||
|
ddc = get_dc(ctl, table, csize);
|
||||||
|
if (state->last)
|
||||||
|
delta *= ddc;
|
||||||
|
else
|
||||||
|
delta *= (1.0 - ddc);
|
||||||
|
when = state->last_time + delta;
|
||||||
|
|
||||||
|
if (TIME >= when) {
|
||||||
|
// If the frequency rose rapidly, the transition has been missed.
|
||||||
|
// Force a shorter time-step and schedule then.
|
||||||
|
|
||||||
|
cm_analog_set_temp_bkpt(state->last_time + FACTOR * delta);
|
||||||
|
OUTPUT_CHANGED(out) = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TIME >= state->last_time + FACTOR * delta) {
|
||||||
|
/* TIME is reasonably close to transition time. Request output. */
|
||||||
|
|
||||||
|
state->last_time = when;
|
||||||
|
state->last ^= ONE;
|
||||||
|
OUTPUT_STATE(out) = state->last;
|
||||||
|
OUTPUT_STRENGTH(out) = STRONG;
|
||||||
|
OUTPUT_DELAY(out) = when - TIME;
|
||||||
|
|
||||||
|
/* Request a call in the next half-cycle. */
|
||||||
|
|
||||||
|
cm_event_queue(when + FACTOR * delta);
|
||||||
|
} else {
|
||||||
|
OUTPUT_CHANGED(out) = FALSE;
|
||||||
|
|
||||||
|
if (TIME < state->last_time) {
|
||||||
|
/* Output transition pending, nothing to do. */
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* Request a call nearer to transition time. */
|
||||||
|
|
||||||
|
cm_event_queue(state->last_time + FACTOR * delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
/*.......1.........2.........3.........4.........5.........6.........7.........8
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
FILE d_pwm/d_pwm.h
|
|
||||||
|
|
||||||
Public Domain
|
|
||||||
|
|
||||||
Georgia Tech Research Corporation
|
|
||||||
Atlanta, Georgia 30332
|
|
||||||
PROJECT A-8503-405
|
|
||||||
The ngspice team
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
25 Jul 1991 Jeffrey P. Murray
|
|
||||||
02 Mar 2022 Holger Vogt
|
|
||||||
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
30 Sept 1991 Jeffrey P. Murray
|
|
||||||
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
This file contains the header information for the d_pwm
|
|
||||||
code model.
|
|
||||||
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
FILE ROUTINE CALLED
|
|
||||||
|
|
||||||
N/A N/A
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
REFERENCED FILES
|
|
||||||
|
|
||||||
N/A
|
|
||||||
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
===============================================================================*/
|
|
||||||
/*
|
|
||||||
Structures, etc. for d_pwm oscillator model.
|
|
||||||
7/25/90
|
|
||||||
Last Modified 7/25/91 J.P.Murray
|
|
||||||
3/02/22 H. Vogt */
|
|
||||||
|
|
||||||
/*=======================================================================*/
|
|
||||||
|
|
||||||
/*=== INCLUDE FILES =====================================================*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== CONSTANTS =========================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
/**** Error Messages ****/
|
|
||||||
char *d_pwm_allocation_error = "\n**** Error ****\nD_PWM: Error allocating VCO block storage \n";
|
|
||||||
char *d_pwm_array_error = "\n**** Error ****\nD_PWM: Size of control array different than duty cycle array \n";
|
|
||||||
char *d_pwm_negative_dc_error = "\n**** Error ****\nD_PWM: The extrapolated value for duty cycle\nhas been found to be negative... \n Lower duty cycle level has been clamped to 0.0 \n";
|
|
||||||
char *d_pwm_positive_dc_error = "\n**** Error ****\nD_PWM: The extrapolated value for duty cycle\nhas been found to be > 1... \n Upper duty cycle level has been clamped to 1.0 \n";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== MACROS ============================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== LOCAL VARIABLES & TYPEDEFS ========================================*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== FUNCTION PROTOTYPE DEFINITIONS ====================================*/
|
|
||||||
|
|
||||||
|
|
||||||
/*=======================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue