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.
This commit is contained in:
parent
0d2d034eb2
commit
fbab9a0fe2
|
|
@ -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
|
||||
|
|
@ -17,3 +17,4 @@ summer
|
|||
s_xfer
|
||||
triangle
|
||||
file_source
|
||||
delay
|
||||
|
|
|
|||
|
|
@ -250,6 +250,8 @@
|
|||
<ClCompile Include="icm\analog\triangle\triangle-ifspec.c" />
|
||||
<ClCompile Include="icm\analog\file_source\file_source-cfunc.c" />
|
||||
<ClCompile Include="icm\analog\file_source\file_source-ifspec.c" />
|
||||
<ClCompile Include="icm\analog\delay\delay-cfunc.c" />
|
||||
<ClCompile Include="icm\analog\delay\delay-ifspec.c" />
|
||||
<ClCompile Include="..\..\src\xspice\icm\dlmain.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
@ -291,6 +293,8 @@
|
|||
<None Include="..\..\src\xspice\icm\analog\triangle\ifspec.ifs" />
|
||||
<None Include="..\..\src\xspice\icm\analog\file_source\cfunc.mod" />
|
||||
<None Include="..\..\src\xspice\icm\analog\file_source\ifspec.ifs" />
|
||||
<None Include="..\..\src\xspice\icm\analog\delay\cfunc.mod" />
|
||||
<None Include="..\..\src\xspice\icm\analog\delay\ifspec.ifs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\include\ngspice\dstring.h" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue