@@ -151,121 +151,87 @@ function ibd(vbd)
151151end
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
195183end
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 )
252213mtk_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
424389p_nodes = plot()
425390for (i, node) in enumerate(key_nodes)
0 commit comments