16 KiB
| id | title | section | difficulty | estimated_time | prerequisites | objectives | tags |
|---|---|---|---|---|---|---|---|
| model-04 | FEMM Extraction for Distributed Models | Advanced Modeling | advanced | 50 | [model-02 model-03] | [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] | [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: <In Group> (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<j, verify |C[i,j] - C[j,i]| / |C[i,j]| < 0.01
Example:
C[1,3] = -0.9 pF
C[3,1] = -0.9 pF
✓ Symmetric
2. Diagonal positive:
C[i,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:
# 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:
* Partial capacitance network
* Between every node pair i,j where i<j:
C_0_1 node0 node1 {-C[0,1]}
C_0_2 node0 node2 {-C[0,2]}
...
C_1_2 node1 node2 {-C[1,2]}
C_1_3 node1 node3 {-C[1,3]}
...
* Each node to ground:
C_0_gnd node0 0 {C[0,0] - sum_of_partial_from_0}
C_1_gnd node1 0 {C[1,1] - sum_of_partial_from_1}
...
* Resistances (in series with segments):
R1 node1 node1_r {R[1]}
R2 node2 node2_r {R[2]}
...
Example: 3×3 matrix (topload + 2 segments):
Given Maxwell matrix:
[0] [1] [2]
[0] [ 30.0 -8.0 -2.0 ] pF
[1] [ -8.0 14.0 -3.0 ] pF
[2] [ -2.0 -3.0 9.0 ] pF
Step 1: Between-node capacitances (flip signs)
C_partial[0,1] = -(-8.0) = 8.0 pF
C_partial[0,2] = -(-2.0) = 2.0 pF
C_partial[1,2] = -(-3.0) = 3.0 pF
Step 2: Ground capacitances
Node 0: C[0,0] = 30.0, partials = 8.0 + 2.0 = 10.0
C_0_gnd = 30.0 - 10.0 = 20.0 pF
Node 1: C[1,1] = 14.0, partials = 8.0 + 3.0 = 11.0
C_1_gnd = 14.0 - 11.0 = 3.0 pF
Node 2: C[2,2] = 9.0, partials = 2.0 + 3.0 = 5.0
C_2_gnd = 9.0 - 5.0 = 4.0 pF
Step 3: SPICE netlist
* Partial capacitance implementation
C_0_1 node0 node1 8.0p
C_0_2 node0 node2 2.0p
C_1_2 node1 node2 3.0p
C_0_gnd node0 0 20.0p
C_1_gnd node1 0 3.0p
C_2_gnd node2 0 4.0p
* Resistances
R1 node1 node1_r 50k
R2 node2 node2_r 100k
Validation:
Total capacitance node0 to ground (all other nodes grounded):
C_total = C_0_gnd + (C_0_1 || C_1_gnd) + (C_0_2 || C_2_gnd)
Should approximately equal C[0,0] = 30 pF
(Small differences due to network topology)
Solution 2: Controlled Sources (VCCS)
Use voltage-controlled current sources:
Laplace domain relation:
I[i] = Σⱼ₌₀ⁿ (jω × C[i,j] × V[j])
In SPICE: G-sources (transconductance)
Implementation:
* For each node i, current from all couplings:
* G_source_i_from_j nodei 0 (nodej 0) {j*omega*C[i,j]}
Example node 1, coupling to node 2:
G_1_from_2 node1 0 node2 0 {2*pi*freq*C[1,2]}
Where C[1,2] is Maxwell value (negative OK!)
Advantages:
- Directly implements Maxwell matrix
- Handles negatives naturally
- Exact representation
Disadvantages:
- More complex netlist
- Some SPICE versions have limited frequency-dependent sources
- Behavioral sources may be needed (B-sources)
- Debugging harder
Solution 3: Nearest-Neighbor Approximation
Simplification: Ignore weak couplings
Keep only:
1. Topload to all segments: C[0,i] for i=1 to n
2. Adjacent segments: C[i,i+1] for i=1 to n-1
3. Diagonal (self): C[i,i] for all i
Discard: C[i,j] for |i-j| > 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):
* 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