计算并联电阻

时间:2015-04-30 09:28:43

标签: python python-3.x floating-point intervals

以下两个代数均衡的并联电阻公式:

par1(r1, r2) = (r1 * r2) / (r1 + r2), or

par2(r1, r2) = 1 / (1/r1 + 1/r2)

遵循两个python函数,每个函数计算parallel_resistors公式:

def par1(r1, r2):
    return div_interval(mul_interval(r1, r2), add_interval(r1, r2))

def par2(r1, r2):
    one = interval(1, 1)
    rep_r1 = div_interval(one, r1)
    rep_r2 = div_interval(one, r2)
    return div_interval(one, add_interval(rep_r1, rep_r2))

下面是上述函数par1par2使用的区间算术抽象。

def interval(a, b):
    """Construct an interval from a to b. """
    return (a, b)

def lower_bound(x):
    """Return the lower bound of interval x. """
    return x[0]

def upper_bound(x):
    """Return the upper bound of interval x. """
    return x[1]

def div_interval(x, y):
    """Return the interval that contains the quotient of any value in x divided
    by any value in y.

    Division is implemented as the multiplication of x by the reciprocal of y.
    >>> str_interval(div_interval(interval(-1, 2), interval(4, 8)))
    '-0.25 to 0.5'
    """
    assert (lower_bound(y) > 0  or upper_bound(y) < 0), "what it means to divide by an interval that spans zero"
    reciprocal_y = interval(1/upper_bound(y), 1/lower_bound(y))
    return mul_interval(x, reciprocal_y)


def str_interval(x):
    """Return a string representation of interval x.
    >>> str_interval(interval(-1, 2))
    '-1 to 2'
    """
    return '{0} to {1}'.format(lower_bound(x), upper_bound(x))

def add_interval(x, y):
    """Return an interval that contains the sum of any value in interval x and
    any value in interval y.
    >>> str_interval(add_interval(interval(-1, 2), interval(4, 8)))
    '3 to 10'
    """
    lower = lower_bound(x) + lower_bound(y)
    upper = upper_bound(x) + upper_bound(y)
    return interval(lower, upper)

def mul_interval(x, y):
    """Return the interval that contains the product of any value in x and any
    value in y.

    >>> str_interval(mul_interval(interval(-1, 2), interval(4, 8)))
    '-8 to 16'
    """
    p1 = lower_bound(x) * lower_bound(y)
    p2 = lower_bound(x) * upper_bound(y)
    p3 = upper_bound(x) * lower_bound(y)
    p4 = upper_bound(x) * upper_bound(y)
    return interval(min(p1, p2, p3, p4), max(p1, p2, p3, p4))

测试结果:

>>> r1 = interval(1, 2) 
>>> r2 = interval(3, 4)
>>> par1(r1, r2) 
(0.5, 2.0) 
>>> par2(r1, r2) 
(0.75, 1.3333333333333333)

我们注意到par1par2的不同结果,它们通过不同但代数相当的表达式计算。 对于上面给出的输入r1和r2,下面是计算。

par1 --> return mul_interval((3, 8), (1/6, 1/4)) = (1/2, 2)
=======
rep_r1 = div_interval((1, 1), (1, 2)) = (1/2, 1)
rep_r2 = div_interval((1, 1), (3, 4)) =  (1/4, 1/3)
par2 --> return  div_interval((1, 1), (3/4, 4/3)) = (3/4, 4/3) 

不同间隔的原因是由于IEEE浮点格式,每div_interval失去精度。

我的理解是否正确?

3 个答案:

答案 0 :(得分:4)

我担心你为什么这两个函数给出不同结果的原因是不正确的。浮点舍入可能是一个真正的问题,但对于大多数计算(包括此处的计算),错误非常非常小。只有在您进行完全相等的测试时,或者当您将大量浮点计算组合在一起时,错误可能会变得非常重要。

这里的真正问题是,在par1中,您的r1r2间隔都出现在除法运算的两侧。当除法函数计算其第二个参数的倒数时,它会反转区间边界的顺序,因此输入的上限会影响输出的下限。

当相同的间隔是除数和被除数的一部分时,你将获得比你应该更宽的间隔。这是因为代码不知道该区间的一个副本在一个极端的结果也必须对另一个副本意味着相同的极端。

考虑r / r的间隔r = (a, b)的计算。您的div_interval函数会将结果计算为(a/b, b/a),当我们通过基本代数时,我们知道结果应该是(1, 1)(因为任何数字除以它都是1)。然而,除法代码必须假设它的每个参数都独立于另一个。如果除数结果是其间隔的最大界限(b),则它可能将被除数除以其最小界限(a)。它无法知道这两件事情不可能同时发生。

第二个公式通过让每个输入间隔仅出现在一个位置来避免此问题。你实际上可以允许一点点重复。只要没有包含负边界的间隔的减法,除法或乘法,就没有问题。

答案 1 :(得分:0)

多个并联阻抗-万无一失

许多impedances in parallel的总阻抗对应于这些阻抗的harmonic mean除以并联阻抗的数量。

from scipy import stats

def par(array):
    """Calculate the impedance of an array of parallel impedances"""
    return stats.hmean(array)/len(array)

In [1]: par([2.7, 3.3, 10])
Out[1]: 1.29299

答案 2 :(得分:-1)

为了证明它不是舍入误差,这里有一些代码使用两种方法来计算并联电阻。只是为了表明两种计算方法产生完全相同的结果,它并不是整洁或特别有效。

def par1(r1,r2):
    r1lower = float(r1[0])
    r1upper = float(r1[1])
    r2lower = float(r2[0])
    r2upper = float(r2[1])
    low = 1/((1/r1lower)+(1/r2lower))
    high = 1/((1/r1upper)+(1/r2upper))
    return(low, high)

def par2(r1,r2):
    r1lower = float(r1[0])
    r1upper = float(r1[1])
    r2lower = float(r2[0])
    r2upper = float(r2[1])
    low = (r1lower * r2lower) / (r1lower + r2lower)
    high = (r1upper * r2upper) / (r1upper + r2upper)
    return(low, high)

if __name__ == '__main__':
    print par1((1,2),(3,4))
    print par2((1,2),(3,4))

输出:

(0.75, 1.3333333333333333)
(0.75, 1.3333333333333333)
[Finished in 0.1s]

你代码中的某个地方有错误......