A Quick Comparison of LTSpice and Julia DiffEq
LTSpice is probably the most popular version of SPICE (Simulation Program with Integrated Circuit Emphasis), a simulator for electronic circuits. It is proprietary software distributed as freeware by Analog Devices but originally developed at Linear Technology which was acquired by Analog.
The Julia programming language has perhaps the best suite of tools for solving differential equations in DifferentialEquations.jl, so it's natural to compare the performance of them.
Here we're comparing simulations of the following schematic, which I copied from this article by Michael Engelhardt, the author of LTSpice.

This circuit features a lossless resonant tank circuit, so after a starting kick from the piece-wise linear (PWL) current source it should repeat the same sinewaves forever.
Here's the circuit expressed as a pair of ODEs, written with a function signature compatible with the DifferentialEquations.jl solvers:
LCIode (generic function with 1 method)xxxxxxxxxxfunction LCIode(u,p,t) V, Il = u C1 = 0.1e-6 L1 = 50e-3 dV = 1/C1*(I1(t)-Il) dIl = V/L1 [dV, dIl]endHere's the piecewise-linear current source:
I1 (generic function with 1 method)xxxxxxxxxxI1(t) = t>200e-6 ? 0.0 : t>100e-6 ? 200e-3-200e-3/200e-6*t : 100e-3/100e-6*tHere we set up the solution with initial conditions, a time span, and tolerance options.
It was necessary to tighten the tolerances from the default values so that the resonance would not lose or gain energy significantly over the 1.0 second span.
run (generic function with 1 method)xxxxxxxxxxfunction run(ode) u0 = [0.0, 0.0] tspan = (0.0, 1.0) prob = ODEProblem(ode, u0, tspan) solve(prob, abstol=1e-6, reltol=1e-6)endAnd here we run it.
xxxxxxxxxxsol=run(LCIode);Meanwhile, let's run the LTSpice version and import the voltage waveform to Julia.
xxxxxxxxxxLTSsol=CSV.File("SDFig2.txt", normalizenames=true);Let's plot the results against each other.
plotboth (generic function with 1 method)xxxxxxxxxxfunction plotboth(tspan...) p1 = plot(sol, vars=[1],xlims=tspan, label="DiffEq.jl") p2 = plot(LTSsol.time, LTSsol.V_n001_, xlims=tspan, label="LTSpice") plot(p1,p2,layout=(2,1),link=:x)endThese start off the same:
xxxxxxxxxxplotboth(0.0, 2e-3)But somehwere along the way they get out of phase. This plot shows the final 2 ms of the simulation. These should be the same frequency but they're not!
xxxxxxxxxxplotboth(0.998, 1.0)Let's multiply the results together; the envelope shows us how different the frequencies are. We seem to be off by about 19.5 cycles over 1 second.
xxxxxxxxxxplot(LTSsol.time, [u[1] for u ∈ sol.(LTSsol.time,idxs=[1])] .* LTSsol.V_n001_, title="product of solutions showing beating", leg=false)The resonant frequency should be
freqcount (generic function with 1 method)xxxxxxxxxxfunction freqcount(times, values) # find first neg-to-pos zero crossing i = 1 ncycles = 0 tlast = 0 t0 = 0 while true if values[i+1]>0 && values[i]≤0 t0 = times[i] break end i += 1 end # find last neg-to-pos zero crossing while i < lastindex(times)-1 i += 1 if values[i+1]>0 && values[i]≤0 ncycles += 1 tlast = times[i] end end ncycles/(tlast-t0)endMeasure the frequency of the Julia DiffEq solution:
2250.866948589712xxxxxxxxxxfreqcount(sol.t, [u[1] for u in sol.u])Measure the frequency of the LTSpice solution:
2231.357208116857xxxxxxxxxxfreqcount(LTSsol.time, LTSsol.V_n001_)Okay, it looks like we found out which solution is right!
Did we pay for that correct answer with more compute time? How long did Julia take?
8.582 ms (84241 allocations: 11.33 MiB)
xxxxxxxxxxwith_terminal() do run(LCIode)endHow long did LTSpice take?
From LTSPice menus: View, SPICE Error Log:
Circuit: * D:\SPICE\SDFig2.asc
.OP point found by inspection.
Date: Wed Dec 16 12:25:34 2020
Total elapsed time: 0.983 seconds.
tnom = 27
temp = 27
method = modified trap
totiter = 130620
traniter = 130620
tranpoints = 65311
accept = 46151
rejected = 19160
matrix size = 1
fillins = 0
solver = Normal
Matrix Compiler1: off 0.0/0.0/[0.0]
Matrix Compiler2: 43 bytes object code size 0.0/0.0/[0.0]
So for this particular problem Julia is approximately 100x faster!
Is this an unfair comparison?
One possible reason is that LTSpice uses "self-authoring assembly language source written at run time", which sounds a bit like JIT compilation so it may be unfair to compare the @btime result of Julia (which removes compilation time) to the LTSpice time.
So let's extend the simulation time by 10x. If the LTSpice assembly authoring took a big chunk of the 1.003 s, it should become less significant.
Temporarily making that change gives 97 ms for Julia and 8 s for LTSpice. So the 100x remains (as does the frequency error).
Some final comments
This is just a quick experiment and not necessarily representative of other problems.
I'm sure I did not explore all options for making these faster. Maybe there is some low hanging fruit on the LTSpice side. If history is any guide, I'm sure the Julia code can be sped up, maybe by picking a different solver algorithm.
Perhaps LTSpice is optimized for larger circuits and performs relatively slowly here. This is in some ways a toy example. A more complicated example should be tried.
When using LTSpice you don't have to write your own differential equations! While not a big deal for this circuit, it's not something one wants to do for a circuit of any complexity. Anyone got a SPICE netlist to DiffEq translator?
This notebook was prepared using the Pluto reactive notebook system for Julia.
Revised 2022-12-17 to resolve inconsistent timings due to laptop power settings.
Julia Version 1.5.3 Commit 788b2c77c1 (2020-11-09 13:37 UTC) Platform Info: OS: Windows (x86_64-w64-mingw32) CPU: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz WORD_SIZE: 64 LIBM: libopenlibm LLVM: libLLVM-9.0.1 (ORCJIT, skylake) Environment: JULIA_REVISE_WORKER_ONLY = 1 Status `C:\Users\klaff\.julia\environments\v1.5\Project.toml` [0c46a032] DifferentialEquations v6.15.0 [90137ffa] StaticArrays v0.12.5
xxxxxxxxxxwith_terminal() do versioninfo() Pkg.status(["DifferentialEquations","StaticArrays"])endxxxxxxxxxxbegin using DifferentialEquations using StaticArrays using Plots using PlutoUI using CSV using BenchmarkTools using Pkgend