基本思想相当简单。您安排一个矩阵 (\$V\$) 来表示系统中的“节点”或顶点。这些节点中的每一个都有一个与之关联的标量值“电压”,可以随着算法的进行而改变或更新。还有两个节点的电压不能改变。我们将在这里应用某种“电池”,所以这两个节点代表这个电池的两端。
另外,另外两个矩阵(\$Rv\$ 和 \$Rh\$)代表系统中的边缘,水平和垂直。我猜这些是你的电阻值。我不确定你打算如何填写这些。但那是你的问题。此技术假设您也能够填充这些矩阵。
根据您使用的计算机语言,您可能会也可能不会使用负索引。没关系。这只是记住你所面临的问题。
假设长度 \$L\$ 被划分为 \$N_L\$ 部分,并且“长度” \$A\$ 被划分为 \$N_A\$ 部分。然后,您需要为标量电压值构建一个带有 \$\left(N_L+1\right)\cdot\left(N_A+1\right)\$ 顶点的矩阵。(或更大。)您还需要其他两个矩阵与 \$N_A\cdot\left(N_L+1\right)\$ 垂直边和 \$N_L\cdot\left(N_A+1\right)\$ 水平这些顶点之间的边。
现在。用 \$0\:\textrm{V}\$ 初始化所有顶点。选择左侧的一个顶点(最好在中间),并将其记为 \$0\:\textrm{V}\$ 值,该值永远不允许更改。使用任何你想要的方法。选择右边的一个顶点(最好在中间)并将其值更改为 \$1\:\textrm{V}\$,同时再次注意它的值不允许更改。在这里有效的一种技术是简单地让它正常变化,然后每一步都替换值。但不管你如何实现这一点,只要你确实实现了它。
(出于效率原因,还有其他技术。但在这里可能不值得打扰它们。)
现在是算法,有时称为棋盘或红黑算法。遍历节点电压矩阵,处理两个索引之和 \$i+j\$ 为偶数的每个节点,执行以下简单分配:
$$\begin{align*} V_{i,j}&=\frac{Rh_{i,j-1}\cdot Rh_{i,j}\cdot\left(V_{i-1,j}\cdot Rv_{i,j}+V_{i+1,j}\cdot Rv_{i-1,j}\right)}{Rh_{i,j-1}\cdot Rh_{i,j}\cdot \left (Rv_{i,j}+Rv_{i-1,j}\right)+Rv_{i-1,j}\cdot Rv_{i,j}\left(Rh_{i,j}+Rh_{i, j-1}\right)}\\\\ &+\frac{Rv_{i-1,j}\cdot Rv_{i,j}\cdot \left(V_{i,j-1}\cdot Rh_{ i,j}+V_{i,j+1}\cdot Rh_{i,j-1}\right)}{Rh_{i,j-1}\cdot Rh_{i,j}\cdot \left(Rv_ {i,j}+Rv_{i-1,j}\right)+Rv_{i-1,j}\cdot Rv_{i,j}\left(Rh_{i,j}+Rh_{i,j- 1}\right)} \end{对齐*}$$
上面的等式只不过是计算一个连接有四个电阻的中心节点的电压,其中四个电阻另一端的电压是已知的。然后从上述等式计算中心节点电压。由于每个术语的除数相同,因此您可以只计算分子的总和,然后除以分母一次。
这将更新总和 \$i+j\$ 为偶数的所有节点。现在您对总和 \$i+j\$ 为奇数的所有节点执行相同的过程。完成这两个步骤后,您就完成了一个周期。
如有必要,重置特殊的两个节点(如前所述,对于 \$0\:\textrm{V}\$ 和 \$1\:\textrm{V}\$。)或者,如果您保护了这两个节点,则没有需要重置它们。
您已为下一个周期做好准备。执行这些循环,只要你觉得有必要让整体状态稳定下来(它会。)
当您停止该过程时,您可以通过选择查看左侧受保护节点周围的节点或查看右侧受保护节点周围的节点来轻松计算阻力。(使矩阵足够大 [在所有方向上增加 1] 可能是个好主意,这样您实际上将有四个节点围绕任一选择。)周围节点和特殊节点之间的电压差除以它们之间边缘的电阻告诉您当前离开/进入您的特殊节点。由于这是一个“电池”节点,因此该电流必须是所有电流。由于电压为 \$1\:\textrm{V}\$,根据定义,将 1 除以这四个电流的总和即可得出总电阻。
我盯着我写的一些代码,总共有很多评论,只有 67 行。所以写起来并不难。
这个想法的“简短总结”是你应用一个 \$1\:\textrm{V}\$ 电池,然后观察电压在整个系统中的分布。一旦电压稳定(您的标准),您所要做的就是查看流入或流出一个电池端子或另一个电池端子的电流。出于显而易见的原因,它们都应该是相同的当前值(在某些数值范围内)。
为什么必须将系统分成 i+j = 偶数和 i+j = 奇数?
假设您计算 \$V_{5,5}=f\left(V_{4,5},V_{6,5},V_{5,4},V_{5,6}\right)\$。这引用了 \$V_{5,5}\$ 周围的节点。没关系。假设你接下来计算 \$V_{5,6}=f\left(V_{4,6},V_{6,6},V_{5,5},V_{5,7}\right)\$。请注意,在参数列表中是您刚刚为 \$V_{5,5}\$? 计算的值?这会“弄脏”很多东西。这不是声音。相反,每个奇数/偶数循环应该“看起来好像”它同时发生。所以你的下一个计算应该是 \$V_{5,7}=f\left(V_{4,7},V_{6,7},V_{5,6},V_{5,8}\right)\ $ 因为函数的所有输入都不是在此步骤中更改的节点。然后你摆动并计算替代品,避免弄脏,但现在更新替代品。你真的必须这样做。
另外,偶数步和奇数步的公式是否相同?
是的,它是一样的。
是否可以使用某种线性系统 Ax=b 一步解决所有问题,其中 A 是线性算子,b 提供边界条件?看着它,它似乎有点类似于求解偏微分方程的有限差分方法。
有一个联系。我认为它被称为“无矩阵”实现。
这是一个例子。将以下一组电阻值放入 LTSpice 进行仿真:
我保持简短。如您所见,\$1\:\textrm{V}\$ 电源的近似计算电流为 \$30.225\:\textrm{mA}\$。(Spice 计算的实际值为 \$30.224552\:\textrm{mA}\$。)
我运行了以下 VB.NET 程序:
Module GEOGRID
Const NL As Integer = 2
Const NA As Integer = 2
Const INF As Double = 1.0E+32
Sub Main()
Static Rh As Double(,) = New Double(NL + 2, NA + 1) {
{INF, INF, INF, INF},
{INF, 5, 21, INF},
{INF, 76, 10, INF},
{INF, 32, 22, INF},
{INF, INF, INF, INF}}
Static Rv As Double(,) = New Double(NA + 1, NL + 2) {
{INF, INF, INF, INF, INF},
{INF, 61, 50, 16, INF},
{INF, 56, 45, 18, INF},
{INF, INF, INF, INF, INF}}
Dim V As Double(,) = New Double(NL + 2, NA + 2) {
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 1, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}}
Dim PDE As Func(Of Integer, Integer, Double) = Function(ByVal i As Integer, ByVal j As Integer) (
Rh(i, j - 1) * Rh(i, j) * (V(i - 1, j) * Rv(i, j) + V(i + 1, j) * Rv(i - 1, j)) +
Rv(i - 1, j) * Rv(i, j) * (V(i, j - 1) * Rh(i, j) + V(i, j + 1) * Rh(i, j - 1))
) / (
Rh(i, j - 1) * Rh(i, j) * (Rv(i, j) + Rv(i - 1, j)) +
Rv(i - 1, j) * Rv(i, j) * (Rh(i, j) + Rh(i, j - 1))
)
Dim IV As Func(Of Integer, Integer, Double) = Function(ByVal i As Integer, ByVal j As Integer) 0 +
(V(i, j) - V(i - 1, j)) / Rv(i - 1, j) + (V(i, j) - V(i + 1, j)) / Rv(i, j) +
(V(i, j) - V(i, j - 1)) / Rh(i, j - 1) + (V(i, j) - V(i, j + 1)) / Rh(i, j)
Dim idx As Integer = NA \ 2 + 1
Dim jdx1 As Integer = NL + 1
Dim jdx2 As Integer = 1
For x As Integer = 1 To 1000
For k As Integer = 0 To (NA + 1) * (NL + 1) - 1 Step 2
Dim i As Integer = k \ (NL + 1)
Dim j As Integer = k - i * (NL + 1) + 1
i += 1
If Not (i = idx AndAlso (j = jdx1 OrElse j = jdx2)) Then V(i, j) = PDE(i, j)
Next
For k As Integer = 1 To (NA + 1) * (NL + 1) - 1 Step 2
Dim i As Integer = k \ (NL + 1)
Dim j As Integer = k - i * (NL + 1) + 1
i += 1
If Not (i = idx AndAlso (j = jdx1 OrElse j = jdx2)) Then V(i, j) = PDE(i, j)
Next
Next
Console.WriteLine("R = " & (1.0 / IV(idx, jdx1)).ToString)
Console.WriteLine("R = " & (-1.0 / IV(idx, jdx2)).ToString)
End Sub
End Module
打印出以下结果:\$R = 33.0856844038614\:\Omega\$。这是正确的答案。
上面的程序显示了一种设置电阻器的方法,垂直和水平,以及电压矩阵,因此它简化了一些不存在节点和/或电阻值的测试。这样,代码会更简洁一些,尽管它确实需要更多的数组元素。(我只是将额外的电阻值设置为无限值。)只需将我设置阵列的方式与原理图的布局方式进行比较,我认为您将能够计算出所有确切的值详情在这里。
当然,我还修改了电阻器和节点值,但没有以任何方式将其作为读取值表的通用程序。但这种普遍性很容易添加。这段代码应该使我写的所有内容都绝对明确。
请注意,我还刚刚运行了 \$x\$ 循环 1000 种类型,在 \$x\$ 循环内交替使用红色和黑色。我刚选了一个号码。为了使这个更通用,您可能更喜欢确定要执行多少次迭代的不同方法。
最后一点。只是为了证明您可以使用任一固定电压节点的电流来计算电阻,我使用了两条线来打印出这两个值:一条从 \$0\:\textrm{V}\$ 侧计算,一个计算从 \$1\:\textrm{V}\$ 方面。无论哪种方式,您都应该看到相同的数字。
(好的。最后一点。这将更好地针对 F# 或任何针对大规模并行计算系统的体面的编译器。“红色”或“黑色”中的每个计算都可以并行执行;彼此完全独立。 F# 使这变得微不足道。所以用 F# 编码,你可以在所有可用的内核上运行它,而无需做任何特别的事情。它只是工作。只是一个注释,以防你以某种方式收集大量数据并且可能想要采取充分利用多核系统。)
结束注:
从 KCL 推导非常简单。将四个电阻器按以下排列:
模拟此电路- 使用CircuitLab创建的原理图
申请 KCL:
$$\begin{align*} \frac{V}{R_1}+\frac{V}{R_2}+\frac{V}{R_3}+\frac{V}{R_4} &= \frac{V_1} {R_1}+\frac{V_2}{R_2}+\frac{V_3}{R_3}+\frac{V_4}{R_4}\\\\ &\因此\\\\ V &=\left(\frac{ V_1}{R_1}+\frac{V_2}{R_2}+\frac{V_3}{R_3}+\frac{V_4}{R_4}\right)\bigg(R_1 \mid\mid R_2 \mid\mid R_3 \中\中 R_4\bigg) \end{对齐*}$$
一些玩代数的人得到了我在代码中使用的结果。