[英]Python algorithm to approximate closest parallel equivalence of resistors from a list
The formula for series equivalence of resistors:电阻串联等效公式:
series equivalence = sum(resistors)系列等效=总和(电阻器)
For parallel it is 1/(sum(1/resistors[i]))对于并行,它是 1/(sum(1/resistors[i]))
I wrote code to return a list of resistors that is closest to a specified target value from a list, within a specified tolerance.我编写了代码以在指定的容差范围内返回最接近列表中指定目标值的电阻器列表。
percentage_difference = lambda xi,xf: 100*(xf-xi)/xi
def series_equivalance(R,target,tolerance):
"""
R = list of resistors present
target = target value
tolerance = range += % of target that is acceptable
This function returns a list of resistors
"""
tol = tolerance/100 #converting tolerance to decimal
if target < min(R):
return "Your target is too small for series equivalence, Try parallel equivalence"
else:
r = R #dummy/copy R
toriginal = target #dummy values for arguments made to not change arguments
approximate = 0 #this is for exit condition, target in and of itself could be used but that would make algo unstable
resistors_list = [] #list to return at the end
while True: #Infinite loop because multiple exit conditions
if (approximate >= (1-tol)*target and approximate <= (1+tol)*target) :#exit condition
break
if len(R) == 0: #If all values are used up
return "All values used up, list: {}, approximate: {}".format(resistors_list,series_sum(resistors_list))
difference_from_target = [abs(toriginal-i) for i in R] #finding absolute difference of target from list of R values
for i,v in enumerate(difference_from_target):
if v == min(difference_from_target): #adding lowest differences to list
approximate += r[i] #increment approximate by value from resistors with least difference
toriginal -= r[i] #remove that from target dummy target
resistors_list.append(r[i]) #adding to list to be returned
r.remove(r[i])
break
return "Resistors to use are {}, Approximated value: {}, %Δ of {}%".format(resistors_list,sum(resistors_list),percentage_difference(target,int(sum(resistors_list))))
So for example series_equivalance([1,2,3,4,5],7,0)
will return [5,2]
.因此,例如
series_equivalance([1,2,3,4,5],7,0)
将返回[5,2]
。
I want to a function that can do the same for parallel equivalence.我想要一个 function 可以为并行等效做同样的事情。 How would I go about it?
我怎么会 go 呢?
Edit: I made a blog post which expands on the mip solution and can solve for minimum resistors satisfying a tolerance.编辑:我发表了一篇博客文章,扩展了 mip 解决方案,可以解决满足容差的最小电阻。
I've solved this two ways我已经解决了这两种方法
This is a half way solution that just feeds in 1/R for the resistor values and gives it a target resistance of 1/target.这是一种中途解决方案,它只为电阻值输入 1/R,并为其提供 1/target 的目标电阻。 Then, take reciprocal of the result and you have your resistor values.
然后,取结果的倒数,你就有了你的电阻值。 Doesn't work with the tolerance value properly.
不适用于公差值。 Need to comment out the "Your target is too small" check for it to work.
需要注释掉“你的目标太小”检查它才能工作。
def parallel_equivalance(R, target, tolerance):
R_recip = [1/x for x in R]
target_recip = 1/target
tolerance_recip = tolerance # TODO: have a think about how to handle this.
result_recip = series_equivalance(R_recip, target_recip, tolerance_recip)
# resistors_to_use = [1/x for x in result_recip]
print(parallel_equivalance([1, 2, 3, 4, 5, 6, 7], 1.5555, 1e-2))
gives Resistors to use are [5, 2], Approximated value: 7, %Δ of 0.0%
print(parallel_equivalance([1, 2, 3, 4, 5, 6, 7], 1.5555, 1e-2))
给出Resistors to use are [5, 2], Approximated value: 7, %Δ of 0.0%
For this method I use a mixed integer linear program to pick out which resistors to use, such that (1/r1 + 1/r2 +...) is as close as possible to 1/target.对于这种方法,我使用混合 integer 线性程序来挑选要使用的电阻器,使得 (1/r1 + 1/r2 +...) 尽可能接近 1/target。 Solves very quickly (<1s) even when given ten thousand resistors to choose from.
即使有一万个电阻器可供选择,也能非常快速地求解(<1s)。
You could modify this to pick the least number of resistors (minimise sum(R_in_use)
) with the constraint that the error value must be within some margin (say, error >= -eps
and error <= +eps
)您可以修改它以选择最少数量的电阻器(最小化
sum(R_in_use)
),并限制误差值必须在一定范围内(例如, error >= -eps
和error <= +eps
)
You'll need to pip install mip
您需要
pip install mip
import mip
def parallel_equivalance(R, target):
R_recip = [1/x for x in R]
target_recip = 1/target
m = mip.Model() # Create new mixed integer/linear model.
# Will take value of 1 when corresponding resistor is in use, otherwise 0.
R_in_use = [m.add_var(var_type=mip.BINARY) for _ in R_recip]
opt_r = sum([b * r for b, r in zip(R_in_use, R_recip)]) # This will be the optimal resistance
error = opt_r - target_recip # Want to minimise the absolute value of this error.
# create a variable which is greater than than the absolute value of the error.
# Because we will be minimizing, this will be forced down to equal the
# absolute value. Common trick, google "linear programming absolute value".
abs_eror = m.add_var(lb=0)
m += abs_eror >= error
m += abs_eror >= -1 * error
# Objective of the optimisation is to minimise the absolute error.
m.objective = mip.minimize(abs_eror)
m.verbose = False # Turn off verbose logging output.
sol_status = m.optimize()
print(sol_status) # This should be `optimal`.
# Get the solution values telling us which resistors are in use.
R_in_use_sol = [float(v) for v in R_in_use]
# Pick out the values of the resistors corresponding to the resistors
# that the optimiser decided to use.
R_to_use = [r for r, i in zip(R, R_in_use_sol) if i > 0]
solved_resistance = 1/sum(1/x for x in R_to_use)
solved_error = 100 * (solved_resistance - target) / target
print(f'Resistors {R_to_use} in parallel will produce '
f'R={solved_resistance:.3f}. '
f'Aiming for R={target:.3f}, '
f'error of {solved_error:.2f}%')
return R_to_use
def main():
print(f'mip version {mip.version}')
sol = parallel_equivalance([1, 2, 3, 4, 5, 6, 7], 1.5555)
sol = parallel_equivalance([1, 2, 3, 4, 5, 6, 7], 1.9)
sol = parallel_equivalance(list(range(1, 100)), 123)
sol = parallel_equivalance(list(range(1, 1000)), 5.954520294)
sol = parallel_equivalance(list(range(1, 10_000)), 5.954520294)
if __name__ == '__main__':
main()
mip version 1.13.0
OptimizationStatus.OPTIMAL
Resistors [2, 7] in parallel will produce R=1.556. Aiming for R=1.556, error of 0.00%
OptimizationStatus.OPTIMAL
Resistors [3, 5] in parallel will produce R=1.875. Aiming for R=1.900, error of -1.32%
OptimizationStatus.OPTIMAL
Resistors [99] in parallel will produce R=99.000. Aiming for R=123.000, error of -19.51%
OptimizationStatus.OPTIMAL
Resistors [27, 40, 41, 68, 69, 83, 123, 166, 172, 219, 277, 384, 391, 435, 453, 782, 837] in parallel will produce R=5.954. Aiming for R=5.955, error of -0.01%
OptimizationStatus.OPTIMAL
Resistors [7, 2001, 2021, 2065, 2130, 2152, 2160, 2176, 2191, 2202, 2216, 2245, 2270, 2279, 2282, 2283, 2313, 2342, 2351, 2381, 2414, 2417, 2497, 2728, 2789, 3449, 3514, 3566, 3575, 3621, 3701, 3789, 3812, 3868, 3879, 3882, 3903, 3936, 3952, 3959, 4128, 4145, 4152, 4158, 4183, 4373, 4382, 4430, 4441, 4498, 4525, 4678, 4722, 4887, 4953, 5138, 5178, 5253, 5345, 5358, 5543, 5593, 5620, 5774, 6002, 6247, 6364, 6580, 6715, 6740, 6819, 6904, 7187, 7293, 7380, 7468, 7533, 7782, 7809, 7846, 7895, 7914, 8018, 8067, 8242, 8309, 8414, 8507, 8515, 8590, 8627, 8872, 8893, 8910, 8952, 9171, 9282, 9311, 9376, 9477, 9550, 9657, 9736, 9792, 9822, 9876, 9982, 9988] in parallel will produce R=5.957. Aiming for R=5.955, error of 0.04%
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.