pub trait Component: Debug {
Show 60 methods
// Required methods
fn clone_box(&self) -> Box<dyn Component>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn dyn_eq(&self, other: &dyn Component) -> bool;
fn type_tag(&self) -> &'static str;
fn is_passive(&self) -> bool;
fn pin_config(&self) -> PinConfig;
fn graph_role(&self) -> GraphRole;
fn stamp_mna(
&self,
comp_id: &str,
n1: Option<usize>,
n2: Option<usize>,
mna: &mut MnaSystem,
sample_rate: f64,
) -> StampResult;
fn footprint_ref(&self) -> (&'static str, &'static str);
// Provided methods
fn solver_hint(&self) -> Option<SolverMethod> { ... }
fn ports(&self) -> Vec<(&'static str, &'static str)> { ... }
fn nonideal_fx(&self, _sample_rate: f64) -> Vec<NonIdealFx> { ... }
fn output_impedance(&self) -> OutputImpedance { ... }
fn signal_terminals(&self) -> SignalTerminals { ... }
fn port_semantic(&self, _pin_a: &str, _pin_b: &str) -> PortSemantic { ... }
fn is_nonlinear(&self) -> bool { ... }
fn is_active_ic(&self) -> bool { ... }
fn is_control_only(&self) -> bool { ... }
fn is_variable(&self) -> bool { ... }
fn modulation_pins(&self) -> &'static [&'static str] { ... }
fn edges(&self) -> Vec<ComponentEdge> { ... }
fn signal_adjacencies(&self) -> Vec<(&'static str, &'static str)> { ... }
fn pin_direction(&self, _pin: &str) -> PinDirection { ... }
fn resolve_edges(
&self,
_neighbors: &ResolveContext,
) -> Option<Vec<ComponentEdge>> { ... }
fn mna_vsource_count(&self) -> usize { ... }
fn mna_internal_node_count(&self) -> usize { ... }
fn stamp_mna_multi(
&self,
comp_id: &str,
ctx: &mut StampContext<'_>,
mna: &mut MnaSystem,
) -> StampResult { ... }
fn make_leaf(&self, _comp_id: &str, _sample_rate: f64) -> Option<DynNode> { ... }
fn resistance(&self) -> Option<f64> { ... }
fn capacitance(&self) -> Option<f64> { ... }
fn inductance(&self) -> Option<f64> { ... }
fn validate_values(&self, _comp_id: &str) -> Vec<(Severity, String)> { ... }
fn terminal_requirements(&self) -> Vec<(&'static str, Vec<NeighborReq>)> { ... }
fn classify_nonlinear(
&self,
_comp_id: &str,
_node_a: usize,
_node_b: usize,
_gnd_node: usize,
_node_names: &HashMap<String, usize>,
) -> Option<(NonlinearKind, Vec<usize>)> { ... }
fn controls(&self) -> Vec<ControlParam> { ... }
fn modulation_sink(&self, _pin: &str) -> Option<ModulationSink> { ... }
fn is_modulation_source(&self) -> bool { ... }
fn is_bjt(&self) -> bool { ... }
fn is_jfet(&self) -> bool { ... }
fn is_mosfet(&self) -> bool { ... }
fn is_tube(&self) -> bool { ... }
fn is_transformer(&self) -> bool { ... }
fn is_pot(&self) -> bool { ... }
fn is_diode_family(&self) -> bool { ... }
fn is_trigger(&self) -> bool { ... }
fn feedback_input_is_barrier(&self) -> bool { ... }
fn k_method_spec(&self) -> Option<KMethodSpec> { ... }
fn k_method_candidacy(&self) -> (bool, usize, &'static str) { ... }
fn is_simple_passive(&self) -> bool { ... }
fn is_gain_device(&self) -> bool { ... }
fn model_name(&self) -> Option<&str> { ... }
fn op_amp_type(&self) -> Option<OpAmpType> { ... }
fn pot_taper(&self) -> Option<PotTaper> { ... }
fn diode_type(&self) -> Option<DiodeType> { ... }
fn transformer_config(&self) -> Option<&TransformerConfig> { ... }
fn apply_bias(
&self,
_bias_voltages: &HashMap<String, f64>,
_supply_voltage: f64,
) -> BiasResult { ... }
fn symbol_name(&self) -> &'static str { ... }
fn layout_class(&self) -> &'static str { ... }
fn display_value(&self) -> Option<String> { ... }
}Expand description
The single source of truth for circuit component behavior.
Every circuit element in PedalKernel — resistors, capacitors, op-amps, BJTs, vacuum tubes, diodes, potentiometers, transformers, BBD delay lines — implements this trait. The compilation pipeline queries these methods to determine topology, solver strategy, stage boundaries, and runtime behavior without ever pattern-matching on concrete component types.
§Trait Object Support
Component is used as Box<dyn Component> throughout the pipeline. It
requires Debug for trait-object formatting and provides clone_box,
as_any, and dyn_eq for trait-object Clone, downcasting, and
PartialEq support.
§Method Groups
The trait methods are organized into functional groups:
§Identity
type_tag— human-readable name (e.g.,"resistor","NPN transistor")
§Ports
ports— terminal pairs carrying current. A resistor has 1 port(a, b); a BJT has 2 ports(base-emitter, collector-emitter).
§Signal Flow
signal_terminals— directionality for feedback analysis. Amplifiers declare input/output pins; passive components are bidirectional. The compiler uses Tarjan’s SCC algorithm on the directed signal graph to detect feedback loops.output_impedance— determines stage split points.OutputImpedance::VoltageSource(op-amps in feedback) allows safe splitting;OutputImpedance::Finite(passives, BJT collectors) prevents it. Based on Harold Black’s negative feedback theorem (1934).
§Non-Idealities
nonideal_fx— declares physical imperfections asNonIdealFxvariants. Values come from SPICE models and datasheets. The stage builder applies these as composable post-processing filters after the ideal WDF/MNA solver.
§Classification
is_passive— whether BFS can collect this component into a stageis_nonlinear— whether this needs a Newton-Raphson solveris_active_ic— whether this counts towardnum_activeis_variable— whether the edge impedance changes at runtime (triggers scattering matrix recomputation)- Family booleans:
is_bjt,is_jfet,is_tube,is_pot, etc.
§Graph Building
graph_role— how this component participates in the circuit graph.GraphRole::Edgefor passives,GraphRole::VcvsEdgefor op-amps,GraphRole::Virtualfor LFOs,GraphRole::Potfor potentiometers.edges— declares circuit edges withEdgeKindclassification.EdgeKind::LinearandEdgeKind::Reactiveform passive WDF trees;EdgeKind::Nonlinearseeds NR solver stages;EdgeKind::Vcvsforces R-node MNA.resolve_edges— context-dependent edge resolution. A JFET with its gate driven by an LFO resolves fromNonlineartoLinear(variable resistor).
§MNA Stamping
stamp_mna— stamp into a 2-terminal MNA system (resistors, caps)stamp_mna_multi— stamp with multi-terminal pin resolution (op-amps resolve pos/neg/out pins)mna_vsource_count— voltage sources needed (op-amps: 1)mna_internal_node_count— internal MNA nodes (op-amps: 1 for GBW pole)
§WDF Leaf Creation
make_leaf— create a runtime WDF leaf node (DynNode). Resistors, capacitors, and inductors return leaf nodes; nonlinear and virtual components returnNone.
§Pin Interface
pin_config— valid pin names and aliasespin_direction— inferred direction for layout (Input, Output, Up, Down)
§Controls
controls— declares runtime-adjustable parameters (ControlParam). Pots declarePotPosition; LFOs declareLfoRateandLfoDepth.modulation_sink— how this component receives LFO/envelope control signals, including bias voltage and modulation range.
§Validation
validate_values— design rule checks for suspicious or invalid component values (e.g., a 1-ohm resistor, a 1-farad capacitor).
§Implementing a New Component
To add a new component type to PedalKernel:
- Create a struct in
super::components(e.g.,MyDevice { model: String }) - Implement
Componentwith at minimum:type_tag()— return a human-readable nameis_passive()—truefor R/C/L,falsefor active devicespin_config()— declare valid pin namesgraph_role()— how it enters the circuit graphedges()— declare edge kinds (Linear, Nonlinear, etc.)stamp_mna()— stamp into MNA matrices (for R-node solving)footprint_ref()— KiCad symbol reference
- For nonlinear devices, also implement
classify_nonlinear()and setis_nonlinear() -> true - For active devices with feedback, implement
output_impedance()andsignal_terminals() - Add the DSL parser variant in
crate::dsl
No changes are needed in the graph builder, SPQR decomposer, stage builder, or any other pipeline module.
Required Methods§
Sourcefn as_any_mut(&mut self) -> &mut dyn Any
fn as_any_mut(&mut self) -> &mut dyn Any
Downcast to Any mutably for in-place mutation (e.g., tolerance tweaks).
Sourcefn dyn_eq(&self, other: &dyn Component) -> bool
fn dyn_eq(&self, other: &dyn Component) -> bool
Dynamic equality: returns true if other is the same concrete type
and compares equal.
Sourcefn type_tag(&self) -> &'static str
fn type_tag(&self) -> &'static str
Human-readable type name (e.g. “resistor”, “NPN transistor”).
Sourcefn is_passive(&self) -> bool
fn is_passive(&self) -> bool
Whether this component is passive (collectible by BFS for stage building).
Sourcefn pin_config(&self) -> PinConfig
fn pin_config(&self) -> PinConfig
Valid pins and aliases for this component type.
Sourcefn graph_role(&self) -> GraphRole
fn graph_role(&self) -> GraphRole
How this component participates in circuit graph construction.
Sourcefn stamp_mna(
&self,
comp_id: &str,
n1: Option<usize>,
n2: Option<usize>,
mna: &mut MnaSystem,
sample_rate: f64,
) -> StampResult
fn stamp_mna( &self, comp_id: &str, n1: Option<usize>, n2: Option<usize>, mna: &mut MnaSystem, sample_rate: f64, ) -> StampResult
Stamp into MNA system. Returns what was produced.
comp_id is the component’s string identifier (needed for DynNode::Pot).
n1/n2 are MNA node indices (None = ground).
Transformers return Skip — they need coupled-edge context from the caller.
Sourcefn footprint_ref(&self) -> (&'static str, &'static str)
fn footprint_ref(&self) -> (&'static str, &'static str)
KiCad symbol library reference and designator prefix.
Provided Methods§
Sourcefn solver_hint(&self) -> Option<SolverMethod>
fn solver_hint(&self) -> Option<SolverMethod>
Return the preferred nonlinear solver method for this component.
Returns None to accept the global default (Newton-Raphson).
Returns Some(SolverMethod::WrightOmega) to request the explicit
closed-form Wright Omega solver (diodes only).
The build pass uses this to choose between DiodePairRoot/DiodeRoot
(NR) and ExplicitDiodePairRoot/ExplicitDiodeRoot (WO).
Sourcefn ports(&self) -> Vec<(&'static str, &'static str)>
fn ports(&self) -> Vec<(&'static str, &'static str)>
Terminal pairs carrying current through this component.
Each port = one graph edge. A resistor has 1 port (a, b). A BJT has 2 ports (base-emitter, collector-emitter). A pot has 2 ports (a-wiper, wiper-b). An op-amp has 1 port (neg-out, pos is voltage-sense).
Sourcefn nonideal_fx(&self, _sample_rate: f64) -> Vec<NonIdealFx>
fn nonideal_fx(&self, _sample_rate: f64) -> Vec<NonIdealFx>
Non-ideal behaviors for this component (GBW, slew, rails, thermal, etc.).
Each component declares what non-idealities it has. Values come from the SPICE model / datasheet lookup. The stage builder attaches them as post-processing. No pattern matching on component type.
Default: empty vec (ideal component).
Sourcefn output_impedance(&self) -> OutputImpedance
fn output_impedance(&self) -> OutputImpedance
Output impedance at this component’s output pin.
VoltageSource means the output node voltage is determined entirely
by the component (via feedback), independent of downstream load.
The compiler can safely split the circuit at these nodes.
Finite (default) means splitting here would change impedances
and break the transfer function.
Sourcefn signal_terminals(&self) -> SignalTerminals
fn signal_terminals(&self) -> SignalTerminals
Signal flow classification for this component’s pins.
Drives feedback analysis: amplifier input→output defines the feedback cycle direction. Passive components have no directionality.
Sourcefn port_semantic(&self, _pin_a: &str, _pin_b: &str) -> PortSemantic
fn port_semantic(&self, _pin_a: &str, _pin_b: &str) -> PortSemantic
Classify the electrical behavior of a port (pin pair) for optimization legality checks. The compiler uses this to determine which subgraphs can be safely lowered to IIR/BlackFeedback vs requiring full MNA/WDF.
Default derives from existing classification methods. Override for multi-port devices where different pin pairs have different semantics (e.g., BJT: B-E is Nonlinear, C-E is Nonlinear).
Sourcefn is_nonlinear(&self) -> bool
fn is_nonlinear(&self) -> bool
Whether this component is a nonlinear element (needs NR solver).
Sourcefn is_active_ic(&self) -> bool
fn is_active_ic(&self) -> bool
Whether this component is an active IC (counted toward num_active).
Sourcefn is_control_only(&self) -> bool
fn is_control_only(&self) -> bool
Whether this component is a control-only element (no circuit pins).
Sourcefn is_variable(&self) -> bool
fn is_variable(&self) -> bool
Whether this component’s edge impedance changes at runtime. Stages containing variable edges need scattering matrix recomputation.
Sourcefn modulation_pins(&self) -> &'static [&'static str]
fn modulation_pins(&self) -> &'static [&'static str]
Extra pins that are valid as modulation targets but may not be in pin_config.
Sourcefn edges(&self) -> Vec<ComponentEdge>
fn edges(&self) -> Vec<ComponentEdge>
Declare this component’s circuit edges with their electrical classification.
Returns empty for Virtual/ActiveIc components (no WDF topology participation). The planner uses these edges to group components into stages by EdgeKind.
Sourcefn signal_adjacencies(&self) -> Vec<(&'static str, &'static str)>
fn signal_adjacencies(&self) -> Vec<(&'static str, &'static str)>
Internal signal-path adjacencies: pin pairs that signal can traverse through.
Used by the validator to check in→out reachability. Default derives pairs
from edges(); if edges is empty, fans out from first valid_pin to all others.
Override for multi-terminal or complex components (BJTs, pots, transformers).
Sourcefn pin_direction(&self, _pin: &str) -> PinDirection
fn pin_direction(&self, _pin: &str) -> PinDirection
Infer the signal direction for a given pin on this component.
Used by the layout engine to determine directed graph edges.
Default: Bidirectional for all pins.
Sourcefn resolve_edges(
&self,
_neighbors: &ResolveContext,
) -> Option<Vec<ComponentEdge>>
fn resolve_edges( &self, _neighbors: &ResolveContext, ) -> Option<Vec<ComponentEdge>>
Context-dependent resolution: if this component’s behavior depends on how it’s wired, return a new edge list reflecting the resolved role.
Called after graph construction with neighbor connectivity info. Default: no resolution needed (return None to keep current edges).
Examples:
- JFET gate → LFO/pot → resolve drain-source as Linear (variable resistor)
- OTA Iabc → envelope → resolve as Vccs (linear mode)
Sourcefn mna_vsource_count(&self) -> usize
fn mna_vsource_count(&self) -> usize
Number of MNA voltage sources this component needs when stamped into an R-node. Default: 0. Op-amps return 1 (for the VCVS constraint).
Sourcefn mna_internal_node_count(&self) -> usize
fn mna_internal_node_count(&self) -> usize
Number of internal MNA nodes this component needs. Default: 0. Op-amps return 1 (internal gain stage node for GBW pole).
Sourcefn stamp_mna_multi(
&self,
comp_id: &str,
ctx: &mut StampContext<'_>,
mna: &mut MnaSystem,
) -> StampResult
fn stamp_mna_multi( &self, comp_id: &str, ctx: &mut StampContext<'_>, mna: &mut MnaSystem, ) -> StampResult
Stamp this component into an MNA system using multi-terminal pin resolution.
Default implementation resolves pins “a” and “b” and delegates to
stamp_mna(). Multi-terminal components (op-amps) override this to
resolve all their pins and stamp directly.
Sourcefn make_leaf(&self, _comp_id: &str, _sample_rate: f64) -> Option<DynNode>
fn make_leaf(&self, _comp_id: &str, _sample_rate: f64) -> Option<DynNode>
Create a WDF leaf node for this component.
Returns None for non-leaf components (diodes, virtual elements, etc.).
fn resistance(&self) -> Option<f64>
fn capacitance(&self) -> Option<f64>
fn inductance(&self) -> Option<f64>
Sourcefn validate_values(&self, _comp_id: &str) -> Vec<(Severity, String)>
fn validate_values(&self, _comp_id: &str) -> Vec<(Severity, String)>
Check for suspicious or invalid component values.
Sourcefn terminal_requirements(&self) -> Vec<(&'static str, Vec<NeighborReq>)>
fn terminal_requirements(&self) -> Vec<(&'static str, Vec<NeighborReq>)>
Per-terminal neighbour requirements for active devices.
Returns (terminal_name, requirements) pairs declaring what each
terminal needs from its connectivity to function as a circuit element.
The completeness pass classifies each terminal’s actual neighbours
(NeighborRole) and reports a compile error when a [Cardinality:: Required] role is missing.
Config tolerance: a NeighborRole::Load declared on more than one
terminal of the same device (e.g. both plate and cathode of a triode)
is satisfied if any of those terminals carries a Load. This lets a
common-cathode stage (plate-load) AND a cathode-follower (cathode-load,
plate straight to B+) both validate without a false positive.
Default: empty (passive / non-active components declare nothing and are never checked).
Sourcefn classify_nonlinear(
&self,
_comp_id: &str,
_node_a: usize,
_node_b: usize,
_gnd_node: usize,
_node_names: &HashMap<String, usize>,
) -> Option<(NonlinearKind, Vec<usize>)>
fn classify_nonlinear( &self, _comp_id: &str, _node_a: usize, _node_b: usize, _gnd_node: usize, _node_names: &HashMap<String, usize>, ) -> Option<(NonlinearKind, Vec<usize>)>
Classify this component as a nonlinear element for the circuit solver.
Returns Some((kind, junction_nodes)) if this is a nonlinear element,
where junction_nodes are the circuit nodes where passive elements connect.
Returns None for passive, virtual, and active-IC components.
- 1 junction node: diodes, JFETs, MOSFETs, zeners, OTAs
- 2 junction nodes: BJTs (collector, emitter), triodes/pentodes (plate, cathode)
Sourcefn controls(&self) -> Vec<ControlParam>
fn controls(&self) -> Vec<ControlParam>
Declare controllable parameters for this component.
The compiler matches ControlDef.property against each param’s name
to determine the control target without heuristic net scanning.
Sourcefn modulation_sink(&self, _pin: &str) -> Option<ModulationSink>
fn modulation_sink(&self, _pin: &str) -> Option<ModulationSink>
If this component can be a modulation sink (LFO/envelope target), return the sink description for the given pin.
Called during LFO/envelope binding to determine bias and range.
fn is_modulation_source(&self) -> bool
fn is_bjt(&self) -> bool
fn is_jfet(&self) -> bool
fn is_mosfet(&self) -> bool
fn is_tube(&self) -> bool
fn is_transformer(&self) -> bool
fn is_pot(&self) -> bool
fn is_diode_family(&self) -> bool
fn is_trigger(&self) -> bool
Sourcefn feedback_input_is_barrier(&self) -> bool
fn feedback_input_is_barrier(&self) -> bool
Whether this element’s input node acts as a summing junction that should block BFS traversal in the signal flow graph.
Op-amp neg nodes are summing junctions: the input signal, feedback network, and interstage coupling all connect to the same node. Without blocking, BFS from a downstream element can traverse backward through this element’s feedback, across shared passives, and reach upstream elements — creating false cycle edges.
Returns true for op-amps (VCVS). Returns false for diodes, BJTs, tubes, etc. — their input nodes don’t create false coupling paths.
Sourcefn k_method_spec(&self) -> Option<KMethodSpec>
fn k_method_spec(&self) -> Option<KMethodSpec>
K-method table shape declared by the component.
Requirements for candidacy:
- Memoryless: the NL is purely algebraic (no internal state/caps)
- Low port count: ≤3 dimensions for practical table sizes
- Monotonic: unique output for any input (no fold-back/hysteresis)
Axis dimensions:
- 1D: incident wave only, e.g. diode/zener junction
- 2D: incident wave + device control, e.g. BJT Vbe or triode Vgk
- 3D: incident wave + two controls, e.g. pentode grids
Linear components return (false, 0, “linear”) — they don’t need NL tabulation. Variable components (pots, photocouplers) return false because their parameters change at runtime.
Sourcefn k_method_candidacy(&self) -> (bool, usize, &'static str)
fn k_method_candidacy(&self) -> (bool, usize, &'static str)
Compatibility wrapper for callers that still only need yes/no +
dimensionality. New code should prefer Component::k_method_spec
because it preserves the meaning of each table axis.
Sourcefn is_simple_passive(&self) -> bool
fn is_simple_passive(&self) -> bool
Passive two-terminal element (R, C, L, etc.) — excludes transformers and pots.
Sourcefn is_gain_device(&self) -> bool
fn is_gain_device(&self) -> bool
Amplifying device: tube, BJT, JFET, MOSFET.
fn model_name(&self) -> Option<&str>
fn op_amp_type(&self) -> Option<OpAmpType>
fn pot_taper(&self) -> Option<PotTaper>
fn diode_type(&self) -> Option<DiodeType>
fn transformer_config(&self) -> Option<&TransformerConfig>
Sourcefn apply_bias(
&self,
_bias_voltages: &HashMap<String, f64>,
_supply_voltage: f64,
) -> BiasResult
fn apply_bias( &self, _bias_voltages: &HashMap<String, f64>, _supply_voltage: f64, ) -> BiasResult
Apply DC bias from a static bias network detected at compile time.
bias_voltages maps pin names (e.g. “pos”, “neg”, “base”, “gate”)
to their DC voltage computed from the circuit’s resistor divider.
supply_voltage is the pedal’s supply rail voltage (e.g. 9.0V).
Each component type interprets bias differently:
- Op-amp: sets positive/negative rail limits from bias point
- BJT: sets quiescent Ic, Vce from collector/emitter voltages
- Triode/Pentode: sets grid bias (Vgk) from grid DC voltage
- JFET: sets Vgs from gate bias voltage
Returns BiasResult describing what was applied.
Default: no-op (passive components don’t need bias).
Sourcefn symbol_name(&self) -> &'static str
fn symbol_name(&self) -> &'static str
Symbol identifier for layout rendering (e.g., “resistor”, “triode”, “opamp”).
Sourcefn layout_class(&self) -> &'static str
fn layout_class(&self) -> &'static str
Layout class identifier for placement grouping (e.g., “resistor”, “npn”, “opamp”).
Sourcefn display_value(&self) -> Option<String>
fn display_value(&self) -> Option<String>
Human-readable display value for labels (e.g., “4.7kΩ”, “100nF”).
Trait Implementations§
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".