Skip to content

Commit 2108701

Browse files
added nand gate problem benchmark
1 parent 2d9d410 commit 2108701

File tree

1 file changed

+347
-0
lines changed

1 file changed

+347
-0
lines changed

benchmarks/DAE/NANDGateProblem.jmd

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
---
2+
title: NAND Gate Differential-Algebraic Equation (DAE) Work-Precision Diagrams
3+
author: Jayant Pranjal
4+
---
5+
6+
```julia
7+
using OrdinaryDiffEq, DiffEqDevTools, ModelingToolkit, ODEInterfaceDiffEq,
8+
Plots
9+
using LinearAlgebra
10+
using ModelingToolkit: t_nounits as t, D_nounits as D
11+
```
12+
13+
## Problem Parameters
14+
15+
```julia
16+
const RGS = 4.0
17+
const RGD = 4.0
18+
const RBS = 10.0
19+
const RBD = 10.0
20+
const CGS = 6e-5
21+
const CGD = 6e-5
22+
const CBD = 2.4e-5
23+
const CBS = 2.4e-5
24+
const C9 = 5e-5
25+
const DELTA = 0.02
26+
const CURIS = 1e-14
27+
const VTH = 25.85
28+
const VDD = 5.0
29+
const VBB = -2.5
30+
const VT0_DEPL = -2.43
31+
const CGAMMA_DEPL = 0.2
32+
const PHI_DEPL = 1.28
33+
const BETA_DEPL = 5.35e-4
34+
const VT0_ENH = 0.2
35+
const CGAMMA_ENH = 0.035
36+
const PHI_ENH = 1.01
37+
const BETA_ENH = 1.748e-3
38+
```
39+
40+
## Input Signal Functions
41+
42+
```julia
43+
function pulse(t, t_start, v_low, t_rise, v_high, t_high, t_fall, t_period)
44+
t_mod = mod(t, t_period)
45+
46+
if t_mod < t_start
47+
return v_low
48+
elseif t_mod < t_start + t_rise
49+
return v_low + (v_high - v_low) * (t_mod - t_start) / t_rise
50+
elseif t_mod < t_start + t_rise + t_high
51+
return v_high
52+
elseif t_mod < t_start + t_rise + t_high + t_fall
53+
return v_high - (v_high - v_low) * (t_mod - t_start - t_rise - t_high) / t_fall
54+
else
55+
return v_low
56+
end
57+
end
58+
59+
V1(t) = pulse(t, 0.0, 0.0, 5.0, 5.0, 5.0, 5.0, 20.0)
60+
V2(t) = pulse(t, 0.0, 0.0, 15.0, 5.0, 15.0, 5.0, 40.0)
61+
62+
function V1_derivative(t)
63+
t_mod = mod(t, 20.0)
64+
if 0.0 < t_mod < 5.0
65+
return 1.0
66+
elseif 10.0 < t_mod < 15.0
67+
return -1.0
68+
else
69+
return 0.0
70+
end
71+
end
72+
function V2_derivative(t)
73+
t_mod = mod(t, 40.0)
74+
if 0.0 < t_mod < 15.0
75+
return 1.0/15.0
76+
elseif 20.0 < t_mod < 35.0
77+
return -1.0/15.0
78+
else
79+
return 0.0
80+
end
81+
end
82+
```
83+
84+
## MOSFET Model Functions
85+
86+
```julia
87+
function gdsp(ned, vds, vgs, vbs)
88+
if ned == 1
89+
vt0, cgamma, phi, beta = VT0_DEPL, CGAMMA_DEPL, PHI_DEPL, BETA_DEPL
90+
else
91+
vt0, cgamma, phi, beta = VT0_ENH, CGAMMA_ENH, PHI_ENH, BETA_ENH
92+
end
93+
phi_vbs = max(phi - vbs, 1e-12)
94+
phi_safe = max(phi, 1e-12)
95+
vte = vt0 + cgamma * (sqrt(phi_vbs) - sqrt(phi_safe))
96+
if vgs - vte <= 0.0
97+
return 0.0
98+
elseif 0.0 < vgs - vte <= vds
99+
return -beta * (vgs - vte)^2 * (1.0 + DELTA * vds)
100+
elseif 0.0 < vds < vgs - vte
101+
return -beta * vds * (2.0 * (vgs - vte) - vds) * (1.0 + DELTA * vds)
102+
else
103+
return 0.0
104+
end
105+
end
106+
107+
function gdsm(ned, vds, vgd, vbd)
108+
if ned == 1
109+
vt0, cgamma, phi, beta = VT0_DEPL, CGAMMA_DEPL, PHI_DEPL, BETA_DEPL
110+
else
111+
vt0, cgamma, phi, beta = VT0_ENH, CGAMMA_ENH, PHI_ENH, BETA_ENH
112+
end
113+
phi_vbd = max(phi - vbd, 1e-12)
114+
phi_safe = max(phi, 1e-12)
115+
vte = vt0 + cgamma * (sqrt(phi_vbd) - sqrt(phi_safe))
116+
if vgd - vte <= 0.0
117+
return 0.0
118+
elseif 0.0 < vgd - vte <= -vds
119+
return beta * (vgd - vte)^2 * (1.0 - DELTA * vds)
120+
elseif 0.0 < -vds < vgd - vte
121+
return -beta * vds * (2.0 * (vgd - vte) + vds) * (1.0 - DELTA * vds)
122+
else
123+
return 0.0
124+
end
125+
end
126+
127+
function ids(ned, vds, vgs, vbs, vgd, vbd)
128+
if vds > 0.0
129+
return gdsp(ned, vds, vgs, vbs)
130+
elseif vds == 0.0
131+
return 0.0
132+
else
133+
return gdsm(ned, vds, vgd, vbd)
134+
end
135+
end
136+
137+
function ibs(vbs)
138+
if vbs <= 0.0
139+
return -CURIS * (exp(vbs / VTH) - 1.0)
140+
else
141+
return 0.0
142+
end
143+
end
144+
145+
function ibd(vbd)
146+
if vbd <= 0.0
147+
return -CURIS * (exp(vbd / VTH) - 1.0)
148+
else
149+
return 0.0
150+
end
151+
end
152+
```
153+
154+
## Capacitance Matrix Function
155+
156+
```julia
157+
function capacitance_matrix!(C, y, t)
158+
fill!(C, 0.0)
159+
160+
C[1,1] = CGS
161+
C[2,2] = CGD
162+
C[3,3] = CBS
163+
C[4,4] = CBD
164+
C[5,5] = 0.0
165+
C[6,6] = CGS
166+
C[7,7] = CGD
167+
C[8,8] = CBS
168+
C[9,9] = CBD
169+
C[10,10] = 0.0
170+
C[11,11] = CGS
171+
C[12,12] = CGD
172+
C[13,13] = CBS
173+
C[14,14] = CBD
174+
175+
return C
176+
end
177+
```
178+
179+
## DAE System Definition
180+
181+
```julia
182+
function nand_rhs!(f, y, p, t)
183+
v1 = V1(t)
184+
v2 = V2(t)
185+
v1d = V1_derivative(t)
186+
v2d = V2_derivative(t)
187+
188+
y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14 = y
189+
190+
f[1] = -(y1 - y5) / RGS - ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)
191+
f[2] = -(y2 - VDD) / RGD + ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)
192+
f[3] = -(y3 - VBB) / RBS + ibs(y3 - y5)
193+
f[4] = -(y4 - VBB) / RBD + ibd(y4 - VDD)
194+
f[5] = -(y5 - y1) / RGS - ibs(y3 - y5) - (y5 - y7) / RGD - ibd(y9 - y5)
195+
196+
f[6] = CGS * v1d - (y6 - y10) / RGS - ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)
197+
f[7] = CGD * v1d - (y7 - y5) / RGD + ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)
198+
f[8] = -(y8 - VBB) / RBS + ibs(y8 - y10)
199+
f[9] = -(y9 - VBB) / RBD + ibd(y9 - y5)
200+
f[10] = -(y10 - y6) / RGS - ibs(y8 - y10) - (y10 - y12) / RGD - ibd(y14 - y10)
201+
202+
f[11] = CGS * v2d - y11 / RGS - ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)
203+
f[12] = CGD * v2d - (y12 - y10) / RGD + ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)
204+
f[13] = -(y13 - VBB) / RBS + ibs(y13)
205+
f[14] = -(y14 - VBB) / RBD + ibd(y14 - y10)
206+
207+
return nothing
208+
end
209+
210+
function nand_mass_matrix!(M, y, p, t)
211+
capacitance_matrix!(M, y, t)
212+
return nothing
213+
end
214+
215+
function create_nand_problem()
216+
y0 = [5.0, 5.0, VBB, VBB, 5.0, 3.62385, 5.0, VBB, VBB, 3.62385, 0.0, 3.62385, VBB, VBB]
217+
dy0 = zeros(14)
218+
tspan = (0.0, 80.0)
219+
M = zeros(14, 14)
220+
capacitance_matrix!(M, y0, 0.0)
221+
f = ODEFunction(nand_rhs!, mass_matrix=M)
222+
prob = ODEProblem(f, y0, tspan)
223+
return prob
224+
end
225+
nand_prob = create_nand_problem()
226+
```
227+
228+
## Generate Reference Solution
229+
230+
```julia
231+
ref_sol = solve(nand_prob, Rodas5P(), abstol=1e-12, reltol=1e-12,
232+
tstops=0.0:5.0:80.0) # Include discontinuity points
233+
234+
plot(ref_sol, title="NAND Gate Circuit - Node Potentials",
235+
xlabel="Time", ylabel="Voltage (V)", legend=:outertopright)
236+
```
237+
238+
## Work-Precision Benchmarks
239+
240+
### High Tolerances
241+
242+
```julia
243+
abstols = 1.0 ./ 10.0 .^ (4:7)
244+
reltols = 1.0 ./ 10.0 .^ (1:4)
245+
246+
setups = [
247+
Dict(:alg=>Rosenbrock23()),
248+
Dict(:alg=>Rodas4()),
249+
Dict(:alg=>Rodas5P()),
250+
Dict(:alg=>FBDF()),
251+
Dict(:alg=>QNDF()),
252+
253+
254+
]
255+
256+
wp = WorkPrecisionSet([nand_prob], abstols, reltols, setups;
257+
save_everystep=false, appxsol=[ref_sol],
258+
maxiters=Int(1e6), numruns=5,
259+
tstops=0.0:5.0:80.0)
260+
plot(wp, title="NAND Gate DAE - Work-Precision (High Tolerances)")
261+
```
262+
263+
### Medium Tolerances
264+
265+
```julia
266+
abstols = 1.0 ./ 10.0 .^ (6:9)
267+
reltols = 1.0 ./ 10.0 .^ (3:6)
268+
269+
setups = [
270+
Dict(:alg=>Rodas4()),
271+
Dict(:alg=>Rodas5P()),
272+
Dict(:alg=>FBDF()),
273+
Dict(:alg=>QNDF()),
274+
275+
276+
]
277+
278+
wp = WorkPrecisionSet([nand_prob], abstols, reltols, setups;
279+
save_everystep=false, appxsol=[ref_sol],
280+
maxiters=Int(1e6), numruns=5,
281+
tstops=0.0:5.0:80.0)
282+
plot(wp, title="NAND Gate DAE - Work-Precision (Medium Tolerances)")
283+
```
284+
285+
### Low Tolerances (High Accuracy)
286+
287+
```julia
288+
abstols = 1.0 ./ 10.0 .^ (8:11)
289+
reltols = 1.0 ./ 10.0 .^ (5:8)
290+
291+
setups = [
292+
Dict(:alg=>Rodas5P()),
293+
Dict(:alg=>FBDF()),
294+
Dict(:alg=>QNDF()),
295+
296+
297+
]
298+
299+
wp = WorkPrecisionSet([nand_prob], abstols, reltols, setups;
300+
save_everystep=false, appxsol=[ref_sol],
301+
maxiters=Int(1e6), numruns=5,
302+
tstops=0.0:5.0:80.0)
303+
plot(wp, title="NAND Gate DAE - Work-Precision (Low Tolerances)")
304+
```
305+
306+
### Timeseries Error Analysis
307+
308+
```julia
309+
abstols = 1.0 ./ 10.0 .^ (5:8)
310+
reltols = 1.0 ./ 10.0 .^ (2:5)
311+
312+
setups = [
313+
Dict(:alg=>Rodas4()),
314+
Dict(:alg=>Rodas5P()),
315+
Dict(:alg=>FBDF()),
316+
317+
318+
]
319+
320+
wp = WorkPrecisionSet([nand_prob], abstols, reltols, setups;
321+
error_estimate=:l2, save_everystep=false,
322+
appxsol=[ref_sol], maxiters=Int(1e6), numruns=5,
323+
tstops=0.0:5.0:80.0)
324+
plot(wp, title="NAND Gate DAE - Timeseries Error Analysis")
325+
```
326+
327+
## Analysis of Key Nodes
328+
329+
```julia
330+
key_nodes = [1, 5, 6, 10, 11, 12] # Representative nodes from different parts of the circuit
331+
node_names = ["Node 1", "Node 5", "Node 6", "Node 10", "Node 11", "Node 12"]
332+
333+
p_nodes = plot()
334+
for (i, node) in enumerate(key_nodes)
335+
plot!(ref_sol.t, [u[node] for u in ref_sol.u],
336+
label=node_names[i], linewidth=2)
337+
end
338+
plot!(p_nodes, title="NAND Gate - Key Node Potentials",
339+
xlabel="Time (s)", ylabel="Voltage (V)", legend=:outertopright)
340+
```
341+
342+
### Conclusion
343+
344+
```julia, echo = false
345+
using SciMLBenchmarks
346+
SciMLBenchmarks.bench_footer(WEAVE_ARGS[:folder],WEAVE_ARGS[:file])
347+
```

0 commit comments

Comments
 (0)