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:
parent
85f5e41710
commit
92c6ff26f5
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue