概述
学习数值分析与电路分析后的练手程序,较粗糙。 没有 加入更多电器元件的数学模型,如二极管、三极管、放大器、数字器件等等。
m脚本在:gittee仓库;
编程实现电路仿真,使用Matlab 。
背景:
电网络分析课程中,学习了电路的矩阵形式,和数值求解方法;数值分析课程了解了数值计算的概念和一些数值算法思想。于是我想,如何编程实现电路的仿真呢?
搞清几个概念
总是理不清思路:编程计算电路?理论分析电路?怎么转换呢?有什么不一样吗?得到各参数变量与待求量之间的关系?得到不同电路参数下的解???
所以首先要明确模糊的概念,以便理清思路。
数值计算
利用计算机求解数学问题,称为数值计算。计算机可以大量、快速的运算,但是它是基于硬件结构的机械式计算,不同于人的计算(更高级、更灵活、更包容、更连续)。
需要考虑到计算机计算与编程的特点,设计恰当的数学模型、合适的数值计算方法和形式。
求解
求解即已知题目求解答案。有得到精确解析解的数值计算方法,也有迭代近似解的数值方法。计算只是个过程,重要的是,题目是什么,想要得到什么样的结果?
需要确定什么是已知的,什么是未知的。再理清求解思路:先分析,列出已知条件,然后计算出结果,再进一步得到更多结果,这才是完整的逻辑。这个逻辑是理论(课程)中学到的,这说明理论与求解是相辅相成的,理论上的分析虽然不需要数值计算,但没有算例验证理论,可信度也不高;同时,算例数据可以直观的反映出问题的特点,给分析带来参考,有助于得出结论。
仿真
计算机仿真:一般以时间为变量,将仿真过程分成极短的片段,求解出每一时刻的状态近似作为对应片段内的状态。从而近似得到整个过程中任意时刻的状态。
而求解得到的是一个问题的答案(一个电路状态信息),而仿真需要每个时间片段的答案(每个时刻电路的状态信息),这意味着“连续求解”一个“连续的题目”,需要将前一个问题的答案作为已知去求解当前问题。
一次仿真,得到的往往是大量的求解,仿真的结果应当是连续的(连续的时间序列)、大量的解的集合(按照时间序列依次求解的解序列)。
思路
清楚上面的概念后,我理清了思路:
- 理论分析电路,编写能求解“某时刻电路”的程序(单次求解);
- 加入相邻时刻间的变量更新,在时间序列的每个时刻求解,实现电路仿真(连续多次求解);
- 改变电路参数,得到相应结果,解析法验证(计算算例,通过理论计算验证)。
具体实行
这是最难的一部分:概念上,混淆了求解与仿真;思想上,纠结于解析法,而忽略数值方法;实现上,多方面知识结合。
描述瞬时电路
利用图论的概念描述电网络,形成网络线图(G图):
- 抽象出节点和支路
- 每一元件为一条支路
- 各支路标有方向箭头(自指定方向)
利用电网络理论的知识,可得到电路的关联矩阵 A boldsymbol A A,用于描述电路的拓扑结构。
- A = { a i j } {boldsymbol A} = {a_{ij}} A={aij}
- a i j = 1 a_{ij} = 1 aij=1:支路 j 箭头指向节点 i
- a i j = − 1 a_{ij}=-1 aij=−1:支路 j 箭头背离节点 i
- a i j = 0 a_{ij}=0 aij=0:支路 j 不与节点 i 关联
若有N+1个节点,M条支路,a个电导(电阻),b个电压源(包括电容),c个电流源(包括电感),
并考虑到极短时间内各参数不变,有以下矩阵:
-
U
s
{boldsymbol U}_{rm s}
Us:支路源电压向量(已知)
- U s = [ u s 1 , u s 2 , ⋯ , u s M ] T {boldsymbol U}_{rm s} = [u_{rm s1}, u_{rm s2},cdots,u_{rm sM}]^{rm T} Us=[us1,us2,⋯,usM]T
- u s k u_{{rm s}k} usk :第 k 条支路的电压源电压,符号以G图对应支路的参考方向为正;k = 1 ~ M
- 电容视为电压源,其值为初始电压
- 无电压源或电容则为0
-
I
s
{boldsymbol I}_{rm s}
Is:支路源电流向量(已知)
- I s = [ i s 1 , i s 2 , ⋯ , i s M ] T {boldsymbol I}_{rm s} = [{i_{rm s1}}, i_{rm s2},cdots,i_{rm sM}]^{rm T} Is=[is1,is2,⋯,isM]T
- i s k i_{{rm s}k} isk:第 k 条支路的电流源电流,符号以G图对应支路的参考方向为正;k = 1 ~ M
- 电感视为电流源,其值为初始电流
- 无电流源或电感则为0
-
Y
boldsymbol Y
Y:支路电导矩阵(已知)
- Y = d i a g [ y 1 y 2 ⋯ y M ] {boldsymbol Y} = {rm diag}[y_1~y_2~cdots~y_{rm M}] Y=diag[y1 y2 ⋯ yM]
- y k y_k yk:第 k 条支路的电导;k = 1 ~ M
- 电阻转化为电导,无电导则为0
- 好像含受控源的电路的受控关系可以用电导矩阵表示出来(没研究)
-
U
boldsymbol U
U:支路电压向量(未知)
- U = [ u 1 , u 2 , ⋯ , u M ] T {boldsymbol U} = [u_1, u_2, cdots, u_{rm M}]^{rm T} U=[u1,u2,⋯,uM]T
- u k u_k uk:第 k 条支路的电压,符号以G图对应支路的参考方向为正;k = 1 ~ M
-
I
boldsymbol I
I:支路电流向量(未知)
- I = [ i 1 , i 2 , ⋯ , i M ] T {boldsymbol I} = [i_1,i_2,cdots,i_{rm M}]^{rm T} I=[i1,i2,⋯,iM]T
- i k i_k ik:第 k 条支路的电流,符号以G图对应支路的参考方向为正;k = 1 ~ M
-
U
n
{boldsymbol U}_{rm n}
Un:节点电压向量(未知)
- U n = [ u n 1 , u n 2 , ⋯ , u n N ] T {boldsymbol U}_{rm n} = [u_{rm n1},u_{rm n2},cdots,u_{rm nN}]^{rm T} Un=[un1,un2,⋯,unN]T
- u n k u_{{rm n}k} unk:第 k 个节点的电压;k = 0 ~ N
- u n 0 u_{{rm n}0} un0:0号节点为参考节点
求解瞬时电路
将电容器和电感器分别看作电压源和电流源,“瞬间”(极短的时间,不是时刻)电路近似为一个只有电源和电阻组成的直流电路。
我只想到了网孔电流法和节点电压法,相比之下,节点电压法不需要“确定网孔”环节,故使用节点电压法。
由电路的 KCL 可知:
A
I
=
0
(1)
boldsymbol {AI}=bf 0 tag 1
AI=0(1)
支路电压可用节点电压表示:
U
=
A
T
U
n
(2)
{boldsymbol U} = {boldsymbol A}^{rm T} {boldsymbol U}_{rm n} tag 2
U=ATUn(2)
支路电流可以分为电导支路电流、电压源支路电流、电流源支路电流三个部分:
I
=
Y
U
+
I
s
+
I
u
(3)
{boldsymbol I} = boldsymbol {YU} + {boldsymbol I}_{rm s} + boldsymbol {I}_{rm u} tag 3
I=YU+Is+Iu(3)
其中
I
u
boldsymbol {I}_{rm u}
Iu是除电压源支路以外的支路电流均为0的支路电流向量。
联立(1)(2)(3),消去的矩阵
U
{boldsymbol U}
U和
I
{boldsymbol I}
I,得
A
Y
A
T
U
n
+
A
I
u
+
A
I
s
=
0
(4)
boldsymbol {AYA}^{rm T} boldsymbol{U}_{rm n} + boldsymbol {AI}_{rm u} + boldsymbol {AI}_{rm s} = 0 tag 4
AYATUn+AIu+AIs=0(4)
在(4)表示的方程组中,
U
n
boldsymbol{U}_{rm n}
Un与
I
u
boldsymbol{I}_{rm u}
Iu是待求量,有 N + b 个;独立方程数是 N 个(
A
boldsymbol A
A行数)。
显然,
U
s
boldsymbol U_{rm s}
Us这个已知量还没有用到。
支路电压也可分为电导支路电压、电压源支路电压、电流源安支路电压三个部分:
U
=
U
y
+
U
s
+
U
i
(5)
boldsymbol U = boldsymbol {U}_{rm y} + boldsymbol {U}_{rm s} + boldsymbol {U}_{rm i} tag 5
U=Uy+Us+Ui(5)
其中
U
y
boldsymbol U_{rm y}
Uy和
U
i
boldsymbol U_{rm i}
Ui分别是除电导支路以外的支路电压均为0的支路电压向量,和除电流源支路以外的支路电压均为0的之路电压向量。
由(2)和(5)可得,
A
T
U
n
=
U
y
+
U
s
+
U
i
boldsymbol A^{rm T} boldsymbol U_{rm n} = boldsymbol {U}_{rm y} + boldsymbol {U}_{rm s} + boldsymbol {U}_{rm i}
ATUn=Uy+Us+Ui
取出该 方程组 中,等号右侧是已知的
u
s
u_{rm s}
us的方程,表示为:
B
U
n
=
U
s
′
(6)
boldsymbol B boldsymbol U_{rm n} = boldsymbol U'_{rm s} tag 6
BUn=Us′(6)
其中,
B
boldsymbol B
B和
U
s
′
boldsymbol U'_{rm s}
Us′分别是
A
T
boldsymbol A^{rm T}
AT和
U
s
boldsymbol U_{rm s}
Us删除
U
s
boldsymbol U_{rm s}
Us中0所在行得到的。
(6)所表示的方程组中,未知量是
U
n
boldsymbol U_{rm n}
Un,独立方程数为 b ,即电压源支路的个数。
将(4)和(6)组成方程组,
{
A
Y
A
T
U
n
+
A
I
u
=
−
A
I
s
B
U
n
=
U
s
′
left { begin{matrix} boldsymbol {AYA}^{rm T} boldsymbol{U}_{rm n} + boldsymbol {AI}_{rm u} = - boldsymbol {AI}_{rm s} \ boldsymbol B boldsymbol U_{rm n} = boldsymbol U'_{rm s} end{matrix} right.
{AYATUn+AIu=−AIsBUn=Us′
其矩阵形式为:
[
A
Y
A
T
A
B
0
]
[
U
n
I
u
]
=
[
−
A
I
s
U
s
′
]
(7)
begin{bmatrix} boldsymbol {AYA}^{rm T} & boldsymbol A \ boldsymbol B & 0 end{bmatrix} begin{bmatrix} boldsymbol U_{rm n} \ boldsymbol I_{rm u} end{bmatrix} = begin{bmatrix} boldsymbol -{AI}_{rm s} \ boldsymbol U'_{rm s} end{bmatrix} tag 7
[AYATBA0][UnIu]=[−AIsUs′](7)
当当当! 该方程组有 N + b 个未知量,N + b 个独立方程,可解出
U
n
boldsymbol U_{rm n}
Un和
I
u
boldsymbol I_{rm u}
Iu。
还可以进一步精简
A
I
u
boldsymbol {AI}_{rm u}
AIu部分的形式:
根据
I
u
boldsymbol I_{rm u}
Iu中0行的位置,删去
A
I
u
boldsymbol {AI}_{rm u}
AIu部分中系数矩阵
A
boldsymbol A
A无用的列,和
I
u
boldsymbol I_{rm u}
Iu中无用的行,
表示为
D
I
u
′
boldsymbol {DI}'_{rm u}
DIu′,则(7)可写为
[
A
Y
A
T
D
B
0
]
[
U
n
I
u
′
]
=
[
−
A
I
s
U
s
′
]
(8)
begin{bmatrix} boldsymbol {AYA}^{rm T} & boldsymbol D \ boldsymbol B & 0 end{bmatrix} begin{bmatrix} boldsymbol U_{rm n} \ boldsymbol I'_{rm u} end{bmatrix} = begin{bmatrix} boldsymbol -{AI}_{rm s} \ boldsymbol U'_{rm s} end{bmatrix} tag 8
[AYATBD0][UnIu′]=[−AIsUs′](8)
将它们分别回代到(2)和(3)则得到电路的此时的所有信息。
更新动态元件初始值
对于含动态元件(一般为电容、电感)的电路,每个瞬间里动态元件的电压和电流都在改变。
所以在每个瞬间电路求解完后,要利用求得的解对动态元件的初始值更新,作为下一瞬间动态元件的初值状态。
易知电容和电感的微分方程可写为:
d
u
C
=
1
C
i
C
d
t
d
i
L
=
1
L
u
L
d
t
{rm d}u_{rm C} = frac 1C i_{rm C} {rm d}t \ {rm d}i_{rm L} = frac 1L u_{rm L} {rm d}t
duC=C1iCdtdiL=L1uLdt
其中
d
t
{rm d}t
dt可近似看作是一个“瞬间”的时间,在计算中称为步长,设为
Δ
t
Delta t
Δt,即
d
t
=
Δ
t
{rm d}t = Delta t
dt=Δt。
则得到电容电压变化量
Δ
u
C
Delta u_{rm C}
ΔuC和电感电流变化量
Δ
i
L
Delta i_{rm L}
ΔiL的表达式:
Δ
u
C
=
1
C
i
C
Δ
t
(8)
Delta u_{rm C} = frac 1C i_{rm C} Delta t tag 8
ΔuC=C1iCΔt(8)
Δ i L = 1 L u L Δ t (9) Delta i_{rm L} = frac 1L u_{rm L} Delta t tag 9 ΔiL=L1uLΔt(9)
其中 i C i_{rm C} iC和 u L u_{rm L} uL分别是电容支路的电流和电感支路的电压,可从 I boldsymbol I I与 U boldsymbol U U中得到。
每次求解后,对每个电容的初始电压根据(8)式更新,每个电感的初始电流根据(9)式更新:
u
C
=
u
C
+
Δ
u
C
(10)
u_{rm C} = u_{rm C} + Delta u_{rm C} tag {10}
uC=uC+ΔuC(10)
i L = i L + Δ i L (11) i_{rm L} = i_{rm L} + Delta i_{rm L} tag {11} iL=iL+ΔiL(11)
编程实现
使用 matlab 实现。
输入与输出
仿真电路需要输入:电路结构模型、信号源(电源)信号、仿真时间、动态元件初始值;
输出:电路的节点电压、支路电压、支路电流矩阵,包含历史记录。
电路结构
变量 | 规模 | 说明 | 意义 |
---|---|---|---|
A boldsymbol A A | n × b n times b n×b | 节点支路的关联情况 行数 = 节点数,列数 = 支路数 | 电路线图的关联矩阵 |
Y boldsymbol Y Y | b b b | 支路电导分布在对角线上 不可为空向量 | 支路电导向量 |
C boldsymbol C C | b b b | 支路上的电容值,单位 F 非电容支路值为 0 | 支路电容向量 |
L boldsymbol L L | b b b | 支路上的电感值,单位 H 非电感支路值为 0 | 支路电感向量 |
信号源
变量 | 规模 | 说明 | 意义 |
---|---|---|---|
U s s boldsymbol U_{rm ss} Uss | b b b | 支路恒压源电压值,单位 V 非恒压源支路值为 0 不可为空向量 | 支路恒压源电压向量 |
I s s boldsymbol I_{rm ss} Iss | b b b | 支路恒流源电流值,单位 V 非恒流源支路值为 0 不可为空向量 | 支路恒流源电压向量 |
U d s boldsymbol U_{rm ds} Uds | u d s × ( 1 + T ) udstimes (1+T) uds×(1+T) | 第一列是索引 其余列是电压源随时间的输入数据 单位 V u d s uds uds:变化的电压源数 T T T:时间步数 | 指定变化电压源的 位置和时变信号 |
I d s boldsymbol I_{rm ds} Ids | i d s × ( 1 + T ) ids times (1+T) ids×(1+T) | 第一列是索引 其余列是电流源随时间的输入数据 单位 A u d s uds uds:变化的电流源数 T T T:时间步数 | 指定变化电流源的 位置和时变信号 |
仿真时间序列
变量 | 规模 | 说明 | 意义 |
---|---|---|---|
T s e q boldsymbol T_{rm seq} Tseq | T T T | 时刻组成的序列,单位 s | 仿真的时间序列 |
初始值
变量 | 规模 | 说明 | 意义 |
---|---|---|---|
U c boldsymbol U_c Uc | c c c | 仿真开始前,各电容的初始值 | 电容初始值的向量 |
I l boldsymbol I_l Il | l l l | 仿真开始前,各电感的初始值 | 电感初始值的向量 |
输出
变量 | 规模 | 说明 | 意义 |
---|---|---|---|
U n boldsymbol U_{rm n} Un | n × T n times T n×T | 每一时刻的节点电压向量组成的矩阵 | 节点电压矩阵 |
U boldsymbol U U | b × T b times T b×T | 每一时刻的支路电压向量组成的矩阵 | 支路电压矩阵 |
I boldsymbol I I | b × T b times T b×T | 每一时刻的支路电流向量组成的矩阵 | 支路电流矩阵 |
数据处理
处理输入信息,生成必要中间变量,构建求解矩阵。
初始化
- 根据输入变量的个数判断所描述电路的类型
- 根据电路求解类型,恰当设置其余变量的值
- 没有用到的变量赋予空,如
U_ds = []
- 输入变量形式转化
- 转化为向量形式,如
U_ss = U_ss(:)
等 - 转化为矩阵形式,
Y = diag(Y)
- 转化为向量形式,如
- 提取出 T s e q boldsymbol T_{rm seq} Tseq的长度与步长
- 确定
U
boldsymbol U
U和
I
boldsymbol I
I矩阵的规模,即是输出矩阵,又作为相关变量的存储矩阵
- 将已知的支路电压和支路电流填入其中
- 在填入前,应判断变量是否存在,或填入空的变量是否影响计算,再决定是否填入
-
U
s
s
boldsymbol U_{rm ss}
Uss是支路恒压源电压向量,长度 = 支路数,不随时间变化
- 可用来创建
U
boldsymbol U
U :
U = repmat(U_ss, 1, T)
- 同时,要创建恒压源支路的索引:
U_ss_idx = find(U_ss)
- 可用来创建
U
boldsymbol U
U :
-
U
d
s
boldsymbol U_{rm ds}
Uds是变压源向量,第一列是支路位置索引,其余是对应时刻数值
- 提取变压源索引:
U_ds_idx = U_ds(:, 1)
- 放入
U
boldsymbol U
U:
U(U_ds_idx,:) = U_ds(:, 2:end)
- 提取变压源索引:
-
U
c
boldsymbol U_{rm c}
Uc是电容初始值向量
- 可通过支路电容向量
C
boldsymbol C
C找到其支路位置索引:
C_idx = find(C)
- 放入
U
boldsymbol U
U:
U(C_idx, 1) = U_c
- 可通过支路电容向量
C
boldsymbol C
C找到其支路位置索引:
-
I
s
s
boldsymbol I_{rm ss}
Iss是支路恒流源电流向量,长度 = 支路数,不随时间变化
- 可用来创建
I
boldsymbol I
I :
I = repmat(I_ss, 1, T)
- 同时,要创建恒压源支路的索引:
I_ss_idx = find(I_ss)
- 可用来创建
I
boldsymbol I
I :
-
I
d
s
boldsymbol I_{rm ds}
Ids是变压源向量,第一列是支路位置索引,其余是对应时刻数值
- 提取变压源索引:
I_ds_idx = I_ds(:, 1)
- 放入
I
boldsymbol I
I:
I(I_ds_idx,:) = I_ds(:, 2:end)
- 提取变压源索引:
-
I
l
boldsymbol I_{rm l}
Il是电感初始值向量
- 可通过支路电感向量
L
boldsymbol L
L找到其支路位置索引:
L_idx = find(L)
- 放入
I
boldsymbol I
I:
I(L_idx, 1) = I_l
- 可通过支路电感向量
L
boldsymbol L
L找到其支路位置索引:
- 除了上述索引,还有构建求解方程组要用到的索引
- 电压源和电容支路的索引:
U_sc_idx = [U_ss_idx; C_idx; U_ds_idx]
- 电流源和电感支路的索引:
I_sl_idx = [I_ss_idx; L_idx; I_ds_idx]
- 电压源和电容支路的索引:
构建方程组的系数矩阵
系数矩阵固定不变,方程组(8)的系数矩阵为:
[
A
Y
A
T
D
B
0
]
begin{bmatrix} boldsymbol {AYA}^{rm T} & boldsymbol D \ boldsymbol B & 0 end{bmatrix}
[AYATBD0]
实现方式为:
AT = A'; % A 的转置矩阵
Y = diag(Y); % 电导向量转化为对角矩阵
B = AT(U_sc_idx,:); % 已知的节点电压关系矩阵
D = A(:,U_sc_idx); % KCL 中电压源和电容支路电流的系数矩阵
R = [A*Y*AT D; B zeros(length(B(:,1)),length(D(1,:)))]; % 构建求解方程组的矩阵
迭代求解与记录
使用for
循环遍历时间序列。每一时刻(每一步)都进行一次求解,将结果填入
U
n
U
I
boldsymbol U_{rm n} ~ boldsymbol U ~boldsymbol I
Un U I矩阵的相应列。
方程的常数项
方程组的常数项向量为:
[
−
A
I
s
U
s
′
]
begin{bmatrix} boldsymbol -{AI}_{rm s} \ boldsymbol U'_{rm s} end{bmatrix}
[−AIsUs′]
常数项向量中的变化源、电容电压、电感电流是随时间变化的,
每次求解前都需要读取当前时刻(t时刻)的值:
I_sl = zeros(b, 1); % I_sl 电流源和电感支路的电流向量
I_sl(I_sl_idx) = I(I_sl_idx,t); % 更新常数项
U_sc = U(U_sc_idx,t); %
I_sl
即是
I
s
boldsymbol I_{rm s}
Is,长度为
b
b
b,除电流源和电感支路的电流以外,其他支路均为0。
U_sc
即是
U
s
′
boldsymbol U'_{rm s}
Us′,长度为电压源和电容个数之和,可以为空;电压源和电容的电压向量。
求解和记录
求解方程组得到的向量是:
[
U
n
I
u
′
]
begin{bmatrix} boldsymbol U_{rm n} \ boldsymbol I'_{rm u} end{bmatrix}
[UnIu′]
U
n
boldsymbol U_{rm n}
Un是此刻的节点电压向量,
I
u
′
boldsymbol I'_{rm u}
Iu′是此刻电压源和电容的电流;
根据方程组(2)得到此刻的
U
boldsymbol U
U,再根据(3)得到此刻的
I
boldsymbol I
I;
最后通过公式(10)、(11)分别更新电容的电压值、电感的电流值,作为下一时刻的初始值。
实现:
temp = R[-A*I_sl; U_sc]; % 求解方程
U_n(:,t) = temp(1:sizeA(1)); % 得到 t 时刻的 U_n
U(:,t) = AT*U_n(:,t); % 得到 t 时刻的 U
temp(1:sizeA(1)) = []; % 删除结果中 U_n 的部分
I_sc = temp; % 得到 I_sc
I(U_sc_idx,t) = I_sc; % 将 t 时刻的 I_sc 添加到 I
I(:,t) = I(:,t) + Y*U(:,t); % 得到 t 时刻的 I
if t < length(T_seq) % 最后一次不需要计算电容或电感的值
a = T_seq(t+1) - T_seq(t); % 计算步长
U_c = U_c + a.*I(C_idx,t)./C(C_idx); % 更新 U_c I(C_idx,t)即是电容的电流向量
I_l = I_l + a.*U(L_idx,t)./L(L_idx); % 更新 I_l U(L_idx,t)即是电感的电压向量
U(C_idx, t+1) = U_c;
I(L_idx, t+1) = I_l;
end
其中,I_sc
即是
I
u
′
boldsymbol I'_{rm u}
Iu′,电压源和电容的电流向量;
完成最后一次求解后,不再需要计算下一时刻电容或电感的值,使用if
实现。
拓展
- 含受控源的电路应该可以用此方法计算
- 对于电路拓扑结构统一的电路(如,分布参数电路),可以快速灵活改变 电路结构 信息,分析拓扑结构相同而节点、支路数量不同对电路的影响
- 加入更多电器元件的数学模型,如二极管、三极管、放大器、数字器件等等
最后
以上就是舒适香烟为你收集整理的【matlab】数值计算实现电路仿真搞清几个概念思路具体实行编程实现拓展的全部内容,希望文章能够帮你解决【matlab】数值计算实现电路仿真搞清几个概念思路具体实行编程实现拓展所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复