You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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