Merge branch 'pre-master-47' into bt_dev

This commit is contained in:
Brian Taylor 2026-04-15 14:45:23 -07:00
commit fc48bf7d05
12 changed files with 360 additions and 60 deletions

View File

@ -0,0 +1,68 @@
NAND-2 Ring Oscillator IHP Open PDK
.lib "$PDK_ROOT/$PDK/libs.tech/ngspice/models/cornerMOSlv.lib" mos_tt
.subckt nand2 a b vdd vss z
xm01 vdd a z vdd sg13_lv_pmos l=0.15u w=0.96u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
xm02 vss a sig3 vss sg13_lv_nmos l=0.15u w=0.82u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
xm03 z b vdd vdd sg13_lv_pmos l=0.15u w=0.96u as=0.20405p ad=0.20405p ps=2.07u pd=2.07u
xm04 sig3 b z vss sg13_lv_nmos l=0.15u w=0.82u as=0.1749p ad=0.1749p ps=1.85u pd=1.85u
c4 a vss 0.549f
c5 b vss 0.578f
c1 z vss 0.609f
.ends
XNAND1 1 1 vd vs 2 nand2
XNAND2 2 2 vd vs 3 nand2
XNAND3 3 3 vd vs 4 nand2
XNAND4 4 4 vd vs 5 nand2
XNAND5 5 5 vd vs 6 nand2
XNAND6 6 6 vd vs 7 nand2
XNAND7 7 7 vd vs 8 nand2
XNAND8 8 8 vd vs 9 nand2
XNAND9 9 9 vd vs 10 nand2
XNAND10 10 10 vd vs 11 nand2
XNAND11 11 11 vd vs 12 nand2
XNAND12 12 12 vd vs 13 nand2
XNAND13 13 13 vd vs 14 nand2
XNAND14 14 14 vd vs 15 nand2
XNAND15 15 15 vd vs 16 nand2
XNAND16 16 16 vd vs 17 nand2
XNAND17 17 17 vd vs 18 nand2
XNAND18 18 18 vd vs 19 nand2
XNAND19 19 19 vd vs 1 nand2
XNAND20 1 1 vd 0 out nand2
Vdd vd 0 1.5
Vss vs 0 0
.option noinit
.tran 10p 80n uic
.control
pre_osdi ../lib/ngspice/psp103_nqs.osdi ../lib/ngspice/psp103.osdi
set temp=0
option klu
run
rusage
set xbrushwidth=3
*plot i(Vss) ylimit 0 500u xlimit 50n 60n
plot out
plot out xlimit 50n 60n
meas tran tdiff TRIG V(out) val=0.7 rise=5 TARG v(out) val=0.7 rise=15
let freq=10/tdiff
print freq
linearize out
fft out
plot mag(out) xlimit 300Meg 2300Meg
meas sp fmax MAX_AT out from=1e8 to=1e9
echo
reset
pss 500e6 10n out 256 10 5 5e-3 uic
plot out xlimit 300Meg 2300Meg
inventory
.endc
.end

View File

@ -0,0 +1,41 @@
Colpitt's Oscillator Circuit
* Colpitt is an harmonic oscillator (LC based) which use
* a capacitive partition of resonator to feed the single
* active device.
* Predicted frequency is about 3.30435e+06 Hz.
* Models:
.model qnl npn(level=1 bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf va=50)
r1 1 0 1
q1 2 1 3 qnl
vcc 4 0 5
rl 4 2 750
c1 2 3 500p
c2 4 3 4500p
l1 4 2 5uH
re 3 6 4.65k
vee 6 0 dc -10 pwl 0 0 1e-9 -10
.control
** transient sim
tran 3n 120u 20u
plot V(2) v(3)
** fft of tran sim
linearize v(3)
fft v(3)
let dbv3 = db(v(3))
plot dbv3 xlimit 1Meg 5Meg
** measure the frequency of oscillation
meas sp fosc MAX_AT dbv3 from=1Meg to=5Meg
** periodic steady state sim
pss 1e6 50e-6 3 256 10 50 5e-3
set xbrushwidth=3
plot v(3) ylimit 0 0.3
.endc
.end

View File

