[大物报告] 程序求解复杂电路问题
程序求解复杂电路问题
摘要
分析复杂的电路时,有着各种模型,而基尔霍夫定律的两组方程(电压和电流),在很多的复杂电路中有着通用的解决方式。而其大量未知数和方程组也十分适合计算机进行计算。本篇采用 python
作为选择的语言,进行较复杂的纯电阻的直流电路的计算机求解。
关键词 基尔霍夫定律
复杂电路
计算机分析
理论背景
从初中开始,教材中便出现了直流电。而随着学习的不断深入,从初中的简单串并联,到高中动态纯电阻电路,再到竞赛的复杂电路,始终离不开的,就是电路分析。各种分析的方法也构建了诸多的模型。而随着电路的愈发复杂,基尔霍夫定律在很多情况下成为了一种虽不优雅但很通用的求解方式。
复杂直流电路与简单直流电路的区别并非是电路结构的繁与简, 而是体现在处理两种电路的方法上.分析复杂直流电路的基本依据是基尔霍夫定律, 该定律包含两个方面的内容.
(1) 基尔霍夫第一定律, 又称节点电流定律 (KCL) .它指出:电路中任意一个节点上, 在任一时刻, 流入节点电流之和等于流出节点电流之和, 即
\sum I_入 = \sum I_出
KCL是电路中各支路在节点 (或封闭面) 处必须满足的电流约束关系, 与电路中各支路元件的性质无关, 是电荷守恒的必然结果.
(2) 基尔霍夫第二定律, 又称回路电压定律 (KVL) .它指出:在一个回路中, 从一点出发绕回路一周回到该点时, 各段电压降的代数和等于零, 即
\sum U = 0
KVL是电路的各回路中必须满足的电压约束关系, 与回路中各元件的性质无关, 是能量守恒的必然结果.
基尔霍夫定律是电路的基本定律之一, 不论在何种电路中, 它阐明的各支路电流之间和回路电压之间的基本关系都是普遍适用的.理论上来讲, 基尔霍夫定律可以解决一切电路问题, 它思路简单清晰, 对于基础好的学生来讲, 是完全可以做到熟练掌握和灵活应用的.但是不足之处在于, 如果支路较多, 所列方程的个数也会随之增多, 从而使得解题过程比较繁琐.
目标
首先实现纯电阻电路的程序分析。通过人工以文本的形式输入电路的元件构成和连接方式。之后由程序进行基尔霍夫定律列举方程组。代入各元件电阻和电动势的数据,求解各元件的电阻。
研究流程
电路的选取
以高中竞赛题中选取的一些题目为测试。其中本文以如图所示电路为例进行分析。
电路的分析
对全部节点进行标注,并将电源拆分成无内阻电源和电阻 r, 如图所示
电路的表示
全部元件列表:
电阻: r, r1, r2, r3, r4, r5, r6
结点:+, p1, p2, p3, -
线路连接
节点 | 节点 | 元件 |
---|---|---|
+ | p1 | r1 |
+ | p2 | r4 |
+ | p3 | r5 |
p1 | p3 | r2 |
p1 | p2 | r3 |
p2 | p3 | r6 |
p3 | – | r |
初始值
元件 | 类型 | 值 |
---|---|---|
r1 | 电阻 | 1(Ω) |
r2 | 电阻 | 1(Ω) |
r3 | 电阻 | 1(Ω) |
r4 | 电阻 | 6(Ω) |
r5 | 电阻 | 6(Ω) |
r6 | 电阻 | 6(Ω) |
r | 电阻 | 1(Ω) |
EE | 电源 | 7(V) |
数据的输入
将上述内容存为文件,输入到程序里面。
define
R r, r1, r2, r3, r4, r5, r6
E +, -
node
+, p1, p2, p3, -
road
+ p1 r1
+ p2 r4
+ p3 r5
p1 p3 r2
p1 p2 r3
p2 p3 r6
p3 - r
set
r1 1
r2 1
r3 1
r4 6
r5 6
r6 6
r 1
EE 7
定律的实现
基尔霍夫电流定律
对于每个节点,均存在一个\sum\limits_{k=1}^{n} I_k = 0
即一个节点相邻的元件(记为R1, R2 .. Rk)\sum\limits^n_{k=1}{I_{R_k}} = 0,因此根据该定律,可以使用与该节点相邻的电阻的电流,对于每个节点的电流方程。
基尔霍夫电压定律
对于一条闭合回路,\sum\limits_{k=1}^{m}U_{k} = 0
这里若将整个闭合电路视作回路,进行深度优先搜索,枚举每一条通路,即从电源正极到电源负极,进行逐一计算,即\sum\limits_{k=1}^{m}{I_{k}*R_{k} = E_{电源电动势}}
电源的内阻
将含内阻的电源视作无内阻电源+纯电阻的表现方式。即内阻相当于一个位于电源干路上的电阻。
电流的方向
在公式中,电流是有方向的。如果计算方向与电流实际方向相反,那么该电流值为负值,即按照该反向计算,电压变化为升压。
对于这种情况的处理,采用了优先级的解决方式。按照 + > 字符串 > -
,字符串之间采用字典序的解决方式。假设从优先级高的节点流向低的节点。进行列式。最终根据运算的结果的符号调整电流方向。
求解
首先经过程序分析电路,形成了如下的方程
电流
程序输出
- i为电源输出电流。
对于节点+ +i - I_r1 - I_r4 - I_r5
对于节点p1 + I_r1 - I_r2 - I_r3
对于节点p2 + I_r4 + I_r3 - I_r6
对于节点p3 + I_r5 + I_r2 + I_r6 - I_r
对于节点- -i + I_r
即如下的数学表达式
i – I_{r1} – I_{r4} – I_{r5} = 0
I_{r1} – I_{r2} – I_{r3} = 0
I_{r4} + I_{r3} – I_{r6} = 0
I_{r5} + I_{r2} + I_{r6} – I_{r} = 0
-i + I_{r} = 0
电压
程序输出
- 采用 EE 作为电动势,以避免与常数 e=2.71828… 混淆
+ r1*I_r1 + r2*I_r2 + r*I_r - EE
+ r1*I_r1 + r3*I_r3 + r6*I_r6 + r*I_r - EE
+ r4*I_r4 - r3*I_r3 + r2*I_r2 + r*I_r - EE
+ r4*I_r4 + r6*I_r6 + r*I_r - EE
+ r5*I_r5 + r*I_r - EE
即如下的数学表达式
r1\times I_{r1} + r2\times I_{r2} + r\times I_{r} – EE = 0
r1\times I_{r1} + r3\times I_{r3} + r6\times I_{r6} + r\times I_{r} – EE = 0
r4\times I_{r4} – r3\times I_{r3} + r2\times I_{r2} + r\times I_{r} – EE = 0
r4\times I_{r4} + r6\times I_{r6} + r\times I_{r} – EE = 0
r5\times I_{r5} + r\times I_{r} – EE = 0
后面会带入常数(电阻r_x和电动势EE,对这些方程联立求解即可。
即
i – I_{r1} – I_{r4} – I_{r5} = 0
I_{r1} – I_{r2} – I_{r3} = 0
I_{r4} + I_{r3} – I_{r6} = 0
I_{r5} + I_{r2} + I_{r6} – I_{r} = 0
-i + I_{r} = 0
1\times I_{r1} + 1\times I_{r2} + 1\times I_{r} – 7 = 0
1\times I_{r1} + 1\times I_{r3} + 6\times I_{r6} + 1\times I_{r} – 7 = 0
6\times I_{r4} – 1\times I_{r3} + 1\times I_{r2} + 1\times I_{r} – 7 = 0
6\times I_{r4} + 6\times I_{r6} + 1\times I_{r} – 7 = 0
6\times I_{r5} + 1\times I_{r} – 7 = 0
测试
运行结果(保留两位小数)
{i: '3.00', I_r6: '0.33', I_r5: '0.67', I_r3: '0.00', I_r4: '0.33', I_r1: '2.00', I_r2: '2.00', I_r: '3.00'}
即
i | I_{r6} | I_{r5} | I_{r3} | I_{r4} | I_{r1} | I_{r2} | I_{r} |
---|---|---|---|---|---|---|---|
3.00 | 0.33 | 0.67 | 0.00 | 0.33 | 2.00 | 2.00 | 3.00 |
经过验证成立
代码
from sympy import *
edge = {}
# 存储所有的边。(即元件)
# 其中按照有向图存储 edge[u] = [(u, v1, w1), (u, v2, w2), (u, v3, w3) ...]
node = []
# 存储所有的节点。包括 + - p1, p2 等等,即元件之间能够由导线直接连通的点。
path = []
# DFS过程的路径记录。
use = {}
# DFS过程中的节点访问记录。
fom = []
# 列出的方程组列表。
values = {}
# 所有的元件的初始值信息(主要是电阻信息和电源电动势)
i_symbol = []
# 求解的电流的未知量的形式。例如 i, i_r1, i_r2_r3 等等
def cmp(u, v): # 根据规则,比较两个节点的优先级。
if u == "+":
con = "-"
elif v == "+":
con = "+"
elif u == "-":
con = "+"
elif v == "-":
con = "-"
else:
if u > v:
con = "+"
else:
con = "-"
return con
def kcl(): # 基尔霍夫电流定律 \sgima I = 0
print("基尔霍夫电流定律")
for x in node: # 对于每一个节点 x
fomular = ""
print("对于节点{x} ".format(x=x), end="")
if x == "+": # 如果节点是正,那么添加 +i ,从电源出来的电流 i
fomular = "+i "
elif x == "-": # 节点是负,添加 -i ,流入电源 i
fomular = "-i "
for y in edge[x]: # 枚举其他的元件
u = y["from"]
v = y["to"]
con = cmp(u, v)
if con: # 根据该元件两端确定正负号。
fomular += con + " I_{0}".format(y["ele"]) + " "
else:
fomular += con + " I_{0}".format(y["ele"]) + " "
print(format(fomular))
fom.append(fomular)
def kvl(d): # 基尔霍夫电压定律 \sgima U = 0
fomular = ""
for x in d: # d是求出的一条回路。对于回路每个元件列电压表示。
con = cmp(x["from"], x["to"])
if con == "+":
con = "-"
else:
con = "+"
fomular += con + " " + x["ele"] + "*I_{0}".format(x["ele"]) + " "
fomular += "- EE"
fom.append(fomular)
print(fomular)
def dfs(cnt):
if cnt == "-": # DFS 到达终点条件。
kvl(path) # path 是一条回路,对这条回路进行分析,列出电压表达式。
return
for x in edge[cnt]: # DFS 过程
v = x["to"]
if use[v] == False:
path.append(x)
use[v] = True
dfs(v)
path.pop()
use[v] = False
f = open("map.txt", "r")
lines = f.read().splitlines()
status = 0
for line in lines:
if line == "define": # 定义所有元件
status = 1
continue
elif line == "node": # 定义所有节点
status = 2
continue
elif line == "road": # 定义连接方式
status = 3
continue
elif line == "set": # 设置元件属性
status = 4
continue
if status == 1: # 定义所有元件
line = line.replace(" ", "")
flag = 0
if line[0] == "R":
flag = 1
line = line[1:]
if flag == 1:
i_symbol += line.split(",")
elif status == 2: # 定义所有节点
node += line.replace(" ", "").split(",")
elif status == 3: # 定义连接方式
line = line.split(" ", maxsplit=2)
u, v, w = line[0], line[1], line[2]
# 添加正向边
if u not in edge.keys():
edge[u] = []
edge[u].append({
"from": u,
"to": v,
"ele": w
})
# 添加反向边
if v not in edge.keys():
edge[v] = []
edge[v].append({
"from": v,
"to": u,
"ele": w
})
elif status == 4: # 设置元件属性
temp = line.split(" ")
values[temp[0]] = float(temp[1])
for x in node:
use[x] = False
use["+"] = True
# 电压定律
print("基尔霍夫电压定律")
dfs("+")
# 电流定律
kcl()
# print("列出的全部表达式")
# print(fom)
exprs = []
for e in fom:
s = sympify(e)
for k, v in values.items():
s = s.subs(k, v)
exprs.append(s)
i_symbol = ["I_" + x for x in list(i_symbol)] + ["i"]
res = solve(exprs, i_symbol)
for x in res:
res[x] = "%.2f" % res[x]
print("结果")
print(res)
for key in res:
print("%8s%5s" % (key, res[key]))
参考文献
[1]李桃.基尔霍夫定律的应用及验证[J].现代工业经济和信息化,2017,7(17):70-72.
[2]陈玉奇.高中物理竞赛中复杂直流电路的分析方法——以一道2015年全国物理竞赛题为例[J].物理通报,2016(04):58-63.
[3]王桃发.图论在电路分析中的应用及其可视化实现[J].硅谷,2008(24):27-28.