从列表中近似电阻最接近并行等效的Python算法

2024-06-14 00:17:12 发布

您现在位置:Python中文网/ 问答频道 /正文

电阻器串联等效公式:

串联等效=和(电阻)

对于并联,它是1/(和(1/电阻[i]))

我编写代码返回一个电阻列表,该列表最接近列表中指定的目标值,在指定的公差范围内

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))))
    

例如series_equivalance([1,2,3,4,5],7,0)将返回[5,2]

我想要一个函数,可以做同样的并行等价。我该怎么做呢


Tags: oftofromtargetforreturniftolerance
1条回答
网友
1楼 · 发布于 2024-06-14 00:17:12

编辑:我制作了一个blog post,它扩展了mip解决方案,可以求解满足公差的最小电阻

我用两种方法解决了这个问题

  1. 使用函数并向其提供反向值
  2. 使用混合整数线性规划

使用函数并向其提供反向值

这是一个中间解决方案,只需为电阻器输入1/R 值,并使其目标电阻为1/target。 然后,取结果的倒数,得到电阻值。 不能正确使用公差值。需要注释掉 “你的目标太小”检查它是否有效

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))给出Resistors to use are [5, 2], Approximated value: 7, %Δ of 0.0%

使用混合整数线性规划

对于这种方法,我使用一个混合整数线性规划来选择 要使用的电阻器,以便(1/r1+1/r2+…)尽可能接近 尽可能达到1/目标。即使在给定的情况下,也能快速求解(<;1s) 一万个电阻器可供选择

您可以对此进行修改,以选取最少数量的电阻器 (最小化sum(R_in_use))的约束 错误值必须在一定范围内(例如,error >= -epserror <= +eps

你需要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%

相关问题 更多 >