@ -0,0 +1,44 @@
Complimentary Cross Quad CMOS Oscillator
* Predicted frequency is 5.61224e+08 Hz.
*
* PLOT i1
* Supply
vdd vdd gnd 1.2 pwl 0 1.2 1e-9 1.2
rdd vdd vdd_ana 70m
rgnd gnd gnd_ana 70m
* Cross quad
mpsx v_plus v_minus vdd_ana vdd_ana pch w=10u l=0.1u
mnsx v_plus v_minus gnd_ana gnd_ana nch w=10u l=0.1u
mpdx v_minus v_plus vdd_ana vdd_ana pch w=10u l=0.1u
mndx v_minus v_plus gnd_ana gnd_ana nch w=10u l=0.1u
* Lumped elements model of real inductor
ls v_plus i1 19.462n ic=0.06
rs i1 v_minus 7.789
cs v_plus v_minus 443f
coxs v_plus is 2.178p
coxd v_minus id 2.178p
rsis is gnd_ana 308
rsid id gnd_ana 308
csis is gnd_ana 51f
csid id gnd_ana 51f
* Parallel capacitor to determine leading resonance
cp v_plus v_minus 3.4p
.model nch nmos ( version=4.7 level=54 lmin=0.1u lmax=20u wmin=0.1u wmax=10u )
.model pch pmos ( version=4.7 level=54 lmin=0.1u lmax=20u wmin=0.1u wmax=10u )
.control
tran 0.05n 1u uic
plot i1
reset
pss 400e6 2u 1 1024 10 10 5e-3 uic
set xbrushwidth=3
plot i1
.endc
.end

View File

@ -0,0 +1,31 @@
Hartley's Oscillator Circuit
* Hartley is an harmonic oscillator (LC based) which use
* an inductive partition of resonator to feed the single
* active device. Output is taken on node 2.
* Prediceted frequency is about 121.176 Hz.
*
* PLOT V(3)
* Models:
.model qnl npn(level=1 bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf va=50)
vcc 1 0 5 pwl 0 0 1e-5 5
r1 1 2 0.2k
q1 2 3 0 qnl
c1 3 4 633n
l1 3 0 1.5
l2 0 4 500m
r2 4 2 100
.control
set xbrushwidth=3
tran 10u 1
plot v(2)
linearize v(2)
fft v(2)
plot mag(V(2)) xlimit 0 500 ylimit 0 1.5
reset
pss 50 200e-3 2 1024 11 10 5e-3
plot v(2) xlimit 0 500 ylimit 0 1.5
.endc

View File

@ -0,0 +1,41 @@
Ring CMOS Oscillator
* Oscillation is taken on node "bout".
* Predicted frequency is 3.8e+09 Hz.
*
* PLOT bout
* Supply
vdd vdd gnd 1.2 pwl 0 1.2 1e-9 1.2
rdd vdd vdd_ana 70m
rgnd gnd gnd_ana 70m
* Inverter
mp1 inv1 inv3 vdd_ana vdd_ana pch w=10u l=0.18u
mn1 inv1 inv3 gnd_ana gnd_ana nch w=10u l=0.18u
mp2 inv2 inv1 vdd_ana vdd_ana pch w=10u l=0.18u
mn2 inv2 inv1 gnd_ana gnd_ana nch w=10u l=0.18u
mp3 inv3 inv2 vdd_ana vdd_ana pch w=10u l=0.18u
mn3 inv3 inv2 gnd_ana gnd_ana nch w=10u l=0.18u
* Buffer out
mp4 bout inv3 vdd_ana vdd_ana pch w=10u l=0.18u
mn4 bout inv3 gnd_ana gnd_ana nch w=10u l=0.18u
.model nch nmos ( version=4.7 level=54 lmin=0.1u lmax=20u wmin=0.1u wmax=10u )
.model pch pmos ( version=4.7 level=54 lmin=0.1u lmax=20u wmin=0.1u wmax=10u )
.control
tran 0.005n 100n uic
plot v(bout)
linearize bout
fft bout
set xbrushwidth=3
plot mag(bout) xlimit 0 35G
reset
pss 2G 10n bout 1024 10 5 5e-3 uic
plot bout xlimit 0 35G
.endc
.end

View File

@ -0,0 +1,33 @@
Vackar's Oscillator Circuit
* Vackar is a derivation of Colpitt's oscillator (LC based).
* Oscillation is taken on node 4.
* Predicted frequency is 1.91803e+06Hz.
* Models:
.model qnl npn(level=1 bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf va=50)
vcc 1 0 5 pwl 0 10 1e-9 5
lrfc 1 2 100u
cdec 2 0 7n
q1 3 2 0 qnl
rb 3 0 4700
c1 3 4 100p
c2 3 0 600p
c0 4 0 1n
l1 4 1 6.2u
.control
tran 10n 20u
plot v(4)
linearize v(4)
fft v(4)
set xbrushwidth=3
plot mag(v(4)) xlimit 0 10Meg
let maxfft=mag(v(4))
meas sp fosc MAX_AT maxfft from=1Meg to=10Meg
reset
pss 1.8e6 10e-6 4 1024 10 50 5e-3 uic
plot v(4) xlimit 0 10Meg
.endc
.end

