--- id: model-04 title: "FEMM Extraction for Distributed Models" section: "Advanced Modeling" difficulty: "advanced" estimated_time: 50 prerequisites: ["model-02", "model-03"] objectives: - Set up multi-body FEMM geometries for n-segment spark models - Extract and validate (n+1)×(n+1) capacitance matrices - Implement capacitance matrices in SPICE with correct sign handling - Apply passivity checks and matrix validation procedures tags: ["FEMM", "distributed-model", "capacitance-matrix", "SPICE", "validation"] --- # FEMM Extraction for Distributed Models This lesson covers the complete procedure for extracting capacitance matrices from FEMM for distributed spark models and implementing them in SPICE circuit simulators. ## Multi-Body Electrostatic Setup ### Geometry Definition **For n segments + topload → (n+1) conductors:** ``` Example: n=5 segments Conductors: Body 0: Toroid topload Body 1: Cylinder segment 1 (base) Body 2: Cylinder segment 2 Body 3: Cylinder segment 3 Body 4: Cylinder segment 4 Body 5: Cylinder segment 5 (tip) Ground: Boundary condition (not explicit conductor) ``` **Cylindrical segments:** ``` Each segment i: Length: L_segment = L_total / n Diameter: d (typically 1-3 mm, uniform) Position: Vertical stack from topload to ground Gap between segments: 0.1 mm (numerical convenience) - Prevents touching in FEMM - Results insensitive to small gap - Represents continuous channel physically ``` ### FEMM Axisymmetric Coordinates **r-z coordinate system:** ``` Example: 2.0 m spark, n=5, each segment 0.4 m Topload (toroid): Major diameter: 30 cm → r_major = 15 cm Minor diameter: 10 cm → r_minor = 5 cm Center: z = 0 Lowest point: z = -5 cm Segment 1 (base): r = 0.1 cm (diameter = 2 mm) z from -5.1 cm to -45.1 cm Length: 40 cm Gap: 0.1 cm below topload Segment 2: z from -45.2 cm to -85.2 cm Gap: 0.1 cm above segment 1 Segment 3: z from -85.3 cm to -125.3 cm Segment 4: z from -125.4 cm to -165.4 cm Segment 5 (tip): z from -165.5 cm to -205.5 cm Ground plane: z = -220 cm (15 cm below tip) r = 0 to 300 cm (large extent) Boundary: V = 0 Outer boundary: r = 300 cm z = -250 cm to +50 cm Boundary: V = 0 (far field) ``` **Critical: Consistent numbering!** ``` FEMM conductor numbers must match array indices: Conductor 0 = Topload = C[0,:] Conductor 1 = Segment 1 (base) = C[1,:] ... Conductor n = Segment n (tip) = C[n,:] ``` ### Step-by-Step FEMM Procedure **Step 1: Problem setup** ``` File → New Problem Type: Electrostatic, Axisymmetric Frequency: 0 Hz Length units: Centimeters (recommended) Precision: 1e-8 ``` **Step 2: Draw geometry** ``` 1. Draw toroid (arcs + lines, right half only) 2. Draw n rectangles for spark segments - Each: width = r_spark, height = L_segment - Stack vertically with small gaps 3. Draw ground plane (horizontal line) 4. Draw outer boundary (large rectangle) 5. Close all contours (check with "Show Points") ``` **Step 3: Define materials** ``` Materials → Add Material: Name: "Air" Relative permittivity: εr = 1 Apply "Air" to all regions (click inside each) ``` **Step 4: Define conductors** ``` Properties → Conductors → Add Property: For i = 0 to n: Name: "Conductor_i" Voltage: i = 0: V = 1V (topload excitation) i = 1 to n: (floating) Assign conductor properties: - Select all boundary nodes/segments for each body - Right-click → Set Conductor - Choose corresponding conductor number CRITICAL: Verify numbering matches geometry! ``` **Step 5: Boundary conditions** ``` Ground plane and outer boundary: Select boundary segments Properties → Boundary → Add Property: Name: "Ground" Type: Fixed Voltage V = 0 Apply to ground plane and outer boundary ``` **Step 6: Meshing** ``` Mesh → Create Mesh Automatic mesh with adaptive refinement: Near conductors: ~0.5 mm triangle size Mid-field: ~5 mm Far field: ~50 mm Expected element count: n = 5: ~15,000-30,000 elements n = 10: ~30,000-60,000 elements n = 20: ~60,000-120,000 elements Visual check: No extremely elongated triangles ``` **Step 7: Solve** ``` Analysis → Solve Convergence: - Should complete in <1 minute for n≤10 - Iterations: 50-200 typical - Final residual < 1e-8 Check for warnings: - Mesh quality issues - Conductor connectivity problems - Non-convergence (increase iterations or refine mesh) ``` **Step 8: Extract capacitance matrix** ``` View Results → Circuit Props Conductor properties window shows: - Voltage on each conductor - Charge on each conductor - Capacitance matrix [C] Copy matrix to file: - Select all text - Copy to spreadsheet or script - Save for processing ``` ## Capacitance Matrix Output ### Matrix Structure **For n=5 segments (6×6 matrix):** ``` [0] [1] [2] [3] [4] [5] [0] [ C₀₀ C₀₁ C₀₂ C₀₃ C₀₄ C₀₅ ] [1] [ C₁₀ C₁₁ C₁₂ C₁₃ C₁₄ C₁₅ ] [2] [ C₂₀ C₂₁ C₂₂ C₂₃ C₂₄ C₂₅ ] [3] [ C₃₀ C₃₁ C₃₂ C₃₃ C₃₄ C₃₅ ] [4] [ C₄₀ C₄₁ C₄₂ C₄₃ C₄₄ C₄₅ ] [5] [ C₅₀ C₅₁ C₅₂ C₅₃ C₅₄ C₅₅ ] All values in pF (picofarads) ``` **Example numerical values:** ``` [0] [1] [2] [3] [4] [5] [0] [ 32.5 -9.2 -3.1 -1.2 -0.6 -0.3 ] [1] [ -9.2 14.8 -2.8 -0.9 -0.4 -0.2 ] [2] [ -3.1 -2.8 10.4 -2.1 -0.7 -0.3 ] [3] [ -1.2 -0.9 -2.1 8.6 -1.8 -0.5 ] [4] [ -0.6 -0.4 -0.7 -1.8 7.4 -1.4 ] [5] [ -0.3 -0.2 -0.3 -0.5 -1.4 5.8 ] (Illustrative values for 2 m spark, n=5) ``` ### Matrix Properties **1. Symmetry:** ``` C[i,j] = C[j,i] Check: For all i 0 for all i Self-capacitance (conductor to infinity) Always positive by definition Example: C[0,0] = 32.5 pF ✓ C[1,1] = 14.8 pF ✓ ...all positive ``` **3. Off-diagonal negative:** ``` C[i,j] < 0 for all i ≠ j Maxwell convention: Mutual capacitances negative Example: C[0,1] = -9.2 pF ✓ C[2,4] = -0.7 pF ✓ ...all negative ``` **4. Row sum ≈ 0:** ``` Σⱼ C[i,j] ≈ 0 (but not exact due to ground at infinity) Check: Sum should be small compared to diagonal Example row 2: -3.1 + (-2.8) + 10.4 + (-2.1) + (-0.7) + (-0.3) = 1.4 pF Compared to C[2,2] = 10.4: ratio = 13% Acceptable if <20% ``` ## Matrix Validation ### Check 1: Symmetry **Procedure:** ```python # Pseudocode for i in range(n+1): for j in range(i+1, n+1): error = abs(C[i,j] - C[j,i]) / abs(C[i,j]) if error > 0.01: print(f"Asymmetry at [{i},{j}]: {error*100:.2f}%") # ACTION: Refine mesh, check convergence ``` **If not symmetric:** - Mesh too coarse → refine near conductors - Poor convergence → increase precision or iterations - Geometry error → check conductor assignments ### Check 2: Positive Semi-Definite (Passivity) **Eigenvalue test:** ``` Calculate eigenvalues λ of matrix C Physically passive if: - All λ ≥ 0 (non-negative) - One λ = 0 (ground reference freedom) - Rest λ > 0 (strictly positive) If any λ < 0 (within numerical precision): - Matrix not physically realizable - Check FEMM setup (conductor assignments) - Refine mesh - Verify boundary conditions ``` **Why this matters:** ``` Negative eigenvalue → negative energy stored Physically impossible for passive capacitance network Indicates error in simulation or extraction ``` ### Check 3: Physical Value Patterns **Nearby vs distant coupling:** ``` Expectation: |C[i,j]| decreases with |i-j| Example: Row 3 (segment 3) C[3,0] = -1.2 (distant from topload) C[3,2] = -2.1 (adjacent segment) C[3,4] = -1.8 (adjacent segment) C[3,5] = -0.5 (distant, tip) Check: |C[3,2]| = 2.1 > |C[3,5]| = 0.5 ✓ |C[3,4]| = 1.8 > |C[3,0]| = 1.2 ✓ Adjacent segments most strongly coupled ✓ ``` **Topload coupling:** ``` Expectation: |C[0,i]| decreases with i (distance from topload) |C[0,1]| = 9.2 (base, closest) |C[0,2]| = 3.1 |C[0,3]| = 1.2 |C[0,4]| = 0.6 |C[0,5]| = 0.3 (tip, farthest) Monotonically decreasing ✓ ``` ### Check 4: Total Shunt Capacitance **Approximate formula:** ``` C_sh_total ≈ Σᵢ₌₁ⁿ (C[i,i] - |C[i,0]|) This sums shunt capacitance of all segments Empirical check: C_sh_total ≈ 2 pF/foot × L_total ``` **Example calculation:** ``` Segment 1: C[1,1] - |C[1,0]| = 14.8 - 9.2 = 5.6 pF Segment 2: C[2,2] - |C[2,0]| = 10.4 - 3.1 = 7.3 pF Segment 3: C[3,3] - |C[3,0]| = 8.6 - 1.2 = 7.4 pF Segment 4: C[4,4] - |C[4,0]| = 7.4 - 0.6 = 6.8 pF Segment 5: C[5,5] - |C[5,0]| = 5.8 - 0.3 = 5.5 pF C_sh_total = 5.6 + 7.3 + 7.4 + 6.8 + 5.5 = 32.6 pF Expected: 2 pF/ft × 6.56 ft = 13.1 pF Ratio: 32.6 / 13.1 = 2.5 Higher than expected, but within factor of 2-3 (acceptable) ``` **Why discrepancy?** ``` 1. Matrix interpretation method - C[i,i] includes all field terminations - Simple sum may overcount mutual terms - Exact extraction more complex 2. Distributed vs lumped geometry - Segmentation changes field distribution - Not directly comparable to continuous cylinder 3. Empirical rule uncertainty - ±50% variation typical - Geometry and environment dependent Conclusion: Factor of 2-3 deviation is NORMAL for distributed models Use FEMM values (more accurate for specific geometry) ``` ## Implementing in SPICE ### The Challenge: Negative Off-Diagonals **Problem:** ``` SPICE capacitor syntax: C_name node1 node2 value Value must be positive! C1 n1 n2 10p ← OK C1 n1 n2 -10p ← ERROR! Unphysical But Maxwell matrix has C[i,j] < 0 for i≠j Cannot use directly in SPICE! ``` ### Solution 1: Partial Capacitance Transformation **Convert Maxwell → Partial (all positive):** **Formula:** ``` For off-diagonal (between nodes): C_partial[i,j] = -C_Maxwell[i,j] (flip sign!) For diagonal (to ground): C_partial[i,ground] = C[i,i] - Σⱼ₌₀ⁿ C_partial[i,j] (j≠i) ``` **SPICE implementation:** ```spice * Partial capacitance network * Between every node pair i,j where i 1 and both i,j ≥ 1 ``` **When acceptable:** ``` Large n (≥10): Distant couplings small (<10% of adjacent) Quick estimates: Engineering accuracy sufficient Weak segment-to-segment coupling: Topload dominates Example: |C[2,8]| << |C[2,3]| Dropping C[2,8] has negligible effect ``` **Validation:** ``` Compare: Full matrix: Z_spark = Z_full Nearest-neighbor: Z_spark = Z_approx If |Z_full - Z_approx| / |Z_full| < 0.1: Approximation acceptable Typically valid for n ≥ 10 ``` ## Worked Example: n=5 Complete Extraction **Given FEMM output (from earlier):** ``` [0] [1] [2] [3] [4] [5] [0] [ 32.5 -9.2 -3.1 -1.2 -0.6 -0.3 ] [1] [ -9.2 14.8 -2.8 -0.9 -0.4 -0.2 ] [2] [ -3.1 -2.8 10.4 -2.1 -0.7 -0.3 ] [3] [ -1.2 -0.9 -2.1 8.6 -1.8 -0.5 ] [4] [ -0.6 -0.4 -0.7 -1.8 7.4 -1.4 ] [5] [ -0.3 -0.2 -0.3 -0.5 -1.4 5.8 ] pF ``` **Validation:** ``` ✓ Symmetric: C[i,j] = C[j,i] for all i,j ✓ Diagonal positive: All C[i,i] > 0 ✓ Off-diagonal negative: All C[i,j] < 0 for i≠j ✓ Adjacent > distant: |C[2,3]| = 2.1 > |C[2,5]| = 0.3 ✓ Total C_sh ≈ 32.6 pF vs expected 13.1 pF (factor 2.5, acceptable) ``` **Convert to partial capacitances (selected):** ``` Between nodes (flip signs): C_0_1 = 9.2 pF C_0_2 = 3.1 pF C_1_2 = 2.8 pF C_2_3 = 2.1 pF C_3_4 = 1.8 pF C_4_5 = 1.4 pF ... (15 between-node caps total) To ground: C_0_gnd = 32.5 - (9.2+3.1+1.2+0.6+0.3) = 18.1 pF C_1_gnd = 14.8 - (9.2+2.8+0.9+0.4+0.2) = 1.3 pF ... (calculate for all nodes) ``` **SPICE implementation (abbreviated):** ```spice * 5-segment distributed spark model .param freq=190k V_test topload 0 AC 1V * Partial capacitances (between nodes) C_0_1 topload seg1 9.2p C_0_2 topload seg2 3.1p C_1_2 seg1 seg2 2.8p C_2_3 seg2 seg3 2.1p C_3_4 seg3 seg4 1.8p C_4_5 seg4 seg5 1.4p * ... (add all others) * To ground C_0_gnd topload 0 18.1p C_1_gnd seg1 0 1.3p * ... (add all segments) * Resistances (to be optimized, placeholder values) R1 seg1 seg1_r 50k R2 seg2 seg2_r 80k R3 seg3 seg3_r 120k R4 seg4 seg4_r 180k R5 seg5 seg5_r 300k .ac lin 1 190k 190k .print ac v(topload) i(V_test) v(seg1) v(seg2) v(seg3) v(seg4) v(seg5) .end ``` **Next step:** Optimize R values (Lesson 5) ## Key Takeaways - **(n+1)×(n+1) matrix** for n segments + topload, extracted from FEMM multi-body electrostatic simulation - **FEMM setup:** Axisymmetric, equal-length cylinder segments, 0.1 mm gaps, conductor numbering consistent with indices - **Matrix validation:** Check symmetry (<1% error), positive semi-definite (passivity), physical patterns (adjacent > distant) - **Total C_sh check:** Σ(C[i,i] - |C[i,0]|) vs 2 pF/ft rule, factor 2-3 deviation normal for distributed models - **SPICE implementation:** Three methods - partial capacitance (flip signs), controlled sources (direct), nearest-neighbor (approximation) - **Partial capacitance:** C_partial[i,j] = -C_Maxwell[i,j], all positive values, standard for SPICE - **Passivity check:** All eigenvalues ≥ 0, ensures physical realizability, critical validation step - **Use FEMM values** over empirical rules for distributed models (more accurate for segmented geometry) ## Practice {exercise:model-ex-04} --- **Next Lesson:** [Resistance Optimization Methods](05-resistance-optimization.md)