Skip to content

Python API Reference

A superfície suportada para usuários é a API Python do módulo pulsim.

Fluxo principal de uso

  1. YamlParser carrega netlist e opções.
  2. Ajuste fino de SimulationOptions em runtime.
  3. Simulator executa DC/transiente/periódico.
  4. SimulationResult entrega sinais e telemetria.

Tipos principais

Tipo Papel
YamlParserOptions, YamlParser Parse/validação de YAML pulsim-v1.
Circuit Grafo/circuito pronto para simulação.
SimulationOptions Configuração completa da simulação.
Simulator Execução de dc_operating_point, run_transient, run_periodic_shooting, run_harmonic_balance.
SimulationResult Sinais (time, states), eventos, telemetria e resumos de perdas/térmico.

As APIs de transiente em Python (Simulator.run_transient, run_transient_streaming, run_transient_shared e ps.run_transient) aplicam perfil robusto por padrão para reduzir falhas de convergência.

Compatibilidade de migração

  • ps.run_transient(...) permanece disponível para compatibilidade procedural.
  • A superfície canônica para novas integrações é YamlParser + SimulationOptions + Simulator.
  • Em casos de migração YAML, prefira simulation.step_mode em vez de simulation.adaptive_timestep (legado) e evite campos removidos como simulation.backend/simulation.sundials/simulation.advanced.

Configuração tipada de núcleo magnético

Para fluxos Python-first com componentes virtuais, a API expõe:

  • MagneticCoreConfig
  • MagneticCoreConfigError
  • apply_magnetic_core_config(...)

Exemplo (merge determinístico em numeric_params + metadata):

import pulsim as ps

cfg = ps.MagneticCoreConfig(
    model="hysteresis",
    loss_policy="loss_summary",
    core_loss_k=0.2,
    core_loss_alpha=2.0,
    core_loss_freq_coeff=1e-4,
    hysteresis_strength=0.25,
)

numeric_params, metadata = ps.apply_magnetic_core_config({}, {}, cfg)
print(numeric_params["core_loss_k"])
print(metadata["magnetic_core_model"])

Quando inválido, cfg.validate() (ou o merge) lança MagneticCoreConfigError com code e field estáveis para automação.

Exemplo completo

import pulsim as ps

parser = ps.YamlParser(ps.YamlParserOptions())
circuit, options = parser.load("benchmarks/circuits/buck_converter.yaml")

options.newton_options.num_nodes = int(circuit.num_nodes())
options.newton_options.num_branches = int(circuit.num_branches())
options.linear_solver = ps.LinearSolverStackConfig.defaults()
options.integrator = ps.Integrator.TRBDF2
options.step_mode = ps.StepMode.Variable

sim = ps.Simulator(circuit, options)
result = sim.run_transient(circuit.initial_state())

print("success:", result.success)
print("steps:", result.total_steps)
print("newton_total:", result.newton_iterations_total)
print("linear_fallbacks:", result.linear_solver_telemetry.total_fallbacks)
print("backend_caps:", ps.backend_capabilities())

Atalho recomendado para transiente

Para uso direto em notebook, ps.run_transient(...) agora aplica fallback automático de robustez por padrão:

  • retry com dt menor e mais iterações de Newton;
  • regularização automática (bleeders + clamp de não linearidades) em caso de falha persistente.

Você pode desativar:

times, states, ok, msg = ps.run_transient(
    ckt, t0, t1, dt, x0,
    robust=False,
    auto_regularize=False,
)

Enums importantes

  • Integrator: Trapezoidal, BDF1..BDF5, TRBDF2, RosenbrockW, SDIRK2
  • ControlUpdateMode: Auto, Continuous, Discrete
  • LinearSolverKind: SparseLU, EnhancedSparseLU, KLU, GMRES, BiCGSTAB, CG
  • PreconditionerKind: None_, Jacobi, ILU0, ILUT, AMG (quando disponível)
  • SolverStatus, DCStrategy, SimulationEventType, FallbackReasonCode

Configurações que mais importam

Solver linear

  • LinearSolverStackConfig.order
  • LinearSolverStackConfig.fallback_order
  • LinearSolverStackConfig.auto_select
  • IterativeSolverConfig.preconditioner, max_iterations, tolerance

Newton e convergência

  • NewtonOptions.max_iterations
  • NewtonOptions.enable_limiting
  • NewtonOptions.max_voltage_step / max_current_step

Timestep e integrador

  • SimulationOptions.step_mode (StepMode.Fixed ou StepMode.Variable)
  • SimulationOptions.control_mode
  • SimulationOptions.control_sample_time
  • SimulationOptions.formulation_mode (FormulationMode.ProjectedWrapper ou FormulationMode.Direct)
  • SimulationOptions.direct_formulation_fallback
  • SimulationOptions.integrator
  • SimulationOptions.adaptive_timestep
  • SimulationOptions.timestep_config
  • SimulationOptions.lte_config

O caminho suportado usa o core nativo com step_mode + formulation_mode.

Controle em malha fechada

import pulsim as ps

options.control_mode = ps.ControlUpdateMode.Auto
options.control_sample_time = 0.0  # 0 => auto/continuous path

Semântica:

  • Auto: usa control_sample_time se > 0; caso contrário tenta inferir por frequência PWM.
  • Continuous: força atualização contínua de controle.
  • Discrete: aplica amostragem global para blocos PI/PID.

Térmico e perdas

  • SimulationOptions.enable_losses
  • SimulationOptions.switching_energy
  • SimulationOptions.thermal
  • SimulationOptions.thermal_devices

Resultados para análise

Campos úteis de SimulationResult:

  • time, states
  • events
  • success, final_status, message
  • newton_iterations_total, timestep_rejections
  • linear_solver_telemetry, fallback_trace
  • loss_summary, thermal_summary
  • component_electrothermal (deterministic per-component loss + temperature telemetry)
  • virtual_channels, virtual_channel_metadata

Traços térmicos canônicos no transiente

Quando as três condições abaixo são verdadeiras:

  • options.enable_losses == True
  • options.thermal.enable == True
  • componente com thermal habilitado (options.thermal_devices[name].enabled == True)

o backend exporta em result.virtual_channels um canal térmico por componente no formato:

  • T(<component_name>) (ex.: T(M1), T(Rload))

Contrato:

  • len(result.virtual_channels["T(M1)"]) == len(result.time)
  • component_electrothermal["M1"].final_temperature == last(T(M1))
  • component_electrothermal["M1"].peak_temperature == max(T(M1))
  • component_electrothermal["M1"].average_temperature == mean(T(M1))

Metadata recomendada para front-end (preenchida no backend):

  • result.virtual_channel_metadata["T(M1)"].domain == "thermal"
  • component_type == "thermal_trace"
  • source_component == "M1"
  • unit == "degC"

Electrothermal Result Example

result = sim.run_transient(circuit.initial_state())

for item in result.component_electrothermal:
    print(item.component_name, item.total_loss, item.peak_temperature)

trace_m1 = result.virtual_channels["T(M1)"]
meta_m1 = result.virtual_channel_metadata["T(M1)"]
print("trace samples:", len(trace_m1), "time samples:", len(result.time))
print("meta:", meta_m1.domain, meta_m1.source_component, meta_m1.unit)

component_electrothermal inclui todos os componentes elétricos não virtuais, com campos térmicos determinísticos mesmo quando a porta térmica não está habilitada.

For full YAML + Python electrothermal setup (global thermal block, component thermal ports, strict/non-strict parser behavior), see Electrothermal Workflow.