Handle the case when control voltages on and off are equal.

Update the linear switch: add the limits to resistance ron, roff
Update the log switch: correct the resistance calculation for
von < voff
Add some examples for the pswitch.
This commit is contained in:
Holger Vogt 2022-08-05 17:30:08 +02:00
parent b94ef139dd
commit c8ed9590b7
3 changed files with 180 additions and 42 deletions

View File

@ -0,0 +1,52 @@
* sw ring-oscillators
.control
destroy all
run
plot I(vmeasurea) I(vmeasureb) I(vmeasurec) I(vmeasured)
plot V(outa) V(outb) V(outc) V(outd)
rusage
.endc
.tran 3m 3
VDD VDD2 0 DC 3
Rla VDD2 outa 1k
Rlb VDD2 outb 1k
Rlc VDD2 outc 1k
Rld VDD2 outd 1k
VMEASUREa DGNDa 0 dc 0
VMEASUREb DGNDb 0 dc 0
VMEASUREc DGNDc 0 dc 0
VMEASUREd DGNDd 0 dc 0
Vin in 0 pulse ( 0 3 0 3 3 10 10 )
xsa in outa DGNDa switcha
xsb in outb DGNDb switchb
xsc in outc DGNDc switchc
xsd in outd DGNDd switchd
.subckt switcha In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=false cntl_on=1.5 cntl_off=2.5 r_on=1k r_off=2g)
.ends
.subckt switchb In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=false cntl_on=1.5 cntl_off=2.5 r_on=1k r_off=2k)
.ends
.subckt switchc In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=false cntl_on=2.5 cntl_off=1.5 r_on=1k r_off=2g)
.ends
.subckt switchd In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=false cntl_on=2.5 cntl_off=1.5 r_on=1k r_off=2k)
.ends
.end

View File

@ -0,0 +1,52 @@
* sw ring-oscillators
.control
destroy all
run
plot I(vmeasurea) I(vmeasureb) I(vmeasurec) I(vmeasured)
plot V(outa) V(outb) V(outc) V(outd)
rusage
.endc
.tran 3m 3
VDD VDD2 0 DC 3
Rla VDD2 outa 1k
Rlb VDD2 outb 1k
Rlc VDD2 outc 1k
Rld VDD2 outd 1k
VMEASUREa DGNDa 0 dc 0
VMEASUREb DGNDb 0 dc 0
VMEASUREc DGNDc 0 dc 0
VMEASUREd DGNDd 0 dc 0
Vin in 0 pulse ( 0 3 0 3 3 10 10 )
xsa in outa DGNDa switcha
xsb in outb DGNDb switchb
xsc in outc DGNDc switchc
xsd in outd DGNDd switchd
.subckt switcha In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=true cntl_on=1.5 cntl_off=2.5 r_on=1k r_off=2g)
.ends
.subckt switchb In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=true cntl_on=1.5 cntl_off=2.5 r_on=1k r_off=2k)
.ends
.subckt switchc In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=true cntl_on=2.5 cntl_off=1.5 r_on=1k r_off=2g)
.ends
.subckt switchd In Out DGND
a.xx17.asn %gd in DGND %gd out DGND aswswitch
.model aswswitch pswitch( log=true cntl_on=2.5 cntl_off=1.5 r_on=1k r_off=2k)
.ends
.end

View File