View File

@ -1,17 +1,25 @@
Van Der Pol Oscillator
* Prediceted frequency is about 4.54167e+06 Hz.
* Third harmonic is high as the first one
Ba gib 0 I=-1e-2*v(gib,0)+1e-2*v(gib,0)^3
* Third harmonic is as high as the first one
Ba gib 0 I=-1e-2*v(gib,0)+1e-2*v(gib,0)^3
* Q is about 10
La gib 0 1.2e-6
Ra gib 0 158.113
Ca gib 0 1e-9 ic=0.5
*La gib 0 1e-9
*Ra gib 0 474.6
*Ca gib 0 1e-9 ic=0.5
* Ghost node... Test for my PSS!
Rb bad 0 1k
RLa gib gib1 1m
La gib1 0 1.2e-6
Ra gib 0 158.113
Ca gib 0 1e-9 ic=-1
Vnew 0 gr 1
Rnew gr gib 5k
*La gib 0 1e-9
*Ra gib 0 474.6
*Ca gib 0 1e-9 ; ic=0.5
* Ghost node... Test for my PSS!
*Rb bad 0 1k
.tran 10e-9 20e-6 uic
.pss 0.5e6 100e-6 1 50 10 50 5e-3 uic
.end
*.tran 1e-9 150e-6 uic
.pss 0.8e6 130e-6 1 50 10 50 5e-3 uic

View File

@ -0,0 +1,37 @@
Van Der Pol Oscillator
* Prediceted frequency is about 4.54167e+06 Hz.
* Third harmonic is as high as the first one
Ba gib 0 I=-1e-2*v(gib,0)+1e-2*v(gib,0)^3
* Q is about 10
RLa gib gib1 1m
La gib1 0 1.2e-6
Ra gib 0 158.113
Ca gib 0 1e-9 ic=-1
Vnew 0 gr 1
Rnew gr gib 5k
*La gib 0 1e-9
*Ra gib 0 474.6
*Ca gib 0 1e-9 ; ic=0.5
* Ghost node... Test for my PSS!
*Rb bad 0 1k
.control
tran 10e-9 20e-6 uic
rusage time
plot gib xlimit 0 5u
meas tran ptdiff TRIG v(gib) val=0 RISE=25 TARG v(gib) val=0 RISE=50
let freq = 25.0/ptdiff
echo frequency is $&freq
reset
pss 0.5e6 100e-6 1 50 10 50 5e-3 uic
rusage time
plot gib
setplot pss1
plot gib
.endc
.end

View File

@ -36,6 +36,7 @@ Author: 1986 Thomas L. Quarles
#define E_BAD_DOMAIN 15 /* output interface begin/end domain calls mismatched */
#define E_EXISTS_BAD 16 /* error - attempt to create duplicate */
/* instance or model. Bail out. */
#define E_ERR_PSS 17 /* error - during PSS. Bail out. */
#define E_PRIVATE 100 /* messages above this number are private to */
/* the simulator and MUST be accompanied by */

View File

