add a flag 'LIMIT' to pwl code model. If set true,

the output is kept constant at y[0] when x is less then
x[0], or at y[xmax] when x > xmax.
Default is FALSE, then the output beyond the x bounds is
extrapolated linearly, as usual up to now.
This commit is contained in:
Holger Vogt 2020-11-01 18:06:01 +01:00
parent 85f5e41710
commit 92c6ff26f5
2 changed files with 160 additions and 122 deletions

View File

@ -8,18 +8,18 @@ Public Domain
Georgia Tech Research Corporation
Atlanta, Georgia 30332
PROJECT A-8503-405
AUTHORS
AUTHORS
19 Apr 1991 Jeffrey P. Murray
MODIFICATIONS
MODIFICATIONS
25 Sep 1991 Jeffrey P. Murray
2 Oct 1991 Jeffrey P. Murray
1 Nov 2020 Holger Vogt
SUMMARY
@ -27,21 +27,21 @@ SUMMARY
functionally describe the pwl (piece-wise linear) code model.
INTERFACES
INTERFACES
FILE ROUTINE CALLED
FILE ROUTINE CALLED
CMutil.c void cm_smooth_corner();
CMutil.c void cm_smooth_corner();
CMmacros.h cm_message_send();
CMmacros.h cm_message_send();
CM.c void cm_analog_not_converged()
REFERENCED FILES
Inputs from and outputs to ARGS structure.
NON-STANDARD FEATURES
@ -53,7 +53,7 @@ NON-STANDARD FEATURES
#include <math.h>
/*=== CONSTANTS ========================*/
@ -66,53 +66,53 @@ NON-STANDARD FEATURES
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
/*==============================================================================
FUNCTION double limit_x_value()
AUTHORS
AUTHORS
25 Sep 1991 Jeffrey P. Murray
MODIFICATIONS
MODIFICATIONS
2 Oct 1991 Jeffrey P. Murray
SUMMARY
Limits a passed input value to some fraction
of the segment length defined by
(x_upper - x_lower). The fractional value in
question is passed as a value to the routine
(fraction).
Limits a passed input value to some fraction
of the segment length defined by
(x_upper - x_lower). The fractional value in
question is passed as a value to the routine
(fraction).
INTERFACES
FILE ROUTINE CALLED
INTERFACES
FILE ROUTINE CALLED
CM.c void cm_analog_not_converged()
RETURNED VALUE
Returns a double.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
@ -124,7 +124,7 @@ NON-STANDARD FEATURES
#include <stdlib.h>
/*=== Static LIMIT_X_VALUE ROUTINE ================*/
/** limit_x_value ******************************************/
/** **/
/** Limits a passed input value to some fraction **/
@ -136,24 +136,24 @@ NON-STANDARD FEATURES
/** 9/25/91 JPM **/
/***********************************************************/
static double limit_x_value(double x_lower,double x_upper,
double x_input,double fraction,
static double limit_x_value(double x_lower,double x_upper,
double x_input,double fraction,
double *last_x_value)
{
double max_x_delta, /* maximum delta value permissible for
double max_x_delta, /* maximum delta value permissible for
this segment domain. */
hold; /* Holding variable for previous x_input value */
hold; /* Holding variable for previous x_input value */
/** Limit effective change of input to fraction of value of lowest **/
/** x-segment length... **/
/** x-segment length... **/
/* calculate maximum delta value for this region */
max_x_delta = fraction * (x_upper - x_lower);
/* Test new input */
if ( max_x_delta < fabs(x_input - *last_x_value) ) {
hold = x_input;
/* Assign new x_input based of direction of movement */
@ -171,13 +171,13 @@ static double limit_x_value(double x_lower,double x_upper,
/*** Debugging printf statement ***/
/* printf("Assigning new x_input...\nPrevious value=%e, New value=%e\n\n",
hold,x_input);
*/
*/
}
else { /* No limiting of x_input required */
*last_x_value = x_input;
}
return x_input;
}
@ -186,11 +186,11 @@ static double limit_x_value(double x_lower,double x_upper,
FUNCTION void cm_pwl(>
AUTHORS
AUTHORS
19 Apr 1991 Jeffrey P. Murray
MODIFICATIONS
MODIFICATIONS
25 Sep 1991 Jeffrey P. Murray
2 Oct 1991 Jeffrey P. Murray
@ -199,23 +199,23 @@ SUMMARY
This function implements the pwl code model.
INTERFACES
INTERFACES
FILE ROUTINE CALLED
FILE ROUTINE CALLED
CMutil.c void cm_smooth_corner();
CMutil.c void cm_smooth_corner();
CMmacros.h cm_message_send();
CMmacros.h cm_message_send();
CM.c void cm_analog_not_converged()
RETURNED VALUE
Returns inputs and outputs via ARGS structure.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
@ -230,14 +230,14 @@ cm_pwl_callback(ARGS, Mif_Callback_Reason_t reason)
switch (reason) {
case MIF_CB_DESTROY: {
double *last_x_value = STATIC_VAR (last_x_value);
double *x = STATIC_VAR (x);
double *y = STATIC_VAR (y);
double *x = STATIC_VAR (x);
double *y = STATIC_VAR (y);
free(last_x_value);
free(x);
free(y);
STATIC_VAR (last_x_value) = NULL;
STATIC_VAR (x) = NULL;
STATIC_VAR (y) = NULL;
STATIC_VAR (y) = NULL;
break;
}
}
@ -245,7 +245,7 @@ cm_pwl_callback(ARGS, Mif_Callback_Reason_t reason)
/*=== CM_PWL ROUTINE ================*/
void cm_pwl(ARGS) /* structure holding parms,
void cm_pwl(ARGS) /* structure holding parms,
inputs, outputs, etc. */
{
int i; /* generic loop counter index */
@ -281,11 +281,17 @@ void cm_pwl(ARGS) /* structure holding parms,
input_domain = PARAM(input_domain);
size = PARAM_SIZE(x_array);
/* size including space for two additional x,y pairs */
size = PARAM_SIZE(x_array) + 2;
if (INIT==1) { /* First pass...allocate storage for previous value... */
/* First pass:
Allocate storage for previous value.
Allocate storage for x an y input arrays
Read input array and store from
Add additional x,y pair at beginning and end of x, y arrays:
*/
if (INIT==1) {
/* Allocate storage for last_x_value */
STATIC_VAR(last_x_value) = (double *) malloc(sizeof(double));
@ -295,22 +301,41 @@ void cm_pwl(ARGS) /* structure holding parms,
STATIC_VAR(x) = (double *) calloc((size_t) size, sizeof(double));
x = (double *) STATIC_VAR(x);
if (!x) {
cm_message_send(allocation_error);
cm_message_send(allocation_error);
}
STATIC_VAR(y) = (double *) calloc((size_t) size, sizeof(double));
y = (double *) STATIC_VAR(y);
if (!y) {
cm_message_send(allocation_error);
cm_message_send(allocation_error);
}
/* Retrieve x and y values. */
for (i=0; i<size; i++) {
x[i] = PARAM(x_array[i]);
y[i] = PARAM(y_array[i]);
}
}
/* Retrieve x and y values. */
for (i=1; i<size-1; i++) {
x[i] = PARAM(x_array[i - 1]);
y[i] = PARAM(y_array[i - 1]);
}
/* Add additional leading and trailing values */
x[0] = 2. * x[1] - x[2];
x[size - 1] = 2. * x[size - 2] - x[size - 3];
if (PARAM(limit) == MIF_TRUE) {
/* const additional y values */
y[0] = y[1];
y[size - 1] = y[size - 2];
}
else {
/* linearily extrapolated additional y values */
y[0] = 2. * y[1] - y[2];
y[size - 1] = 2. * y[size - 2] - y[size - 3];
}
/* debug printout
for (i = 0; i < size; i++)
fprintf(stderr, "%e ", y[i]);
fprintf(stderr, "\n");
for (i = 0; i < size; i++)
fprintf(stderr, "%e ", x[i]);
fprintf(stderr, "\n"); */
}
else {
last_x_value = (double *) STATIC_VAR(last_x_value);
@ -329,25 +354,25 @@ void cm_pwl(ARGS) /* structure holding parms,
/* breakpoint segments for violation of 50% rule... */
if (PARAM(fraction) == MIF_FALSE) {
if ( 3 < size ) {
for (i=1; i<(size-2); i++) {
for (i=1; i<(size-2); i++) {
/* Test for overlap...0.999999999 factor is to */
/* prevent floating point problems with comparison. */
if ( (test1 = x[i+1] - x[i]) <
if ( (test1 = x[i+1] - x[i]) <
(test2 = 0.999999999 * (2.0 * input_domain)) ) {
cm_message_send(limit_error);
}
cm_message_send(limit_error);
}
}
}
}
/* Retrieve x_input value. */
/* Retrieve x_input value. */
x_input = INPUT(in);
/* If this is the first call, set *last_x_value to x_input */
if (INIT == 1)
if (INIT == 1)
*last_x_value=x_input;
@ -355,8 +380,8 @@ void cm_pwl(ARGS) /* structure holding parms,
/* printf("Last x_input=%e, Current x_input=%e,\n",
*last_x_value,x_input);
*/
/**** Add internal limiting to input value ****/
/* Determine region of input, and limit accordingly */
@ -369,19 +394,19 @@ void cm_pwl(ARGS) /* structure holding parms,
else {
test = limit_x_value(x[0],x[1],x_input,FRACTION,last_x_value);
}
/* If the test value is greater than x[0], force to x[0] */
if ( test >= x[0] ) {
x_input = *last_x_value = x[0];
/* Alert the simulator to non-convergence */
cm_analog_not_converged();
}
}
else {
x_input = *last_x_value = test;
}
}
else
else
if ( *last_x_value >= x[size-1] ) { /** Non-Limited input greater than x[size-1] **/
/* Obtain the test value of the input, if it has changed excessively */
@ -391,7 +416,7 @@ void cm_pwl(ARGS) /* structure holding parms,
else {
test = limit_x_value(x[size-2],x[size-1],x_input,FRACTION,last_x_value);
}
/* If the test value is less than x[size-1], force to x[size-1] */
/* minus some epsilon value. */
if ( test < x[size-1] ) {
@ -399,7 +424,7 @@ void cm_pwl(ARGS) /* structure holding parms,
/* Alert the simulator to non-convergence */
cm_analog_not_converged();
}
}
else {
x_input = *last_x_value = test;
}
@ -407,10 +432,10 @@ void cm_pwl(ARGS) /* structure holding parms,
else {
for (i=1; i<size; i++) {
if ( *last_x_value < x[i] ) {
/* Obtain the test value of the input */
test = limit_x_value(x[i-1],x[i],x_input,FRACTION,last_x_value);
/* If the test value is greater than x[i], force to x[i] */
if ( test > x[i] ) {
x_input = *last_x_value = x[i];
@ -419,8 +444,8 @@ void cm_pwl(ARGS) /* structure holding parms,
cm_analog_not_converged();
break;
}
else
}
else
/* If the test value is less than x[i-1], force to x[i-1] */
/* minus some epsilon value... */
if ( test < x[i-1] ) {
@ -432,7 +457,7 @@ void cm_pwl(ARGS) /* structure holding parms,
break;
}
else { /* Use returned value for next input */
x_input = *last_x_value = test;
x_input = *last_x_value = test;
break;
}
}
@ -440,9 +465,9 @@ void cm_pwl(ARGS) /* structure holding parms,
}
/* Assign new limited value back to the input for */
/* use in the matrix calculations.... */
INPUT(in) = x_input;
/* use in the matrix calculations.... */
INPUT(in) = x_input;
/*** Add debugging printf statement ***/
/* printf("Limited x_input=%e\n\n",
@ -450,7 +475,7 @@ void cm_pwl(ARGS) /* structure holding parms,
*/
/**** End internal limiting ****/
/**** End internal limiting ****/
@ -459,13 +484,13 @@ void cm_pwl(ARGS) /* structure holding parms,
if (x_input <= (x[0] + x[1])/2.0) {/*** x_input below lowest midpoint ***/
dout_din = (y[1] - y[0])/(x[1] - x[0]);
/* Compute new output */
out = y[0] + (x_input - x[0]) * dout_din;
}
else {
if (x_input >= (x[size-2] + x[size-1])/2.0) {
if (x_input >= (x[size-2] + x[size-1])/2.0) {
/*** x_input above highest midpoint ***/
dout_din = (y[size-1] - y[size-2]) /
(x[size-1] - x[size-2]);
@ -477,10 +502,10 @@ void cm_pwl(ARGS) /* structure holding parms,
/*** calculate required output. ***/
for (i=1; i<size; i++) {
if (x_input < (x[i] + x[i+1])/2.0) {
if (x_input < (x[i] + x[i+1])/2.0) {
/* approximate position known... */
lower_seg = (x[i] - x[i-1]);
upper_seg = (x[i+1] - x[i]);
@ -497,8 +522,8 @@ void cm_pwl(ARGS) /* structure holding parms,
/* segment */
/* for % calc.*/
input_domain = input_domain * upper_seg;
}
}
/* Set up threshold values about breakpoint... */
threshold_lower = x[i] - input_domain;
threshold_upper = x[i] + input_domain;
@ -510,7 +535,7 @@ void cm_pwl(ARGS) /* structure holding parms,
out = y[i] + (x_input - x[i]) * dout_din;
}
else {
else {
if (x_input < threshold_upper) { /* Parabolic region */
lower_slope = (y[i] - y[i-1])/lower_seg;
upper_slope = (y[i+1] - y[i])/upper_seg;
@ -540,5 +565,5 @@ void cm_pwl(ARGS) /* structure holding parms,
ac_gain.imag= 0.0;
AC_GAIN(out,in) = ac_gain;
}
}
}

View File

@ -6,68 +6,81 @@ Georgia Tech Research Corporation
Atlanta, Georgia 30332
AUTHORS
AUTHORS
19 Apr 1991 Jeffrey P. Murray
01 Nov 2020 Holger Vogt
SUMMARY
This file contains the interface specification file for the
This file contains the interface specification file for the
analog pwl code model.
===============================================================================*/
NAME_TABLE:
C_Function_Name: cm_pwl
Spice_Model_Name: pwl
Spice_Model_Name: pwl
Description: "piecwise linear controlled source"
PORT_TABLE:
Port_Name: in out
Port_Name: in out
Description: "input" "output"
Direction: in out
Direction: in out
Default_Type: v v
Allowed_Types: [v,vd,i,id,vnam] [v,vd,i,id]
Allowed_Types: [v,vd,i,id,vnam] [v,vd,i,id]
Vector: no no
Vector_Bounds: - -
Null_Allowed: no no
Vector_Bounds: - -
Null_Allowed: no no
PARAMETER_TABLE:
Parameter_Name: x_array y_array
Parameter_Name: x_array y_array
Description: "x-element array" "y-element array"
Data_Type: real real
Default_Value: - -
Limits: - -
Vector: yes yes
Vector_Bounds: [2 -] [2 -]
Null_Allowed: no no
Data_Type: real real
Default_Value: - -
Limits: - -
Vector: yes yes
Vector_Bounds: [2 -] [2 -]
Null_Allowed: no no
PARAMETER_TABLE:
Parameter_Name: input_domain fraction
Parameter_Name: input_domain fraction
Description: "input sm. domain" "smoothing %/abs switch"
Data_Type: real boolean
Default_Value: 0.01 TRUE
Limits: [1e-12 0.5] -
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
Data_Type: real boolean
Default_Value: 0.01 TRUE
Limits: [1e-12 0.5] -
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: limit
Description: "const or linearily extrapolated output"
Data_Type: boolean
Default_Value: FALSE
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
STATIC_VAR_TABLE:
Static_Var_Name: last_x_value
Data_Type: pointer
Vector: no
Description: "iteration holding variable for limiting"
Static_Var_Name: last_x_value
Data_Type: pointer
Vector: no
Description: "iteration holding variable for limiting"
STATIC_VAR_TABLE: