You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

295 lines
8.6 KiB

/*.......1.........2.........3.........4.........5.........6.........7.........8
================================================================================
FILE pswitch/cfunc.mod
3-Clause BSD
Copyright 2020 The ngspice team
AUTHORS
27 September 2020 Holger Vogt
MODIFICATIONS
SUMMARY
This file contains the functional description of the pswitch
code model.
INTERFACES
FILE ROUTINE CALLED
CMmacros.h cm_message_send();
REFERENCED FILES
Inputs from and outputs to ARGS structure.
NON-STANDARD FEATURES
NONE
===============================================================================*/
/*=== INCLUDE FILES ====================*/
#include <stdlib.h>
#include <math.h>
/*=== CONSTANTS ========================*/
/*=== MACROS ===========================*/
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
typedef struct {
double logmean; /* log-mean of resistor values */
double logratio; /* log-ratio of resistor values */
double cntl_mean; /* mean of control values */
double cntl_diff; /* diff of control values */
double intermediate; /* intermediate value used to calculate
the resistance of the switch when the
controlling voltage is between cntl_on
and cntl_of */
double c1; /* some constants */
double c2;
double c3;
} Local_Data_t;
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
static void
cm_pswitch_callback(ARGS, Mif_Callback_Reason_t reason)
{
switch (reason) {
case MIF_CB_DESTROY: {
Local_Data_t *loc = STATIC_VAR (locdata);
free(loc);
break;
}
}
}
/*==============================================================================
FUNCTION cm_pswitch()
AUTHORS
27 September 2020 Holger Vogt
MODIFICATIONS
SUMMARY
This function implements the pswitch code model.
INTERFACES
FILE ROUTINE CALLED
CMmacros.h cm_message_send();
RETURNED VALUE
Returns inputs and outputs via ARGS structure.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
NONE
==============================================================================*/
/*=== CM_PSWITCH ROUTINE ===*/
void cm_pswitch(ARGS) /* structure holding parms,
inputs, outputs, etc. */
{
double cntl_on; /* voltage above which switch come on */
double cntl_off; /* voltage below the switch has resistance roff */
double r_on; /* on resistance */
double r_off; /* off resistance */
double r_cntl_in; /* input resistance for control terminal */
double logmean; /* log-mean of resistor values */
double logratio; /* log-ratio of resistor values */
double cntl_mean; /* mean of control values */
double cntl_diff; /* diff of control values */
double intermediate; /* intermediate value used to calculate
the resistance of the switch when the
controlling voltage is between cntl_on
and cntl_of */
double r; /* value of the resistance of the switch */
double pi_pvout; /* partial of the output wrt input */
double pi_pcntl; /* partial of the output wrt control input */
Mif_Complex_t ac_gain;
Local_Data_t *loc; /* Pointer to local static data, not to be included
in the state vector */
/* Retrieve frequently used parameters... */
cntl_on = PARAM(cntl_on);
cntl_off = PARAM(cntl_off);
r_on = PARAM(r_on);
r_off = PARAM(r_off);
r_cntl_in = PARAM(r_cntl_in);
r_on = (r_on < 1.0e-3) ? 1.0e-3 : r_on; /* Set minimum 'ON' resistance */
r_off = (r_off > 1.0e12) ? 1.0e12 : r_off; /* Set maximum 'OFF' resistance */
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";
if( (fabs(cntl_on - cntl_off) < 1.0e-12) ) {
cm_message_send(cntl_error);
return;
}
CALLBACK = cm_pswitch_callback;
/*** allocate static storage for *loc ***/
STATIC_VAR (locdata) = calloc (1 , sizeof ( Local_Data_t ));
loc = STATIC_VAR (locdata);
if ( PARAM(log) == MIF_TRUE ) { /* Logarithmic Variation in 'R' */
if (cntl_on > cntl_off)
{
cntl_on = 1;
cntl_off = 0;
}
else
{
cntl_on = 0;
cntl_off = 1;
}
loc->logmean = log(sqrt(r_on * r_off));
loc->logratio = log(r_on / r_off);
loc->cntl_mean = 0.5;
loc->cntl_diff = cntl_on - cntl_off;
loc->intermediate = loc->logratio / loc->cntl_diff;
loc->c1 = 1.5 * loc->logratio / loc->cntl_diff;
loc->c3 = 2. * loc->logratio / (loc->cntl_diff * loc->cntl_diff * loc->cntl_diff); //pow(loc->cntl_diff, 3);
loc->c2 = 3 * loc->c3;
} else {
loc->cntl_diff = cntl_on - cntl_off;
loc->intermediate = (r_on - r_off) / (cntl_on - cntl_off);
}
}
loc = STATIC_VAR (locdata);
if ( PARAM(log) == MIF_TRUE ) { /* Logarithmic Variation in 'R' */
logmean = loc->logmean;
logratio = loc->logratio;
cntl_mean = loc->cntl_mean;
cntl_diff = loc->cntl_diff;
intermediate = loc->intermediate;
double inmean;// = INPUT(cntl_in) - cntl_mean;
int outOfLimit = 0;
if (cntl_on > cntl_off) {
inmean = ((INPUT(cntl_in) - PARAM(cntl_off)) / (PARAM(cntl_on) - PARAM(cntl_off))) - cntl_mean;
if (INPUT(cntl_in) > cntl_on) {
r = r_on;
outOfLimit = 1;
}
else if (INPUT(cntl_in) < cntl_off) {
r = r_off;
outOfLimit = 1;
}
else {
r = exp(logmean + loc->c1 * inmean - loc->c3 * inmean * inmean * inmean);
if(r<r_on) r=r_on;/* minimum resistance limiter */
}
} else {
inmean = (PARAM(cntl_on) - (INPUT(cntl_in)) / (PARAM(cntl_off) - PARAM(cntl_on))) - cntl_mean;
if (INPUT(cntl_in) < cntl_on) {
r = r_on;
outOfLimit = 1;
}
else if (INPUT(cntl_in) > cntl_off) {
r = r_off;
outOfLimit = 1;
}
else {
r = exp(logmean + loc->c1 * inmean - loc->c3 * inmean * inmean * inmean);
if(r<r_on) r=r_on;/* minimum resistance limiter */
}
}
pi_pcntl = INPUT(out) / r * (loc->c2 * inmean * inmean - loc->c1);
if(1 == outOfLimit){
pi_pcntl = 0;
}
pi_pvout = 1.0 / r;
}
else { /* Linear Variation in 'R' */
intermediate = loc->intermediate;
cntl_diff = loc->cntl_diff;
r = INPUT(cntl_in) * intermediate + ((r_off*cntl_on -
r_on*cntl_off) / cntl_diff);
if(r<=1.0e-9) r=1.0e-9;/* minimum resistance limiter */
pi_pvout = 1.0 / r;
pi_pcntl = -intermediate * INPUT(out) / (r*r);
}
if(ANALYSIS != MIF_AC) { /* Output DC & Transient Values */
OUTPUT(out) = INPUT(out) / r;
OUTPUT(cntl_in) = INPUT(cntl_in) / r_cntl_in;
// PARTIAL(out,out) = pi_pvout;
// PARTIAL(out,cntl_in) = pi_pcntl;
// PARTIAL(cntl_in,cntl_in) = 1 / r_cntl_in;
// PARTIAL(cntl_in,out) = 0; /* cntl input resistance is
// independent to out port */
cm_analog_auto_partial();
/* Note that the minus signs are required because current is positive
flowing INTO rather than OUT OF a component node. */
}
else { /* Output AC Gain Values */
ac_gain.real = -pi_pvout; /* See comment on minus signs above... */
ac_gain.imag= 0.0;
AC_GAIN(out,out) = ac_gain;
ac_gain.real = -pi_pcntl;
ac_gain.imag= 0.0;
AC_GAIN(out,cntl_in) = ac_gain;
}
}