Browse Source
Add an analog delay source for transient simulation
Add an analog delay source for transient simulation
Internal circular memory of size tstop/tstep or user defined. (aprox.) every tstep a value is stored. Delay time in multiples of tstep, by control voltage or user defined. Dc or ac sim will simply connect input to output.pre-master-46
4 changed files with 430 additions and 0 deletions
-
344src/xspice/icm/analog/delay/cfunc.mod
-
81src/xspice/icm/analog/delay/ifspec.ifs
-
1src/xspice/icm/analog/modpath.lst
-
4visualc/xspice/analog.vcxproj
@ -0,0 +1,344 @@ |
|||||
|
/*.......1.........2.........3.........4.........5.........6.........7.........8 |
||||
|
================================================================================ |
||||
|
|
||||
|
FILE delay/cfunc.mod |
||||
|
|
||||
|
3-clause BSD |
||||
|
|
||||
|
Copyright 2021 |
||||
|
The ngspice team |
||||
|
|
||||
|
AUTHORS |
||||
|
|
||||
|
21 May 2021 Holger Vogt |
||||
|
|
||||
|
|
||||
|
MODIFICATIONS |
||||
|
|
||||
|
|
||||
|
|
||||
|
SUMMARY |
||||
|
|
||||
|
This file contains the functional description of the analog |
||||
|
delay code model. |
||||
|
|
||||
|
|
||||
|
INTERFACES |
||||
|
|
||||
|
FILE ROUTINE CALLED |
||||
|
|
||||
|
CMutil.c void cm_smooth_corner(); |
||||
|
|
||||
|
CM.c void *cm_analog_alloc() |
||||
|
void *cm_analog_get_ptr() |
||||
|
int cm_analog_integrate() |
||||
|
cm_delay_callback() |
||||
|
|
||||
|
|
||||
|
|
||||
|
REFERENCED FILES |
||||
|
|
||||
|
Inputs from and outputs to ARGS structure. |
||||
|
|
||||
|
|
||||
|
NON-STANDARD FEATURES |
||||
|
|
||||
|
NONE |
||||
|
|
||||
|
===============================================================================*/ |
||||
|
|
||||
|
/*=== INCLUDE FILES ====================*/ |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
|
||||
|
/*=== CONSTANTS ========================*/ |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
/*=== MACROS ===========================*/ |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
/*=== LOCAL VARIABLES & TYPEDEFS =======*/ |
||||
|
|
||||
|
typedef struct { |
||||
|
|
||||
|
double *buffer; /* the storage array for input values */ |
||||
|
int buffer_size; /* size of buffer */ |
||||
|
int buff_write; /* buffer write index */ |
||||
|
int buff_del; /* buffer index, delayed */ |
||||
|
int step_count; /* steps processed */ |
||||
|
double tdelmin; /* min delay, if controlled */ |
||||
|
double tdelmax; /* max delay, if controlled */ |
||||
|
double tdelay; /* time delay */ |
||||
|
double tstep; /* tran step size */ |
||||
|
double tstop; /* tran stop value */ |
||||
|
double tprev; /* previous time value */ |
||||
|
double prev_val; /* previous data value */ |
||||
|
double start_val; /* signal time 0 value */ |
||||
|
} mLocal_Data_t; |
||||
|
|
||||
|
|
||||
|
struct CKTcircuitmin { |
||||
|
|
||||
|
/* This is a minimum re-definition of the circuit structure defined in |
||||
|
cktdefs.h. We are interested in TSTEP and TSTOP */ |
||||
|
|
||||
|
GENmodel **CKThead; |
||||
|
STATistics *CKTstat; /* The STATistics structure */ |
||||
|
double *CKTstates[8]; /* Used as memory of past steps ??? */ |
||||
|
double CKTtime; /* Current transient simulation time */ |
||||
|
double CKTdelta; /* next time step in transient simulation */ |
||||
|
double CKTdeltaOld[7]; /* Memory for the 7 most recent CKTdelta */ |
||||
|
double CKTtemp; /* Actual temperature of CKT, initialzed to 300.15 K in cktinit.c*/ |
||||
|
double CKTnomTemp; /* Reference temperature 300.15 K set in cktinit.c */ |
||||
|
double CKTvt; /* Thernmal voltage at CKTtemp */ |
||||
|
double CKTag[7]; /* the gear variable coefficient matrix */ |
||||
|
#ifdef PREDICTOR |
||||
|
double CKTagp[7]; /* the gear predictor variable coefficient matrix */ |
||||
|
#endif /*PREDICTOR*/ |
||||
|
int CKTorder; /* the integration method order */ |
||||
|
int CKTmaxOrder; /* maximum integration method order */ |
||||
|
int CKTintegrateMethod; /* the integration method to be used */ |
||||
|
double CKTxmu; /* for trapezoidal method */ |
||||
|
int CKTindverbosity; /* control check of inductive couplings */ |
||||
|
SMPmatrix *CKTmatrix; /* pointer to sparse matrix */ |
||||
|
int CKTniState; /* internal state */ |
||||
|
double *CKTrhs; /* current rhs value - being loaded */ |
||||
|
double *CKTrhsOld; /* previous rhs value for convergence testing */ |
||||
|
double *CKTrhsSpare; /* spare rhs value for reordering */ |
||||
|
double *CKTirhs; /* current rhs value - being loaded imag) */ |
||||
|
double *CKTirhsOld; /* previous rhs value (imaginary)*/ |
||||
|
double *CKTirhsSpare; /* spare rhs value (imaginary)*/ |
||||
|
#ifdef PREDICTOR |
||||
|
double *CKTpred; /* predicted solution vector */ |
||||
|
double *CKTsols[8]; /* previous 8 solutions */ |
||||
|
#endif /* PREDICTOR */ |
||||
|
double *CKTrhsOp; /* opearating point values */ |
||||
|
double *CKTsenRhs; /* current sensitivity rhs values */ |
||||
|
double *CKTseniRhs; /* current sensitivity rhs values (imag)*/ |
||||
|
int CKTmaxEqNum; /* And this ? */ |
||||
|
int CKTcurrentAnalysis; /* the analysis in progress (if any) */ |
||||
|
CKTnode *CKTnodes; /* ??? */ |
||||
|
CKTnode *CKTlastNode; /* ??? */ |
||||
|
CKTnode *prev_CKTlastNode; /* just before model setup */ |
||||
|
int CKTnumStates; /* Number of sates effectively valid ??? */ |
||||
|
long CKTmode; /* Mode of operation of the circuit ??? */ |
||||
|
int CKTbypass; /* bypass option, how does it work ? */ |
||||
|
int CKTdcMaxIter; /* iteration limit for dc op. (itl1) */ |
||||
|
int CKTdcTrcvMaxIter; /* iteration limit for dc tran. curv (itl2) */ |
||||
|
int CKTtranMaxIter; /* iteration limit for each timepoint for tran*/ |
||||
|
int CKTbreakSize; /* ??? */ |
||||
|
int CKTbreak; /* ??? */ |
||||
|
double CKTsaveDelta; /* ??? */ |
||||
|
double CKTminBreak; /* ??? */ |
||||
|
double *CKTbreaks; /* List of breakpoints ??? */ |
||||
|
double CKTabstol; /* --- */ |
||||
|
double CKTpivotAbsTol; /* --- */ |
||||
|
double CKTpivotRelTol; /* --- */ |
||||
|
double CKTreltol; /* --- */ |
||||
|
double CKTchgtol; /* --- */ |
||||
|
double CKTvoltTol; /* --- */ |
||||
|
/* What is this define for ? */ |
||||
|
#ifdef NEWTRUNC |
||||
|
double CKTlteReltol; |
||||
|
double CKTlteAbstol; |
||||
|
#endif /* NEWTRUNC */ |
||||
|
double CKTgmin; /* .options GMIN */ |
||||
|
double CKTgshunt; /* .options RSHUNT */ |
||||
|
double CKTcshunt; /* .options CSHUNT */ |
||||
|
double CKTdelmin; /* minimum time step for tran analysis */ |
||||
|
double CKTtrtol; /* .options TRTOL */ |
||||
|
double CKTfinalTime; /* TSTOP */ |
||||
|
double CKTstep; /* TSTEP */ |
||||
|
double CKTmaxStep; /* TMAX */ |
||||
|
double CKTinitTime; /* TSTART */ |
||||
|
/* struct is truncated here */ |
||||
|
}; |
||||
|
|
||||
|
typedef struct CKTcircuitmin CKTcircuitmin; |
||||
|
|
||||
|
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ |
||||
|
|
||||
|
static void cm_delay_callback(ARGS, Mif_Callback_Reason_t reason); |
||||
|
|
||||
|
/*=== CM_DELAY ROUTINE ===*/ |
||||
|
|
||||
|
void cm_delay(ARGS) |
||||
|
{ |
||||
|
int buffer_size, delay_step; |
||||
|
double delay; |
||||
|
double delmin, delmax; |
||||
|
double *ins, *ins_old; |
||||
|
|
||||
|
mLocal_Data_t *loc; /* Pointer to local static data, not to be included |
||||
|
in the state vector */ |
||||
|
CKTcircuitmin *ckt; |
||||
|
|
||||
|
|
||||
|
if (ANALYSIS != MIF_AC) { /**** only Transient Analysis and dc ****/ |
||||
|
|
||||
|
/** INIT: allocate storage **/ |
||||
|
|
||||
|
if (INIT==1) { |
||||
|
|
||||
|
CALLBACK = cm_delay_callback; |
||||
|
|
||||
|
ckt = (CKTcircuitmin*)cm_get_circuit(); |
||||
|
|
||||
|
if (PARAM_NULL(buffer_size)) { |
||||
|
/* size depends on TSTOP/TSTEP, if no parameter given */ |
||||
|
buffer_size = (int) (ckt->CKTfinalTime / ckt->CKTstep) + 1; |
||||
|
} |
||||
|
else { |
||||
|
buffer_size = PARAM(buffer_size); |
||||
|
if (buffer_size < 0) { |
||||
|
cm_message_send("Negative buffer size is not allowed " |
||||
|
"in a delay code model"); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
delay = PARAM(delay); |
||||
|
if (delay < 0.0) { |
||||
|
delay = 0.0; |
||||
|
} |
||||
|
|
||||
|
/*** allocate static storage for *loc ***/ |
||||
|
if ((loc = (mLocal_Data_t *) (STATIC_VAR(locdata) = calloc(1, |
||||
|
sizeof(mLocal_Data_t)))) == (mLocal_Data_t *) NULL) { |
||||
|
cm_message_send("Unable to allocate Local_Data_t " |
||||
|
"in cm_delay()"); |
||||
|
return; |
||||
|
} |
||||
|
/*** allocate static storage for the delay buffer ***/ |
||||
|
loc->buffer = (double *) calloc((size_t)buffer_size, sizeof(double)); |
||||
|
if (loc->buffer == (double *) NULL) { |
||||
|
cm_message_send("Unable to allocate delay buffer " |
||||
|
"in cm_delay()"); |
||||
|
return; |
||||
|
} |
||||
|
loc->buffer_size = buffer_size; |
||||
|
|
||||
|
cm_analog_alloc(TRUE,sizeof(double)); |
||||
|
ins = (double *) cm_analog_get_ptr(TRUE,0); /* Set out pointer to current |
||||
|
time storage */ |
||||
|
ins_old = (double *) cm_analog_get_ptr(TRUE,1); /* Set old-output-state pointer |
||||
|
to previous time storage */ |
||||
|
|
||||
|
*ins = *ins_old = loc->start_val = INPUT(in); |
||||
|
|
||||
|
/* The delay is controlled by input delay_cnt */ |
||||
|
if (PARAM(has_delay_cnt) == MIF_TRUE) { |
||||
|
if (PARAM_NULL(delmin)) |
||||
|
loc->tdelmin = 0.0; |
||||
|
else |
||||
|
loc->tdelmin = PARAM(delmin); |
||||
|
|
||||
|
if (PARAM_NULL(delmax)) |
||||
|
loc->tdelmax = ckt->CKTfinalTime; |
||||
|
else |
||||
|
loc->tdelmax = PARAM(delmax); |
||||
|
} |
||||
|
|
||||
|
loc->buff_write = 0; |
||||
|
loc->buff_del = 0; |
||||
|
loc->step_count = 0; |
||||
|
loc->tdelay = delay; |
||||
|
loc->tstop = ckt->CKTfinalTime; |
||||
|
loc->tstep = ckt->CKTstep; |
||||
|
loc->tprev = 0.0; |
||||
|
loc->prev_val = 0.0; |
||||
|
} |
||||
|
/* retrieve previous values */ |
||||
|
|
||||
|
loc = STATIC_VAR (locdata); |
||||
|
|
||||
|
ins = (double *) cm_analog_get_ptr(TRUE,0); /* Set out pointer to current |
||||
|
time storage */ |
||||
|
ins_old = (double *) cm_analog_get_ptr(TRUE,1); /* Set old-output-state pointer |
||||
|
to previous time storage */ |
||||
|
|
||||
|
delay = loc->tdelay; |
||||
|
if (delay == 0.0) { |
||||
|
OUTPUT(out) = INPUT(in); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (TIME == 0.0) |
||||
|
loc->start_val = INPUT(in); |
||||
|
|
||||
|
/* input, simply interpolated to TSTEP */ |
||||
|
double tacct = loc->step_count * loc->tstep; |
||||
|
if (TIME >= tacct) { |
||||
|
double curr_in; |
||||
|
/* double tdiff = TIME - tacct; |
||||
|
// interpolate |
||||
|
if (tdiff > 0) { |
||||
|
curr_in = loc->prev_val + (INPUT(in) - loc->prev_val) / (TIME - loc->tprev) * tacct; |
||||
|
} |
||||
|
else*/ |
||||
|
curr_in = INPUT(in); |
||||
|
|
||||
|
loc->buffer[loc->buff_write] = *ins = curr_in; |
||||
|
/* next buffer location, circular, for writing */ |
||||
|
loc->buff_write = (loc->buff_write + 1) % loc->buffer_size; |
||||
|
loc->step_count++; |
||||
|
loc->tprev = tacct; |
||||
|
loc->prev_val = curr_in; |
||||
|
} |
||||
|
|
||||
|
delmin = loc->tdelmin; |
||||
|
delmax = loc->tdelmax; |
||||
|
|
||||
|
if (PARAM(has_delay_cnt) == MIF_TRUE) { |
||||
|
delay = (delmax - delmin) * INPUT(cntrl) + delmin; |
||||
|
} |
||||
|
|
||||
|
/* time not yet advanced for delay output */ |
||||
|
if (TIME < delay) { |
||||
|
OUTPUT(out) = loc->start_val; |
||||
|
} |
||||
|
else |
||||
|
OUTPUT(out) = loc->buffer[loc->buff_del]; |
||||
|
|
||||
|
/* delay in steps */ |
||||
|
delay_step = (int)(delay / loc->tstep); |
||||
|
/* FIXME: For whatever reason the model is assessed two times per time step */ |
||||
|
|
||||
|
/* next readout location, delayed after writing */ |
||||
|
if ((loc->buff_write - delay_step) >= 0) |
||||
|
loc->buff_del = loc->buff_write - delay_step; |
||||
|
else |
||||
|
loc->buff_del = loc->buff_write - delay_step + loc->buffer_size; |
||||
|
} |
||||
|
|
||||
|
else { /**** all others ****/ |
||||
|
OUTPUT(out) = INPUT(in); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* free the memory created locally */ |
||||
|
static void cm_delay_callback(ARGS, Mif_Callback_Reason_t reason) |
||||
|
{ |
||||
|
switch (reason) { |
||||
|
case MIF_CB_DESTROY: { |
||||
|
mLocal_Data_t *loc = (mLocal_Data_t *) STATIC_VAR(locdata); |
||||
|
if (loc == (mLocal_Data_t *) NULL) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (loc->buffer != (double *) NULL) { |
||||
|
free(loc->buffer); |
||||
|
} |
||||
|
|
||||
|
free(loc); |
||||
|
|
||||
|
STATIC_VAR(locdata) = NULL; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} /* end of function cm_delay_callback */ |
||||
@ -0,0 +1,81 @@ |
|||||
|
/*.......1.........2.........3.........4.........5.........6.........7.........8 |
||||
|
================================================================================ |
||||
|
|
||||
|
------------------------------------------------------------------------- |
||||
|
Copyright 2011 Thomas Sailer |
||||
|
3 - Clause BSD license |
||||
|
(see COPYING or https://opensource.org/licenses/BSD-3-Clause) |
||||
|
------------------------------------------------------------------------- |
||||
|
|
||||
|
AUTHORS |
||||
|
|
||||
|
19 May 2011 Thomas Sailer |
||||
|
|
||||
|
|
||||
|
SUMMARY |
||||
|
|
||||
|
This file contains the interface specification file for the |
||||
|
delay code model. |
||||
|
|
||||
|
===============================================================================*/ |
||||
|
|
||||
|
NAME_TABLE: |
||||
|
|
||||
|
C_Function_Name: cm_delay |
||||
|
Spice_Model_Name: delay |
||||
|
Description: "analog delay line" |
||||
|
|
||||
|
|
||||
|
PORT_TABLE: |
||||
|
|
||||
|
Port_Name: in out cntrl |
||||
|
Description: "input" "output" "control" |
||||
|
Direction: in out in |
||||
|
Default_Type: v v v |
||||
|
Allowed_Types: [v,vd,vnam] [v,vd] [v,vd,i,id] |
||||
|
Vector: no no no |
||||
|
Vector_Bounds: - - - |
||||
|
Null_Allowed: no no yes |
||||
|
|
||||
|
|
||||
|
PARAMETER_TABLE: |
||||
|
|
||||
|
Parameter_Name: delay buffer_size |
||||
|
Description: "time delay" "size of delay buffer" |
||||
|
Data_Type: real int |
||||
|
Default_Value: 0.0 1024 |
||||
|
Limits: - [1 -] |
||||
|
Vector: no no |
||||
|
Vector_Bounds: - - |
||||
|
Null_Allowed: yes yes |
||||
|
|
||||
|
|
||||
|
PARAMETER_TABLE: |
||||
|
|
||||
|
Parameter_Name: has_delay_cnt |
||||
|
Description: "controlled delay" |
||||
|
Data_Type: boolean |
||||
|
Default_Value: FALSE |
||||
|
Limits: - |
||||
|
Vector: no |
||||
|
Vector_Bounds: - |
||||
|
Null_Allowed: yes |
||||
|
|
||||
|
|
||||
|
PARAMETER_TABLE: |
||||
|
|
||||
|
Parameter_Name: delmin delmax |
||||
|
Description: "min delay" "max delay" |
||||
|
Data_Type: real real |
||||
|
Default_Value: 0 0 |
||||
|
Limits: [0 -] [0 -] |
||||
|
Vector: no no |
||||
|
Vector_Bounds: - - |
||||
|
Null_Allowed: yes yes |
||||
|
|
||||
|
|
||||
|
STATIC_VAR_TABLE: |
||||
|
|
||||
|
Static_Var_Name: locdata |
||||
|
Description: "local static data" |
||||
|
Data_Type: pointer |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue