Skip to content

Instantly share code, notes, and snippets.

@mattmelling
Last active September 9, 2025 12:10
Show Gist options
  • Select an option

  • Save mattmelling/cecedfbd1f0b889f33e08281be37cc9f to your computer and use it in GitHub Desktop.

Select an option

Save mattmelling/cecedfbd1f0b889f33e08281be37cc9f to your computer and use it in GitHub Desktop.
Magnetic Loop Switch Capacitor Bank calculator
import math
variable = (10, 150)
targets = {
40: (189, 206),
30: (93.7, 94.8),
20: (42.8, 45.4),
17: (23.7, 24),
15: (14.7, 15.7),
12: (8.69, 8.83)
}
capacitances = [
0,
10,
12,
15,
22,
33,
47,
56,
68,
82,
100,
120,
150,
180,
220,
330,
470,
680
]
def p_c(c):
"""
Calculate parallel capacitance interval given fixed value
"""
return (variable[0] + c, variable[1] + c)
def s_c(p, s):
"""
Calculate series capacitance interval given series/parallel values
"""
p_i = p_c(p)
try:
return (
1 / ((1 / p_i[0]) + (1 / s)),
1 / ((1 / p_i[1]) + (1 / s)),
)
except ZeroDivisionError:
return (0, 0)
def add_tolerance(rng, amount):
"""
Adds amount tolerance to (min, max) range specified in rng
"""
mn, mx = rng
return (
mn - (mn * amount),
mx + (mx * amount)
)
def pf(v):
return f'{v:.2f}pF'
def pfs(v):
return f'{pf(v[0])}, {pf(v[1])}'
def compute_optimum(target):
# # Target capacitance range
# target = add_tolerance(targets[20], 0.1)
# Optimum setting for (parallel, series) capacitance
optimum = (0, 0)
# Error computed from last optimum
error = 99999.9
for p in capacitances:
for s in capacitances:
# Calculate range of capacitance given (p, s)
c = s_c(p, s)
# Compute differences from target capacitance
d_min = target[0] - c[0] # Delta from min
d_max = target[1] - c[1] # Delta from max
# The minimum should be less than target minimum
if d_min < 0:
continue
# Maximum should be greater than target maximum
if d_max > 0:
continue
# Calculate root mean square error
e = (
math.sqrt(math.pow(target[0] - c[0], 2))
+ math.sqrt(math.pow(target[1] - c[1], 2))
) / 2
print(f'Testing {pfs((p, s))}')
print(f' Target: {pfs(target)}')
print(f' Range: {pfs(c)}')
print(f' Error: {e:.4f}')
if e < error:
print(f'*** New optimium: {(p, s)}')
optimum = (p, s)
error = e
print(f'Optimum settings: {optimum}')
return optimum
results = {}
for band in targets.keys():
print(band)
results[band] = compute_optimum(add_tolerance(targets[band], 0.1))
required_values = {}
print()
print('*** Results ***')
print(f'{'Band':<10}{'Target':<25}{'Parallel':<15}{'Series':<15}{'Actual':<25}{'Range':<15}{'Deg/pF':<15}')
for band in results.keys():
p, s = results[band]
if p > 0:
required_values[p] = required_values.get(p, 0) + 1
if s > 0:
required_values[s] = required_values.get(s, 0) + 1
c = s_c(p, s)
rng = c[1] - c[0]
if rng == 0:
rng = variable[1] - variable[0]
deg_per_pf = f'{360 / rng:.2f}'
print(f'{f'{band}m':<10}{pfs(targets[band]):<25}{pf(p):<15}{pf(s):<15}{pfs(c):<25}{pf(rng):<15}{deg_per_pf:<15}')
print()
print("*** BOM ***")
print(f'{'Value':<15}{'Quantity':<15}')
for c in sorted(required_values.keys()):
print(f'{pf(c):<15}{required_values[c]:<15}')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment