Source code for psc_sim.ltspice_netlist
"""LTspice .net deck generation (HTML-compatible topology)."""
from __future__ import annotations
from pathlib import Path
from typing import Literal
import numpy as np
from psc_sim.parameters import CellParameters
from psc_sim.simulation.defaults import DEFAULT_IV_SWEEP, DEFAULT_TRAN_SPEC
from psc_sim.simulation.eis_grid import default_eis_freqs
from psc_sim.simulation.types import SweepSpec, TranSpec
SimKind = Literal["dc", "ac", "tran"]
def _ac_list_command(freqs: np.ndarray) -> str:
parts = " ".join(f"{float(f):.6g}" for f in np.asarray(freqs, dtype=float))
return f".ac list {parts}"
def _format_lt_time(seconds: float) -> str:
return f"{seconds * 1e3:g}m"
def _pulse_string(tran: TranSpec) -> str:
return (
f"PULSE({tran.pulse_v_low:g} {tran.pulse_v_high:g} "
f"{_format_lt_time(tran.pulse_delay_s)} "
f"{_format_lt_time(tran.pulse_rise_s)} "
f"{_format_lt_time(tran.pulse_fall_s)} "
f"{_format_lt_time(tran.pulse_on_s)} "
f"{_format_lt_time(tran.pulse_period_s)})"
)
[docs]
def build_netlist(
p: CellParameters,
sim: SimKind = "dc",
spec: SweepSpec | None = None,
ac_freqs: np.ndarray | None = None,
tran_spec: TranSpec | None = None,
) -> str:
"""Return a .net deck matching `solar_cell_sim_app.html` `renderSpice` topology."""
if sim == "dc":
s = spec or DEFAULT_IV_SWEEP
cmd = f".dc Vbias {s.v_min:g} {s.v_max:g} {s.step:g}"
vac = ""
vtran = ""
elif sim == "ac":
freqs = ac_freqs if ac_freqs is not None else default_eis_freqs()
cmd = _ac_list_command(freqs)
vac = " AC 1"
vtran = ""
else:
tran = tran_spec or DEFAULT_TRAN_SPEC
cmd = f".tran {_format_lt_time(tran.t_step_s)} {_format_lt_time(tran.t_stop_s)}"
vac = ""
vtran = f" {_pulse_string(tran)}"
return f"""* psc-sim auto-generated (aligned with solar_cell_sim_app.html)
* Mode: {sim.upper()} | T={p.T:g} K
Iph_src net_A 0 DC {p.Iph:.12g}
.model DCEL D(Is={p.I0:.12g} N={p.n:g} Rs=0 Cjo={p.Cj:.12g} T_ABS={p.T:g})
D1 net_A net_K DCEL
Rs_ext net_K V_out {p.Rs:.12g}
Rsh_ext net_A 0 {p.Rsh:.12g}
Rion_ext V_out net_ion {p.Rion:.12g}
Cion_ext net_ion 0 {p.Cion:.12g}
Vbias V_out 0 DC 0{vac}{vtran}
{cmd}
.probe I(Vbias) V(V_out)
.end
"""
def write_netlist(
path: Path | str,
p: CellParameters,
sim: SimKind = "dc",
spec: SweepSpec | None = None,
ac_freqs: np.ndarray | None = None,
tran_spec: TranSpec | None = None,
) -> Path:
path = Path(path)
path.write_text(
build_netlist(p, sim, spec=spec, ac_freqs=ac_freqs, tran_spec=tran_spec),
encoding="utf-8",
)
return path