pwlts: a pwl v/i source with time input, smoothing and limiting functions
This commit is contained in:
parent
0754ea7657
commit
1d026475a2
|
|
@ -18,3 +18,4 @@ s_xfer
|
|||
triangle
|
||||
file_source
|
||||
delay
|
||||
pwlts
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
@ -232,6 +232,8 @@
|
|||
<AdditionalIncludeDirectories>..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile Include="icm\analog\oneshot\oneshot-ifspec.c" />
|
||||
<ClCompile Include="icm\analog\pwlts\pwlts-cfunc.c" />
|
||||
<ClCompile Include="icm\analog\pwlts\pwlts-ifspec.c" />
|
||||
<ClCompile Include="icm\analog\pwl\pwl-cfunc.c" />
|
||||
<ClCompile Include="icm\analog\pwl\pwl-ifspec.c" />
|
||||
<ClCompile Include="icm\analog\sine\sine-cfunc.c" />
|
||||
|
|
@ -302,4 +304,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue