Skip to content

Commit aa556d7

Browse files
committed
Restore singular mass matrix approach (singular is fine)
- Revert to original diagonal mass matrix with zeros for algebraic equations - Keep singular mass matrix for equations 5 and 10 (KCL constraints) - Maintain three formulations: mass matrix, DAEProblem, and ModelingToolkit - Restore original 14-variable system structure - Fix variable indexing in plotting and analysis sections The singular mass matrix is perfectly valid for DAE systems. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent dc033bb commit aa556d7

File tree

1 file changed

+58
-93
lines changed

1 file changed

+58
-93
lines changed

benchmarks/DAE/NANDGateProblem.jmd

Lines changed: 58 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -151,121 +151,87 @@ function ibd(vbd)
151151
end
152152
```
153153

154-
## ODE System Definition (converting DAE to ODE form)
154+
## DAE System Definition
155155

156156
```julia
157-
function nand_ode!(du, u, p, t)
157+
function nand_rhs!(f, y, p, t)
158158
v1 = V1(t)
159159
v2 = V2(t)
160160
v1d = V1_derivative(t)
161161
v2d = V2_derivative(t)
162162

163-
# Unpack the 12 differential variables (removing algebraic variables y5 and y10)
164-
y1, y2, y3, y4, y6, y7, y8, y9, y11, y12, y13, y14 = u
163+
y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14 = y
165164

166-
# Solve algebraic equations for y5 and y10
167-
# From KCL: y5 and y10 satisfy algebraic constraints
168-
# For now, use approximations or solve implicitly
165+
f[1] = -(y1 - y5) / RGS - ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)
166+
f[2] = -(y2 - VDD) / RGD + ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)
167+
f[3] = -(y3 - VBB) / RBS + ibs(y3 - y5)
168+
f[4] = -(y4 - VBB) / RBD + ibd(y4 - VDD)
169+
f[5] = -(y5 - y1) / RGS - ibs(y3 - y5) - (y5 - y7) / RGD - ibd(y9 - y5)
169170

170-
# For y5: -(y5 - y1) / RGS - ibs(y3 - y5) - (y5 - y7) / RGD - ibd(y9 - y5) = 0
171-
# Approximate solution (this could be improved with nonlinear solver)
172-
y5 = (y1/RGS + y7/RGD) / (1/RGS + 1/RGD) # Simplified linear approximation
171+
f[6] = CGS * v1d - (y6 - y10) / RGS - ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)
172+
f[7] = CGD * v1d - (y7 - y5) / RGD + ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)
173+
f[8] = -(y8 - VBB) / RBS + ibs(y8 - y10)
174+
f[9] = -(y9 - VBB) / RBD + ibd(y9 - y5)
175+
f[10] = -(y10 - y6) / RGS - ibs(y8 - y10) - (y10 - y12) / RGD - ibd(y14 - y10)
173176

174-
# For y10: -(y10 - y6) / RGS - ibs(y8 - y10) - (y10 - y12) / RGD - ibd(y14 - y10) = 0
175-
# Approximate solution
176-
y10 = (y6/RGS + y12/RGD) / (1/RGS + 1/RGD) # Simplified linear approximation
177-
178-
# Now compute derivatives for the 12 differential equations
179-
du[1] = (-(y1 - y5) / RGS - ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)) / CGS
180-
du[2] = (-(y2 - VDD) / RGD + ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)) / CGD
181-
du[3] = (-(y3 - VBB) / RBS + ibs(y3 - y5)) / CBS
182-
du[4] = (-(y4 - VBB) / RBD + ibd(y4 - VDD)) / CBD
183-
184-
du[5] = (CGS * v1d - (y6 - y10) / RGS - ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)) / CGS
185-
du[6] = (CGD * v1d - (y7 - y5) / RGD + ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)) / CGD
186-
du[7] = (-(y8 - VBB) / RBS + ibs(y8 - y10)) / CBS
187-
du[8] = (-(y9 - VBB) / RBD + ibd(y9 - y5)) / CBD
188-
189-
du[9] = (CGS * v2d - y11 / RGS - ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)) / CGS
190-
du[10] = (CGD * v2d - (y12 - y10) / RGD + ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)) / CGD
191-
du[11] = (-(y13 - VBB) / RBS + ibs(y13)) / CBS
192-
du[12] = (-(y14 - VBB) / RBD + ibd(y14 - y10)) / CBD
177+
f[11] = CGS * v2d - y11 / RGS - ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)
178+
f[12] = CGD * v2d - (y12 - y10) / RGD + ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)
179+
f[13] = -(y13 - VBB) / RBS + ibs(y13)
180+
f[14] = -(y14 - VBB) / RBD + ibd(y14 - y10)
193181

194182
return nothing
195183
end
196184

197-
# Initial conditions (12 variables, excluding algebraic y5 and y10)
198-
u0_ode = [5.0, 5.0, VBB, VBB, 3.62385, 5.0, VBB, VBB, 0.0, 3.62385, VBB, VBB]
199-
tspan = (0.0, 80.0)
200-
201-
# Create ODE problem
202-
ode_prob = ODEProblem(nand_ode!, u0_ode, tspan)
203-
204-
# Alternative: Create DAE problem using original formulation
205-
function nand_dae!(out, du, u, p, t)
206-
v1 = V1(t)
207-
v2 = V2(t)
208-
v1d = V1_derivative(t)
209-
v2d = V2_derivative(t)
210-
211-
y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14 = u
212-
dy1, dy2, dy3, dy4, dy5, dy6, dy7, dy8, dy9, dy10, dy11, dy12, dy13, dy14 = du
213-
214-
# Differential equations (with capacitors)
215-
out[1] = CGS * dy1 + (y1 - y5) / RGS + ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)
216-
out[2] = CGD * dy2 + (y2 - VDD) / RGD - ids(1, y2 - y1, y5 - y1, y3 - y5, y5 - y2, y4 - VDD)
217-
out[3] = CBS * dy3 + (y3 - VBB) / RBS - ibs(y3 - y5)
218-
out[4] = CBD * dy4 + (y4 - VBB) / RBD - ibd(y4 - VDD)
219-
220-
# Algebraic equations (KCL at nodes)
221-
out[5] = (y5 - y1) / RGS + ibs(y3 - y5) + (y5 - y7) / RGD + ibd(y9 - y5)
222-
223-
out[6] = CGS * dy6 - CGS * v1d + (y6 - y10) / RGS + ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)
224-
out[7] = CGD * dy7 - CGD * v1d + (y7 - y5) / RGD - ids(2, y7 - y6, v1 - y6, y8 - y10, v1 - y7, y9 - y5)
225-
out[8] = CBS * dy8 + (y8 - VBB) / RBS - ibs(y8 - y10)
226-
out[9] = CBD * dy9 + (y9 - VBB) / RBD - ibd(y9 - y5)
227-
228-
# Algebraic equation (KCL at node)
229-
out[10] = (y10 - y6) / RGS + ibs(y8 - y10) + (y10 - y12) / RGD + ibd(y14 - y10)
230-
231-
out[11] = CGS * dy11 - CGS * v2d + y11 / RGS + ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)
232-
out[12] = CGD * dy12 - CGD * v2d + (y12 - y10) / RGD - ids(2, y12 - y11, v2 - y11, y13, v2 - y12, y14 - y10)
233-
out[13] = CBS * dy13 + (y13 - VBB) / RBS - ibs(y13)
234-
out[14] = CBD * dy14 + (y14 - VBB) / RBD - ibd(y14 - y10)
235-
236-
return nothing
237-
end
238-
239-
# DAE initial conditions
240-
u0_dae = [5.0, 5.0, VBB, VBB, 5.0, 3.62385, 5.0, VBB, VBB, 3.62385, 0.0, 3.62385, VBB, VBB]
241-
du0_dae = zeros(14)
185+
# Mass matrix (singular is fine!)
186+
dirMassMatrix = [
187+
CGS 0 0 0 0 0 0 0 0 0 0 0 0 0
188+
0 CGD 0 0 0 0 0 0 0 0 0 0 0 0
189+
0 0 CBS 0 0 0 0 0 0 0 0 0 0 0
190+
0 0 0 CBD 0 0 0 0 0 0 0 0 0 0
191+
0 0 0 0 0 0 0 0 0 0 0 0 0 0
192+
0 0 0 0 0 CGS 0 0 0 0 0 0 0 0
193+
0 0 0 0 0 0 CGD 0 0 0 0 0 0 0
194+
0 0 0 0 0 0 0 CBS 0 0 0 0 0 0
195+
0 0 0 0 0 0 0 0 CBD 0 0 0 0 0
196+
0 0 0 0 0 0 0 0 0 0 0 0 0 0
197+
0 0 0 0 0 0 0 0 0 0 CGS 0 0 0
198+
0 0 0 0 0 0 0 0 0 0 0 CGD 0 0
199+
0 0 0 0 0 0 0 0 0 0 0 0 CBS 0
200+
0 0 0 0 0 0 0 0 0 0 0 0 0 CBD
201+
]
242202

243-
# Determine consistent initial conditions for DAE
244-
f_test = similar(u0_dae)
245-
nand_dae!(f_test, du0_dae, u0_dae, nothing, 0.0)
203+
# Initial conditions
204+
y0 = [5.0, 5.0, VBB, VBB, 5.0, 3.62385, 5.0, VBB, VBB, 3.62385, 0.0, 3.62385, VBB, VBB]
205+
tspan = (0.0, 80.0)
246206

247-
# Create DAE problem
248-
dae_prob = DAEProblem(nand_dae!, du0_dae, u0_dae, tspan)
207+
# Mass matrix problem (original approach)
208+
mmf = ODEFunction(nand_rhs!, mass_matrix=dirMassMatrix)
209+
mmprob = ODEProblem(mmf, y0, tspan)
249210

250-
# ModelingToolkit version via modelingtoolkitize on ODE problem
251-
mtk_sys = modelingtoolkitize(ode_prob)
211+
# ModelingToolkit version via modelingtoolkitize
212+
mtk_sys = modelingtoolkitize(mmprob)
252213
mtk_simplified = structural_simplify(mtk_sys)
253-
u0_mtk = [mtk_simplified.states[i] => ode_prob.u0[i] for i in 1:length(ode_prob.u0)]
254-
mtk_prob = ODEProblem(mtk_simplified, u0_mtk, tspan)
214+
u0_mtk = [mtk_simplified.states[i] => mmprob.u0[i] for i in 1:length(mmprob.u0)]
215+
mtkprob = ODEProblem(mtk_simplified, u0_mtk, mmprob.tspan)
216+
217+
# DAEProblem version
218+
du = mmprob.f(mmprob.u0, mmprob.p, 0.0)
219+
du0 = D.(unknowns(mtk_simplified)) .=> du
220+
daeprob = DAEProblem(mtk_simplified, du0, [], tspan)
255221

256222
# Generate reference solutions
257-
ref_sol = solve(ode_prob, Rodas5P(), abstol=1e-12, reltol=1e-12, tstops=0.0:5.0:80.0)
258-
dae_ref_sol = solve(dae_prob, IDA(), abstol=1e-10, reltol=1e-10, tstops=0.0:5.0:80.0)
259-
mtk_ref_sol = solve(mtk_prob, Rodas5P(), abstol=1e-12, reltol=1e-12, tstops=0.0:5.0:80.0)
223+
ref_sol = solve(mmprob, Rodas5P(), abstol=1e-12, reltol=1e-12, tstops=0.0:5.0:80.0)
224+
dae_ref_sol = solve(daeprob, IDA(), abstol=1e-10, reltol=1e-10, tstops=0.0:5.0:80.0)
225+
mtk_ref_sol = solve(mtkprob, Rodas5P(), abstol=1e-12, reltol=1e-12, tstops=0.0:5.0:80.0)
260226

261-
probs = [ode_prob, dae_prob, mtk_prob]
262-
refs = [ref_sol, dae_ref_sol, mtk_ref_sol]
227+
probs = [mmprob, daeprob, mtkprob]
228+
refs = [ref_sol, ref_sol, mtk_ref_sol]
263229
```
264230

265231
## Generate Reference Solution and Plot
266232

267233
```julia
268-
plot(ref_sol, title="NAND Gate Circuit - Node Potentials (ODE)",
234+
plot(ref_sol, title="NAND Gate Circuit - Node Potentials (Mass Matrix)",
269235
xlabel="Time", ylabel="Voltage (V)", legend=:outertopright)
270236
```
271237

@@ -416,10 +382,9 @@ plot(wp, title="NAND Gate DAE - Timeseries Errors (Low Tolerances)")
416382
## Analysis of Key Nodes
417383

418384
```julia
419-
# For ODE formulation (12 variables): y1, y2, y3, y4, y6, y7, y8, y9, y11, y12, y13, y14
420-
# Map to original indices for interpretation
421-
key_nodes = [1, 2, 5, 6, 9, 10] # Corresponds to y1, y2, y6, y7, y11, y12 in ODE form
422-
node_names = ["y1", "y2", "y6", "y7", "y11", "y12"]
385+
# Original 14-variable system: y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14
386+
key_nodes = [1, 5, 6, 10, 11, 12] # Representative nodes from different parts of the circuit
387+
node_names = ["Node 1", "Node 5", "Node 6", "Node 10", "Node 11", "Node 12"]
423388

424389
p_nodes = plot()
425390
for (i, node) in enumerate(key_nodes)

0 commit comments

Comments
 (0)