Skip to main content

Overview

KiCad includes integrated SPICE simulation capabilities through ngspice, allowing you to simulate analog and mixed-signal circuits directly from your schematic. The simulation system supports AC, DC, transient, and noise analysis.

Architecture

The simulation system consists of several key components:

NGSPICE Interface

Defined in /eeschema/sim/ngspice.h:
class NGSPICE : public SPICE_SIMULATOR
{
public:
    NGSPICE();
    virtual ~NGSPICE();
    
    // Initialize simulator
    void Init( const SPICE_SETTINGS* aSettings = nullptr ) override;
    
    // Attach model and prepare simulation
    bool Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel,
                 const wxString& aSimCommand,
                 unsigned aSimOptions,
                 const wxString& aInputPath,
                 REPORTER& aReporter ) override;
    
    // Load and run netlist
    bool LoadNetlist( const std::string& aNetlist ) override;
    bool Run() override;
    bool Stop() override;
    
    // Query simulation results
    std::vector<std::string> AllPlots() const override;
    std::vector<std::string> GetPlotVectors( const std::string& aPlot ) override;
    std::vector<double> GetRealPlotVector( const std::string& aName ) override;
    std::vector<double> GetImagPlotVector( const std::string& aName ) override;
};

Simulation Library Manager

Defined in /eeschema/sim/sim_lib_mgr.h:
class SIM_LIB_MGR
{
public:
    SIM_LIB_MGR( const PROJECT* aPrj );
    
    void SetLibrary( const wxString& aLibraryPath, REPORTER& aReporter );
    
    // Create models from symbols
    SIM_LIBRARY::MODEL CreateModel(
        const SCH_SHEET_PATH* aSheetPath,
        SCH_SYMBOL& aSymbol,
        bool aResolve,
        int aDepth,
        const wxString& aVariantName,
        REPORTER& aReporter,
        const wxString& aMergedSimPins = wxEmptyString
    );
    
    // Get all libraries and models
    std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>>
        GetLibraries() const;
    std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
};

SPICE Model Types

KiCad supports various SPICE model types:

Built-in Primitive Models

  • R: Resistor
  • C: Capacitor
  • L: Inductor
  • V: Voltage source (DC, AC, transient)
  • I: Current source
  • D: Diode
  • Q: BJT transistor
  • M: MOSFET
  • J: JFET
  • X: Subcircuit

Assigning Models to Symbols

In the schematic, symbols are assigned simulation models through fields:
Sim.Device: R
Sim.Type: RESISTOR
Sim.Params: r=10k
Or reference external SPICE models:
Sim.Library: /path/to/model.lib
Sim.Name: 2N2222
Sim.Pins: 1=C 2=B 3=E

Running Simulations

DC Operating Point

Analyze DC voltages and currents:
.op

DC Sweep

Sweep a voltage or current source:
.dc V1 0 10 0.1

AC Analysis

Frequency domain analysis:
.ac dec 10 1 100k
Parameters:
  • dec: Decade sweep (10 points per decade)
  • 1: Start frequency (1 Hz)
  • 100k: End frequency (100 kHz)

Transient Analysis

Time-domain simulation:
.tran 1u 100u
Parameters:
  • 1u: Time step (1 microsecond)
  • 100u: Total time (100 microseconds)

Noise Analysis

.noise v(out) V1 dec 10 1 100k

SPICE Netlist Export

KiCad generates SPICE netlists from schematics using /eeschema/netlist_exporters/netlist_exporter_spice.h:

Netlist Structure

* KiCad SPICE Netlist
* Circuit: My Amplifier
* Date: 2024-01-15

.title My Amplifier

* Components
R1 1 2 10k
R2 2 0 1k
C1 2 3 100n
Q1 3 2 0 2N2222

* Sources
V1 1 0 DC 12

* Analysis
.tran 1u 1m
.ac dec 10 1 1MEG

.control
run
plot v(3)
.endc

.end

Probe Points and Measurements

Voltage Probes

.print tran v(out) v(in) v(ref)

Current Probes

Insert voltage source with 0V to measure current:
Vmeas 5 6 DC 0
.print tran i(Vmeas)

Power Calculations

.print tran {v(out)*i(Vmeas)}

Python Scripting Integration

While KiCad’s simulation is primarily GUI-based, you can export and run netlists programmatically:
import subprocess
import os

def run_spice_simulation(netlist_path, output_path):
    """
    Run ngspice simulation from Python
    """
    # Create control file
    control_script = f"""
    source {netlist_path}
    run
    print all > {output_path}
    quit
    """
    
    control_file = netlist_path.replace('.cir', '.control')
    with open(control_file, 'w') as f:
        f.write(control_script)
    
    # Run ngspice
    result = subprocess.run(
        ['ngspice', '-b', control_file],
        capture_output=True,
        text=True
    )
    
    return result.returncode == 0

def parse_results(output_path):
    """
    Parse simulation results
    """
    with open(output_path, 'r') as f:
        lines = f.readlines()
    
    # Parse data (simplified)
    data = {}
    for line in lines:
        if line.strip() and not line.startswith('#'):
            parts = line.split()
            if len(parts) >= 2:
                data[parts[0]] = float(parts[1])
    
    return data

# Usage
if run_spice_simulation('circuit.cir', 'results.txt'):
    results = parse_results('results.txt')
    print(f"Output voltage: {results.get('v(out)', 'N/A')}")

Advanced SPICE Features

Behavioral Sources

* Arbitrary voltage source
BV1 out 0 V={sin(2*pi*1k*time)}

* Arbitrary current source
BI1 out 0 I={V(in)*0.001}

Subcircuits

.subckt opamp in+ in- vcc vee out
Rin in+ in- 1MEG
Cin in+ in- 1pF
Gm 0 int {(V(in+)-V(in-))*0.001}
Rout int out 75
Cout int 0 10pF
.ends opamp

* Usage
X1 inp inn vcc vee output opamp

Parameter Sweeps

.param R1val=1k
R1 1 2 {R1val}

.step param R1val list 1k 2k 5k 10k

Temperature Analysis

.temp 0 25 50 75 100
.tran 1u 1m

Model Libraries

Loading External Models

.lib /usr/share/ngspice/models/standard.lib
.include /path/to/custom_models.mod

IBIS Models

For signal integrity analysis, KiCad supports IBIS models through /eeschema/sim/kibis/:
class KIBIS
{
public:
    bool Init( const std::string& aFileName );
    KIBIS_COMPONENT* GetComponent( const std::string& aName );
    std::vector<KIBIS_PIN> GetPins( const std::string& aComponent );
};

Performance Optimization

Convergence Issues

* Improve convergence
.options RELTOL=1e-4
.options ABSTOL=1e-10
.options VNTOL=1e-4

* Reduce timestep
.tran 0.1u 1m 0 0.01u

Memory Management

* Limit memory usage
.options MAXORD=2
.options ITL1=300
.options ITL4=100

Simulation Results Analysis

Fourier Analysis

.fourier 1kHz v(out)

Distortion Analysis

.distortion dec 10 1 100k -0.1

Pole-Zero Analysis

.pz v(out) V1

Common Simulation Patterns

RC Low-Pass Filter

* Input
V1 in 0 AC 1

* Filter
R1 in out 1k
C1 out 0 159n

* Analysis
.ac dec 10 1 100k
.control
run
plot vdb(out)
.endc

BJT Amplifier

* Bias
VCC vcc 0 DC 12
R1 vcc base 47k
R2 base 0 10k
Rc vcc coll 2k
Re emit 0 500

* Coupling
Cin in base 10u
Cout coll out 10u

* Transistor
Q1 coll base emit 2N2222

* Signal
Vin in 0 AC 0.01

.ac dec 10 10 1MEG

Troubleshooting

Common Errors

“Singular matrix”
  • Add small resistor to floating nodes
  • Check for loops of voltage sources or capacitors
“Timestep too small”
  • Reduce RELTOL
  • Add small resistance to capacitors
  • Check for unrealistic component values
“No convergence”
  • Set better initial conditions
  • Use .nodeset to hint at solutions
  • Reduce circuit complexity

Best Practices

  1. Start simple: Verify basic operation before adding complexity
  2. Use realistic values: Avoid extreme component values
  3. Set appropriate tolerances: Balance speed vs. accuracy
  4. Include parasitics: Add ESR, ESL for real-world behavior
  5. Validate with measurements: Compare simulation to hardware
  6. Document models: Comment model sources and parameters

See Also

Build docs developers (and LLMs) love