📄 cmutil.c
字号:
/* ===========================================================================FILE CMutil.cMEMBER OF process XSPICECopyright 1991Georgia Tech Research CorporationAtlanta, Georgia 30332All Rights ReservedPROJECT A-8503AUTHORS 9/12/91 Jeff MurrayMODIFICATIONS <date> <person name> <nature of modifications>SUMMARY This file contains functions callable from user code models. These functions were written to support code models in the XSPICE library, but may be useful in general.INTERFACES cm_smooth_corner() cm_smooth_discontinuity() cm_smooth_pwl() cm_climit_fcn() cm_complex_set() cm_complex_add() cm_complex_subtract() cm_complex_multiply() cm_complex_divide() REFERENCED FILES None.NON-STANDARD FEATURES None.=========================================================================== */#include <stdio.h>#include <math.h>#include "cm.h" /* Corner Smoothing Function ************************************* ** The following function smooths the transition between two ** slopes into a quadratic (parabolic) curve. The calling ** function passes an x,y coordinate representing the ** "breakpoint", a smoothing domain value (d), and the slopes at ** both endpoints, and the x value itself. The situation is ** shown below: B C ** A |<-d->| ^ y ** ---------*-----* | | ** lower_slope-^ |<-d->|\ | | ** \ | | ** \ | *------>x ** At A<x<C, cm_smooth_corner \ | ** returns a "y" value which \| ** smoothly transitions from *__ ** f(A) to f(C) in a parabolic \ | upper_slope ** fashion...the slope of the new \| ** function is also returned. \ ** ******************************************************************/void cm_smooth_corner( double x_input, /* The value of the x input */ double x_center, /* The x intercept of the two slopes */ double y_center, /* The y intercept of the two slopes */ double domain, /* The smoothing domain */ double lower_slope, /* The lower slope */ double upper_slope, /* The upper slope */ double *y_output, /* The smoothed y output */ double *dy_dx) /* The partial of y wrt x */{ double x_upper,y_upper,a,b,c,dy_dx_temp; /* Set up parabolic constants */ x_upper = x_center + domain; y_upper = y_center + (upper_slope * domain); a = ((upper_slope - lower_slope) / 4.0) * (1 / domain); b = upper_slope - (2.0 * a * x_upper); c = y_upper - (a * x_upper * x_upper) - (b * x_upper); /* Calculate y value & derivative */ dy_dx_temp = 2.0*a*x_input + b; /* Prevents reassignment problems */ /* for x-limiting cases. */ *y_output = a*x_input*x_input + b*x_input + c; *dy_dx = dy_dx_temp;}/* Discontinuity Smoothing Function ****************************** ** The following function smooths the transition between two ** values using an x^2 function. The calling function ** function passes an x1,y1 coordinate representing the ** starting point, an x2,y2 coordinate representing an ending ** point, and the x value itself. The situation is shown below: ** ** ^ y (xu,yu) ** | ---*----------- ** | --- | ** | -- ** | - | ** | - ** | - | ** | -- ** | (xl,yl) --- | ** ----|----*--- ** | | | ** O------------------------------------->x ******************************************************************/void cm_smooth_discontinuity( double x_input, /* The x value at which to compute y */ double x_lower, /* The x value of the lower corner */ double y_lower, /* The y value of the lower corner */ double x_upper, /* The x value of the upper corner */ double y_upper, /* The y value of the upper corner */ double *y_output, /* The computed smoothed y value */ double *dy_dx) /* The partial of y wrt x */{ double x_center,y_center,a,b,c,center_slope; /* Derive x_center, y_center & center_slope values */ x_center = (x_upper + x_lower) / 2.0; y_center = (y_upper + y_lower) / 2.0; center_slope = 2.0 * (y_upper - y_lower) / (x_upper - x_lower); if (x_input < x_lower) { /* x_input @ lower level */ *y_output = y_lower; *dy_dx = 0.0; } else { if (x_input < x_center) { /* x_input in lower transition */ a = center_slope / (x_upper - x_lower); b = center_slope - 2.0 * a * x_center; c = y_center - a * x_center * x_center - b * x_center; *y_output = a * x_input * x_input + b * x_input + c; *dy_dx = 2.0 * a * x_input + b; } else { /* x_input in upper transition */ if (x_input < x_upper) { a = -center_slope / (x_upper - x_lower); b = -2.0 * a * x_upper; c = y_upper - a * x_upper * x_upper - b * x_upper; *y_output = a * x_input * x_input + b * x_input + c; *dy_dx = 2.0 * a * x_input + b; } else { /* x_input @ upper level */ *y_output = y_upper; *dy_dx = 0.0; } } }}/* Controlled Limiter Function (modified CLIMIT) *//*This is a special function created for use with the CLIMITcontrolled limiter model.*/void cm_climit_fcn( double in, /* The input value */ double in_offset, /* The input offset */ double cntl_upper, /* The upper control input value */ double cntl_lower, /* The lower control input value */ double lower_delta, /* The delta from control to limit value */ double upper_delta, /* The delta from control to limit value */ double limit_range, /* The limiting range */ double gain, /* The gain from input to output */ int percent, /* The fraction vs. absolute range flag */ double *out_final, /* The output value */ double *pout_pin_final, /* The partial of output wrt input */ double *pout_pcntl_lower_final, /* The partial of output wrt lower control input */ double *pout_pcntl_upper_final) /* The partial of output wrt upper control input */{/* Define error message string constants */char *climit_range_error = "\n**** ERROR ****\n* CLIMIT function linear range less than zero. *\n";double threshold_upper,threshold_lower,linear_range, out_lower_limit,out_upper_limit,limited_out, out,pout_pin,pout_pcntl_lower,pout_pcntl_upper,junk; /* Find Upper & Lower Limits */ out_lower_limit = cntl_lower + lower_delta; out_upper_limit = cntl_upper - upper_delta; if (percent == TRUE) /* Set range to absolute value */ limit_range = limit_range * (out_upper_limit - out_lower_limit); threshold_upper = out_upper_limit - /* Set Upper Threshold */ limit_range; threshold_lower = out_lower_limit + /* Set Lower Threshold */ limit_range; linear_range = threshold_upper - threshold_lower; /* Test the linear region & make sure there IS one... */ if (linear_range < 0.0) { printf("%s\n",climit_range_error); /* limited_out = 0.0; pout_pin = 0.0; pout_pcntl_lower = 0.0; pout_pcntl_upper = 0.0; return;*/ } /* Compute Un-Limited Output */ out = gain * (in_offset + in); if (out < threshold_lower) { /* Limit Out @ Lower Bound */ pout_pcntl_upper= 0.0; if (out > (out_lower_limit - limit_range)) { /* Parabolic */ cm_smooth_corner(out,out_lower_limit,out_lower_limit, limit_range,0.0,1.0,&limited_out, &pout_pin); pout_pin = gain * pout_pin; cm_smooth_discontinuity(out,out_lower_limit,1.0,threshold_lower, 0.0,&pout_pcntl_lower,&junk); } else { /* Hard-Limited Region */ limited_out = out_lower_limit; pout_pin = 0.0; pout_pcntl_lower = 1.0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -