Skip to content

Instantly share code, notes, and snippets.

@ES-Alexander
Created January 11, 2022 12:09
Show Gist options
  • Save ES-Alexander/30a6d4091293ba47c1c97ea7d937319c to your computer and use it in GitHub Desktop.
Save ES-Alexander/30a6d4091293ba47c1c97ea7d937319c to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
from itertools import combinations_with_replacement
from typing import List, Tuple, Generator
VALID_E_SERIES = (3, 6, 12, 24, 48, 96, 192)
def E(m: int) -> Generator[float, None, None]:
""" A generator of IEEE E-series values.
Calculates ideal spacings, then adjusts to match legacy industry values,
as per https://en.wikipedia.org/wiki/E_series_of_preferred_numbers
"""
assert m in VALID_E_SERIES, ("Invalid E-series length - "
f"must be one of {VALID_E_SERIES}.")
digits = 2 if m > 24 else 1
for n in range(m):
calculated = round(10**(n/m), digits)
# adjust legacy values as required
if m <= 24:
if 2.5 < calculated < 4.7:
yield round(calculated + 0.1, 1)
continue
elif calculated == 8.3:
yield 8.2
continue
elif calculated == 9.19:
yield 9.2
continue
yield calculated
def find_voltage_divider_resistors(v_target: float, v_in: float=5, seq=E(12)) \
-> Tuple[float, List[Tuple[int, int, float]]]:
""" Finds the closest pair of resistors from 'seq' to achieve 'v_target'.
Returns (best_diff, [(r1, r2, v_out), ...])
If multiple pairings have the same diffence from 'v_target', all similar
pairings are included in the output list.
'v_target' is the output voltage to aim for.
"""
best_diff = float('inf')
for r1, r2 in combinations_with_replacement(seq, 2):
v_out = v_in * r2 / (r1 + r2)
diff = abs(v_out - v_target)
if diff < best_diff:
best_diff, best_results = diff, [(r1, r2, v_out)]
elif diff == best_diff:
best_results.append((r1, r2, v_out))
return best_diff, best_results
if __name__ == '__main__':
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
parser = ArgumentParser(description=
'determine best resitors for voltage divider',
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('target', type=float, help='v_out to aim for')
parser.add_argument('-i', '--v_in', type=float, default=5.0,
help='v_in across the divider')
parser.add_argument('-e', '--e_series', type=int, default=12,
choices=VALID_E_SERIES,
help='E-series of resistor values to consider.')
args = parser.parse_args()
v_target, v_in, e_series = args.target, args.v_in, args.e_series
best_diff, results = find_voltage_divider_resistors(v_target, v_in,
E(e_series))
print(f"Input parameters: {v_target=}V, {v_in=}V, {e_series=}",
"Best results found: [(r1, r2, v_out)]", results,
f"Difference from target: {best_diff:.5f}V", sep='\n')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment