Browse Source
pwlts: a pwl v/i source with time input, smoothing and limiting functions
pre-master-46
pwlts: a pwl v/i source with time input, smoothing and limiting functions
pre-master-46
4 changed files with 438 additions and 1 deletions
-
1src/xspice/icm/analog/modpath.lst
-
342src/xspice/icm/analog/pwlts/cfunc.mod
-
92src/xspice/icm/analog/pwlts/ifspec.ifs
-
4visualc/xspice/analog.vcxproj
@ -0,0 +1,342 @@ |
|||||
|
/*.......1.........2.........3.........4.........5.........6.........7.........8 |
||||
|
================================================================================ |
||||
|
|
||||
|
FILE pwlts/cfunc.mod |
||||
|
|
||||
|
Public Domain |
||||
|
|
||||
|
|
||||
|
AUTHORS |
||||
|
|
||||
|
Original author of pwl |
||||
|
19 Apr 1991 Jeffrey P. Murray |
||||
|
|
||||
|
Pwl with time input and smoothing: pwlts |
||||
|
9 Sep 2022 Holger Vogt |
||||
|
|
||||
|
SUMMARY |
||||
|
|
||||
|
This file contains the model-specific routines used to |
||||
|
functionally describe the pwlts (piece-wise linear time based) code model. |
||||
|
|
||||
|
|
||||
|
INTERFACES |
||||
|
|
||||
|
FILE ROUTINE CALLED |
||||
|
|
||||
|
CMutil.c void cm_smooth_corner(); |
||||
|
|
||||
|
CMmacros.h cm_message_send(); |
||||
|
|
||||
|
|
||||
|
REFERENCED FILES |
||||
|
|
||||
|
Inputs from and outputs to ARGS structure. |
||||
|
|
||||
|
|
||||
|
NON-STANDARD FEATURES |
||||
|
|
||||
|
NONE |
||||
|
|
||||
|
===============================================================================*/ |
||||
|
|
||||
|
/*=== INCLUDE FILES ====================*/ |
||||
|
|
||||
|
#include <math.h> |
||||
|
|
||||
|
|
||||
|
|
||||
|
/*=== CONSTANTS ========================*/ |
||||
|
|
||||
|
#define FRACTION 0.30 |
||||
|
#define EPSILON 1.0e-9 |
||||
|
|
||||
|
|
||||
|
|
||||
|
/*=== MACROS ===========================*/ |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
/*=== LOCAL VARIABLES & TYPEDEFS =======*/ |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ |
||||
|
|
||||
|
|
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
|
||||
|
/*============================================================================== |
||||
|
|
||||
|
FUNCTION void cm_pwlts |
||||
|
|
||||
|
AUTHORS |
||||
|
|
||||
|
9 Sep 2022 Holger Vogt |
||||
|
|
||||
|
MODIFICATIONS |
||||
|
|
||||
|
|
||||
|
SUMMARY |
||||
|
|
||||
|
This function implements the pwlts code model. |
||||
|
|
||||
|
INTERFACES |
||||
|
|
||||
|
FILE ROUTINE CALLED |
||||
|
|
||||
|
CMutil.c void cm_smooth_corner(); |
||||
|
|
||||
|
CMmacros.h cm_message_send(); |
||||
|
|
||||
|
|
||||
|
RETURNED VALUE |
||||
|
|
||||
|
Returns outputs via ARGS structure. |
||||
|
|
||||
|
GLOBAL VARIABLES |
||||
|
|
||||
|
NONE |
||||
|
|
||||
|
NON-STANDARD FEATURES |
||||
|
|
||||
|
NONE |
||||
|
|
||||
|
==============================================================================*/ |
||||
|
|
||||
|
static void |
||||
|
cm_pwlts_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); |
||||
|
if (last_x_value) |
||||
|
free(last_x_value); |
||||
|
if (x) |
||||
|
free(x); |
||||
|
if (y) |
||||
|
free(y); |
||||
|
STATIC_VAR (last_x_value) = NULL; |
||||
|
STATIC_VAR (x) = NULL; |
||||
|
STATIC_VAR (y) = NULL; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*=== CM_PWLTS ROUTINE ================*/ |
||||
|
|
||||
|
void cm_pwlts(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 = 0.0; /* output |
||||
|
* Init to 0 to suppress compiler warning */ |
||||
|
double dout_din = 0.0; /* partial derivative of the output wrt input. |
||||
|
* Init to 0 to suppress compiler warning */ |
||||
|
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; |
||||
|
|
||||
|
CALLBACK = cm_pwlts_callback; |
||||
|
|
||||
|
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 including space for two additional x,y pairs */ |
||||
|
size = PARAM_SIZE(x_array) + 2; |
||||
|
|
||||
|
|
||||
|
/* 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)); |
||||
|
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=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); |
||||
|
|
||||
|
x = (double *) STATIC_VAR(x); |
||||
|
|
||||
|
y = (double *) STATIC_VAR(y); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/* See if input_domain is absolute...if so, test against */ |
||||
|
/* breakpoint segments for violation of 50% rule... */ |
||||
|
if (PARAM(fraction) == MIF_FALSE) { |
||||
|
if ( 3 < size ) { |
||||
|
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]) < |
||||
|
(test2 = 0.999999999 * (2.0 * input_domain)) ) { |
||||
|
cm_message_send(limit_error); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/* Retrieve x_input value as current simulation time. */ |
||||
|
x_input = TIME; |
||||
|
|
||||
|
|
||||
|
/* If this is the first call, set *last_x_value to x_input */ |
||||
|
if (INIT == 1) |
||||
|
*last_x_value=x_input; |
||||
|
|
||||
|
|
||||
|
/*** Add debugging printf statement ***/ |
||||
|
/* printf("Last x_input=%e, Current x_input=%e,\n", |
||||
|
*last_x_value,x_input); |
||||
|
*/ |
||||
|
|
||||
|
/* 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<size; i++) { |
||||
|
|
||||
|
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]); |
||||
|
|
||||
|
|
||||
|
/* Calculate input_domain about this region's breakpoint.*/ |
||||
|
|
||||
|
if (PARAM(fraction) == MIF_TRUE) { /* Translate input_domain */ |
||||
|
/* into an absolute.... */ |
||||
|
if ( lower_seg <= upper_seg ) /* Use lower */ |
||||
|
/* segment */ |
||||
|
/* for % calc.*/ |
||||
|
input_domain = input_domain * lower_seg; |
||||
|
else /* Use upper */ |
||||
|
/* 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; |
||||
|
|
||||
|
/* Determine where x_input is within region & determine */ |
||||
|
/* output and partial values.... */ |
||||
|
if (x_input < threshold_lower) { /* Lower linear region */ |
||||
|
dout_din = (y[i] - y[i-1])/lower_seg; |
||||
|
|
||||
|
out = y[i] + (x_input - x[i]) * dout_din; |
||||
|
} |
||||
|
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; |
||||
|
|
||||
|
cm_smooth_corner(x_input,x[i],y[i],input_domain, |
||||
|
lower_slope,upper_slope,&out,&dout_din); |
||||
|
} |
||||
|
else { /* Upper linear region */ |
||||
|
dout_din = (y[i+1] - y[i])/upper_seg; |
||||
|
out = y[i] + (x_input - x[i]) * dout_din; |
||||
|
} |
||||
|
} |
||||
|
break; /* Break search loop...x_input has been found, */ |
||||
|
/* and out and dout_din have been assigned. */ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
/* returns time 0 value for dc and 0 for ac simulation */ |
||||
|
OUTPUT(out) = out; |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,92 @@ |
|||||
|
/*.......1.........2.........3.........4.........5.........6.........7.........8 |
||||
|
================================================================================ |
||||
|
Public Domain |
||||
|
|
||||
|
Georgia Tech Research Corporation |
||||
|
Atlanta, Georgia 30332 |
||||
|
|
||||
|
|
||||
|
AUTHORS |
||||
|
|
||||
|
19 Apr 1991 Jeffrey P. Murray |
||||
|
01 Nov 2020 Holger Vogt |
||||
|
|
||||
|
|
||||
|
SUMMARY |
||||
|
|
||||
|
This file contains the interface specification file for the |
||||
|
analog pwl code model. |
||||
|
|
||||
|
===============================================================================*/ |
||||
|
|
||||
|
NAME_TABLE: |
||||
|
|
||||
|
|
||||
|
C_Function_Name: cm_pwlts |
||||
|
Spice_Model_Name: pwlts |
||||
|
Description: "piecwise linear controlled source, time input" |
||||
|
|
||||
|
|
||||
|
PORT_TABLE: |
||||
|
|
||||
|
Port_Name: out |
||||
|
Description: "output" |
||||
|
Direction: out |
||||
|
Default_Type: v |
||||
|
Allowed_Types: [v,vd,i,id] |
||||
|
Vector: no |
||||
|
Vector_Bounds: - |
||||
|
Null_Allowed: no |
||||
|
|
||||
|
|
||||
|
PARAMETER_TABLE: |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
|
||||
|
PARAMETER_TABLE: |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
|
||||
|
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_TABLE: |
||||
|
|
||||
|
Static_Var_Name: x y |
||||
|
Data_Type: pointer pointer |
||||
|
Description: "time array" "y-coefficient array" |
||||
|
|
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue