使用VBA迭代求解方程组

时间:2017-03-16 09:10:58

标签: vba loops iteration

我正在尝试在VBA中解决以下方程组:

Equation 1 Equation 2

我已经找了其他类似的问题,我找不到合适的解决方案。我已经在工作表中解决了方程式,只需输入方程式,因为公式是单独的单元格(最初将创建循环参考警告)和启用迭代计算) - 假设我知道DR总是大于PR,我想从DR的初始值递增地减少PR的迭代方法将在VBA中起作用。作为参考,使用的工作表如下所示:

Worksheet showing solution using formulae and iterative calculation

G9中的公式为=(G8*B6)/(G10+273.15),即公式2(见上文),G10中的公式为=(B6+(B6*(-1+((G9*(B3-B35))/(B3-B35))^0.263)/B34))-B33*(B6+(B6*(-1+((G9*(B3-B35))/(B3-B35))^0.263)/B34)),即公式1(见上文)。

当我尝试通过从DR的初始值逐步减少PR在VBA中以编程方式执行此操作时,它不起作用。我的代码如下:

Sub ChargeTempAndPressureCalculations()

Dim AP_hPa As Double
Dim AP_psi As Double
Dim TIn_C As Double
Dim TIn_K As Double
Dim PR As Double
Dim Ei As Double
Dim Et As Double
Dim Vci As Double
Dim DR As Double
Dim TOut_C As Double

AP_hPa = 1029 'Input
AP_psi = AP_hPa * 100 * 0.000145038

TIn_C = 15 'Input
TIn_K = TIn_C + 273.15

Et = 0.75 'Input
Ei = 0.75 'Input
Vci = 0.5 'Input
DR = 2.7103502887329 'Input
PR = DR

Do Until TOut_C = (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et)) - Ei * (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et)) And PR = (DR * TIn_K) / (TOut_C + 273)
PR = PR - 0.00000000001
Loop

Debug.Print "Charge air temperature = " & TOut_C
Debug.Print "Pressure Ratio = " & PR


End Sub

这显然是循环问题,但是我做错了什么呢?

编辑:

我已经拆分了等式1,以防止评论中提到的另一个用户观察到的“等式太复杂”错误。我还添加了一个控件来防止步数超过1000.

Sub ChargeTempAndPressureCalculations()

Dim AP_hPa As Double
Dim AP_psi As Double
Dim TIn_C As Double
Dim TIn_K As Double
Dim PR As Double
Dim Ei As Double
Dim Et As Double
Dim Vci As Double
Dim DR As Double
Dim TOut_C As Double
Dim A As Double
Dim B As Double
Dim i As Integer

AP_hPa = 1029 'Input
AP_psi = AP_hPa * 100 * 0.000145038

TIn_C = 15 'Input
TIn_K = TIn_C + 273.15

Et = 0.75 'Input
Ei = 0.75 'Input
Vci = 0.5 'Input
DR = 2.7103502887329 'Input
PR = DR

Do Until i > 1000 Or (TOut_C = A - Ei * B And PR = (DR * TIn_K) / (TOut_C + 273))
'Spliting equation for TOut_C to simplify the expression and prevent an error
A = (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et))
B = (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et))

PR = PR - 0.00000000001
i = i + 1
Loop

Debug.Print "Charge air temperature = " & TOut_C
Debug.Print "Pressure Ratio = " & PR


End Sub

在阅读了所提供的答案之后,我仍然不知道如何解决我的问题。

4 个答案:

答案 0 :(得分:0)

请注意:

Do Until TOut_C = ...

=符号是 comparisson ,而不是赋值。由于尚未使用TOut_C,因此VB将其设置为零,因此您要比较右侧是否为零。这似乎不是您的意图,因为您在TOut_C部分中使用AND作为TOut_C + 273,然后始终为273.

但是如果你想与零比较,那么请注意RHS在浮点运算中可能永远不会变为零,你必须与“epsilon”进行比较,这是一个小的值,即你的精确阈值。例如:

Private Const eps = 0.00000000001   ' must be smaller than your step size

Do Until Abs(TOut_C - RHS) < eps

我把这件事告诉你。 (我的Excel版本也出现“Expression too complex”错误。)

答案 1 :(得分:0)

主要有两个问题...... 在您的Do..Loop中,您希望代码在TOut_C = <something based on PR> AND PR = <something based on TOut_C>

上中断

然而,这两个方程都会导致双数据类型,这几乎是无法比较的,因为点击该等点的可能性实际为零(正如我解释here

因此,您需要设置更灵活的参数,例如TOut_C > 63

我能找到的第二件事是方程就是方程式。所以他们会产生一个数字,但是这个数字是等式的结果,但是什么会定义终点?永远不会定义TOut_C并随后按照指示进行比较,您的代码以PR开头为2.71 ...但Tout_C为0。

那么你能详细说明TOut_CPR之间的相关性以及它们中的一个或两个的解决方案值是什么?或者您是否正在尝试解决平衡点,即TOut_C两个函数实现相同的结果? (这需要在数学上重写任一函数来表达相同的输出)所以重写PR的函数来生成Tout_C ......

循环工作(即它循环),如果你这样写... 它没有解决它,但至少你知道它循环......

Do Until TOut_C = 15 And PR = 22
TOut_C = (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et)) - Ei * (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et))
PR = (DR * TIn_K) / (TOut_C + 273)
PR = PR - 0.00000000001
Loop

答案 2 :(得分:0)

我已经超过你的计算了一点,如果PRTOut_C的增量非常小,我想你想要停止...

以下代码就是这样做的。它会计算给定TOut_C的{​​{1}},随后计算与PR对应的PR,然后循环将新计算的TOut_C替换为PR 1}}计算等。

它计算替代计算与先前计算之间的差异,如果两者之间不再存在“大”偏移,则会停止循环。

TOut_C

根据您的初始输入,输出为:

Sub ChargeTempAndPressureCalculations()

Dim AP_hPa As Double
Dim AP_psi As Double
Dim TIn_C As Double
Dim TIn_K As Double
Dim PR As Double
Dim Ei As Double
Dim Et As Double
Dim Vci As Double
Dim DR As Double
Dim TOut_C As Double

AP_hPa = 1029 'Input
AP_psi = AP_hPa * 100 * 0.000145038

TIn_C = 15 'Input
TIn_K = TIn_C + 273.15

Et = 0.75 'Input
Ei = 0.75 'Input
Vci = 0.5 'Input
DR = 2.7103502887329 'Input
PR = DR

dTOut_C = 1     'Set to arbitrary number to initialize the loop
dPR = 1         'Set to arbitrary number to initialize the loop

Do Until dPR < 0.0000000001 And dTOut_C < 0.0000000001
'Calculate the TOut_C and PR
TOut_C = (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et)) - Ei * (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et))
PR = (DR * TIn_K) / (TOut_C + 273)

'Calculate difference relative to last calculation
dPR = PR - PR0
dTOut_C = TOut_C - TOut_C0

'Set the last calculation as previous calculation and re-do loop
PR0 = PR
TOut_C0 = TOut_C

Loop

Debug.Print "Charge air temperature = " & TOut_C
Debug.Print "Pressure Ratio = " & PR

End Sub

那是你在找什么?

PS:从技术上讲,你应该做的是在数学上重写方程式来解决基于DR的PR问题,因为这实质上就是你在做什么......

答案 3 :(得分:0)

有关Excel如何处理循环引用的信息,请参阅http://www.decisionmodels.com/calcsecretsc.htm。基本上,它只计算每个单元格,忽略循环引用,然后更新每次迭代中的值。

将此应用于您的VBA例程会产生以下子例程:

Sub ChargeTempAndPressureCalculations()

    ' input variables
    Dim AP_hPa As Double
    Dim AP_psi As Double
    Dim TIn_C As Double
    Dim TIn_K As Double
    Dim Ei As Double
    Dim Et As Double
    Dim Vci As Double
    Dim DR As Double

    ' temporary variables
    Dim Td As Double
    Dim Pd As Double
    Dim A As Double

    ' output variables
    Dim TOut_C As Double
    Dim PR As Double

    ' iteration control
    Dim eps As Double
    Dim i As Integer

    AP_hPa = 1029
    AP_psi = AP_hPa * 100 * 0.000145038

    TIn_C = 15
    TIn_K = TIn_C + 273.15

    Et = 0.75
    Ei = 0.75
    Vci = 0.5
    DR = 2.7103502887329
    PR = DR

    eps = 0.00000000001
    i = 0
    Do
        Td = TOut_C     ' remember values from previous iteration ( 'd' means 'delta')
        Pd = PR

        A = (TIn_K + (TIn_K * (-1 + ((PR * (AP_psi - Vci)) / (AP_psi - Vci)) ^ 0.263) / Et))
        TOut_C = A - Ei * A
        PR = (DR * TIn_K) / (TOut_C + 273)
        i = i + 1

        Debug.Print TOut_C & ", " & PR & "(" & Abs(Td - TOut_C) & ", " & Abs(Pd - PR) & ")" ' show progression

        ' loop until the difference is less than eps or max iterations reached
    Loop While (i < 100 And (Abs(Td - TOut_C) > eps And Abs(Pd - PR) > eps))


    Debug.Print "Charge air temperature = " & TOut_C
    Debug.Print "Pressure Ratio = " & PR
    Debug.Print "number of iterations: " & i

End Sub

输出:

100.835921416446, 2.08911822261291(100.835921416446, 0.621232066119993)
92.5738330344343, 2.13633297880164(8.26208838201211, 4.72147561887288E-02)
93.2611120407512, 2.13232420812257(0.687279006316899, 4.00877067907057E-03)
93.2031960023579, 2.13266144103602(5.79160383933299E-02, 3.37232913455665E-04)
93.2080712078647, 2.13263304962791(4.87520550686327E-03, 2.83914081067316E-05)
93.2076607895546, 2.13263543972443(4.10418310181626E-04, 2.39009651137323E-06)
93.2076953402811, 2.13263523851592(3.45507265677725E-05, 2.01208508077144E-07)
93.2076924316548, 2.1326352554545(2.90862628560262E-06, 1.6938581648418E-08)
93.2076926765153, 2.13263525402854(2.44860444809092E-07, 1.42596112695514E-09)
93.2076926559019, 2.13263525414858(2.06133563551703E-08, 1.200430865822E-10)
93.2076926576372, 2.13263525413848(1.73530168012803E-09, 1.01052499701382E-11)
93.2076926574912, 2.13263525413933(1.46073375617561E-10, 8.5043083686287E-13)
Charge air temperature = 93.2076926574912
Pressure Ratio = 2.13263525413933
number of iterations: 12