Skip to content

Instantly share code, notes, and snippets.

@tclarke
Last active February 1, 2021 20:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tclarke/e87400f7e239fb5f801bf4a804ea40ea to your computer and use it in GitHub Desktop.
Save tclarke/e87400f7e239fb5f801bf4a804ea40ea to your computer and use it in GitHub Desktop.
Find E96 resistor pairs which match a specific ration.
#!/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)
#!/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