Last active
February 1, 2021 20:47
-
-
Save tclarke/e87400f7e239fb5f801bf4a804ea40ea to your computer and use it in GitHub Desktop.
Find E96 resistor pairs which match a specific ration.
This file contains 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 | |
import numpy as np | |
## | |
# Define different resistor series. You almost never see e3 and e6 but they are here for completeness. | |
# E96 are widely available and generally inexpensive so that's the default series. | |
# 40% tolerance | |
e3 = np.array([1. , 2.2, 4.7]) | |
# 20% tolerance | |
e6 = np.array([1. , 1.5, 2.2, 3.3, 4.7, 6.8]) | |
# 10% tolerance | |
e12 = np.array([1. , 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2]) | |
# 5% and 1% tolerance | |
e24 = np.array([1. , 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2. , 2.2, 2.4, 2.7, 3. , 3.3, | |
3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1]) | |
# 2% tolerance | |
e48 = np.array([1. , 1.05, 1.1 , 1.15, 1.21, 1.27, 1.33, 1.4 , 1.47, 1.54, 1.62, | |
1.69, 1.78, 1.87, 1.96, 2.05, 2.15, 2.26, 2.37, 2.49, 2.61, 2.74, | |
2.87, 3.01, 3.16, 3.32, 3.48, 3.65, 3.83, 4.02, 4.22, 4.42, 4.64, | |
4.87, 5.11, 5.36, 5.62, 5.9 , 6.19, 6.49, 6.81, 7.15, 7.5 , 7.87, | |
8.25, 8.66, 9.09, 9.53]) | |
# 1% tolerance | |
e96 = np.array([1. , 1.02, 1.05, 1.07, 1.1 , 1.13, 1.15, 1.18, 1.21, 1.24, 1.27, | |
1.3 , 1.33, 1.37, 1.4 , 1.43, 1.47, 1.5 , 1.54, 1.58, 1.62, 1.65, | |
1.69, 1.74, 1.78, 1.82, 1.87, 1.91, 1.96, 2. , 2.05, 2.1 , 2.16, | |
2.21, 2.26, 2.32, 2.37, 2.43, 2.49, 2.55, 2.61, 2.67, 2.74, 2.8 , | |
2.87, 2.94, 3.01, 3.09, 3.16, 3.24, 3.32, 3.4 , 3.48, 3.57, 3.65, | |
3.74, 3.83, 3.92, 4.02, 4.12, 4.22, 4.32, 4.42, 4.53, 4.64, 4.75, | |
4.87, 4.99, 5.11, 5.23, 5.36, 5.49, 5.62, 5.76, 5.9 , 6.04, 6.19, | |
6.34, 6.49, 6.65, 6.81, 6.98, 7.15, 7.32, 7.5 , 7.68, 7.87, 8.06, | |
8.25, 8.45, 8.66, 8.87, 9.09, 9.31, 9.53, 9.76]) | |
# 0.5%, 0.25%, and 0.1% tolerance | |
e192 = np.array([1. , 1.01, 1.02, 1.04, 1.05, 1.06, 1.07, 1.09, 1.1 , 1.11, 1.13, | |
1.14, 1.15, 1.17, 1.18, 1.2 , 1.21, 1.23, 1.24, 1.26, 1.27, 1.29, | |
1.3 , 1.32, 1.33, 1.35, 1.37, 1.38, 1.4 , 1.42, 1.43, 1.45, 1.47, | |
1.49, 1.5 , 1.52, 1.54, 1.56, 1.58, 1.6 , 1.62, 1.64, 1.65, 1.67, | |
1.69, 1.72, 1.74, 1.76, 1.78, 1.8 , 1.82, 1.84, 1.87, 1.89, 1.91, | |
1.93, 1.96, 1.98, 2. , 2.03, 2.05, 2.08, 2.1 , 2.13, 2.15, 2.18, | |
2.21, 2.23, 2.26, 2.29, 2.32, 2.34, 2.37, 2.4 , 2.43, 2.46, 2.49, | |
2.52, 2.55, 2.58, 2.61, 2.64, 2.67, 2.71, 2.74, 2.77, 2.8 , 2.84, | |
2.87, 2.91, 2.94, 2.98, 3.01, 3.05, 3.09, 3.12, 3.16, 3.2 , 3.24, | |
3.28, 3.32, 3.36, 3.4 , 3.44, 3.48, 3.52, 3.57, 3.61, 3.65, 3.7 , | |
3.74, 3.79, 3.83, 3.88, 3.92, 3.97, 4.02, 4.07, 4.12, 4.17, 4.22, | |
4.27, 4.32, 4.37, 4.42, 4.48, 4.53, 4.59, 4.64, 4.7 , 4.75, 4.81, | |
4.87, 4.93, 4.99, 5.05, 5.11, 5.17, 5.23, 5.3 , 5.36, 5.42, 5.49, | |
5.56, 5.62, 5.69, 5.76, 5.83, 5.9 , 5.97, 6.04, 6.12, 6.19, 6.26, | |
6.34, 6.42, 6.49, 6.57, 6.65, 6.73, 6.81, 6.9 , 6.98, 7.06, 7.15, | |
7.23, 7.32, 7.41, 7.5 , 7.59, 7.68, 7.77, 7.87, 7.96, 8.06, 8.16, | |
8.25, 8.35, 8.45, 8.56, 8.66, 8.76, 8.87, 8.98, 9.09, 9.2 , 9.31, | |
9.42, 9.53, 9.65, 9.76, 9.88]) | |
def find_pair(ratio, start=None, end=None, max_diff=None, series=e96, multiplier=1, all=True): | |
"""find a matching resistor pair | |
@param ratio The R1/R2 ratio desired | |
@param start If specified, don't use R1 values less than this. (will be divided by multiplier) | |
@param end If specified, don' use R1 values greater than this. (will be divided by multiplier) | |
@param max_diff The maximum difference allowed between calculated R2 and closest standard value. | |
Values are between 0.0 and 1.0. If None, will allow any difference. | |
@param multiplier R1 and R2 values will be multiplied by this. Start and end will be divided by this. | |
Only used to make output range match desired range. Must be a multiple of 10 | |
Examples: | |
>>> find_pair(3) # 3/1 ratio | |
>>> find_pair(2.5, max_diff=0.01) # 5/2 ratio with a maximum deviation of 1% | |
>>> find_pair(10, start=2., series=e192, multiplier=10) # 10/1 ratio from the E192 series. Nothing less than 20 (ohms, kOhm, MOhm) and display matches x10 | |
""" | |
multiplier = int(multiplier) | |
assert(multiplier > 0) | |
assert(multiplier % 10 == 0 or multiplier == 1) | |
if start is None: | |
start = series[0] | |
else: | |
start /= multiplier | |
if end is None: | |
end = series[-1] | |
else: | |
end /= multiplier | |
p = series[np.where(series >= start)] | |
p = p[np.where(series <= end)] | |
vals = [] | |
for v1 in p: | |
v2 = ratio * v1 | |
m2 = 1 | |
while v2 >= 10.: | |
v2 /= 10 | |
m2 *= 10 | |
idx = (np.abs(series - v2)).argmin() | |
v2_closest = series[idx] | |
diff = np.abs(v2-v2_closest) / np.max([v2,v2_closest]) | |
if max_diff is None or diff <= max_diff: | |
vals.append((v1, v2_closest * m2, diff)) | |
vals = sorted(vals, key=lambda x: x[2]) | |
if not all: | |
vals = vals[:1] | |
for v1,v2,diff in vals: | |
v1 *= multiplier | |
v2 *= multiplier | |
print(f'R1={v1:7.2f}, R2={v2:7.2f}, R1/R2={(v2 / v1):8.3f} ({(100 * diff):6.3f}%)') | |
if __name__ == '__main__': | |
import argparse | |
p = argparse.ArgumentParser() | |
p.add_argument('--max-diff', type=float) | |
p.add_argument('--start', type=float) | |
p.add_argument('--end', type=float) | |
p.add_argument('--multiplier', type=int, default=1) | |
p.add_argument('--series', choices=['E3', 'E6', 'E12','E24', 'E48', 'E96', 'E192'], default='E96') | |
p.add_argument('--all', action='store_true', default=False, help='Print all matches instead of just the best match?') | |
p.add_argument('ratio', type=float) | |
a = p.parse_args() | |
series = globals()[a.series.lower()] | |
find_pair(a.ratio, start=a.start, end=a.end, max_diff=a.max_diff, series=series, multiplier=a.multiplier, all=a.all) |
This file contains 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 | |
import numpy as np | |
## | |
# Define different resistor series. You almost never see e3 and e6 but they are here for completeness. | |
# E96 are widely available and generally inexpensive so that's the default series. | |
# 40% tolerance | |
e3 = np.array([1. , 2.2, 4.7]) | |
# 20% tolerance | |
e6 = np.array([1. , 1.5, 2.2, 3.3, 4.7, 6.8]) | |
# 10% tolerance | |
e12 = np.array([1. , 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2]) | |
# 5% and 1% tolerance | |
e24 = np.array([1. , 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2. , 2.2, 2.4, 2.7, 3. , 3.3, | |
3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1]) | |
# 2% tolerance | |
e48 = np.array([1. , 1.05, 1.1 , 1.15, 1.21, 1.27, 1.33, 1.4 , 1.47, 1.54, 1.62, | |
1.69, 1.78, 1.87, 1.96, 2.05, 2.15, 2.26, 2.37, 2.49, 2.61, 2.74, | |
2.87, 3.01, 3.16, 3.32, 3.48, 3.65, 3.83, 4.02, 4.22, 4.42, 4.64, | |
4.87, 5.11, 5.36, 5.62, 5.9 , 6.19, 6.49, 6.81, 7.15, 7.5 , 7.87, | |
8.25, 8.66, 9.09, 9.53]) | |
# 1% tolerance | |
e96 = np.array([1. , 1.02, 1.05, 1.07, 1.1 , 1.13, 1.15, 1.18, 1.21, 1.24, 1.27, | |
1.3 , 1.33, 1.37, 1.4 , 1.43, 1.47, 1.5 , 1.54, 1.58, 1.62, 1.65, | |
1.69, 1.74, 1.78, 1.82, 1.87, 1.91, 1.96, 2. , 2.05, 2.1 , 2.16, | |
2.21, 2.26, 2.32, 2.37, 2.43, 2.49, 2.55, 2.61, 2.67, 2.74, 2.8 , | |
2.87, 2.94, 3.01, 3.09, 3.16, 3.24, 3.32, 3.4 , 3.48, 3.57, 3.65, | |
3.74, 3.83, 3.92, 4.02, 4.12, 4.22, 4.32, 4.42, 4.53, 4.64, 4.75, | |
4.87, 4.99, 5.11, 5.23, 5.36, 5.49, 5.62, 5.76, 5.9 , 6.04, 6.19, | |
6.34, 6.49, 6.65, 6.81, 6.98, 7.15, 7.32, 7.5 , 7.68, 7.87, 8.06, | |
8.25, 8.45, 8.66, 8.87, 9.09, 9.31, 9.53, 9.76]) | |
# 0.5%, 0.25%, and 0.1% tolerance | |
e192 = np.array([1. , 1.01, 1.02, 1.04, 1.05, 1.06, 1.07, 1.09, 1.1 , 1.11, 1.13, | |
1.14, 1.15, 1.17, 1.18, 1.2 , 1.21, 1.23, 1.24, 1.26, 1.27, 1.29, | |
1.3 , 1.32, 1.33, 1.35, 1.37, 1.38, 1.4 , 1.42, 1.43, 1.45, 1.47, | |
1.49, 1.5 , 1.52, 1.54, 1.56, 1.58, 1.6 , 1.62, 1.64, 1.65, 1.67, | |
1.69, 1.72, 1.74, 1.76, 1.78, 1.8 , 1.82, 1.84, 1.87, 1.89, 1.91, | |
1.93, 1.96, 1.98, 2. , 2.03, 2.05, 2.08, 2.1 , 2.13, 2.15, 2.18, | |
2.21, 2.23, 2.26, 2.29, 2.32, 2.34, 2.37, 2.4 , 2.43, 2.46, 2.49, | |
2.52, 2.55, 2.58, 2.61, 2.64, 2.67, 2.71, 2.74, 2.77, 2.8 , 2.84, | |
2.87, 2.91, 2.94, 2.98, 3.01, 3.05, 3.09, 3.12, 3.16, 3.2 , 3.24, | |
3.28, 3.32, 3.36, 3.4 , 3.44, 3.48, 3.52, 3.57, 3.61, 3.65, 3.7 , | |
3.74, 3.79, 3.83, 3.88, 3.92, 3.97, 4.02, 4.07, 4.12, 4.17, 4.22, | |
4.27, 4.32, 4.37, 4.42, 4.48, 4.53, 4.59, 4.64, 4.7 , 4.75, 4.81, | |
4.87, 4.93, 4.99, 5.05, 5.11, 5.17, 5.23, 5.3 , 5.36, 5.42, 5.49, | |
5.56, 5.62, 5.69, 5.76, 5.83, 5.9 , 5.97, 6.04, 6.12, 6.19, 6.26, | |
6.34, 6.42, 6.49, 6.57, 6.65, 6.73, 6.81, 6.9 , 6.98, 7.06, 7.15, | |
7.23, 7.32, 7.41, 7.5 , 7.59, 7.68, 7.77, 7.87, 7.96, 8.06, 8.16, | |
8.25, 8.35, 8.45, 8.56, 8.66, 8.76, 8.87, 8.98, 9.09, 9.2 , 9.31, | |
9.42, 9.53, 9.65, 9.76, 9.88]) | |
def find_pair(Vin, Vout, start=None, end=None, max_diff=None, series=e96, multiplier=1, all=True): | |
"""find a matching resistor pair | |
@param Vin The input voltage | |
@param Vout The output voltage | |
@param start If specified, don't use R1 values less than this. (will be divided by multiplier) | |
@param end If specified, don' use R1 values greater than this. (will be divided by multiplier) | |
@param max_diff The maximum difference allowed between calculated R2 and closest standard value. | |
Values are between 0.0 and 1.0. If None, will allow any difference. | |
@param multiplier R1 and R2 values will be multiplied by this. Start and end will be divided by this. | |
Only used to make output range match desired range. Must be a multiple of 10 | |
Examples: | |
>>> find_pair(12, 5) # 12v in 5v out | |
>>> find_pair(9, 5, max_diff=0.01) # 9v in 5v out with a maximum deviation of 1% | |
>>> find_pair(9, 5, start=2., series=e192, multiplier=10) # 9v in 5v out from the E192 series. Nothing less than 20 (ohms, kOhm, MOhm) and display matches x10 | |
""" | |
multiplier = int(multiplier) | |
assert(multiplier > 0) | |
assert(multiplier % 10 == 0 or multiplier == 1) | |
assert(Vin >= Vout) | |
if start is None: | |
start = series[0] | |
else: | |
start /= multiplier | |
if end is None: | |
end = series[-1] | |
else: | |
end /= multiplier | |
p = series[np.where(series >= start)] | |
p = p[np.where(series <= end)] | |
vals = [] | |
for r1 in p: | |
r2 = ((Vin * r1) / Vout) - r1 | |
m2 = 1 | |
while r2 >= 10.: | |
r2 /= 10 | |
m2 *= 10 | |
idx = (np.abs(series - r2)).argmin() | |
r2_closest = series[idx] | |
diff = np.abs(r2-r2_closest) / np.max([r2,r2_closest]) | |
if max_diff is None or diff <= max_diff: | |
vals.append((r1, r2_closest * m2, (r1 / (r1 + r2_closest * m2)) * Vin, diff)) | |
vals = sorted(vals, key=lambda x: x[3]) | |
if not all: | |
vals = vals[:1] | |
for r1,r2,vout2,diff in vals: | |
r1 *= multiplier | |
r2 *= multiplier | |
print(f'R1={r1:7.2f}, R2={r2:7.2f}, Vout={vout2:8.3f} ({(100 * diff):6.3f}%)') | |
if __name__ == '__main__': | |
import argparse | |
p = argparse.ArgumentParser() | |
p.add_argument('--max-diff', type=float) | |
p.add_argument('--start', type=float) | |
p.add_argument('--end', type=float) | |
p.add_argument('--multiplier', type=int, default=1) | |
p.add_argument('--series', choices=['E3', 'E6', 'E12','E24', 'E48', 'E96', 'E192'], default='E96') | |
p.add_argument('--all', action='store_true', default=False, help='Print all matches instead of just the best match?') | |
p.add_argument('Vin', type=float) | |
p.add_argument('Vout', type=float) | |
a = p.parse_args() | |
series = globals()[a.series.lower()] | |
find_pair(a.Vin, a.Vout, start=a.start, end=a.end, max_diff=a.max_diff, series=series, multiplier=a.multiplier, all=a.all) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment