OTA (operational transconductance amplifier) code model as a

reference implementation that exercises the programmatic noise interface.
This commit is contained in:
Seth Hillbrand 2026-03-23 21:20:57 +01:00 committed by Holger Vogt
parent 1ccf795b9b
commit d5bfe3af4a
2 changed files with 224 additions and 0 deletions

View File

@ -0,0 +1,110 @@
/*
================================================================================
FILE ota/cfunc.mod
Public Domain
AUTHORS
20 Mar 2026 Seth Hillbrand
SUMMARY
This file contains the model-specific routines for the OTA
(Operational Transconductance Amplifier) code model.
DC/TRAN: Vout as current = gm * (Vp - Vn)
AC: Complex gain = gm
NOISE: Programmatic noise with en, in_noise, enk, ink, incm, incmk.
Parameter naming follows LTSPICE convention for OTA compatibility.
================================================================================
*/
#include <stdlib.h>
void cm_ota(ARGS)
{
double gm_val = PARAM(gm);
double rout = PARAM(rout);
double rin = PARAM(rin);
Mif_Complex_t ac_gain;
if (ANALYSIS == NOISE) {
/* Register noise sources on every call (N_OPEN and N_CALC).
* During N_OPEN: registers and returns index.
* During N_CALC: returns same sequential index. */
int src_en_w = cm_noise_add_source("en_white", 1, 0, MIF_NOISE_CURRENT);
int src_en_f = cm_noise_add_source("en_flicker", 1, 0, MIF_NOISE_CURRENT);
int src_in_w = cm_noise_add_source("in_white", 0, 0, MIF_NOISE_CURRENT);
int src_in_f = cm_noise_add_source("in_flicker", 0, 0, MIF_NOISE_CURRENT);
/* Common-mode current noise: independent sources from each input pin to ground */
int src_icm_pw = cm_noise_add_source("incm_p_white", 0, 0, MIF_NOISE_CURRENT_POS);
int src_icm_pf = cm_noise_add_source("incm_p_flicker", 0, 0, MIF_NOISE_CURRENT_POS);
int src_icm_nw = cm_noise_add_source("incm_n_white", 0, 0, MIF_NOISE_CURRENT_NEG);
int src_icm_nf = cm_noise_add_source("incm_n_flicker", 0, 0, MIF_NOISE_CURRENT_NEG);
if (!mif_private->noise->registering) {
double en = PARAM(en);
double in_n = PARAM(in_noise);
double enk_val = PARAM(enk);
double ink_val = PARAM(ink);
double incm = PARAM(incm);
double incmk_val = PARAM(incmk);
double f = NOISE_FREQ;
/* en referred to output as current noise: (en * gm)^2 A^2/Hz */
NOISE_DENSITY(src_en_w) = en * en * gm_val * gm_val;
NOISE_DENSITY(src_en_f) = (enk_val > 0 && f > 0) ?
en * en * gm_val * gm_val * enk_val / f : 0.0;
/* in as differential current noise at input: in^2 A^2/Hz */
NOISE_DENSITY(src_in_w) = in_n * in_n;
NOISE_DENSITY(src_in_f) = (ink_val > 0 && f > 0) ?
in_n * in_n * ink_val / f : 0.0;
/* incm as current noise from each input pin to ground */
NOISE_DENSITY(src_icm_pw) = incm * incm;
NOISE_DENSITY(src_icm_pf) = (incmk_val > 0 && f > 0) ?
incm * incm * incmk_val / f : 0.0;
NOISE_DENSITY(src_icm_nw) = incm * incm;
NOISE_DENSITY(src_icm_nf) = (incmk_val > 0 && f > 0) ?
incm * incm * incmk_val / f : 0.0;
}
return;
}
if (ANALYSIS != MIF_AC) {
double v_in = INPUT(inp);
double v_out = INPUT(out);
OUTPUT(out) = gm_val * v_in + v_out / rout;
PARTIAL(out, inp) = gm_val;
PARTIAL(out, out) = 1.0 / rout;
OUTPUT(inp) = v_in / rin;
PARTIAL(inp, inp) = 1.0 / rin;
}
else {
Mif_Complex_t ac_rout;
Mif_Complex_t ac_rin;
ac_gain.real = gm_val;
ac_gain.imag = 0.0;
AC_GAIN(out, inp) = ac_gain;
ac_rout.real = 1.0 / rout;
ac_rout.imag = 0.0;
AC_GAIN(out, out) = ac_rout;
ac_rin.real = 1.0 / rin;
ac_rin.imag = 0.0;
AC_GAIN(inp, inp) = ac_rin;
}
}

View File

@ -0,0 +1,114 @@
/*
================================================================================
Public Domain
SUMMARY
Interface specification for the OTA (Operational Transconductance Amplifier)
code model. LTSPICE-compatible parameter naming convention.
Noise is implemented via the programmatic API (cm_noise_add_source /
NOISE_DENSITY). Set noise_programmatic = TRUE to enable noise analysis.
================================================================================
*/
NAME_TABLE:
C_Function_Name: cm_ota
Spice_Model_Name: ota
Description: "Operational Transconductance Amplifier with noise"
PORT_TABLE:
Port_Name: inp out
Description: "input" "output"
Direction: inout inout
Default_Type: gd g
Allowed_Types: [gd] [g]
Vector: no no
Vector_Bounds: - -
Null_Allowed: no no
PARAMETER_TABLE:
Parameter_Name: gm rout
Description: "transconductance" "output resistance"
Data_Type: real real
Default_Value: 1.0e-3 1.0e12
Limits: [1e-15 -] [0 -]
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: rin
Description: "input resistance"
Data_Type: real
Default_Value: 1.0e12
Limits: [0 -]
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: en in_noise
Description: "input voltage noise density V/rtHz" "input current noise density A/rtHz"
Data_Type: real real
Default_Value: 0.0 0.0
Limits: [0 -] [0 -]
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: enk ink
Description: "voltage noise 1/f corner Hz" "current noise 1/f corner Hz"
Data_Type: real real
Default_Value: 0.0 0.0
Limits: [0 -] [0 -]
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: incm incmk
Description: "CM current noise density A/rtHz" "CM current noise 1/f corner Hz"
Data_Type: real real
Default_Value: 0.0 0.0
Limits: [0 -] [0 -]
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: noise_programmatic
Description: "enable programmatic noise sources"
Data_Type: boolean
Default_Value: TRUE
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes