Skip to main content

pedalkernel/compiler/components/
transformer.rs

1//! Transformer component struct.
2
3use crate::compiler::component::{
4    Component, ComponentEdge, EdgeKind, GraphRole, PinConfig, PinDirection, StampResult,
5};
6use crate::compiler::dyn_node::DynNode;
7use crate::dsl::{TransformerConfig, WindingType};
8use crate::tree::MnaSystem;
9
10use super::impl_component_dyn;
11
12// ═══════════════════════════════════════════════════════════════════════════
13// TransformerComp
14// ═══════════════════════════════════════════════════════════════════════════
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct TransformerComp {
18    pub config: TransformerConfig,
19}
20
21impl Component for TransformerComp {
22    impl_component_dyn!();
23
24    fn type_tag(&self) -> &'static str {
25        "transformer"
26    }
27
28    fn is_passive(&self) -> bool {
29        true
30    }
31
32    fn pin_config(&self) -> PinConfig {
33        PinConfig {
34            valid_pins: &[
35                "a",
36                "b",
37                "c",
38                "d",
39                "e",
40                "f",
41                "primary.a",
42                "primary.b",
43                "secondary.a",
44                "secondary.b",
45                "tertiary.a",
46                "tertiary.b",
47                "pri.a",
48                "pri.b",
49                "sec.a",
50                "sec.b",
51                "ter.a",
52                "ter.b",
53                "pri_a",
54                "pri_b",
55                "sec_a",
56                "sec_b",
57                "ter_a",
58                "ter_b",
59                "pri_ct",
60                "pri.ct",
61                "sec_ct",
62                "sec.ct",
63                "ct",
64                "primary.ct",
65                "secondary.ct",
66            ],
67            aliases: &[],
68        }
69    }
70
71    fn graph_role(&self) -> GraphRole {
72        GraphRole::Transformer
73    }
74
75    fn stamp_mna(
76        &self,
77        _comp_id: &str,
78        _n1: Option<usize>,
79        _n2: Option<usize>,
80        _mna: &mut MnaSystem,
81        _sample_rate: f64,
82    ) -> StampResult {
83        StampResult::Skip
84    }
85
86    fn make_leaf(&self, _comp_id: &str, sample_rate: f64) -> Option<DynNode> {
87        let config = crate::model_lookup::transformer_config_from_dsl(&self.config);
88        let l_primary = config.primary_inductance;
89        let n = config.turns_ratio;
90        let l_secondary = l_primary / (n * n);
91        let secondary = Box::new(DynNode::Inductor(
92            None,
93            l_secondary as crate::Wave,
94            (2.0 * sample_rate * l_secondary) as crate::Wave,
95        ));
96        if let Some(n_tertiary) = config.tertiary_turns_ratio {
97            let l_tertiary = l_primary / (n_tertiary * n_tertiary);
98            let tertiary = Box::new(DynNode::Inductor(
99                None,
100                l_tertiary as crate::Wave,
101                (2.0 * sample_rate * l_tertiary) as crate::Wave,
102            ));
103            let r_sec = secondary.port_resistance();
104            let r_ter = tertiary.port_resistance();
105            let adaptor =
106                crate::tree::RTypeAdaptor::three_winding_transformer(
107                    n as crate::Wave,
108                    n_tertiary as crate::Wave,
109                    r_sec,
110                    r_ter,
111                );
112            Some(DynNode::RType {
113                adaptor,
114                children: vec![secondary, tertiary],
115            })
116        } else {
117            Some(DynNode::TransformerNode(secondary, n as crate::Wave))
118        }
119    }
120
121    fn edges(&self) -> Vec<ComponentEdge> {
122        vec![ComponentEdge {
123            pin_a: "a",
124            pin_b: "b",
125            kind: EdgeKind::Reactive,
126            port_group: None,
127        }]
128    }
129
130    fn footprint_ref(&self) -> (&'static str, &'static str) {
131        match (self.config.primary_type, self.config.secondary_type) {
132            (WindingType::PushPull, WindingType::Standard) => {
133                ("Transformer:Transformer_1P_1S", "T")
134            }
135            (WindingType::Standard, WindingType::CenterTap) => {
136                ("Transformer:Transformer_1P_1S_CT", "T")
137            }
138            (WindingType::PushPull, WindingType::CenterTap) => {
139                ("Transformer:Transformer_1P_CT_1S_CT", "T")
140            }
141            _ => ("Transformer:Transformer_1P_1S", "T"),
142        }
143    }
144
145    fn symbol_name(&self) -> &'static str {
146        "transformer"
147    }
148    fn layout_class(&self) -> &'static str {
149        "transformer"
150    }
151
152    fn signal_adjacencies(&self) -> Vec<(&'static str, &'static str)> {
153        let mut adj = vec![("a", "b"), ("c", "d")];
154        if self.config.has_tertiary() {
155            adj.push(("e", "f"));
156        }
157        adj
158    }
159
160    fn pin_direction(&self, pin: &str) -> PinDirection {
161        if pin.starts_with("pri") || pin == "a" || pin == "b" {
162            PinDirection::Input
163        } else if pin.starts_with("sec")
164            || pin == "c"
165            || pin == "d"
166            || pin.starts_with("ter")
167            || pin == "e"
168            || pin == "f"
169        {
170            PinDirection::Output
171        } else {
172            PinDirection::Bidirectional
173        }
174    }
175
176    fn is_transformer(&self) -> bool {
177        true
178    }
179    fn transformer_config(&self) -> Option<&crate::dsl::TransformerConfig> {
180        Some(&self.config)
181    }
182}