Package overview¶
PSC / solar cell equivalent-circuit simulation package.
- class psc_sim.CellParameters(I0: 'float' = 1e-08, n: 'float' = 1.5, Iph: 'float' = 0.03, Rs: 'float' = 1.0, Rsh: 'float' = 1000.0, T: 'float' = 300.0, Cj: 'float' = 1e-07, Rion: 'float' = 500.0, Cion: 'float' = 1e-06)[source]¶
- I0: float = 1e-08¶
- n: float = 1.5¶
- Iph: float = 0.03¶
- Rs: float = 1.0¶
- Rsh: float = 1000.0¶
- T: float = 300.0¶
- Cj: float = 1e-07¶
- Rion: float = 500.0¶
- Cion: float = 1e-06¶
- class psc_sim.CellMetrics(voc: 'float', isc: 'float', ff: 'float', pce: 'float', rs_extracted: 'float', pmax: 'float', vmp: 'float', imp: 'float')[source]¶
- voc: float¶
- isc: float¶
- ff: float¶
- pce: float¶
- rs_extracted: float¶
- pmax: float¶
- vmp: float¶
- imp: float¶
- class psc_sim.SimulationSession(params: CellParameters, iv_backend: IVBackend = <factory>, eis_backend: EISBackend = <factory>, iv_spec: SweepSpec = SweepSpec(v_min=-0.3, v_max=1.25, step=0.01), sr_spec: SweepSpec = SweepSpec(v_min=0.0, v_max=0.9, step=0.01), rs_spec: SweepSpec = SweepSpec(v_min=0.0, v_max=0.8, step=0.02), tran_spec: TranSpec = TranSpec(t_step_s=0.0001, t_stop_s=0.01, pulse_v_low=0.0, pulse_v_high=0.5, pulse_delay_s=0.001, pulse_rise_s=0.0001, pulse_fall_s=0.0001, pulse_on_s=0.005, pulse_period_s=0.01), lt_iv_result: IVResult | None = None, lt_eis_result: tuple[~numpy.ndarray, ~numpy.ndarray, ~numpy.ndarray] | None=None, lt_tran_result: TRANResult | None = None, measured_eis: MeasuredEIS | None = None, rs_fit_mask: RsFitMask | None = None, _dispatcher_cache: SimulationDispatcher | None = None, _dispatcher_key: tuple[float, ...] | None=None)[source]¶
Orchestrates cell parameters, sweep specs, Python/LTspice backends, and overlays.
Typical library usage:
from psc_sim import CellParameters, SimulationSession session = SimulationSession(CellParameters()) V, I, P = session.iv_curve() met = session.metrics() f, zre, zim = session.eis_default_sweep()
- params: CellParameters¶
- eis_backend: EISBackend¶
- tran_spec: TranSpec = TranSpec(t_step_s=0.0001, t_stop_s=0.01, pulse_v_low=0.0, pulse_v_high=0.5, pulse_delay_s=0.001, pulse_rise_s=0.0001, pulse_fall_s=0.0001, pulse_on_s=0.005, pulse_period_s=0.01)¶
- lt_eis_result: tuple[ndarray, ndarray, ndarray] | None = None¶
- lt_tran_result: TRANResult | None = None¶
- measured_eis: MeasuredEIS | None = None¶
- property dispatcher: SimulationDispatcher¶
- iv_curve(v_min: float | None = None, v_max: float | None = None, step: float | None = None, rs: float | None = None) tuple[ndarray, ndarray, ndarray][source]¶
- extract_rs_from_sr_inv(i_mA: ndarray | None = None, sr_inv: ndarray | None = None, mask: slice | ndarray | None = None, rs: float | None = None) float[source]¶
- metrics(pin_w_cm2: float = 0.1) CellMetrics[source]¶
- sr_vs_bias(v_min: float | None = None, v_max: float | None = None, step: float | None = None, rs: float | None = None) tuple[ndarray, ndarray][source]¶
- rs_extraction_series(v_min: float | None = None, v_max: float | None = None, step: float | None = None, rs: float | None = None) tuple[ndarray, ndarray][source]¶
- rs_fit(i_mA_lo: float | None = None, i_mA_hi: float | None = None, *, positive_generation: bool | None = None) float[source]¶
- run_ltspice_iv(ltspice_exe: str | Path | None = None, workdir: str | Path | None = None, *, spec: SweepSpec | None = None) IVResult[source]¶
- run_ltspice_eis(ltspice_exe: str | Path | None = None, workdir: str | Path | None = None) tuple[ndarray, ndarray, ndarray][source]¶
- run_ltspice_tran(ltspice_exe: str | Path | None = None, workdir: str | Path | None = None, *, tran_spec: TranSpec | None = None) TRANResult[source]¶
- class psc_sim.SweepSpec(v_min: 'float' = -0.3, v_max: 'float' = 1.25, step: 'float' = 0.01)[source]¶
- v_min: float = -0.3¶
- v_max: float = 1.25¶
- step: float = 0.01¶
- class psc_sim.IVResult(V: 'np.ndarray', I: 'np.ndarray', P: 'np.ndarray', truncated: 'bool' = False)[source]¶
- V: ndarray¶
- I: ndarray¶
- P: ndarray¶
- truncated: bool = False¶
- class psc_sim.TRANResult(t: ndarray, V: ndarray, I: ndarray)[source]¶
Transient waveform from LTspice .tran.
- t: ndarray¶
- V: ndarray¶
- I: ndarray¶
- psc_sim.residual_iv_implicit(I: float, V: float, p: CellParameters, rs: float) float[source]¶
f(I)=0 for the implicit one-diode equation.
Simulation layer¶
Unified access to IV and EIS simulation backends.
- class psc_sim.simulation.dispatcher.SimulationDispatcher(params: 'CellParameters', iv_backend: 'IVBackend' = <factory>, eis_backend: 'EISBackend' = <factory>, iv_spec: 'SweepSpec' = SweepSpec(v_min=-0.3, v_max=1.25, step=0.01))[source]¶
Thin orchestrator for parameters, backends, and sweep specs.
- class psc_sim.simulation.session.SimulationSession(params: CellParameters, iv_backend: IVBackend = <factory>, eis_backend: EISBackend = <factory>, iv_spec: SweepSpec = SweepSpec(v_min=-0.3, v_max=1.25, step=0.01), sr_spec: SweepSpec = SweepSpec(v_min=0.0, v_max=0.9, step=0.01), rs_spec: SweepSpec = SweepSpec(v_min=0.0, v_max=0.8, step=0.02), tran_spec: TranSpec = TranSpec(t_step_s=0.0001, t_stop_s=0.01, pulse_v_low=0.0, pulse_v_high=0.5, pulse_delay_s=0.001, pulse_rise_s=0.0001, pulse_fall_s=0.0001, pulse_on_s=0.005, pulse_period_s=0.01), lt_iv_result: IVResult | None = None, lt_eis_result: tuple[~numpy.ndarray, ~numpy.ndarray, ~numpy.ndarray] | None=None, lt_tran_result: TRANResult | None = None, measured_eis: MeasuredEIS | None = None, rs_fit_mask: RsFitMask | None = None, _dispatcher_cache: SimulationDispatcher | None = None, _dispatcher_key: tuple[float, ...] | None=None)[source]¶
Orchestrates cell parameters, sweep specs, Python/LTspice backends, and overlays.
Typical library usage:
from psc_sim import CellParameters, SimulationSession session = SimulationSession(CellParameters()) V, I, P = session.iv_curve() met = session.metrics() f, zre, zim = session.eis_default_sweep()
IV simulation backends: Python implicit solver and optional LTspice.
- class psc_sim.simulation.backends.PythonIVBackend[source]¶
Default backend: implicit 1-diode generation branch.
- class psc_sim.simulation.backends.LTspiceIVBackend(ltspice_exe: str | Path | None = None, workdir: str | Path | None = None)[source]¶
LTspice .dc sweep; point solve uses nearest sweep sample.
- class psc_sim.simulation.backends.LTspiceEISBackend(ltspice_exe: str | Path | None = None, workdir: str | Path | None = None)[source]¶
LTspice AC analysis; Z = V(v_out) / I(Vbias) from .raw.
- class psc_sim.simulation.backends.LTspiceTRANBackend(ltspice_exe: str | Path | None = None, workdir: str | Path | None = None, tran_spec: TranSpec | None = None)[source]¶
LTspice transient analysis from .tran netlist.
Shared types for I–V sweeps and simulation results.
- class psc_sim.simulation.types.SweepSpec(v_min: 'float' = -0.3, v_max: 'float' = 1.25, step: 'float' = 0.01)[source]¶
- class psc_sim.simulation.types.IVResult(V: 'np.ndarray', I: 'np.ndarray', P: 'np.ndarray', truncated: 'bool' = False)[source]¶
- class psc_sim.simulation.types.RsFitMask(i_mA_lo: float, i_mA_hi: float, positive_generation: bool = True)[source]¶
Rs linear-fit interval on the I_mA axis (generation-positive convention).
- class psc_sim.simulation.types.TranSpec(t_step_s: float = 0.0001, t_stop_s: float = 0.01, pulse_v_low: float = 0.0, pulse_v_high: float = 0.5, pulse_delay_s: float = 0.001, pulse_rise_s: float = 0.0001, pulse_fall_s: float = 0.0001, pulse_on_s: float = 0.005, pulse_period_s: float = 0.01)[source]¶
LTspice .tran step/stop and Vbias PULSE (times in seconds; formatted with m = ms).
GUI plots¶
GUI session bridge¶
Sync CellParameters between Qt spin boxes and SimulationSession.
Solvers and metrics¶
Implicit 1-diode I–V solver (generation branch, Voc bracketing, IV sweep).
- psc_sim.iv_solver.terminal_voc(p: CellParameters, rs: float | None = None, *, v_hi: float = 2.0) float | None[source]¶
Return the I=0 terminal voltage for the diode + shunt branch.
- psc_sim.iv_solver.solve_generation_current(V: float, p: CellParameters, rs: float, i_hint: float | None = None) float[source]¶
Solve the physical photovoltaic branch between generated current and Voc.
- psc_sim.iv_solver.solve_current(V: float, p: CellParameters, rs: float | None = None, *, i_hint: float | None = None) float[source]¶
Single public API for terminal current at bias V (generation branch).
- psc_sim.iv_solver.sweep_iv_curve(p: CellParameters, v_min: float = -0.3, v_max: float = 1.25, step: float = 0.01, rs: float | None = None, *, spec: SweepSpec | None = None) tuple[ndarray, ndarray, ndarray][source]¶
Voltage sweep with Voc truncation beyond the physical open-circuit point.
- psc_sim.iv_solver.sweep_iv_result(p: CellParameters, spec: SweepSpec, rs: float | None = None) IVResult[source]¶
Voltage sweep returning IVResult with truncation flag.
Lumped-element EIS: canonical series blocks (HTML computeEIS).
- psc_sim.eis_lumped.eis_impedance(p: CellParameters, freqs: ndarray) tuple[ndarray, ndarray][source]¶
Return Zre, Zim (mathematical Im) for the canonical series model:
Z = Rs + Z_parallel(Rsh, Cj) + (Rion + 1/(jω Cion))
Same algebra as solar_cell_sim_app.html
computeEIS.
Cell metrics, SR curves, and Rs extraction from the implicit diode model.
- psc_sim.cell_metrics.normalized_sr_at_bias(v: float, i: float, p: CellParameters, rs: float) tuple[float, float][source]¶
Return (SR, SRinv) = (dI/dIs, (dI/dIs)^-1) at one bias point.
- psc_sim.cell_metrics.rs_extraction_series(p: CellParameters, v0: float = 0.0, v1: float = 0.8, step: float = 0.02, rs: float | None = None, *, iv_backend: IVBackend | None = None) tuple[ndarray, ndarray][source]¶
Returns I_mA and SRinv = (dI/dIs)^-1.
- psc_sim.cell_metrics.extract_rs_from_sr_inv(p: CellParameters, i_mA: ndarray | None = None, sr_inv: ndarray | None = None, mask: slice | ndarray | None = None, rs: float | None = None, *, iv_backend: IVBackend | None = None) float[source]¶
Linear regression SRinv vs I_mA; Rs = slope * vt * 1000.
- psc_sim.cell_metrics.compute_metrics(p: CellParameters, pin_w_cm2: float = 0.1, *, iv_backend: IVBackend | None = None) CellMetrics[source]¶
Compute Voc/Isc/FF/PCE metrics using the same sampling as the HTML app.
LTspice bridge¶
LTspice .net deck generation (HTML-compatible topology).
- psc_sim.ltspice_netlist.build_netlist(p: CellParameters, sim: Literal['dc', 'ac', 'tran'] = 'dc', spec: SweepSpec | None = None, ac_freqs: ndarray | None = None, tran_spec: TranSpec | None = None) str[source]¶
Return a .net deck matching solar_cell_sim_app.html renderSpice topology.
LTspice batch execution and .raw parsing.
Settings and user presets¶
User settings persisted as JSON (preset, sweep, Rs mask, LTspice path, optional params).
- class psc_sim.settings.UserSettings(last_preset: 'str' = 'perovskite', iv_spec: 'SweepSpec' = <factory>, rs_fit_lo_mA: 'float' = 5.0, rs_fit_hi_mA: 'float' = 28.0, ltspice_exe: 'str | None' = None, custom_params: 'CellParameters | None' = None, tran_spec: 'TranSpec | None' = None, eis_plot_f_min_hz: 'float' = 1.0)[source]¶
Named user-defined parameter presets persisted beside settings.json.
- class psc_sim.user_presets.UserPreset(id: 'str', label: 'str', params: 'CellParameters', note: 'str' = '')[source]¶
Metrics for comparing Python vs LTspice I–V curves.
- psc_sim.compare_metrics.interpolate_current_at(v_grid: ndarray, v_samples: ndarray, i_samples: ndarray) ndarray[source]¶
Linear interpolation of I(V) onto v_grid; NaN outside sample range.
- psc_sim.compare_metrics.iv_curve_rmse(v_ref: ndarray, i_ref: ndarray, v_other: ndarray, i_other: ndarray) tuple[float, float][source]¶
Return (rmse_A, max_abs_error_A) of i_other interpolated onto v_ref.
EIS CSV and fitting¶
Load measured EIS CSV (see docs/conventions.md).
- psc_sim.eis_csv.load_eis_csv(path: str | Path) tuple[ndarray, ndarray, ndarray][source]¶
Return (freq_hz, zreal_ohm, zimag_ohm). Accepts header aliases.
- psc_sim.eis_csv.write_eis_csv(path: str | Path, freqs_hz: ndarray, zre: ndarray, zim: ndarray, *, zre_lt: ndarray | None = None, zim_lt: ndarray | None = None) None[source]¶
Write EIS CSV with canonical headers (see docs/conventions.md).
- psc_sim.eis_csv.rmse_z(f_meas: ndarray, zre_meas: ndarray, zim_meas: ndarray, zre_model: ndarray, zim_model: ndarray) float[source]¶
RMSE on real and imag (same length arrays). f_meas is accepted for API stability.
Fit measured EIS to the lumped Rs + (Rsh||Cj) + (Rion + Cion) model using scipy.
- psc_sim.eis_fit.fit_lumped_eis(freqs_hz: ndarray, zre_meas: ndarray, zim_meas: ndarray, p0: CellParameters, *, max_nfev: int = 500) tuple[CellParameters, Any][source]¶
Adjust Rs, Rsh, Cj, Rion, Cion to minimize (Zre,Zim) RMSE. I0,n,Iph,T are held fixed from
p0.
CLI¶
psc-sim command-line interface.