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
|
s_xfer
|
||||||
triangle
|
triangle
|
||||||
file_source
|
file_source
|
||||||
|
delay
|
||||||
|
|
|
||||||
|
|
@ -250,6 +250,8 @@
|
||||||
<ClCompile Include="icm\analog\triangle\triangle-ifspec.c" />
|
<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-cfunc.c" />
|
||||||
<ClCompile Include="icm\analog\file_source\file_source-ifspec.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" />
|
<ClCompile Include="..\..\src\xspice\icm\dlmain.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -291,6 +293,8 @@
|
||||||
<None Include="..\..\src\xspice\icm\analog\triangle\ifspec.ifs" />
|
<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\cfunc.mod" />
|
||||||
<None Include="..\..\src\xspice\icm\analog\file_source\ifspec.ifs" />
|
<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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\include\ngspice\dstring.h" />
|
<ClInclude Include="..\..\src\include\ngspice\dstring.h" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue