Skip to main content

pcb_toolkit/
wire_gauge.rs

1//! AWG wire gauge property lookup — Saturn PCB Toolkit Mode 8.
2//!
3//! Contains a 44-entry table covering AWG 4/0 (largest) through AWG 40 (smallest).
4//! Diameter data is in inches; resistance data is in ohms per 1000 ft.
5//! Area is computed in circular mils (diameter_mils²).
6
7use serde::{Deserialize, Serialize};
8
9/// AWG wire gauge sizes from 4/0 (largest) to 40 (smallest).
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11pub enum Awg {
12    Awg4_0,
13    Awg3_0,
14    Awg2_0,
15    Awg1_0,
16    Awg1,
17    Awg2,
18    Awg3,
19    Awg4,
20    Awg5,
21    Awg6,
22    Awg7,
23    Awg8,
24    Awg9,
25    Awg10,
26    Awg11,
27    Awg12,
28    Awg13,
29    Awg14,
30    Awg15,
31    Awg16,
32    Awg17,
33    Awg18,
34    Awg19,
35    Awg20,
36    Awg21,
37    Awg22,
38    Awg23,
39    Awg24,
40    Awg25,
41    Awg26,
42    Awg27,
43    Awg28,
44    Awg29,
45    Awg30,
46    Awg31,
47    Awg32,
48    Awg33,
49    Awg34,
50    Awg35,
51    Awg36,
52    Awg37,
53    Awg38,
54    Awg39,
55    Awg40,
56}
57
58/// Properties computed for a single AWG wire gauge.
59#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
60pub struct WireGaugeResult {
61    /// Human-readable AWG label: "4/0", "3/0", ..., "40".
62    pub awg_label: &'static str,
63    /// Diameter in inches.
64    pub diameter_in: f64,
65    /// Diameter in mils (diameter_in × 1000).
66    pub diameter_mils: f64,
67    /// DC resistance in ohms per 1000 ft.
68    pub resistance_ohm_per_kft: f64,
69    /// Cross-sectional area in circular mils (diameter_mils²).
70    pub area_circular_mils: f64,
71    /// Saturn display area: diameter_mils² / 700.0.
72    pub area_saturn: f64,
73}
74
75/// Static table entry: (label, diameter_in, resistance_ohm_per_kft).
76struct Entry {
77    label: &'static str,
78    diameter_in: f64,
79    resistance_ohm_per_kft: f64,
80}
81
82static TABLE: [Entry; 44] = [
83    Entry { label: "4/0",  diameter_in: 0.4600, resistance_ohm_per_kft: 0.050 },
84    Entry { label: "3/0",  diameter_in: 0.4096, resistance_ohm_per_kft: 0.060 },
85    Entry { label: "2/0",  diameter_in: 0.3648, resistance_ohm_per_kft: 0.080 },
86    Entry { label: "1/0",  diameter_in: 0.3249, resistance_ohm_per_kft: 0.100 },
87    Entry { label: "1",    diameter_in: 0.2893, resistance_ohm_per_kft: 0.120 },
88    Entry { label: "2",    diameter_in: 0.2576, resistance_ohm_per_kft: 0.160 },
89    Entry { label: "3",    diameter_in: 0.2294, resistance_ohm_per_kft: 0.200 },
90    Entry { label: "4",    diameter_in: 0.2043, resistance_ohm_per_kft: 0.250 },
91    Entry { label: "5",    diameter_in: 0.1819, resistance_ohm_per_kft: 0.310 },
92    Entry { label: "6",    diameter_in: 0.1620, resistance_ohm_per_kft: 0.400 },
93    Entry { label: "7",    diameter_in: 0.1443, resistance_ohm_per_kft: 0.500 },
94    Entry { label: "8",    diameter_in: 0.1285, resistance_ohm_per_kft: 0.630 },
95    Entry { label: "9",    diameter_in: 0.1144, resistance_ohm_per_kft: 0.790 },
96    Entry { label: "10",   diameter_in: 0.1019, resistance_ohm_per_kft: 1.000 },
97    Entry { label: "11",   diameter_in: 0.0907, resistance_ohm_per_kft: 1.260 },
98    Entry { label: "12",   diameter_in: 0.0808, resistance_ohm_per_kft: 1.590 },
99    Entry { label: "13",   diameter_in: 0.0720, resistance_ohm_per_kft: 2.000 },
100    Entry { label: "14",   diameter_in: 0.0641, resistance_ohm_per_kft: 2.530 },
101    Entry { label: "15",   diameter_in: 0.0571, resistance_ohm_per_kft: 3.190 },
102    Entry { label: "16",   diameter_in: 0.0508, resistance_ohm_per_kft: 4.020 },
103    Entry { label: "17",   diameter_in: 0.0453, resistance_ohm_per_kft: 5.060 },
104    Entry { label: "18",   diameter_in: 0.0403, resistance_ohm_per_kft: 6.390 },
105    Entry { label: "19",   diameter_in: 0.0359, resistance_ohm_per_kft: 8.050 },
106    Entry { label: "20",   diameter_in: 0.0320, resistance_ohm_per_kft: 10.150 },
107    Entry { label: "21",   diameter_in: 0.0285, resistance_ohm_per_kft: 12.800 },
108    Entry { label: "22",   diameter_in: 0.0254, resistance_ohm_per_kft: 16.140 },
109    Entry { label: "23",   diameter_in: 0.0226, resistance_ohm_per_kft: 20.360 },
110    Entry { label: "24",   diameter_in: 0.0201, resistance_ohm_per_kft: 25.670 },
111    Entry { label: "25",   diameter_in: 0.0179, resistance_ohm_per_kft: 32.370 },
112    Entry { label: "26",   diameter_in: 0.0159, resistance_ohm_per_kft: 40.810 },
113    Entry { label: "27",   diameter_in: 0.0142, resistance_ohm_per_kft: 51.470 },
114    Entry { label: "28",   diameter_in: 0.0126, resistance_ohm_per_kft: 64.900 },
115    Entry { label: "29",   diameter_in: 0.0113, resistance_ohm_per_kft: 81.830 },
116    Entry { label: "30",   diameter_in: 0.0100, resistance_ohm_per_kft: 103.200 },
117    Entry { label: "31",   diameter_in: 0.0089, resistance_ohm_per_kft: 130.100 },
118    Entry { label: "32",   diameter_in: 0.0080, resistance_ohm_per_kft: 164.100 },
119    Entry { label: "33",   diameter_in: 0.0071, resistance_ohm_per_kft: 206.900 },
120    Entry { label: "34",   diameter_in: 0.0063, resistance_ohm_per_kft: 260.900 },
121    Entry { label: "35",   diameter_in: 0.0056, resistance_ohm_per_kft: 329.000 },
122    Entry { label: "36",   diameter_in: 0.0050, resistance_ohm_per_kft: 414.800 },
123    Entry { label: "37",   diameter_in: 0.0045, resistance_ohm_per_kft: 523.100 },
124    Entry { label: "38",   diameter_in: 0.0040, resistance_ohm_per_kft: 659.600 },
125    Entry { label: "39",   diameter_in: 0.0035, resistance_ohm_per_kft: 831.800 },
126    Entry { label: "40",   diameter_in: 0.0031, resistance_ohm_per_kft: 1049.000 },
127];
128
129static ALL_AWG: [Awg; 44] = [
130    Awg::Awg4_0, Awg::Awg3_0, Awg::Awg2_0, Awg::Awg1_0,
131    Awg::Awg1,  Awg::Awg2,  Awg::Awg3,  Awg::Awg4,
132    Awg::Awg5,  Awg::Awg6,  Awg::Awg7,  Awg::Awg8,
133    Awg::Awg9,  Awg::Awg10, Awg::Awg11, Awg::Awg12,
134    Awg::Awg13, Awg::Awg14, Awg::Awg15, Awg::Awg16,
135    Awg::Awg17, Awg::Awg18, Awg::Awg19, Awg::Awg20,
136    Awg::Awg21, Awg::Awg22, Awg::Awg23, Awg::Awg24,
137    Awg::Awg25, Awg::Awg26, Awg::Awg27, Awg::Awg28,
138    Awg::Awg29, Awg::Awg30, Awg::Awg31, Awg::Awg32,
139    Awg::Awg33, Awg::Awg34, Awg::Awg35, Awg::Awg36,
140    Awg::Awg37, Awg::Awg38, Awg::Awg39, Awg::Awg40,
141];
142
143impl Awg {
144    /// Returns the table index for this gauge (0 = 4/0, 43 = 40).
145    fn index(self) -> usize {
146        self as usize
147    }
148
149    /// Returns all 44 AWG variants in order from largest (4/0) to smallest (40).
150    pub fn all() -> &'static [Awg] {
151        &ALL_AWG
152    }
153
154    /// Returns the `Awg` variant for the given ComboBox-style index, or `None` if out of range.
155    pub fn from_index(idx: usize) -> Option<Awg> {
156        ALL_AWG.get(idx).copied()
157    }
158}
159
160/// Look up wire gauge properties for the given AWG size.
161///
162/// All data originates from the Saturn PCB Toolkit Mode 8 binary table.
163/// This function is infallible because all inputs are compile-time enum variants.
164pub fn lookup(awg: Awg) -> WireGaugeResult {
165    let entry = &TABLE[awg.index()];
166    let diameter_mils = entry.diameter_in * 1000.0;
167    let area_circular_mils = diameter_mils * diameter_mils;
168    WireGaugeResult {
169        awg_label: entry.label,
170        diameter_in: entry.diameter_in,
171        diameter_mils,
172        resistance_ohm_per_kft: entry.resistance_ohm_per_kft,
173        area_circular_mils,
174        area_saturn: area_circular_mils / 700.0,
175    }
176}
177
178#[cfg(test)]
179mod tests {
180    use approx::assert_relative_eq;
181
182    use super::*;
183
184    // AWG 4/0: diameter=0.4600 in, resistance=0.050 ohm/kft
185    // diameter_mils = 460.0, area_circular_mils = 211600.0
186    // area_saturn = 211600 / 700 = 302.285714...
187    #[test]
188    fn awg_4_0_properties() {
189        let r = lookup(Awg::Awg4_0);
190        assert_eq!(r.awg_label, "4/0");
191        assert_relative_eq!(r.diameter_in, 0.4600, epsilon = 1e-10);
192        assert_relative_eq!(r.resistance_ohm_per_kft, 0.050, epsilon = 1e-10);
193        assert_relative_eq!(r.diameter_mils, 460.0, epsilon = 1e-10);
194        assert_relative_eq!(r.area_circular_mils, 211_600.0, epsilon = 1e-6);
195        assert_relative_eq!(r.area_saturn, 302.285_714_285, epsilon = 1e-6);
196    }
197
198    // AWG 22: diameter=0.0254 in, resistance=16.140 ohm/kft
199    #[test]
200    fn awg_22_properties() {
201        let r = lookup(Awg::Awg22);
202        assert_eq!(r.awg_label, "22");
203        assert_relative_eq!(r.diameter_in, 0.0254, epsilon = 1e-10);
204        assert_relative_eq!(r.resistance_ohm_per_kft, 16.140, epsilon = 1e-10);
205        assert_relative_eq!(r.diameter_mils, 25.4, epsilon = 1e-8);
206        assert_relative_eq!(r.area_circular_mils, 645.16, epsilon = 1e-6);
207    }
208
209    // AWG 40: diameter=0.0031 in, resistance=1049.000 ohm/kft
210    #[test]
211    fn awg_40_properties() {
212        let r = lookup(Awg::Awg40);
213        assert_eq!(r.awg_label, "40");
214        assert_relative_eq!(r.diameter_in, 0.0031, epsilon = 1e-10);
215        assert_relative_eq!(r.resistance_ohm_per_kft, 1049.000, epsilon = 1e-10);
216        assert_relative_eq!(r.diameter_mils, 3.1, epsilon = 1e-10);
217        assert_relative_eq!(r.area_circular_mils, 9.61, epsilon = 1e-8);
218    }
219
220    #[test]
221    fn all_has_44_entries() {
222        assert_eq!(Awg::all().len(), 44);
223    }
224
225    #[test]
226    fn from_index_boundary() {
227        assert_eq!(Awg::from_index(0), Some(Awg::Awg4_0));
228        assert_eq!(Awg::from_index(43), Some(Awg::Awg40));
229        assert_eq!(Awg::from_index(44), None);
230    }
231}