Created
January 11, 2022 12:09
-
-
Save ES-Alexander/30a6d4091293ba47c1c97ea7d937319c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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