@cascode/cascode-js 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/binding.gyp +26 -0
- package/lib/std/Bundles.cas +6 -0
- package/lib/std/InverterLike.cas +11 -0
- package/lib/std/amp/Common.cas +16 -0
- package/lib/std/amp/FullyDifferentialOpAmp.cas +61 -0
- package/lib/std/amp/SingleEndedAmp.cas +48 -0
- package/lib/std/amp/SingleEndedOpAmp.cas +48 -0
- package/lib/std/bench/DCBiasBenches.cas +41 -0
- package/lib/std/bench/NoiseBenches.cas +167 -0
- package/lib/std/bench/PowerBenches.cas +202 -0
- package/lib/std/bench/TranBenches.cas +164 -0
- package/lib/std/bench/TransferBenches.cas +329 -0
- package/lib/std/composites/PadDriver.cas +10 -0
- package/lib/std/prim/Devices.cas +20 -0
- package/lib/std/prim/Passives.cas +23 -0
- package/lib/std/refs/ConstantGm.cas +25 -0
- package/lib/std/refs/CurrentReference.cas +7 -0
- package/lib/std/refs/ReferenceCircuit.cas +6 -0
- package/lib/std/refs/VoltageReference.cas +7 -0
- package/native/cascode_native_addon.c +788 -0
- package/native/osx-arm64/Cascode.Native.dylib +0 -0
- package/native/osx-arm64/google-ortools-native.dylib +0 -0
- package/native/osx-arm64/libortools.9.dylib +0 -0
- package/package.json +48 -0
- package/platform-packages/cascode-js-darwin-arm64/README.md +4 -0
- package/platform-packages/cascode-js-darwin-arm64/index.js +10 -0
- package/platform-packages/cascode-js-darwin-arm64/package.json +28 -0
- package/platform-packages/cascode-js-darwin-x64/README.md +4 -0
- package/platform-packages/cascode-js-darwin-x64/index.js +10 -0
- package/platform-packages/cascode-js-darwin-x64/package.json +28 -0
- package/platform-packages/cascode-js-linux-x64/README.md +4 -0
- package/platform-packages/cascode-js-linux-x64/index.js +10 -0
- package/platform-packages/cascode-js-linux-x64/package.json +28 -0
- package/platform-packages/cascode-js-win32-x64/README.md +4 -0
- package/platform-packages/cascode-js-win32-x64/index.js +10 -0
- package/platform-packages/cascode-js-win32-x64/package.json +28 -0
- package/scripts/stage-platform-package.mjs +128 -0
- package/scripts/sync-stdlib.mjs +35 -0
- package/src/index.d.ts +38 -0
- package/src/index.js +453 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
VERSION 3.1
|
|
2
|
+
|
|
3
|
+
library lib.std.bench
|
|
4
|
+
|
|
5
|
+
// Minimal quiescent-power bench.
|
|
6
|
+
//
|
|
7
|
+
// This bench assumes the circuit harness provides a VDC supply source between the mapped
|
|
8
|
+
// supply/return terminals (e.g. VDD -> GND). The bench runtime measures the operating-point
|
|
9
|
+
// current through that source and reports positive static power drawn from the rail.
|
|
10
|
+
bench QuiescentPower {
|
|
11
|
+
stim PWR : supply
|
|
12
|
+
resp RET : ground
|
|
13
|
+
|
|
14
|
+
measurements {
|
|
15
|
+
measurement QuiescentPower : W {
|
|
16
|
+
return quiescent_power(PWR, RET)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
abstract bench AbstractPSRR {
|
|
22
|
+
abstract stim IN
|
|
23
|
+
stim PWR : supply
|
|
24
|
+
abstract resp OUT
|
|
25
|
+
|
|
26
|
+
analysis {
|
|
27
|
+
ACAnalysis ac = new ACAnalysis(
|
|
28
|
+
space=Log,
|
|
29
|
+
samples=100,
|
|
30
|
+
start=(if constraints.HighpassBandwidth { constraints.HighpassBandwidth * 0.1 } else { 1Hz }),
|
|
31
|
+
stop=(if constraints.GainBandwidth { constraints.GainBandwidth * 10 } else { 10GHz }))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
measurements {
|
|
35
|
+
measurement SupplyGain : dB {
|
|
36
|
+
return calc_passband_gain(ac, PWR, OUT, constraints.LowpassBandwidth, constraints.GainBandwidth)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
measurement PSRR : dB {
|
|
40
|
+
return -SupplyGain()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
measurement InputReferredPSRR(VoltageRatio dmGain) : dB {
|
|
44
|
+
return (dmGain - SupplyGain())
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Power supply rejection ratio (PSRR) bench for single-ended output amplifiers.
|
|
50
|
+
//
|
|
51
|
+
// Applies AC ripple to the supply rail and measures the resulting output perturbation.
|
|
52
|
+
// SupplyGain is the supply-to-output gain (Asupply). PSRR is output-referred PSRR
|
|
53
|
+
// (does not depend on amplifier gain). InputReferredPSRR is gain-normalized PSRR.
|
|
54
|
+
bench SupplyToSERejection extends AbstractPSRR {
|
|
55
|
+
stim IN : Diff
|
|
56
|
+
stim PWR : supply
|
|
57
|
+
resp OUT : analog
|
|
58
|
+
|
|
59
|
+
fill {
|
|
60
|
+
net vcm : analog
|
|
61
|
+
net gnd : ground
|
|
62
|
+
GND g = new GND() { .GND--gnd }
|
|
63
|
+
|
|
64
|
+
// Bias the input common-mode so the DUT inputs are not floating (avoids singular matrices in AC).
|
|
65
|
+
VDC commonModeVDC = new VDC(V=env.InputCommonModeRange) {
|
|
66
|
+
.P--vcm
|
|
67
|
+
.N--gnd
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Impedor sourceP = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
71
|
+
Impedor sourceN = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
72
|
+
|
|
73
|
+
sourceP.P--vcm
|
|
74
|
+
sourceP.N--IN.P
|
|
75
|
+
|
|
76
|
+
sourceN.P--vcm
|
|
77
|
+
sourceN.N--IN.N
|
|
78
|
+
|
|
79
|
+
// Supply bias + ripple injection:
|
|
80
|
+
// - VDC sets the nominal rail voltage
|
|
81
|
+
// - VAC injects small-signal ripple on top
|
|
82
|
+
// This also prevents harness auto-injection for this rail (bench supplies override).
|
|
83
|
+
net vdd_dc : supply
|
|
84
|
+
VDC supplyDC = new VDC(V=harness.VDD) {
|
|
85
|
+
.P--vdd_dc
|
|
86
|
+
.N--gnd
|
|
87
|
+
}
|
|
88
|
+
VAC supplyAC = new VAC(A=1V, phase=0deg) {
|
|
89
|
+
.P--PWR
|
|
90
|
+
.N--vdd_dc
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Load impedance
|
|
94
|
+
Impedor loadZ = new Impedor(Z=env.LoadImpedance) {
|
|
95
|
+
.P--OUT
|
|
96
|
+
.N--gnd
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Power supply rejection ratio (PSRR) bench for single-ended input / single-ended output amplifiers.
|
|
102
|
+
//
|
|
103
|
+
// Applies AC ripple to the supply rail and measures the resulting output perturbation.
|
|
104
|
+
// SupplyGain is the supply-to-output gain (Asupply). PSRR is output-referred PSRR
|
|
105
|
+
// (does not depend on amplifier gain). InputReferredPSRR is gain-normalized PSRR.
|
|
106
|
+
bench SupplyToSERejectionSEInput extends AbstractPSRR {
|
|
107
|
+
stim IN : analog
|
|
108
|
+
stim PWR : supply
|
|
109
|
+
resp OUT : analog
|
|
110
|
+
|
|
111
|
+
fill {
|
|
112
|
+
net vcm : analog
|
|
113
|
+
net gnd : ground
|
|
114
|
+
GND g = new GND() { .GND--gnd }
|
|
115
|
+
|
|
116
|
+
// Bias the input so the DUT input is not floating (avoids singular matrices in AC).
|
|
117
|
+
VDC biasDC = new VDC(V=env.InputCommonModeRange) {
|
|
118
|
+
.P--vcm
|
|
119
|
+
.N--gnd
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
Impedor sourceZ = new Impedor(Z=env.SourceImpedance) { }
|
|
123
|
+
sourceZ.P--vcm
|
|
124
|
+
sourceZ.N--IN
|
|
125
|
+
|
|
126
|
+
// Supply bias + ripple injection:
|
|
127
|
+
// - VDC sets the nominal rail voltage
|
|
128
|
+
// - VAC injects small-signal ripple on top
|
|
129
|
+
// This also prevents harness auto-injection for this rail (bench supplies override).
|
|
130
|
+
net vdd_dc : supply
|
|
131
|
+
VDC supplyDC = new VDC(V=harness.VDD) {
|
|
132
|
+
.P--vdd_dc
|
|
133
|
+
.N--gnd
|
|
134
|
+
}
|
|
135
|
+
VAC supplyAC = new VAC(A=1V, phase=0deg) {
|
|
136
|
+
.P--PWR
|
|
137
|
+
.N--vdd_dc
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Load impedance
|
|
141
|
+
Impedor loadZ = new Impedor(Z=env.LoadImpedance) {
|
|
142
|
+
.P--OUT
|
|
143
|
+
.N--gnd
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Power supply rejection ratio (PSRR) bench for fully-differential output amplifiers.
|
|
149
|
+
//
|
|
150
|
+
// Applies AC ripple to the supply rail and measures the resulting differential output perturbation.
|
|
151
|
+
// SupplyGain is the supply-to-output gain (Asupply). PSRR is output-referred PSRR
|
|
152
|
+
// (does not depend on amplifier gain). InputReferredPSRR is gain-normalized PSRR.
|
|
153
|
+
bench SupplyToDiffRejection extends AbstractPSRR {
|
|
154
|
+
stim IN : Diff
|
|
155
|
+
stim PWR : supply
|
|
156
|
+
resp OUT : Diff
|
|
157
|
+
|
|
158
|
+
fill {
|
|
159
|
+
net vcm : analog
|
|
160
|
+
net gnd : ground
|
|
161
|
+
GND g = new GND() { .GND--gnd }
|
|
162
|
+
|
|
163
|
+
// Bias the input common-mode so the DUT inputs are not floating (avoids singular matrices in AC).
|
|
164
|
+
VDC commonModeVDC = new VDC(V=env.InputCommonModeRange) {
|
|
165
|
+
.P--vcm
|
|
166
|
+
.N--gnd
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
Impedor sourceP = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
170
|
+
Impedor sourceN = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
171
|
+
|
|
172
|
+
sourceP.P--vcm
|
|
173
|
+
sourceP.N--IN.P
|
|
174
|
+
|
|
175
|
+
sourceN.P--vcm
|
|
176
|
+
sourceN.N--IN.N
|
|
177
|
+
|
|
178
|
+
// Supply bias + ripple injection:
|
|
179
|
+
// - VDC sets the nominal rail voltage
|
|
180
|
+
// - VAC injects small-signal ripple on top
|
|
181
|
+
// This also prevents harness auto-injection for this rail (bench supplies override).
|
|
182
|
+
net vdd_dc : supply
|
|
183
|
+
VDC supplyDC = new VDC(V=harness.VDD) {
|
|
184
|
+
.P--vdd_dc
|
|
185
|
+
.N--gnd
|
|
186
|
+
}
|
|
187
|
+
VAC supplyAC = new VAC(A=1V, phase=0deg) {
|
|
188
|
+
.P--PWR
|
|
189
|
+
.N--vdd_dc
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Load impedances for differential output
|
|
193
|
+
Impedor loadP = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
194
|
+
.P--OUT.P
|
|
195
|
+
.N--gnd
|
|
196
|
+
}
|
|
197
|
+
Impedor loadN = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
198
|
+
.P--OUT.N
|
|
199
|
+
.N--gnd
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
VERSION 3.1
|
|
2
|
+
|
|
3
|
+
library lib.std.bench
|
|
4
|
+
|
|
5
|
+
// Transient benches (time-domain).
|
|
6
|
+
//
|
|
7
|
+
// Benches are parameterized by stimulus frequency. Different invocations with different
|
|
8
|
+
// frequencies produce separate testbench instances (e.g., tran_bench(stim_freq=1kHz)::...).
|
|
9
|
+
|
|
10
|
+
abstract bench AbstractTran(Frequency stim_freq = 1kHz) {
|
|
11
|
+
abstract stim IN
|
|
12
|
+
abstract resp OUT
|
|
13
|
+
|
|
14
|
+
analysis {
|
|
15
|
+
// Capture 10 cycles total and evaluate on the last cycle for steady-state measurement.
|
|
16
|
+
TranAnalysis tran = new TranAnalysis(
|
|
17
|
+
step=period(stim_freq) / 200,
|
|
18
|
+
start=9 * period(stim_freq),
|
|
19
|
+
stop=10 * period(stim_freq)
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
measurements {
|
|
24
|
+
measurement OutputSwing : V {
|
|
25
|
+
VoltageWaveform vout = voltage(tran, OUT)
|
|
26
|
+
return vout.Max() - vout.Min()
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
bench DiffToSETran extends AbstractTran {
|
|
32
|
+
stim IN : Diff
|
|
33
|
+
resp OUT : analog
|
|
34
|
+
|
|
35
|
+
fill {
|
|
36
|
+
net vcm : analog
|
|
37
|
+
net gnd : ground
|
|
38
|
+
|
|
39
|
+
GND _ = new GND() {
|
|
40
|
+
.GND--gnd
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Bias the input common-mode.
|
|
44
|
+
VDC commonModeVDC = new VDC(V=env.InputCommonModeRange) {
|
|
45
|
+
.P--vcm
|
|
46
|
+
.N--gnd
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Differential sine excitation around vcm at the specified frequency.
|
|
50
|
+
//
|
|
51
|
+
// Choose a modest default amplitude so the metric is "about usable swing" rather than
|
|
52
|
+
// "rail-to-rail saturation". Circuits can override by setting env.TranInputAmplitude.
|
|
53
|
+
VSIN inP = new VSIN(A=25mV, freq=stim_freq, phase=0deg) {
|
|
54
|
+
.N--vcm
|
|
55
|
+
}
|
|
56
|
+
VSIN inN = new VSIN(A=25mV, freq=stim_freq, phase=180deg) {
|
|
57
|
+
.N--vcm
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Impedor sourceP = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
61
|
+
Impedor sourceN = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
62
|
+
|
|
63
|
+
inP.P--sourceP.P
|
|
64
|
+
sourceP.N--IN.P
|
|
65
|
+
|
|
66
|
+
inN.P--sourceN.P
|
|
67
|
+
sourceN.N--IN.N
|
|
68
|
+
|
|
69
|
+
// Default load model uses env.LoadImpedance (consistent with AC benches).
|
|
70
|
+
Impedor loadZ = new Impedor(Z=env.LoadImpedance) {
|
|
71
|
+
.P--OUT
|
|
72
|
+
.N--gnd
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
bench DiffToDiffTran extends AbstractTran {
|
|
78
|
+
stim IN : Diff
|
|
79
|
+
resp OUT : Diff
|
|
80
|
+
|
|
81
|
+
fill {
|
|
82
|
+
net vcm : analog
|
|
83
|
+
net gnd : ground
|
|
84
|
+
|
|
85
|
+
GND _ = new GND() {
|
|
86
|
+
.GND--gnd
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Bias the input common-mode.
|
|
90
|
+
VDC commonModeVDC = new VDC(V=env.InputCommonModeRange) {
|
|
91
|
+
.P--vcm
|
|
92
|
+
.N--gnd
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Differential sine excitation around vcm at the specified frequency.
|
|
96
|
+
//
|
|
97
|
+
// Choose a modest default amplitude so the metric is "about usable swing" rather than
|
|
98
|
+
// "rail-to-rail saturation". Circuits can override by setting env.TranInputAmplitude.
|
|
99
|
+
VSIN inP = new VSIN(A=25mV, freq=stim_freq, phase=0deg) {
|
|
100
|
+
.N--vcm
|
|
101
|
+
}
|
|
102
|
+
VSIN inN = new VSIN(A=25mV, freq=stim_freq, phase=180deg) {
|
|
103
|
+
.N--vcm
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
Impedor sourceP = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
107
|
+
Impedor sourceN = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
108
|
+
|
|
109
|
+
inP.P--sourceP.P
|
|
110
|
+
sourceP.N--IN.P
|
|
111
|
+
|
|
112
|
+
inN.P--sourceN.P
|
|
113
|
+
sourceN.N--IN.N
|
|
114
|
+
|
|
115
|
+
// Differential target load. Diff benches split this to per-side shunts via DiffToShunt().
|
|
116
|
+
Impedor loadP = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
117
|
+
.P--OUT.P
|
|
118
|
+
.N--gnd
|
|
119
|
+
}
|
|
120
|
+
Impedor loadN = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
121
|
+
.P--OUT.N
|
|
122
|
+
.N--gnd
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
bench SEToSETran extends AbstractTran {
|
|
128
|
+
stim IN : analog
|
|
129
|
+
resp OUT : analog
|
|
130
|
+
|
|
131
|
+
fill {
|
|
132
|
+
net vcm : analog
|
|
133
|
+
net gnd : ground
|
|
134
|
+
|
|
135
|
+
GND _ = new GND() {
|
|
136
|
+
.GND--gnd
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Bias the input common-mode.
|
|
140
|
+
VDC biasDC = new VDC(V=env.InputCommonModeRange) {
|
|
141
|
+
.P--vcm
|
|
142
|
+
.N--gnd
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Single-ended sine excitation around vcm at the specified frequency.
|
|
146
|
+
//
|
|
147
|
+
// Choose a modest default amplitude so the metric is "about usable swing" rather than
|
|
148
|
+
// "rail-to-rail saturation". Circuits can override by setting env.TranInputAmplitude.
|
|
149
|
+
VSIN vin = new VSIN(A=25mV, freq=stim_freq, phase=0deg) {
|
|
150
|
+
.N--vcm
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Impedor sourceZ = new Impedor(Z=env.SourceImpedance) { }
|
|
154
|
+
|
|
155
|
+
vin.P--sourceZ.P
|
|
156
|
+
sourceZ.N--IN
|
|
157
|
+
|
|
158
|
+
// Default load model uses env.LoadImpedance (consistent with AC benches).
|
|
159
|
+
Impedor loadZ = new Impedor(Z=env.LoadImpedance) {
|
|
160
|
+
.P--OUT
|
|
161
|
+
.N--gnd
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
VERSION 3.1
|
|
2
|
+
|
|
3
|
+
library lib.std.bench
|
|
4
|
+
|
|
5
|
+
function calc_passband_freq(ACAnalysis ac, Frequency hp, Frequency lp) : Frequency {
|
|
6
|
+
Frequency f = sqrt(hp * lp)
|
|
7
|
+
|
|
8
|
+
if f < ac.start { return ac.start }
|
|
9
|
+
if f > ac.stop { return ac.stop }
|
|
10
|
+
return f
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function infer_hp_corner(Frequency fallback) : Frequency {
|
|
14
|
+
if constraints.HighpassBandwidth { return constraints.HighpassBandwidth }
|
|
15
|
+
return fallback
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function infer_lp_corner(ACAnalysis ac, Frequency lpConstraint, Frequency gbwConstraint) : Frequency {
|
|
19
|
+
if lpConstraint { return lpConstraint }
|
|
20
|
+
return ac.stop
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function calc_passband_gain(ACAnalysis ac, stim IN, resp OUT, Frequency lpConstraint, Frequency gbwConstraint) : VoltageRatio {
|
|
24
|
+
TransferFunction H = transfer(ac, IN, OUT)
|
|
25
|
+
GainSpectrum G = db20(H.Mag())
|
|
26
|
+
|
|
27
|
+
Frequency hp = infer_hp_corner(1Hz)
|
|
28
|
+
Frequency lp = infer_lp_corner(ac, lpConstraint, gbwConstraint)
|
|
29
|
+
Frequency fpb = calc_passband_freq(ac, hp, lp)
|
|
30
|
+
|
|
31
|
+
return G.ValueAt(fpb)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function calc_gain_bandwidth(ACAnalysis ac, stim IN, resp OUT) : Frequency {
|
|
35
|
+
TransferFunction H = transfer(ac, IN, OUT)
|
|
36
|
+
GainSpectrum G = db20(H.Mag())
|
|
37
|
+
|
|
38
|
+
return G.FindCrossing(0dB, dir=falling, cross=1, from=ac.start, to=ac.stop)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function calc_phase_margin(ACAnalysis ac, stim IN, resp OUT) : Phase {
|
|
42
|
+
// Approximate unity-feedback phase margin from the open-loop transfer function:
|
|
43
|
+
// PM = 180deg + phase(A(jw)) at the gain crossover (|A|=1, i.e. 0dB).
|
|
44
|
+
TransferFunction H = transfer(ac, IN, OUT)
|
|
45
|
+
GainSpectrum G = db20(H.Mag())
|
|
46
|
+
PhaseSpectrum P = H.Phase()
|
|
47
|
+
|
|
48
|
+
Frequency fg = G.FindCrossing(0dB, dir=falling, cross=1, from=ac.start, to=ac.stop)
|
|
49
|
+
Phase phi = P.ValueAt(fg)
|
|
50
|
+
return 180deg + phi
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function calc_lowpass_bandwidth(ACAnalysis ac, stim IN, resp OUT, Frequency lpConstraint, Frequency gbwConstraint) : Frequency {
|
|
54
|
+
TransferFunction H = transfer(ac, IN, OUT)
|
|
55
|
+
GainSpectrum G = db20(H.Mag())
|
|
56
|
+
|
|
57
|
+
Frequency hp = infer_hp_corner(1Hz)
|
|
58
|
+
Frequency lp = infer_lp_corner(ac, lpConstraint, gbwConstraint)
|
|
59
|
+
Frequency fpb = calc_passband_freq(ac, hp, lp)
|
|
60
|
+
|
|
61
|
+
VoltageRatio gpb = G.ValueAt(fpb)
|
|
62
|
+
VoltageRatio thr = gpb - 3dB
|
|
63
|
+
|
|
64
|
+
return G.FindCrossing(thr, dir=falling, cross=1, from=fpb, to=ac.stop)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function calc_highpass_bandwidth(ACAnalysis ac, stim IN, resp OUT, Frequency lpConstraint, Frequency gbwConstraint) : Frequency {
|
|
68
|
+
TransferFunction H = transfer(ac, IN, OUT)
|
|
69
|
+
GainSpectrum G = db20(H.Mag())
|
|
70
|
+
|
|
71
|
+
Frequency hp = infer_hp_corner(1Hz)
|
|
72
|
+
Frequency lp = infer_lp_corner(ac, lpConstraint, gbwConstraint)
|
|
73
|
+
Frequency fpb = calc_passband_freq(ac, hp, lp)
|
|
74
|
+
|
|
75
|
+
VoltageRatio gpb = G.ValueAt(fpb)
|
|
76
|
+
VoltageRatio thr = gpb - 3dB
|
|
77
|
+
|
|
78
|
+
return G.FindCrossing(thr, dir=rising, cross=1, from=ac.start, to=fpb)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
abstract bench AbstractTransfer {
|
|
82
|
+
abstract stim IN
|
|
83
|
+
abstract resp OUT
|
|
84
|
+
|
|
85
|
+
analysis {
|
|
86
|
+
ACAnalysis ac = new ACAnalysis(
|
|
87
|
+
space=Log,
|
|
88
|
+
samples=100,
|
|
89
|
+
start=(if constraints.HighpassBandwidth { constraints.HighpassBandwidth * 0.1 } else { 1Hz }),
|
|
90
|
+
stop=(if constraints.GainBandwidth { constraints.GainBandwidth * 10 } else { 10GHz }))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
measurements {
|
|
94
|
+
measurement PassbandGain : dB {
|
|
95
|
+
return calc_passband_gain(ac, IN, OUT, constraints.LowpassBandwidth, constraints.GainBandwidth)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
measurement GainBandwidth : Hz {
|
|
99
|
+
return calc_gain_bandwidth(ac, IN, OUT)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
measurement PhaseMargin : deg {
|
|
103
|
+
return calc_phase_margin(ac, IN, OUT)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
measurement LowpassBandwidth : Hz {
|
|
107
|
+
return calc_lowpass_bandwidth(ac, IN, OUT, constraints.LowpassBandwidth, constraints.GainBandwidth)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
measurement HighpassBandwidth : Hz {
|
|
111
|
+
return calc_highpass_bandwidth(ac, IN, OUT, constraints.LowpassBandwidth, constraints.GainBandwidth)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
measurement BandpassBandwidth : Hz {
|
|
115
|
+
return abs(LowpassBandwidth() - HighpassBandwidth())
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
bench DiffToSETransfer extends AbstractTransfer {
|
|
121
|
+
stim IN : Diff
|
|
122
|
+
resp OUT : analog
|
|
123
|
+
|
|
124
|
+
fill {
|
|
125
|
+
net vcm : analog
|
|
126
|
+
net gnd : ground
|
|
127
|
+
|
|
128
|
+
GND g = new GND() {
|
|
129
|
+
.GND--gnd
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
VDC commonModeVDC = new VDC(V=env.InputCommonModeRange) {
|
|
133
|
+
.P--vcm
|
|
134
|
+
.N--gnd
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
VAC acP = new VAC(A=0.5V, phase=0deg) {
|
|
138
|
+
.N--vcm
|
|
139
|
+
}
|
|
140
|
+
VAC acN = new VAC(A=0.5V, phase=180deg) {
|
|
141
|
+
.N--vcm
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Impedor sourceP = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
145
|
+
Impedor sourceN = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
146
|
+
|
|
147
|
+
acP.P--sourceP.P
|
|
148
|
+
sourceP.N--IN.P
|
|
149
|
+
|
|
150
|
+
acN.P--sourceN.P
|
|
151
|
+
sourceN.N--IN.N
|
|
152
|
+
|
|
153
|
+
Impedor loadZ = new Impedor(Z=env.LoadImpedance) {
|
|
154
|
+
.P--OUT
|
|
155
|
+
.N--gnd
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
bench DiffToDiffTransfer extends AbstractTransfer {
|
|
161
|
+
stim IN : Diff
|
|
162
|
+
resp OUT : Diff
|
|
163
|
+
|
|
164
|
+
fill {
|
|
165
|
+
net vcm : analog
|
|
166
|
+
net gnd : ground
|
|
167
|
+
|
|
168
|
+
GND g = new GND() {
|
|
169
|
+
.GND--gnd
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
VDC commonModeVDC = new VDC(V=env.InputCommonModeRange) {
|
|
173
|
+
.P--vcm
|
|
174
|
+
.N--gnd
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
VAC acP = new VAC(A=0.5V, phase=0deg) {
|
|
178
|
+
.N--vcm
|
|
179
|
+
}
|
|
180
|
+
VAC acN = new VAC(A=0.5V, phase=180deg) {
|
|
181
|
+
.N--vcm
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
Impedor sourceP = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
185
|
+
Impedor sourceN = new Impedor(Z=env.SourceImpedance.DiffToShunt()) { }
|
|
186
|
+
|
|
187
|
+
acP.P--sourceP.P
|
|
188
|
+
sourceP.N--IN.P
|
|
189
|
+
|
|
190
|
+
acN.P--sourceN.P
|
|
191
|
+
sourceN.N--IN.N
|
|
192
|
+
|
|
193
|
+
Impedor loadP = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
194
|
+
.P--OUT.P
|
|
195
|
+
.N--gnd
|
|
196
|
+
}
|
|
197
|
+
Impedor loadN = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
198
|
+
.P--OUT.N
|
|
199
|
+
.N--gnd
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
bench SEToSETransfer extends AbstractTransfer {
|
|
205
|
+
stim IN : analog
|
|
206
|
+
resp OUT : analog
|
|
207
|
+
|
|
208
|
+
fill {
|
|
209
|
+
net vcm : analog
|
|
210
|
+
net gnd : ground
|
|
211
|
+
|
|
212
|
+
GND g = new GND() {
|
|
213
|
+
.GND--gnd
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
VDC biasDC = new VDC(V=env.InputCommonModeRange) {
|
|
217
|
+
.P--vcm
|
|
218
|
+
.N--gnd
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
VAC ac = new VAC(A=1V, phase=0deg) {
|
|
222
|
+
.N--vcm
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
Impedor sourceZ = new Impedor(Z=env.SourceImpedance) { }
|
|
226
|
+
|
|
227
|
+
ac.P--sourceZ.P
|
|
228
|
+
sourceZ.N--IN
|
|
229
|
+
|
|
230
|
+
Impedor loadZ = new Impedor(Z=env.LoadImpedance) {
|
|
231
|
+
.P--OUT
|
|
232
|
+
.N--gnd
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
abstract bench AbstractCMRejection {
|
|
238
|
+
abstract stim CM
|
|
239
|
+
abstract resp OUT
|
|
240
|
+
|
|
241
|
+
analysis {
|
|
242
|
+
ACAnalysis ac = new ACAnalysis(
|
|
243
|
+
space=Log,
|
|
244
|
+
samples=100,
|
|
245
|
+
start=(if constraints.HighpassBandwidth { constraints.HighpassBandwidth * 0.1 } else { 1Hz }),
|
|
246
|
+
stop=(if constraints.GainBandwidth { constraints.GainBandwidth * 10 } else { 10GHz }))
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
measurements {
|
|
250
|
+
measurement CommonModeGain : dB {
|
|
251
|
+
return calc_passband_gain(ac, CM, OUT, constraints.LowpassBandwidth, constraints.GainBandwidth)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
measurement CMRR(VoltageRatio dmGain) : dB {
|
|
255
|
+
VoltageRatio cmGain = CommonModeGain()
|
|
256
|
+
return (dmGain - cmGain)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
bench DiffCMRejection extends AbstractCMRejection {
|
|
262
|
+
stim CM : analog
|
|
263
|
+
resp OUT : Diff
|
|
264
|
+
|
|
265
|
+
fill {
|
|
266
|
+
net vcm : analog
|
|
267
|
+
net gnd : ground
|
|
268
|
+
|
|
269
|
+
GND g = new GND() {
|
|
270
|
+
.GND--gnd
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
VDC biasDC = new VDC(V=env.InputCommonModeRange) {
|
|
274
|
+
.P--vcm
|
|
275
|
+
.N--gnd
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
VAC cmAC = new VAC(A=1V, phase=0deg) {
|
|
279
|
+
.N--vcm
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
Impedor sourceZ = new Impedor(Z=env.SourceImpedance) { }
|
|
283
|
+
|
|
284
|
+
cmAC.P--sourceZ.P
|
|
285
|
+
sourceZ.N--CM
|
|
286
|
+
|
|
287
|
+
Impedor loadP = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
288
|
+
.P--OUT.P
|
|
289
|
+
.N--gnd
|
|
290
|
+
}
|
|
291
|
+
Impedor loadN = new Impedor(Z=env.LoadImpedance.DiffToShunt()) {
|
|
292
|
+
.P--OUT.N
|
|
293
|
+
.N--gnd
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Common-mode rejection bench for differential-input / single-ended-output amplifiers.
|
|
299
|
+
//
|
|
300
|
+
// Applies a common-mode signal to both differential inputs (inputs tied together) and measures the
|
|
301
|
+
// resulting single-ended output. CommonModeGain is the CM-to-out gain (Acm).
|
|
302
|
+
// CMRR takes the differential gain as a parameter and computes CMRR = Ad - Acm (in dB).
|
|
303
|
+
bench DiffToSECMRejection extends AbstractCMRejection {
|
|
304
|
+
stim CM : analog
|
|
305
|
+
resp OUT : analog
|
|
306
|
+
|
|
307
|
+
fill {
|
|
308
|
+
net vcm : analog
|
|
309
|
+
net gnd : ground
|
|
310
|
+
|
|
311
|
+
GND g = new GND() { .GND--gnd }
|
|
312
|
+
|
|
313
|
+
VDC biasDC = new VDC(V=env.InputCommonModeRange) {
|
|
314
|
+
.P--vcm
|
|
315
|
+
.N--gnd
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
VAC cmAC = new VAC(A=1V, phase=0deg) { .N--vcm }
|
|
319
|
+
|
|
320
|
+
Impedor srcZ = new Impedor(Z=env.SourceImpedance) { }
|
|
321
|
+
cmAC.P--srcZ.P
|
|
322
|
+
srcZ.N--CM
|
|
323
|
+
|
|
324
|
+
Impedor loadZ = new Impedor(Z=env.LoadImpedance) {
|
|
325
|
+
.P--OUT
|
|
326
|
+
.N--gnd
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|