Implement MIFnoise(), the generic noise callback for all XSPICE code
models. Two discovery modes are supported: declarative, where models define reserved parameter names (noise_voltage, noise_current, noise_corner, noise_exponent) and get automatic noise sources and programmatic, where models register sources via cm_noise_add_source() during MIF_NOI analysis calls. Also add an OTA (operational transconductance amplifier) code model as a reference implementation that exercises the programmatic noise interface.
This commit is contained in:
parent
2d3e032a3f
commit
8841a3a658
|
|
@ -49,6 +49,7 @@ NON-STANDARD FEATURES
|
|||
#define DC MIF_DC
|
||||
#define AC MIF_AC
|
||||
#define TRANSIENT MIF_TRAN
|
||||
#define NOISE MIF_NOI
|
||||
|
||||
#define ANALOG MIF_ANALOG
|
||||
#define EVENT MIF_EVENT_DRIVEN
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ Complex_t cm_complex_subtract(Complex_t x, Complex_t y);
|
|||
Complex_t cm_complex_multiply(Complex_t x, Complex_t y);
|
||||
Complex_t cm_complex_divide(Complex_t x, Complex_t y);
|
||||
|
||||
int cm_noise_add_source(const char *name, int conn_index, int port_index, Mif_Noise_Src_Type_t type);
|
||||
|
||||
char *cm_get_path(void);
|
||||
CKTcircuit *cm_get_circuit(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ struct coreInfo_t {
|
|||
int ((*dllitf_MIFbindCSCComplex) (GENmodel *, CKTcircuit *)) ;
|
||||
int ((*dllitf_MIFbindCSCComplexToReal) (GENmodel *, CKTcircuit *)) ;
|
||||
#endif
|
||||
int ((*dllitf_MIFnoise)(int, int, GENmodel *, CKTcircuit *, Ndata *, double *));
|
||||
int ((*dllitf_cm_noise_add_source)(const char *, int, int, Mif_Noise_Src_Type_t));
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ extern int MIFiSize;
|
|||
extern int MIFmSize;
|
||||
|
||||
|
||||
extern Mif_Info_t g_mif_info;
|
||||
extern Mif_Info_t g_mif_info;
|
||||
extern Mif_Private_t g_mif_noise_cm_data;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -386,6 +386,28 @@ typedef struct Mif_Inst_Var_Data_s {
|
|||
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
|
||||
/*
|
||||
* Noise analysis context passed to code models via mif_private->noise.
|
||||
* Stack-local in MIFnoise, valid only during cm_func call.
|
||||
*/
|
||||
|
||||
typedef struct Mif_Noise_Data_s {
|
||||
Mif_Boolean_t registering; /* TRUE during N_OPEN, FALSE during N_CALC */
|
||||
int next_index; /* Monotonic counter, reset before each cm_func call */
|
||||
int num_prog_srcs; /* Total programmatic sources after N_OPEN */
|
||||
int max_prog_srcs; /* Allocated capacity of registration arrays */
|
||||
Mif_Noise_Src_Type_t *prog_types; /* Source type per programmatic source */
|
||||
int *prog_conn; /* Connection index per source */
|
||||
int *prog_port; /* Port index per source */
|
||||
char **prog_names; /* Source name suffix per source */
|
||||
double *density; /* Spectral density array (N_CALC, sized num_prog_srcs) */
|
||||
double freq; /* Current noise frequency in Hz */
|
||||
} Mif_Noise_Data_t;
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
|
||||
|
|
@ -405,6 +427,7 @@ struct Mif_Private {
|
|||
int num_inst_var; /* Number of instance variables */
|
||||
Mif_Inst_Var_Data_t **inst_var; /* Information about each inst variable */
|
||||
Mif_Callback_t *callback; /* Callback function */
|
||||
Mif_Noise_Data_t *noise; /* Noise context, NULL when not in noise analysis */
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,17 @@ struct MIFinstance {
|
|||
|
||||
int inst_index; /* Index into inst_table in evt struct in ckt */
|
||||
Mif_Callback_t callback; /* instance callback function */
|
||||
|
||||
int num_noise_srcs; /* Total noise sources (declarative + programmatic) */
|
||||
Mif_Boolean_t noise_initialized; /* TRUE once sources discovered and allocated */
|
||||
double *MIFnVar; /* Flat array [NSTATVARS * num_noise_srcs] */
|
||||
int *noise_node1; /* Positive/branch node per source */
|
||||
int *noise_node2; /* Negative/ground node per source */
|
||||
char **noise_src_names; /* Suffix name per source */
|
||||
int noise_decl_nv_base; /* Base index of voltage noise group, -1 if none */
|
||||
int noise_decl_nc_base; /* Base index of current noise group, -1 if none */
|
||||
int noise_prog_offset; /* Index where programmatic sources start */
|
||||
double *noise_prog_density; /* Reusable density array for cm_func */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/inpdefs.h"
|
||||
#include "ngspice/smpdefs.h"
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "ngspice/noisedef.h"
|
||||
#include "ngspice/miftypes.h"
|
||||
|
||||
|
||||
|
|
@ -154,6 +155,17 @@ extern Mif_Cntl_Src_Type_t MIFget_cntl_src_type(
|
|||
|
||||
extern char *MIFcopy(char *);
|
||||
|
||||
extern int MIFnoise(
|
||||
int mode,
|
||||
int operation,
|
||||
GENmodel *inModel,
|
||||
CKTcircuit *ckt,
|
||||
Ndata *data,
|
||||
double *OnDens
|
||||
);
|
||||
|
||||
extern void MIF_free_noise_state(MIFinstance *here);
|
||||
|
||||
#ifdef KLU
|
||||
extern int MIFbindCSC (GENmodel*, CKTcircuit*) ;
|
||||
extern int MIFbindCSCComplex (GENmodel*, CKTcircuit*) ;
|
||||
|
|
|
|||
|
|
@ -232,4 +232,16 @@ typedef struct MIFmodel MIFmodel;
|
|||
typedef void (* Mif_Callback_t)(Mif_Private_t *, Mif_Callback_Reason_t);
|
||||
|
||||
|
||||
/*
|
||||
* Noise source type for MIFnoise
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
MIF_NOISE_CURRENT, /* Current source between port nodes (pos_node, neg_node) */
|
||||
MIF_NOISE_VOLTAGE, /* Voltage source at port branch equation (branch, 0) */
|
||||
MIF_NOISE_CURRENT_POS, /* Current source from pos_node to ground */
|
||||
MIF_NOISE_CURRENT_NEG, /* Current source from neg_node to ground */
|
||||
} Mif_Noise_Src_Type_t;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -336,8 +336,9 @@ NOISEan(CKTcircuit* ckt, int restart)
|
|||
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
/* MIF_NOI is not yet supported by code models, so use their AC capabilities */
|
||||
/* MIFnoise handles noise analysis for code models via DEVnoise.
|
||||
* Set anal_type to MIF_AC so that MIFload generates correct AC matrix
|
||||
* entries needed for gain computation during noise analysis. */
|
||||
g_mif_info.circuit.anal_type = MIF_AC;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
|
|
|
|||
|
|
@ -926,3 +926,85 @@ bool cm_probe_node(unsigned int conn_index, // Connection index
|
|||
this->output_value[edata->output_subindex] = hold;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_noise_add_source
|
||||
|
||||
Register a programmatic noise source during noise analysis.
|
||||
|
||||
During N_OPEN (registering=TRUE): validates parameters, stores source info
|
||||
in the noise data registration arrays, and returns a sequential index.
|
||||
|
||||
During N_CALC (registering=FALSE): returns the same sequential index
|
||||
without storing anything. The code model uses this index to set
|
||||
NOISE_DENSITY(index).
|
||||
*/
|
||||
|
||||
int
|
||||
cm_noise_add_source(const char *name, int conn_index, int port_index,
|
||||
Mif_Noise_Src_Type_t type)
|
||||
{
|
||||
Mif_Noise_Data_t *nd;
|
||||
int idx;
|
||||
|
||||
nd = g_mif_noise_cm_data.noise;
|
||||
|
||||
if (!nd || !name)
|
||||
return -1;
|
||||
|
||||
if (type != MIF_NOISE_CURRENT && type != MIF_NOISE_VOLTAGE &&
|
||||
type != MIF_NOISE_CURRENT_POS && type != MIF_NOISE_CURRENT_NEG)
|
||||
return -1;
|
||||
|
||||
idx = nd->next_index++;
|
||||
|
||||
if (!nd->registering)
|
||||
return idx;
|
||||
|
||||
/* Registering mode: validate conn/port.
|
||||
* Always store the source to keep indices aligned between N_OPEN and N_CALC.
|
||||
* Invalid sources get conn_index = -1 so MIFnoise skips them during evaluation. */
|
||||
{
|
||||
MIFinstance *inst = g_mif_info.instance;
|
||||
Mif_Boolean_t valid = MIF_TRUE;
|
||||
|
||||
if (conn_index < 0 || conn_index >= inst->num_conn ||
|
||||
inst->conn[conn_index]->is_null ||
|
||||
port_index < 0 || port_index >= inst->conn[conn_index]->size) {
|
||||
|
||||
fprintf(stderr, "cm_noise_add_source: invalid conn %d port %d for '%s'\n",
|
||||
conn_index, port_index, name);
|
||||
valid = MIF_FALSE;
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
conn_index = -1;
|
||||
}
|
||||
|
||||
/* Grow arrays if needed */
|
||||
if (nd->num_prog_srcs >= nd->max_prog_srcs) {
|
||||
int new_max = (nd->max_prog_srcs == 0) ? 8 : nd->max_prog_srcs * 2;
|
||||
Mif_Noise_Src_Type_t *t = TREALLOC(Mif_Noise_Src_Type_t, nd->prog_types, new_max);
|
||||
int *c = TREALLOC(int, nd->prog_conn, new_max);
|
||||
int *p = TREALLOC(int, nd->prog_port, new_max);
|
||||
char **n = TREALLOC(char *, nd->prog_names, new_max);
|
||||
|
||||
if (!t || !c || !p || !n)
|
||||
return -1;
|
||||
|
||||
nd->prog_types = t;
|
||||
nd->prog_conn = c;
|
||||
nd->prog_port = p;
|
||||
nd->prog_names = n;
|
||||
nd->max_prog_srcs = new_max;
|
||||
}
|
||||
|
||||
nd->prog_types[nd->num_prog_srcs] = type;
|
||||
nd->prog_conn[nd->num_prog_srcs] = conn_index;
|
||||
nd->prog_port[nd->num_prog_srcs] = port_index;
|
||||
nd->prog_names[nd->num_prog_srcs] = tprintf("_%s", name);
|
||||
nd->num_prog_srcs++;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,4 +98,7 @@ struct coreInfo_t coreInfo =
|
|||
MIFbindCSCComplex,
|
||||
MIFbindCSCComplexToReal
|
||||
#endif
|
||||
,
|
||||
MIFnoise,
|
||||
cm_noise_add_source
|
||||
};
|
||||
|
|
|
|||
|
|
@ -124,6 +124,8 @@ OUTPUT_STATE {return TOK_OUTPUT_STATE;}
|
|||
OUTPUT_STRENGTH {return TOK_OUTPUT_STRENGTH;}
|
||||
OUTPUT_TYPE {return TOK_OUTPUT_TYPE;}
|
||||
OUTPUT_CHANGED {return TOK_OUTPUT_CHANGED;}
|
||||
NOISE_DENSITY {return TOK_NOISE_DENSITY;}
|
||||
NOISE_FREQ {return TOK_NOISE_FREQ;}
|
||||
|
||||
"(" {return TOK_LPAREN;}
|
||||
")" {return TOK_RPAREN;}
|
||||
|
|
|
|||
|
|
@ -369,6 +369,8 @@ static void append (char *str)
|
|||
%token TOK_TOTAL_LOAD
|
||||
%token TOK_MESSAGE
|
||||
%token TOK_CALL_TYPE
|
||||
%token TOK_NOISE_DENSITY
|
||||
%token TOK_NOISE_FREQ
|
||||
|
||||
%start mod_file
|
||||
|
||||
|
|
@ -589,9 +591,14 @@ macro : TOK_INIT
|
|||
subscript($3));}
|
||||
| TOK_MESSAGE TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
fprintf (mod_yyout,
|
||||
fprintf (mod_yyout,
|
||||
"mif_private->conn[%d]->port[%s]->msg", i,
|
||||
subscript($3));}
|
||||
| TOK_NOISE_DENSITY TOK_LPAREN buffered_c_code TOK_RPAREN
|
||||
{fprintf (mod_yyout,
|
||||
"mif_private->noise->density[%s]", $3);}
|
||||
| TOK_NOISE_FREQ
|
||||
{fprintf (mod_yyout, "mif_private->noise->freq");}
|
||||
;
|
||||
|
||||
subscriptable_id : id
|
||||
|
|
|
|||
|
|
@ -1106,7 +1106,7 @@ static int write_SPICEdev(
|
|||
" .DEVsenPrint = NULL,\n"
|
||||
" .DEVsenTrunc = NULL,\n"
|
||||
" .DEVdisto = NULL,\n"
|
||||
" .DEVnoise = NULL,\n"
|
||||
" .DEVnoise = MIFnoise,\n"
|
||||
" .DEVsoaCheck = NULL,\n"
|
||||
" .DEVinstSize = &val_sizeofMIFinstance,\n"
|
||||
" .DEVmodSize = &val_sizeofMIFmodel,\n"
|
||||
|
|
|
|||
|
|
@ -21,3 +21,4 @@ file_source
|
|||
delay
|
||||
pwlts
|
||||
astate
|
||||
ota
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "ngspice/devdefs.h"
|
||||
#include "ngspice/dstring.h"
|
||||
#include "ngspice/dllitf.h"
|
||||
#include "ngspice/noisedef.h"
|
||||
#include "ngspice/evtudn.h"
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "ngspice/inertial.h"
|
||||
|
|
@ -157,10 +158,21 @@ int MIFload(
|
|||
}
|
||||
|
||||
|
||||
int MIFnoise(
|
||||
int mode,
|
||||
int operation,
|
||||
GENmodel *inModel,
|
||||
CKTcircuit *ckt,
|
||||
Ndata *data,
|
||||
double *OnDens
|
||||
) {
|
||||
return (coreitf->dllitf_MIFnoise)(mode,operation,inModel,ckt,data,OnDens);
|
||||
}
|
||||
|
||||
int MIFmParam(
|
||||
int param_index,
|
||||
IFvalue *value,
|
||||
GENmodel *inModel
|
||||
GENmodel *inModel
|
||||
) {
|
||||
return (coreitf->dllitf_MIFmParam)(param_index,value,inModel);
|
||||
}
|
||||
|
|
@ -444,6 +456,10 @@ void cm_cexit(const int exitcode) {
|
|||
(coreitf->dllitf_cexit)(exitcode);
|
||||
}
|
||||
|
||||
int cm_noise_add_source(const char *name, int conn_index, int port_index, Mif_Noise_Src_Type_t type) {
|
||||
return (coreitf->dllitf_cm_noise_add_source)(name, conn_index, port_index, type);
|
||||
}
|
||||
|
||||
#ifdef KLU
|
||||
int MIFbindCSC (GENmodel *inModel, CKTcircuit *ckt) {
|
||||
return (coreitf->dllitf_MIFbindCSC) (inModel, ckt) ;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ libmifxsp_la_SOURCES = \
|
|||
mifdelete.c \
|
||||
mifmdelete.c \
|
||||
mifdestr.c \
|
||||
mifnoise.c \
|
||||
mif.c
|
||||
|
||||
if KLU_WANTED
|
||||
|
|
|
|||
|
|
@ -57,3 +57,7 @@ Mif_Info_t g_mif_info = {
|
|||
{ 0.0, 0.0,},
|
||||
{ MIF_FALSE, MIF_FALSE,},
|
||||
};
|
||||
|
||||
/* Mif_Private_t used by MIFnoise to call cm_func during noise analysis.
|
||||
* Also accessed by cm_noise_add_source() in cm.c. */
|
||||
Mif_Private_t g_mif_noise_cm_data;
|
||||
|
|
|
|||
|
|
@ -194,5 +194,7 @@ MIFdelete(GENinstance *gen_inst)
|
|||
if (here->num_conv && here->conv)
|
||||
FREE(here->conv);
|
||||
|
||||
MIF_free_noise_state(here);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -574,6 +574,8 @@ MIFunsetup(GENmodel *inModel,CKTcircuit *ckt)
|
|||
here->callback(&cm_data, MIF_CB_DESTROY);
|
||||
}
|
||||
|
||||
MIF_free_noise_state(here);
|
||||
|
||||
here->initialized = MIF_FALSE;
|
||||
} /* end for all instances */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,4 +89,7 @@ struct coreInfo_t coreInfo =
|
|||
MIFbindCSCComplex,
|
||||
MIFbindCSCComplexToReal
|
||||
#endif
|
||||
,
|
||||
MIFnoise,
|
||||
cm_noise_add_source
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2620,6 +2620,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\xspice\mif\mifgetvalue.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifload.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmask.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifnoise.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmdelete.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmpara.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifsetup.c" />
|
||||
|
|
|
|||
|
|
@ -2840,6 +2840,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\xspice\mif\mifgetvalue.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifload.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmask.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifnoise.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmdelete.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmpara.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifsetup.c" />
|
||||
|
|
|
|||
|
|
@ -2855,6 +2855,7 @@
|
|||
<ClCompile Include="..\src\xspice\mif\mifgetvalue.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifload.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmask.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifnoise.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmdelete.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifmpara.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifsetup.c" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue