SLiCAP noise analysis
SLiCAP noise analysis helps to create design equations for the noise performance of a circuit.
Noise can be assigned to independent voltage and current sources and to resistors. SLiCAP also has buit-in subcircuits with noise sources.
SLiCAP output displayed on this manual page, is generated with the script: noise.py
, imported by Manual.py
.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4"""
5noise.py: SLiCAP scripts for the HTML help file
6"""
7import SLiCAP as sl
8import sympy as sp
9import numpy as np
Noise parameters
During noise analysis, SLiCAP uses the noise
parameter of independent voltage sources and independent current sources as uncorrelated noise sources. It inserts noise current sources in parallel with resistors with their noise spectrum determined by the parameters noisetemp
and noiseflow
.
10# Create a circuit object
11cir = sl.makeCircuit("kicad/noiseSources/noiseSources.kicad_sch")
1noiseSources
2C1 out 0 C value={C_a} vinit=0
3I1 0 out I value=0 noise={S_i} dc=0 dcvar=0
4L1 1 out L value={L_a} iinit=0
5R1 1 2 R value={R_a} noisetemp={T} noiseflow={f_ell} dcvar=0 dcvarlot=0
6V1 2 0 V value=0 noise={S_v} dc=0 dcvar=0
7.end
Noise voltage sources
The noise parameter of independent voltage sources must be specified in \(\mathrm{\left[ \frac{V^2}{Hz} \right] }\)
In the circuit above, the spectral density of the voltage noise from V1
equals \(S_v\) \(\mathrm{\left[ \frac{V^2}{Hz} \right] }\).
Noise current sources
The noise parameter of independent current sources must be specified in \(\mathrm{\left[ \frac{A^2}{Hz} \right] }\)
In the circuit above, the spectral density of the curent noise from I1
equals \(S_i\) \(\mathrm{\left[ \frac{A^2}{Hz} \right] }\).
Resistors
The noise contributed by resistors is governed by two parameters:
noisetemp
: The noise temperature of the resistornoiseflow
: The flicker noise corner frequency
Addition of noise current sources
Before executing a doNoise()
instruction, SLiCAP adds noise current sources in parallel with resistors that have a nonzero positive noise temperature. These current sources obtain the reference designator I_noise_<resID>
, where resID
is the reference designator of the resistor. After the noise analysis, all independent current sources with reference designators starting with I_noise_
will be removed from the circuit.
The noise current spectral density \(S_\mathrm{I\_noise\_Rxx}\) of a resistor Rxx
is set to:
where:
\(k\) is Boltzmann’s constant in [J/K]
\(T_{noise_\mathrm{Rxx}}\) is the noise temperature
noisetemp
of resistorRxx
in [K]\(R_\mathrm{Rxx}\) is the resistance
value
ofRxx
in [Ohm]\(f_{\ell_\mathrm{Rxx}}\) is the flicker noise corner frequency
flow
ofRxx
in [Hz]
In the circuit above:
the noise temperature of the resistor
R1
is set to the gobal parameter \(T\)the flicker noise corner frequency equals \(f_{\ell}\)
Hence, SLiCAP will insert a noise current source in parallel with R1
with a spectral density:
Global parameters
Global parameters are defined in the file SLiCAPmodels.lib
in the folder given by ini.main_lib_path
. If global parameters are found in circuit element expressions or in circuit parameter definitions, SLiCAP automatically adds their definition to the circuit parameter definitions.
In the circuit above, the global parameter \(T\) is found in the noisetemp
parameter of R1
. Its definition with a default value of 300 K is added to the circuit parameter definitions:
13for par in cir.parDefs:
14 print(par, cir.parDefs[par])
T 300
Noise Analysis
At the beginning of the noise analysis, SLiCAP adds resistor noise current sources to the circuit (see above). This also adds the Boltzmann constant \(k\) to the circuit parameter definitions:
16noiseResult = sl.doNoise(cir, detector="V_out", source="V1")
17
18for par in cir.parDefs:
19 print(par, cir.parDefs[par])
This yields:
T 300
k 34516213/2500000000000000000000000000000
Important
The function doNoise() sets the noise attributes onoise
, snoiseTerms
, and onoiseTerms
of the returned instruction object. The inoise
and inoiseTerms
attributes are only set if the circuit has a source specification.
Detector-referred noise
21onoise = noiseResult.onoise
22print(onoise)
This yields:
4*T*k*(f + f_ell)*Abs(R_a**2)/(R_a*f*(16*pi**4*C_a**2*L_a**2*f**4 + 4*pi**2*C_a**2*R_a**2*f**2 - 8*pi**2*C_a*L_a*f**2 + 1)) + S_i*(4*pi**2*L_a**2*f**2 + R_a**2)*Abs(R_a**2)/(R_a**2*(16*pi**4*C_a**2*L_a**2*f**4 + 4*pi**2*C_a**2*R_a**2*f**2 - 8*pi**2*C_a*L_a*f**2 + 1)) + S_v*Abs(R_a**2)/(R_a**2*(16*pi**4*C_a**2*L_a**2*f**4 + 4*pi**2*C_a**2*R_a**2*f**2 - 8*pi**2*C_a*L_a*f**2 + 1))
Formatted output:
Source-referred noise
24inoise = noiseResult.inoise
25print(inoise)
This yields:
4*R_a*T*k*(f + f_ell)/f + S_i*(4*pi**2*L_a**2*f**2 + R_a**2) + S_v
Formatted output:
Contributions to detector-referred and source-referred noise
27snoiseTerms = noiseResult.snoiseTerms
28onoiseTerms = noiseResult.onoiseTerms
29inoiseTerms = noiseResult.inoiseTerms
30for term in snoiseTerms:
31 print("\n= " + term + " =")
32 print("value :", snoiseTerms[term])
33 print("det-referred :", onoiseTerms[term])
34 print("src-referred :", inoiseTerms[term])
This yields:
= I1 =
value : S_i
det-referred : S_i*(4*pi**2*L_a**2*f**2 + R_a**2)*Abs(R_a**2)/(R_a**2*(16*pi**4*C_a**2*L_a**2*f**4 + 4*pi**2*C_a**2*R_a**2*f**2 - 8*pi**2*C_a*L_a*f**2 + 1))
src-referred : S_i*(4*pi**2*L_a**2*f**2 + R_a**2)
= V1 =
value : S_v
det-referred : S_v*Abs(R_a**2)/(R_a**2*(16*pi**4*C_a**2*L_a**2*f**4 + 4*pi**2*C_a**2*R_a**2*f**2 - 8*pi**2*C_a*L_a*f**2 + 1))
src-referred : S_v
= I_noise_R1 =
value : 4*T*k*(1 + f_ell/f)/R_a
det-referred : 4*T*k*(f + f_ell)*Abs(R_a**2)/(R_a*f*(16*pi**4*C_a**2*L_a**2*f**4 + 4*pi**2*C_a**2*R_a**2*f**2 - 8*pi**2*C_a*L_a*f**2 + 1))
src-referred : 4*R_a*T*k*(f + f_ell)/f
Formatted output:
Value |
Units |
|
---|---|---|
I1: Source value |
\(S_{i}\) |
\(\mathrm{\frac{A^2}{Hz}}\) |
I1: Source-referred |
\(S_{i} \left(4 \pi^{2} L_{a}^{2} f^{2} + R_{a}^{2}\right)\) |
\(\mathrm{\frac{V^2}{Hz}}\) |
I1: Detector-referred |
\(\frac{S_{i} \left(4 \pi^{2} L_{a}^{2} f^{2} + R_{a}^{2}\right)}{16 \pi^{4} C_{a}^{2} L_{a}^{2} f^{4} + 4 \pi^{2} C_{a}^{2} R_{a}^{2} f^{2} - 8 \pi^{2} C_{a} L_{a} f^{2} + 1}\) |
\(\mathrm{\frac{V^2}{Hz}}\) |
V1: Source value |
\(S_{v}\) |
\(\mathrm{\frac{V^2}{Hz}}\) |
V1: Source-referred |
\(S_{v}\) |
\(\mathrm{\frac{V^2}{Hz}}\) |
V1: Detector-referred |
\(\frac{S_{v}}{16 \pi^{4} C_{a}^{2} L_{a}^{2} f^{4} + 4 \pi^{2} C_{a}^{2} R_{a}^{2} f^{2} - 8 \pi^{2} C_{a} L_{a} f^{2} + 1}\) |
\(\mathrm{\frac{V^2}{Hz}}\) |
I_noise_R1: Source value |
\(\frac{4 T k \left(1 + \frac{f_{\ell}}{f}\right)}{R_{a}}\) |
\(\mathrm{\frac{A^2}{Hz}}\) |
I_noise_R1: Source-referred |
\(\frac{4 R_{a} T k \left(f + f_{\ell}\right)}{f}\) |
\(\mathrm{\frac{V^2}{Hz}}\) |
I_noise_R1: Detector-referred |
\(\frac{4 R_{a} T k \left(f + f_{\ell}\right)}{f \left(16 \pi^{4} C_{a}^{2} L_{a}^{2} f^{4} + 4 \pi^{2} C_{a}^{2} R_{a}^{2} f^{2} - 8 \pi^{2} C_{a} L_{a} f^{2} + 1\right)}\) |
\(\mathrm{\frac{V^2}{Hz}}\) |
Subcircuits with noise
Built-in subcircuits
Below an overview of subcircuits and symbols for noise analysis. Subcircuits are defined in the library SLiCAP.lib
in the folder indicated by ini.main_lib_path
.
subcircuit name |
description |
parameters |
KiCAD |
gschem/Lepton-EDA |
LTspice |
---|---|---|---|---|---|
N_noise |
Nullor with equivalent-input noise sources |
si, sv |
N_noise |
N_noise |
SLN_noise |
O_noise |
Nullor with equivalent-input noise sources |
si, sv |
O_noise |
O_noise |
SLO_noise |
NM18_noise |
NMOS 180nm equivalent-input noise EKV model |
ID, IG, W, L |
M_noise |
M_noise |
SLM_noise |
PM18_noise |
PMOS 180nm equivalent-input noise EKV model |
ID, IG, W, L |
M_noise |
M_noise |
SLM_noise |
NM18_noisyNullor |
Nullor with NMOS 180nm equivalent-input noise EKV model |
ID, IG, W, L |
XM_noisyNullor |
XM_noisyNullor |
SLM_noisyNullor |
PM18_noisyNullor |
Nullor with PMOS 180nm equivalent-input noise EKV model |
ID, IG, W, L |
XM_noisyNullor |
XM_noisyNullor |
SLM_noisyNullor |
J_noise |
MOS/JFET equivalent-input noise sources |
ID, IG, W, L |
J_noise |
M_noise |
SLM_noise |
Q_noise |
BJT equivalent-input noise sources, r_b=0 |
IC, VCE |
Q_noise |
Q_noise |
SLQ_noise |
Wide table: slide below the table!
Create noise elements
The user can create noisy circuits or subcircuits using independent noise sources, independend current sources, resistors and predefined noisy subcircuits from above.
Noise post processing functions
RMS noise
SLiCAP can perform symbolic and numeric integration and calculate the source-referred or detector-referred rmsNoise .
rmsNoise() calculates the RMS value by integrating each of the noise terms in the onoiseTerms
or the inoiseTerms
attribute of the noise analysis result. For each term it tries to find the best integration method. However, success is not always guaranteed:
Symbolic integration of functions with many variables, may take very long
Symbolic integration of functions is not always possible or implemented in Sympy.
The following may help:
Keep the circuit model as simple as possible and use only one or two symbolic design parameters.
Calculate the variance instead of the RMS noise (standard deviation), and try to obtain expressions with symbolic variables as coefficients of numeric integrals (see below).
Below an example how to express the RMS noise in terms of the source spectral densities \(S_v\) and \(S_i\).
36params = {"R_a" : "1k",
37 "C_a" : "10u",
38 "L_a" : "1m",
39 "f_ell": 100}
40
41cir.defPars(params)
42
43numNoise = sl.doNoise(cir, detector="V_out", pardefs="circuit", numeric=True)
44
45f_min = 1e3
46f_max = 1e6
47
48RMS = sl.rmsNoise(numNoise, 'onoise', f_min, f_max)
49print(RMS)
This yields:
711.447029712076*sqrt(S_i + 4.95576373211838e-7*S_v + 7.6162627945633e-24)
Typesetted:
Noise Figure
The noise figure of a system is a measure for the deterioration of the signal-to-noise ratio by that system. It can be found as the ratio of the total weighted output noise power (variance) and the contribution of the signal source noise to it. Alternatively, one can take the ratio of the total weighted source-referred noise and the weighted source noise.
51# noise figure; V1 is signal source, with associated noise spectrum S_v
52o_var = RMS**2
53src_var = sl.rmsNoise(numNoise, 'onoise', f_min, f_max, source="V1")**2
54noiseF = sp.expand(o_var/src_var)
55print(noiseF)
This yields:
2017852.45232533*S_i/S_v + 1.0 + 1.53684945575637e-17/S_v
Commonly the noise figure is expressed in [dB]:
56F = 10*sp.log(noiseF)/sp.log(10)
57print(F)
This yields:
10*log(2017852.45232533*S_i/S_v + 1.0 + 1.53684945575637e-17/S_v)/log(10)
Typesetted:
Noise weighting functions
DIN A
SLiCAP has the frequency weighting function DIN_A(), which is often used for spectral weighting of noise and distortion components in audio applications. See WiKi R_A(f).
59print(sl.DIN_A())
18719114681919*f**4/(100000*sqrt((f**2 + 1159929/100)*(f**2 + 54449641/100))*(f**2 + 10609/25)*(f**2 + 148693636))
61# Plot the DIN A weighting curve
62frequencies = np.geomspace(10, 20e3, 200, endpoint=True)
63din_A_func = sp.lambdify(sl.ini.frequency, 20*sp.log(sl.DIN_A())/sp.log(10))
64din_A_num = din_A_func(frequencies)
65din_A_trace = sl.trace([frequencies, din_A_num])
66din_A_trace.label = "DIN A"
67traceDict = {"DINA": din_A_trace}
68sl.plot("DINA", "DIN A weighting curve", "semilogx", traceDict,
69 xName="Frequency", xUnits="Hz", yUnits="dB", show=False)
Use assumptions
Below the script to obtain the integral from above.
89var = sl.assumePosParams(var).doit()
90var = sl.clearAssumptions(var)
91print(var)
With \(\tau>0\) the above integral can be evaluated:
S_i*tau/(2*C_i**2)
Typesetted:
The following SLiCAP functions can be used to change the domain of variables:
Obtain symbolic coefficients of numeric intergals
Sometimes numeric integration over frequency becomes possible after symbolic design parameters have been elimated from the integral.
The function integrate_monomial_coeffs() returns an experssion in which monomials of two selected parameters have been taken out of the integral:
93Si, Sv = sp.symbols("S_i, S_v")
94integrated_noise = sl.integrate_monomial_coeffs(numNoise.onoise, [Si, Sv],
95 sl.ini.frequency, f_min, f_max,
96 doit=True)
This yields:
253078.438043065*S_i + 0.250839388927001*S_v + 3.85502378354722e-18
Typesetted:
The function integrated_monomial_coeffs() returns a dictionary of which the keys are monomials consisting of two variables, and the coefficients of these monomials are numeric integrals.
99integrated_noise_coeffs = sl.integrated_monomial_coeffs(numNoise.onoise, [Si, Sv],
100 sl.ini.frequency, f_min, f_max, doit=False)
Typesetted output:
\(S_{i}\) |
\(\int\limits_{1000}^{1.0 \cdot 10^{6}} \frac{1.0 \cdot 10^{38} \left(3.948 \cdot 10^{29} f^{2} + 1.0 \cdot 10^{40}\right)}{1.559 \cdot 10^{59} f^{4} + 3.947 \cdot 10^{69} f^{2} + 1.0 \cdot 10^{72}}\, df\) |
\(S_{v}\) |
\(\int\limits_{1000}^{1.0 \cdot 10^{6}} \frac{1.0 \cdot 10^{72}}{1.559 \cdot 10^{59} f^{4} + 3.947 \cdot 10^{69} f^{2} + 1.0 \cdot 10^{72}}\, df\) |
\(1\) |
\(\int\limits_{1000}^{1.0 \cdot 10^{6}} \frac{1.657 \cdot 10^{55} \left(f + 100\right)}{f \left(1.559 \cdot 10^{59} f^{4} + 3.947 \cdot 10^{69} f^{2} + 1.0 \cdot 10^{72}\right)}\, df\) |
Display equations on HTML pages and in LaTeX documents
The report module Create reports, discusses how HTML snippets and LaTeX snippets can be created for variables, expressions, equations and tables.
As a matter of fact, all equations, tables and figures on this page are created with this module:
102# Create an RST formatter
103rst = sl.RSTformatter()
104# Save expressions in the sphinx/SLiCAPdata folder of the project directory
105rst.eqn("S_vno", onoise, multiline=1, label="eqn-Svno", units="V**2/Hz").save("eqn-Svno")
106rst.eqn("S_vni", inoise, label="eqn-Svni", units="V**2/Hz").save("eqn-Svni")
107rst.noiseContribs(noiseResult, "Noise contributions").save("table-noiseContribs")
108rst.eqn("V_nRMS", RMS, units="V").save("eqn-RMS")
109rst.eqn("F", F, units="dB").save("eqn-F")
110rst.eqn("S_vCDS", cds_weighted, units="V**2/Hz").save("eqn-CDSweighting")
111rst.eqn("sigma^2", var, units="V**2").save("eqn-CDSint")
112rst.eqn("v_n^2", integrated_noise, units="V**2").save("eqn-intCoeffs")
113rst.dictTable(integrated_noise_coeffs,
114 caption="Numeric integrals as coeffs of :math:`S_v` and :math:`S_i`").save("table-coeffsNoise")
The typesetted tables and equations are shown on this page.
Plot noise spectrum
SLiCAP plot functions are discussed in Create plots.