In that case, you might find JosephsonCircuits.jl helpful. It is a harmonic balance solver for arbitrary netlists containing capacitors, inductors, resistors, mutual inductors, and Josephson junctions (which you don’t need). It performs nodal analysis in the node flux basis. Here is an example of simulating the scattering parameters and node voltages of a transmission line with an impedance mismatch. The input is a SPICE style netlist with a unique component name, the two nodes, and the component value (here I define them with symbolic variables but you can enter numbers if you prefer):
using JosephsonCircuits
using Plots
@variables R C L
circuit = Tuple{String,String,String,Num}[]
# port on the input side
push!(circuit,("P$(1)_$(0)","1","0",1))
push!(circuit,("R$(1)_$(0)","1","0",R))
Ncells=50
#first half unit cell
push!(circuit,("C$(1)_$(0)","1","0",C/2))
push!(circuit,("L$(1)_$(2)","1","2",L))
j=2
for i = 2:Ncells-1
push!(circuit,("C$(j)_$(0)","$(j)","$(0)",C))
push!(circuit,("L$(j)_$(j+1)","$(j)","$(j+1)",L))
# increment the index
j+=1
end
#last jj
push!(circuit,("C$(j)_$(0)","$(j)","$(0)",C/2))
push!(circuit,("R$(j)_$(0)","$(j)","$(0)",R))
# port on the output side
push!(circuit,("P$(j)_$(0)","$(j)","$(0)",2))
circuitdefs = Dict(
L => 5e-10,
C => 45.0e-15,
R => 50.0,
)
w=2*pi*(1.0:0.01:80)*1e9
@time sol = hblinsolve(w, circuit, circuitdefs;returnvoltage=true)
p1=plot(sol.w/(2*pi*1e9),
10*log10.(abs2.(sol.S(
outputmode=(0,),
outputport=2,
inputmode=(0,),
inputport=1,
freqindex=:),
)),
ylim=(-40,30),label="S21",
xlabel="Signal Frequency (GHz)",
legend=:bottomright,
title="Scattering Parameters",
ylabel="dB")
plot!(sol.w/(2*pi*1e9),
10*log10.(abs2.(sol.S((0,),1,(0,),2,:))),
label="S12",
)
plot!(sol.w/(2*pi*1e9),
10*log10.(abs2.(sol.S((0,),1,(0,),1,:))),
label="S11",
)
plot!(sol.w/(2*pi*1e9),
10*log10.(abs2.(sol.S((0,),2,(0,),2,:))),
label="S22",
)
and we can compare the simulated voltages at one node to those from the SPICE solver WRspice packaged in XicTools_jll.jl (or Xyce.jl, etc).
using XicTools_jll
n = JosephsonCircuits.exportnetlist(circuit,circuitdefs);
input = JosephsonCircuits.wrspice_input_ac(n.netlist,sol.w/(2*pi),(2,1),n.portcurrent); # warning: this wrapper code is very crude
@time output = JosephsonCircuits.spice_run(input,XicTools_jll.wrspice());
and plot them both:
plot(sol.w/(2*pi*1e9),real.(sol.voltage(
outputmode=(0,),
node="1",
inputmode=(0,),
inputport=1,
freqindex=:)),label="Re, JosephsonCircuits.jl",ylabel="Voltage (V)",xlabel="Frequency (GHz)")
plot!(sol.w/(2*pi*1e9),imag.(sol.voltage(
outputmode=(0,),
node="1",
inputmode=(0,),
inputport=1,
freqindex=:)),label="Im, JosephsonCircuits.jl")
plot!(sol.w/(2*pi*1e9),
real.(output.values["V"][1,:]),
linecolor=:black,
linestyle=:dash,
label="Re, WRspice")
plot!(sol.w/(2*pi*1e9),
imag.(output.values["V"][1,:]),
linecolor=:gray,
linestyle=:dash,
label="Im, WRspice")
You could also take the sparse capacitance, conductance, and inverse inductances matrices generated from the netlist and solve them yourself (a lot of the codebase is for dealing with nonlinear systems and quantum noise which you probably don’t need). Here is a snippet of code to generate those:
nm = JosephsonCircuits.numericmatrices(circuit, circuitdefs);
# capacitance matrix
nm.Cnm
# inverse inductance matrix
nm.invLnm
# conductance matrix
nm.Gnm