【问题标题】:Computing parallel connected resistance计算并联电阻
【发布时间】:2015-07-09 22:24:05
【问题描述】:

下面两个并联电阻的代数等效公式:

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 都会丢失精度。

我的理解正确吗?

【问题讨论】:

  • 上限应该是x[-1]我猜?
  • @anmol_uppal 请测试并找到您问题的答案。
  • 就个人而言,我正在为使用“间隔”来描述电阻器的概念而苦苦挣扎。为什么你需要两个数字来描述具有数量的东西,阻力,可以表示为一个数字?
  • @SiHa 好的。在现实世界中提到了设备的电阻,例如3.5 ohms with +/- 0.15 tolerance。所以,我们需要(3.35, 3.65) 之间的所有值,包括端点。
  • @overexchange 啊。这更有意义。不过,对于如此简单的操作,这段代码似乎仍然非常复杂。我会说,导致您出现不同结果的原因可能是因为所有代码中的某个地方都有错误,而不是浮点表示错误。

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


【解决方案1】:

恐怕您对为什么这两个函数给出不同结果的推理不正确。浮点舍入可能是一个真正的问题,但对于大多数计算(包括这里的计算)来说,误差非常非常小。只有当您测试完全相等或当您组合了大量浮点计算时,错误才可能变得显着。

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

当除数和被除数都包含相同的区间时,您将获得比应有的更宽的区间。这是因为代码不知道区间副本之一的一个极端结果也必然意味着另一个极端的相同极端。

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

第二个公式通过让每个输入区间只出现在一个位置来避免这个问题。您实际上可以允许一些重复。只要不存在负边界区间的减法、除法或乘法,应该没有问题。

【讨论】:

  • 如果我将其设置为reciprocal_y = interval(1/lower_bound(y), 1/upper_bound(y)) 它没有任何区别。因为我们在mul_interval中选择minmax
  • 没错,乘法代码确实取边界乘积的最小值和最大值,但如果边界都是正数,则最小值将是输入下限的乘积,最大值将是输入上限的乘积。计算倒数时不反转值会给你一个虚假的区间(下限将大于上限)。
  • 我们如何更改par1par2 以获得相似的结果?
  • @overexchange: par2 par1 的固定版本。您不需要让他们给出相同的答案,只需了解为什么par1 会出错。从问题的初稿中阅读作业文本,Eva 基本上是正确的。多引用是par1的问题,但并不是所有的公式多引用都会出问题。
  • “基本”我指的是非区间算术。这是合适的,因为区间只是指定单个实数的一些不确定性的一种方式。 r/r 将是 1,不管我们测量它的误差如何。您应该学习的问题是区间算术不能很好地处理这种情况。避免在公式中的多个位置使用相同的间隔是一种解决限制的方法。
【解决方案2】:

多个并联阻抗——万无一失

多个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

【讨论】:

    【解决方案3】:

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

    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]
    

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

    【讨论】:

    • par1/par2 来自here
    • 您的代码得到了par2 的正确结果(使用问题中的par1 公式),因为它假设(正确地,事实证明)输出的下限来自组合两个输入区间的下限(上限相同)。但是,区间操作并不总是如此。例如,a/b 的上限受b 的下限影响。这是代码中逻辑错误的根源。没有通用间隔代码将得到正确的a/a
    • @Blckknght:我现在明白了。我想应该很明显,除了学术练习之外,没有人会编写如此晦涩的代码。
    • @Blckknght 从这个code 我明白,a/b 的上限受b 的下限影响。但我想了解,这一点与par1par2 的不同输出有何关系?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    相关资源
    最近更新 更多