@ -6,14 +6,14 @@ FILE pswitch/cfunc.mod
3-Clause BSD 3-Clause BSD
Copyright 2020 The ngspice team Copyright 2020 The ngspice team
AUTHORS
AUTHORS
27 September 2020 Holger Vogt 27 September 2020 Holger Vogt
MODIFICATIONS MODIFICATIONS
03 June 2021 Yurii Demchyna 03 June 2021 Yurii Demchyna
@ -24,17 +24,17 @@ SUMMARY
code model. code model.
INTERFACES INTERFACES
FILE ROUTINE CALLED FILE ROUTINE CALLED
CMmacros.h cm_message_send(); CMmacros.h cm_message_send();
REFERENCED FILES REFERENCED FILES
Inputs from and outputs to ARGS structure. Inputs from and outputs to ARGS structure.
NON-STANDARD FEATURES NON-STANDARD FEATURES
@ -47,7 +47,7 @@ NON-STANDARD FEATURES
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
/*=== CONSTANTS ========================*/ /*=== CONSTANTS ========================*/
@ -58,8 +58,8 @@ NON-STANDARD FEATURES
/*=== LOCAL VARIABLES & TYPEDEFS =======*/ /*=== LOCAL VARIABLES & TYPEDEFS =======*/
typedef struct { typedef struct {
@ -71,12 +71,14 @@ typedef struct {
the resistance of the switch when the the resistance of the switch when the
controlling voltage is between cntl_on controlling voltage is between cntl_on
and cntl_of */ and cntl_of */
double cntl_on; /* voltage above which switch come on */
double cntl_off; /* voltage below the switch has resistance roff */
double c1; /* some constants */ double c1; /* some constants */
double c2; double c2;
double c3; double c3;
} Local_Data_t; } Local_Data_t;
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
static void static void
@ -98,33 +100,33 @@ cm_pswitch_callback(ARGS, Mif_Callback_Reason_t reason)
/*============================================================================== /*==============================================================================
FUNCTION cm_pswitch() FUNCTION cm_pswitch()
AUTHORS AUTHORS
27 September 2020 Holger Vogt 27 September 2020 Holger Vogt
MODIFICATIONS MODIFICATIONS
SUMMARY SUMMARY
This function implements the pswitch code model. This function implements the pswitch code model.
INTERFACES INTERFACES
FILE ROUTINE CALLED FILE ROUTINE CALLED
CMmacros.h cm_message_send(); CMmacros.h cm_message_send();
RETURNED VALUE RETURNED VALUE
Returns inputs and outputs via ARGS structure. Returns inputs and outputs via ARGS structure.
GLOBAL VARIABLES GLOBAL VARIABLES
NONE NONE
NON-STANDARD FEATURES NON-STANDARD FEATURES
@ -137,11 +139,11 @@ NON-STANDARD FEATURES
void cm_pswitch(ARGS) /* structure holding parms, void cm_pswitch(ARGS) /* structure holding parms,
inputs, outputs, etc. */ inputs, outputs, etc. */
{ {
double cntl_on; /* voltage above which switch come on */ double cntl_on; /* voltage above which switch come on */
double cntl_off; /* voltage below the switch has resistance roff */ double cntl_off; /* voltage below the switch has resistance roff */
double r_on; /* on resistance */ double r_on; /* on resistance */
double r_off; /* off resistance */ double r_off; /* off resistance */
double r_cntl_in; /* input resistance for control terminal */ double r_cntl_in; /* input resistance for control terminal */
@ -158,17 +160,15 @@ void cm_pswitch(ARGS) /* structure holding parms,
double pi_pcntl; /* partial of the output wrt control input */ double pi_pcntl; /* partial of the output wrt control input */
Mif_Complex_t ac_gain; Mif_Complex_t ac_gain;
Local_Data_t *loc; /* Pointer to local static data, not to be included Local_Data_t *loc; /* Pointer to local static data, not to be included
in the state vector */ in the state vector */
/* Retrieve frequently used parameters... */ /* Retrieve frequently used parameters... */
cntl_on = PARAM(cntl_on);
cntl_off = PARAM(cntl_off);
r_on = PARAM(r_on); r_on = PARAM(r_on);
r_off = PARAM(r_off); r_off = PARAM(r_off);
r_cntl_in = PARAM(r_cntl_in); r_cntl_in = PARAM(r_cntl_in);
@ -180,9 +180,11 @@ void cm_pswitch(ARGS) /* structure holding parms,
if(INIT == 1) { /* first time through, allocate memory, set static parameters */ if(INIT == 1) { /* first time through, allocate memory, set static parameters */
char *cntl_error = "\n*****ERROR*****\nPSWITCH: CONTROL voltage delta less than 1.0e-12\n"; char *cntl_error = "\n*****ERROR*****\nPSWITCH: CONTROL voltage delta less than 1.0e-12\n";
cntl_on = PARAM(cntl_on);
cntl_off = PARAM(cntl_off);
if( (fabs(cntl_on - cntl_off) < 1.0e-12) ) { if( (fabs(cntl_on - cntl_off) < 1.0e-12) ) {
cm_message_send(cntl_error); cntl_on += 0.001;
return; cntl_off -= 0.001;
} }
CALLBACK = cm_pswitch_callback; CALLBACK = cm_pswitch_callback;
@ -191,6 +193,9 @@ void cm_pswitch(ARGS) /* structure holding parms,
STATIC_VAR (locdata) = calloc (1 , sizeof ( Local_Data_t )); STATIC_VAR (locdata) = calloc (1 , sizeof ( Local_Data_t ));
loc = STATIC_VAR (locdata); loc = STATIC_VAR (locdata);
loc->cntl_on = cntl_on;
loc->cntl_off = cntl_off;
if ( PARAM(log) == MIF_TRUE ) { /* Logarithmic Variation in 'R' */ if ( PARAM(log) == MIF_TRUE ) { /* Logarithmic Variation in 'R' */
if (cntl_on > cntl_off) if (cntl_on > cntl_off)
{ {
@ -219,6 +224,8 @@ void cm_pswitch(ARGS) /* structure holding parms,
loc = STATIC_VAR (locdata); loc = STATIC_VAR (locdata);
cntl_on = loc->cntl_on;
cntl_off = loc->cntl_off;
if ( PARAM(log) == MIF_TRUE ) { /* Logarithmic Variation in 'R' */ if ( PARAM(log) == MIF_TRUE ) { /* Logarithmic Variation in 'R' */
logmean = loc->logmean; logmean = loc->logmean;
logratio = loc->logratio; logratio = loc->logratio;
@ -228,7 +235,7 @@ void cm_pswitch(ARGS) /* structure holding parms,
double inmean;// = INPUT(cntl_in) - cntl_mean; double inmean;// = INPUT(cntl_in) - cntl_mean;
int outOfLimit = 0; int outOfLimit = 0;
if (cntl_on > cntl_off) { if (cntl_on > cntl_off) {
inmean = ((INPUT(cntl_in) - PARAM(cntl_off)) / (PARAM(cntl_on) - PARAM(cntl_off))) - cntl_mean; inmean = (INPUT(cntl_in) - cntl_off) / (cntl_on - cntl_off) - cntl_mean;
if (INPUT(cntl_in) > cntl_on) { if (INPUT(cntl_in) > cntl_on) {
r = r_on; r = r_on;
outOfLimit = 1; outOfLimit = 1;
@ -239,10 +246,10 @@ void cm_pswitch(ARGS) /* structure holding parms,
} }
else { else {
r = exp(logmean + loc->c1 * inmean - loc->c3 * inmean * inmean * inmean); r = exp(logmean + loc->c1 * inmean - loc->c3 * inmean * inmean * inmean);
if(r<r_on) r=r_on;/* minimum resistance limiter */ if(r<r_on) r=r_on;/* minimum resistance limiter */
} }
} else { } else {
inmean = ((PARAM(cntl_on) - INPUT(cntl_in)) / (PARAM(cntl_off) - PARAM(cntl_on))) - cntl_mean; inmean = (cntl_on - INPUT(cntl_in)) / (cntl_on - cntl_off) - cntl_mean;
if (INPUT(cntl_in) < cntl_on) { if (INPUT(cntl_in) < cntl_on) {
r = r_on; r = r_on;
outOfLimit = 1; outOfLimit = 1;
@ -253,26 +260,53 @@ void cm_pswitch(ARGS) /* structure holding parms,
} }
else { else {
r = exp(logmean + loc->c1 * inmean - loc->c3 * inmean * inmean * inmean); r = exp(logmean + loc->c1 * inmean - loc->c3 * inmean * inmean * inmean);
if(r<r_on) r=r_on;/* minimum resistance limiter */ if(r<r_on) r=r_on;/* minimum resistance limiter */
} }
} }
pi_pcntl = INPUT(out) / r * (loc->c2 * inmean * inmean - loc->c1); pi_pcntl = INPUT(out) / r * (loc->c2 * inmean * inmean - loc->c1);
if(1 == outOfLimit){ if(1 == outOfLimit){
pi_pcntl = 0; pi_pcntl = 0;
} }
pi_pvout = 1.0 / r; pi_pvout = 1.0 / r;
} }
else { /* Linear Variation in 'R' */ else { /* Linear Variation in 'R' */
intermediate = loc->intermediate; intermediate = loc->intermediate;
cntl_diff = loc->cntl_diff; cntl_diff = loc->cntl_diff;
r = INPUT(cntl_in) * intermediate + ((r_off*cntl_on - if (cntl_diff >=0) {
r_on*cntl_off) / cntl_diff); if (INPUT(cntl_in) < cntl_off) {
r = r_off;
pi_pcntl = 0;
}
else if (INPUT(cntl_in) > cntl_on) {
r = r_on;
pi_pcntl = 0;
}
else {
r = INPUT(cntl_in) * intermediate + ((r_off*cntl_on -
r_on*cntl_off) / cntl_diff);
pi_pcntl = -intermediate * INPUT(out) / (r*r);
}
}
else {
if (INPUT(cntl_in) > cntl_off) {
r = r_off;
pi_pcntl = 0;
}
else if (INPUT(cntl_in) < cntl_on) {
r = r_on;
pi_pcntl = 0;
}
else {
r = INPUT(cntl_in) * intermediate + ((r_off*cntl_on -
r_on*cntl_off) / cntl_diff);
pi_pcntl = -intermediate * INPUT(out) / (r*r);
}
}
if(r<=1.0e-9) r=1.0e-9;/* minimum resistance limiter */ if(r<=1.0e-9) r=1.0e-9;/* minimum resistance limiter */
pi_pvout = 1.0 / r; pi_pvout = 1.0 / r;
pi_pcntl = -intermediate * INPUT(out) / (r*r); }
}
if(ANALYSIS != MIF_AC) { /* Output DC & Transient Values */ if(ANALYSIS != MIF_AC) { /* Output DC & Transient Values */
OUTPUT(out) = INPUT(out) / r; OUTPUT(out) = INPUT(out) / r;
@ -284,7 +318,7 @@ void cm_pswitch(ARGS) /* structure holding parms,
// independent to out port */ // independent to out port */
cm_analog_auto_partial(); cm_analog_auto_partial();
/* Note that the minus signs are required because current is positive /* Note that the minus signs are required because current is positive
flowing INTO rather than OUT OF a component node. */ flowing INTO rather than OUT OF a component node. */
} }
else { /* Output AC Gain Values */ else { /* Output AC Gain Values */
@ -296,5 +330,5 @@ void cm_pswitch(ARGS) /* structure holding parms,
ac_gain.imag= 0.0; ac_gain.imag= 0.0;
AC_GAIN(out,cntl_in) = ac_gain; AC_GAIN(out,cntl_in) = ac_gain;
} }
} }