/*.......1.........2.........3.........4.........5.........6.........7.........8 ================================================================================ FILE pwl/cfunc.mod Copyright 1991 Georgia Tech Research Corporation, Atlanta, Ga. 30332 All Rights Reserved PROJECT A-8503-405 AUTHORS 19 Apr 1991 Jeffrey P. Murray MODIFICATIONS 25 Sep 1991 Jeffrey P. Murray 2 Oct 1991 Jeffrey P. Murray SUMMARY This file contains the model-specific routines used to functionally describe the pwl (piece-wise linear) code model. INTERFACES FILE ROUTINE CALLED CMutil.c void cm_smooth_corner(); CMmacros.h cm_message_send(); CM.c void cm_analog_not_converged() REFERENCED FILES Inputs from and outputs to ARGS structure. NON-STANDARD FEATURES NONE ===============================================================================*/ /*=== INCLUDE FILES ====================*/ #include /*=== CONSTANTS ========================*/ #define FRACTION 0.30 #define EPSILON 1.0e-9 /*=== MACROS ===========================*/ /*=== LOCAL VARIABLES & TYPEDEFS =======*/ /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ /*============================================================================== FUNCTION double limit_x_value() AUTHORS 25 Sep 1991 Jeffrey P. Murray 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). INTERFACES FILE ROUTINE CALLED CM.c void cm_analog_not_converged() RETURNED VALUE Returns a double. GLOBAL VARIABLES NONE NON-STANDARD FEATURES NONE ==============================================================================*/ #include /*=== Static LIMIT_X_VALUE ROUTINE ================*/ /** limit_x_value ******************************************/ /** **/ /** 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). **/ /** **/ /** 9/25/91 JPM **/ /***********************************************************/ 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 this segment domain. */ hold; /* Holding variable for previous x_input value */ /** Limit effective change of input to fraction of value of lowest **/ /** 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 */ /* since last iteration call */ if ( 0.0 <= (x_input - *last_x_value) ) { x_input = *last_x_value = *last_x_value + max_x_delta; } else { x_input = *last_x_value = *last_x_value - max_x_delta; } /* Alert the simulator to non-convergence */ cm_analog_not_converged(); /*** 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; } /*============================================================================== FUNCTION void cm_pwl(> AUTHORS 19 Apr 1991 Jeffrey P. Murray MODIFICATIONS 25 Sep 1991 Jeffrey P. Murray 2 Oct 1991 Jeffrey P. Murray SUMMARY This function implements the pwl code model. INTERFACES FILE ROUTINE CALLED CMutil.c void cm_smooth_corner(); 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 NONE ==============================================================================*/ /*=== CM_PWL ROUTINE ================*/ void cm_pwl(ARGS) /* structure holding parms, inputs, outputs, etc. */ { int i; /* generic loop counter index */ int size; /* size of the x_array */ double input_domain; /* smoothing range */ double *x; /* pointer to the x-coordinate array */ double *y; /* pointer to the y-coordinate array */ double lower_seg; /* x segment below which input resides */ double upper_seg; /* x segment above which the input resides */ double lower_slope; /* slope of the lower segment */ double upper_slope; /* slope of the upper segment */ double x_input; /* input */ double out; /* output */ double dout_din; /* partial derivative of the output wrt input */ double threshold_lower; /* value below which the output begins smoothing */ double threshold_upper; /* value above which the output begins smoothing */ double test1; /* debug testing value */ double test2; /* debug testing value */ double *last_x_value; /* static variable for limiting */ double test; /* temp storage variable for limit testing */ Mif_Complex_t ac_gain; char *allocation_error="\n***ERROR***\nPWL: Allocation calloc failed!\n"; char *limit_error="\n***ERROR***\nPWL: Violation of 50% rule in breakpoints!\n"; /* Retrieve frequently used parameters... */ input_domain = PARAM(input_domain); size = PARAM_SIZE(x_array); if (INIT==1) { /* First pass...allocate storage for previous value... */ /* Allocate storage for last_x_value */ STATIC_VAR(last_x_value) = (double *) malloc(sizeof(double)); last_x_value = (double *) STATIC_VAR(last_x_value); /* Allocate storage for breakpoint domain & range values */ STATIC_VAR(x) = (double *) calloc((size_t) size, sizeof(double)); x = (double *) STATIC_VAR(x); if (!x) { 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); } /* Retrieve x and y values. */ for (i=0; i (x[1] - x[0]) ) { test = limit_x_value(x_input,x[0],x_input,FRACTION,last_x_value); } 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 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 */ if ( (x_input - x[size-1]) > (x[size-1] - x[size-2]) ) { test = limit_x_value(x[size-1],x_input,x_input,FRACTION,last_x_value); } 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] ) { x_input = *last_x_value = x[size-1] - EPSILON; /* Alert the simulator to non-convergence */ cm_analog_not_converged(); } else { x_input = *last_x_value = test; } } else { for (i=1; i x[i] ) { x_input = *last_x_value = x[i]; /* Alert the simulator to non-convergence */ cm_analog_not_converged(); break; } 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] ) { x_input = *last_x_value = x[i-1] - EPSILON; /* Alert the simulator to non-convergence */ cm_analog_not_converged(); break; } else { /* Use returned value for next input */ x_input = *last_x_value = test; break; } } } } /* Assign new limited value back to the input for */ /* use in the matrix calculations.... */ INPUT(in) = x_input; /*** Add debugging printf statement ***/ /* printf("Limited x_input=%e\n\n", x_input); */ /**** End internal limiting ****/ /* Determine segment boundaries within which x_input resides */ 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) { /*** x_input above highest midpoint ***/ dout_din = (y[size-1] - y[size-2]) / (x[size-1] - x[size-2]); out = y[size-1] + (x_input - x[size-1]) * dout_din; } else { /*** x_input within bounds of end midpoints... ***/ /*** must determine position progressively & then ***/ /*** calculate required output. ***/ for (i=1; i