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