@ -50,6 +50,7 @@ do { \
#define HISTORY 1024
#define GF_LAST 313
//#define PSSDEBUG
static int
DFT(long int, int, double *, double *, double *, double, double *, double *, double *, double *, double *);
@ -132,7 +133,7 @@ DCpss(CKTcircuit *ckt,
msize = SMPmatSize (ckt->CKTmatrix) ;
RHS_copy_se = TMALLOC (double, msize) ; /* Set the current RHS reference for next Shooting Evaluation */
RHS_copy_der = TMALLOC (double, msize) ; /* Used to compute current Derivative */
RHS_copy_der = TMALLOC (double, msize) ; /* Used to compute current derivative */
RHS_derivative = TMALLOC (double, msize) ;
pred = TMALLOC (double, msize) ;
RHS_max = TMALLOC (double, msize) ;
@ -264,7 +265,7 @@ DCpss(CKTcircuit *ckt,
(ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITFLOAT,
ckt->CKTdcMaxIter);
#ifdef STEPDEBUG
#if defined(STEPDEBUG) || defined(PSSDEBUG)
if(converged != 0) {
fprintf(stdout,"\nTransient solution failed -\n");
CKTncDump(ckt);
@ -425,7 +426,7 @@ DCpss(CKTcircuit *ckt,
if ((AlmostEqualUlps (ckt->CKTtime, nextstep, 10)) || (ckt->CKTtime > time_temp + 1 / ckt->CKTguessedFreq))
{
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "IN_PSS: time point accepted in evolution for FFT calculations.\n") ;
fprintf (stderr, "Circuit time %1.15g, final time %1.15g, point index %d and total requested points %ld\n",
ckt->CKTtime, nextstep, pss_points_cycle, ckt->CKTpsspoints) ;
@ -446,14 +447,14 @@ DCpss(CKTcircuit *ckt,
/* Set the next BreakPoint for PSS */
CKTsetBreak (ckt, time_temp + (1 / ckt->CKTguessedFreq) * ((double)pss_points_cycle / (double)ckt->CKTpsspoints)) ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "Next breakpoint set in: %1.15g\n", time_temp + 1 / ckt->CKTguessedFreq * ((double)pss_points_cycle / (double)ckt->CKTpsspoints)) ;
#endif
} else {
/* Algo can enter here but should do nothing */
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "IN_PSS: time point accepted in evolution but dropped for FFT calculations\n") ;
#endif
@ -538,7 +539,7 @@ DCpss(CKTcircuit *ckt,
/* Save the RHS_copy_der as the NEW CKTrhsOld */
RHS_copy_der [i] = ckt->CKTrhsOld [i + 1] ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "Pred is so high or so low! Diff is: %g\n", err_conv [i]) ;
#endif
@ -638,7 +639,7 @@ DCpss(CKTcircuit *ckt,
/* pred is treated as FREQUENCY to avoid numerical overflow when derivative is close to ZERO */
pred [i] = RHS_derivative [i] / err_conv [i] ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "Pred is so high or so low! Diff is: %g\n", err_conv [i]) ;
#endif
@ -652,7 +653,7 @@ DCpss(CKTcircuit *ckt,
predsum += pred [i] ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "Predsum in time before to be divided by dynamic_test has value %g\n", 1 / predsum) ;
fprintf (stderr, "Current Diff: %g, Derivative: %g, Frequency Projection: %g\n", err_conv [i], RHS_derivative [i], pred [i]) ;
#endif
@ -717,7 +718,7 @@ DCpss(CKTcircuit *ckt,
if (dynamic_test == 0)
{
/* Test for dynamic existence */
fprintf (stderr, "No detectable dynamic on voltages nodes or currents branches. PSS analysis aborted\n") ;
fprintf (stderr, "Error: No detectable dynamic on voltages nodes or currents branches.\n PSS analysis aborted\n") ;
/* Terminates plot in Time Domain and frees the allocated memory */
SPfrontEnd->OUTendPlot (job->PSSplot_td) ;
@ -728,7 +729,7 @@ DCpss(CKTcircuit *ckt,
FREE (err_conv) ;
FREE (psstimes) ;
FREE (pssvalues) ;
return (E_PANIC) ; /* to be corrected with definition of new error macro in iferrmsg.h */
return (E_ERR_PSS) ; /* error macro in iferrmsg.h */
}
else if ((time_err_min_0 - time_temp) < 0)
{
@ -766,7 +767,7 @@ DCpss(CKTcircuit *ckt,
/* Enters here if guessed frequency is higher than the 'real' value */
ckt->CKTguessedFreq = 1 / (1 / ckt->CKTguessedFreq + fabs (predsum)) ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "Frequency DOWN: est per %g, err min %g, err min 1 %g, err max %g, err %g\n",
time_err_min_0 - time_temp, err_min_0, err_min_1, err_max, err) ;
#endif
@ -775,7 +776,7 @@ DCpss(CKTcircuit *ckt,
/* Enters here if guessed frequency is lower than the 'real' value */
ckt->CKTguessedFreq = 1 / (time_err_min_0 - time_temp) ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "Frequency UP: est per %g, err min %g, err min 1 %g, err max %g, err %g\n",
time_err_min_0 - time_temp, err_min_0, err_min_1, err_max, err) ;
#endif
@ -809,7 +810,7 @@ DCpss(CKTcircuit *ckt,
for (i = 1 ; i <= msize ; i++)
RHS_copy_se [i - 1] = ckt->CKTrhsOld [i] ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "RHS on new shooting cycle: ") ;
for (i = 0 ; i < msize ; i++)
fprintf (stderr, "%-15g ", RHS_copy_se [i]) ;
@ -833,7 +834,7 @@ DCpss(CKTcircuit *ckt,
pss_state = PSS ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "\nFrequency estimation (FE) and RHS period residual (PR) evolution\n") ;
#endif
@ -882,7 +883,7 @@ DCpss(CKTcircuit *ckt,
else
fprintf (stderr, "\nConvergence not reached. However the most near convergence iteration has predicted (iteration %d) a fundamental frequency of %15.10g Hz\n", k, ckt->CKTguessedFreq) ;
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "time_temp %g\n", time_temp) ;
fprintf (stderr, "IN_PSS: FIRST time point accepted in evolution for FFT calculations\n") ;
fprintf (stderr, "Circuit time %1.15g, final time %1.15g, point index %d and total requested points %ld\n",
@ -907,7 +908,7 @@ DCpss(CKTcircuit *ckt,
{
/* The algorithm enters here when in_pss is set */
#ifdef STEPDEBUG
#ifdef PSSDEBUG
fprintf (stderr, "ttemp %1.15g, final_time %1.15g, current_time %1.15g\n", time_temp, time_temp + 1 / ckt->CKTguessedFreq, ckt->CKTtime) ;
#endif
@ -1133,20 +1134,17 @@ resume:
/* gtri - begin - wbk - Modify Breakpoint stuff */
/* Throw out any permanent breakpoint times <= current time */
for (;;) {
while ((ckt->CKTbreaks[0] <= ckt->CKTtime + ckt->CKTminBreak ||
AlmostEqualUlps(ckt->CKTbreaks[0], ckt->CKTtime, 100)) &&
ckt->CKTbreaks[0] < ckt->CKTfinalTime) {
#ifdef STEPDEBUG
fprintf (stderr, " brk_pt: %g ckt_time: %g ckt_min_break: %g\n", ckt->CKTbreaks [0], ckt->CKTtime, ckt->CKTminBreak) ;
printf("throwing out permanent breakpoint times <= current time "
"(brk pt: %g)\n",
ckt->CKTbreaks[0]);
printf(" ckt_time: %g ckt_min_break: %g\n",
ckt->CKTtime, ckt->CKTminBreak);
#endif
if(AlmostEqualUlps(ckt->CKTbreaks[0], ckt->CKTtime, 100) ||
ckt->CKTbreaks[0] <= ckt->CKTtime + ckt->CKTminBreak) {
#ifdef STEPDEBUG
fprintf (stderr, "throwing out permanent breakpoint times <= current time (brk pt: %g)\n", ckt->CKTbreaks [0]) ;
fprintf (stderr, "ckt_time: %g ckt_min_break: %g\n", ckt->CKTtime, ckt->CKTminBreak) ;
#endif
CKTclrBreak(ckt);
} else {
break;
}
CKTclrBreak(ckt);
}
/* Force the breakpoint if appropriate */
if(ckt->CKTtime + ckt->CKTdelta > ckt->CKTbreaks[0]) {
@ -1286,7 +1284,7 @@ resume:
return(converged);
}
#ifdef STEPDEBUG
#ifdef PSSDEBUG
if (pss_state == PSS)
fprintf (stderr, "pss_state: %d, converged: %d\n", pss_state, converged) ;
#endif

View File

@ -69,24 +69,21 @@ double
PTpower(double arg1, double arg2)
{
double res;
if (newcompat.lt) {
if (arg1 == 0)
if (arg1 == 0)
res = 0;
else if(arg1 > 0)
res = pow(arg1, arg2);
else {
/* If arg2 is quasi an integer, round it to have pow not fail
when arg1 is negative. Takes into account the double
representation which sometimes differs in the last digit(s). */
if (AlmostEqualUlps(nearbyint(arg2), arg2, 10))
res = pow(arg1, round(arg2));
else
/* As per LTSPICE specification for ** */
res = 0;
else if(arg1 > 0)
res = pow(arg1, arg2);
else {
/* If arg2 is quasi an integer, round it to have pow not fail
when arg1 is negative. Takes into account the double
representation which sometimes differs in the last digit(s). */
if (AlmostEqualUlps(nearbyint(arg2), arg2, 10))
res = pow(arg1, round(arg2));
else
/* As per LTSPICE specification for ** */
res = 0;
}
}
else
res = pow(fabs(arg1), arg2);
return res;
}
@ -106,7 +103,7 @@ PTpowerH(double arg1, double arg2)
res = pow(arg1, arg2);
}
}
else if (newcompat.lt) {
else {
if (arg1 >= 0)
res = pow(arg1, arg2);
else {
@ -120,8 +117,6 @@ PTpowerH(double arg1, double arg2)
res = 0;
}
}
else
res = pow(fabs(arg1), arg2);
return res;
}

View File

@ -107,6 +107,9 @@ const char *SPerror(int type)
case E_NOF2SRC:
msg = "no F2 source for IM disto analysis";
break;
case E_ERR_PSS:
msg = "pss failed";
break;
case OK:
return (NULL);
default: