【APPdesigner】使用appdesigner设计的一个潮流计算器

基本面板组成

使用APPdesinger自带的菜单栏、工具栏、三个表、一个面板、一个坐标区、两个文本编辑字段以及若干个标签等组件。菜单栏中可进行新建、加载、保存等操作。工具栏用于选择所绘制的目标,以及开始潮流计算。三个表分别展示已经绘制的节点、导线、变压器的信息,面板为坐标区的父图窗,用于固定坐标区位置及属性。两个文本编辑字段用于展示所选节点和所选工具。
主界面

多窗口组成

分为主界面、用于填写节点信息的Node Data界面、用于填写导线信息的Transm Line Data界面、用于填写变压器信息的Transformer Data界面,以及展示潮流计算结果的Result界面。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

功能实现

(1)节点绘制

通过app.UIFigure.CurrentPoint属性获得鼠标在图窗中的位置,再在该位置创建一个uiimage实体,并在该实体的ImageClickedFcn属性下,通过createCallbackFcn添加节点回调函数。

function DrawImage(app,x,y,pen)
            switch pen
                case 1
                    DrawNode(app,x,y);                      %画点
                    
                    app.UITable.Data = app.node{2}(:,3:12);     %更新表
                    
                case 2
                    DrawTransf(app,x,y);
                
                case 3
                    DrawLine(app,x,y);
            end
            
        end
        %画节点
        %app.node{3}为元胞数组,每个cell记录一个imgae对象,用于删除和修改属性
        function DrawNode(app,x,y)
            app.node{1}=app.node{1}+1;              %计数
            app.node{2}=[app.node{2};zeros(1,13)];   %添加新行
            app.node{2}(app.node{1},1:2)=[x y];     %记录点坐标
            app.node{2}(app.node{1},3)=app.node{1}; %记录点的编号
                    
            app.node{3}{app.node{1}} = uiimage(app.Panel);
            app.node{3}{app.node{1}}.ImageClickedFcn = createCallbackFcn(app, @NodeClicked, true);
            app.node{3}{app.node{1}}.Position = [x-app.nodeimgw/2 y-app.nodeimgh/2 30 30];
            app.node{3}{app.node{1}}.ImageSource = 'node.png';
        end

(2)导线和变压器绘制

通过点选两个不同位置的节点以确定所要绘制的线段的起始点和终止点坐标,再将该坐标通过比例转换为坐标区的坐标,随后使用plot函数创建线段实体,并在该实体的ButtonDownFcn属性下通过createCallbackFcn函数添加相应的回调函数。

%画变压器
        function DrawTransf(app,x,y)
            persistent i;
            persistent p1;
            
            if isempty(i)
                i=1;        %初始化i
                p1=0;
            end
            
%             app.UIAxes.Visible = 'on';
%             [ax,ay] = MousePointInAxis(app);
%             app.UIAxes.Visible = 'off';
            
            if i == 1
                p1 = app.SelectedPoint;
%                app.SelectedPointEditField.Value = num2str(p1);
                i = i+1;
            elseif i == 2
                p2 = app.SelectedPoint;
                %避免重复
                for i=1:app.transf{1}
                    if (app.node{2}(p1,3) == app.transf{2}(i,1) && app.node{2}(p2,3) == app.transf{2}(i,2))...
                     ||(app.node{2}(p1,3) == app.transf{2}(i,2) && app.node{2}(p2,3) == app.transf{2}(i,1))
                        i=1;
                        return;
                    end
                end
                
                for i=1:app.line{1}
                    if (app.node{2}(p1,3) == app.line{2}(i,1) && app.node{2}(p2,3) == app.line{2}(i,2))...
                     ||(app.node{2}(p1,3) == app.line{2}(i,2) && app.node{2}(p2,3) == app.line{2}(i,1))
                        i=1;
                        return;
                    end
                end
                
                if p1 ~= p2 %不能是同一个点
                   x1 = (app.node{2}(p1,1)/1003);
                   y1 = (app.node{2}(p1,2)/599);
                   x2 = (app.node{2}(app.SelectedPoint,1)/1003);
                   y2 = (app.node{2}(app.SelectedPoint,2)/599);
                   
                   app.transf{1} = app.transf{1} + 1;
                   app.transf{2} = [app.transf{2};zeros(1,9)];
                   app.transf{2}(app.transf{1},8) = 220;
                   app.transf{2}(app.transf{1},9) = 220;
                   if(app.node{2}(p1,3) < app.node{2}(p2,3))
                       app.transf{2}(app.transf{1},1:2)=[app.node{2}(p1,3),app.node{2}(p2,3)];
                   else
                       app.transf{2}(app.transf{1},1:2)=[app.node{2}(p2,3),app.node{2}(p1,3)];
                   end
                   
                   app.transf{3}(app.transf{1})=plot(app.UIAxes,[x1,x2],[y1,y2],"LineStyle","-","LineWidth",3,"Color",'r');
                   app.transf{3}(app.transf{1}).ButtonDownFcn = createCallbackFcn(app,@TransfClicked,true);
                   hold(app.UIAxes,"on");
                   
                   app.UITable3.Data = app.transf{2};
                   
                   i = 1;
                else
                    i=1;
                    return;
                end
            end
        end
        
        %画线
        function DrawLine(app,x,y)
            persistent i;
            persistent p1;
            
            if isempty(i)
                i=1;        %初始化i
                p1=0;
            end
            
%             app.UIAxes.Visible = 'on';
%             [ax,ay] = MousePointInAxis(app);
%             app.UIAxes.Visible = 'off';
            
            if i == 1
                p1 = app.SelectedPoint;
%                app.SelectedPointEditField.Value = num2str(p1);
                i = i+1;
            elseif i == 2
                p2 = app.SelectedPoint;
                %避免重复
                for i=1:app.line{1}
                    if (app.node{2}(p1,3) == app.line{2}(i,1) && app.node{2}(p2,3) == app.line{2}(i,2))...
                     ||(app.node{2}(p1,3) == app.line{2}(i,2) && app.node{2}(p2,3) == app.line{2}(i,1))
                        i=1;
                        return;
                    end
                end
                
                for i=1:app.transf{1}
                    if (app.node{2}(p1,3) == app.transf{2}(i,1) && app.node{2}(p2,3) == app.transf{2}(i,2))...
                     ||(app.node{2}(p1,3) == app.transf{2}(i,2) && app.node{2}(p2,3) == app.transf{2}(i,1))
                        i=1;
                        return;
                    end
                end
                
                if p1 ~= p2 %不能是同一个点
                   x1 = (app.node{2}(p1,1)/1003);
                   y1 = (app.node{2}(p1,2)/599);
                   x2 = (app.node{2}(app.SelectedPoint,1)/1003);
                   y2 = (app.node{2}(app.SelectedPoint,2)/599);

                   
                   app.line{1} = app.line{1} + 1;
                   app.line{2} = [app.line{2};zeros(1,7)];
                   app.line{2}(app.line{1},7) = 1;
                   if(app.node{2}(p1,3) < app.node{2}(p2,3))
                       app.line{2}(app.line{1},1:2)=[app.node{2}(p1,3),app.node{2}(p2,3)];
                   else
                       app.line{2}(app.line{1},1:2)=[app.node{2}(p2,3),app.node{2}(p1,3)];
                   end
                   
                   app.line{3}(app.line{1})=plot(app.UIAxes,[x1,x2],[y1,y2],"LineStyle","-","LineWidth",3,"Color",'b');
                   app.line{3}(app.line{1}).ButtonDownFcn = createCallbackFcn(app,@LineClicked,true);
                   hold(app.UIAxes,"on");
                   
                   app.UITable2.Data = app.line{2}(:,1:7);
                   i = 1;
                else
                    i=1;
                    return;
                end
            end
        end

(3)数据添加

在鼠标点击选择目标后,通过回调函数打开相应的数据填写图窗,同时将原有数据传给图窗,在图窗中填写完信息并点击Save后通过DataUpdata_node、DataUpdata_line、DataUpdata_transf等函数将数据传回主窗口并存放在各类数据矩阵中。

 %更新node数据
        %seq-序号;type-节点类型;
        function DataUpdata_node(app,seq,type,Pd,Qd,Gs,Bs,Vm,Va,Gen,Pg,Qg)
            app.node{2}(app.SelectedPoint,3)=seq;
            app.node{2}(app.SelectedPoint,4)=type;
            app.node{2}(app.SelectedPoint,5)=Pd;
            app.node{2}(app.SelectedPoint,6)=Qd;
            app.node{2}(app.SelectedPoint,7)=Gs;
            app.node{2}(app.SelectedPoint,8)=Bs;
            app.node{2}(app.SelectedPoint,9)=Vm;
            app.node{2}(app.SelectedPoint,10)=Va;
            
            app.node{2}(app.SelectedPoint,11)=Gen;
            app.node{2}(app.SelectedPoint,12)=Pg;
            app.node{2}(app.SelectedPoint,13)=Qg;
            app.UITable.Data = app.node{2}(:,3:13);     %更新表
        end
        
        %更新line数据
        %
        function DataUpdata_line(app,rou,req,Dm,L,n)
            app.line{2}(app.SelectedLine,3)=rou;
            app.line{2}(app.SelectedLine,4)=req;
            app.line{2}(app.SelectedLine,5)=Dm;
            app.line{2}(app.SelectedLine,6)=L;
            app.line{2}(app.SelectedLine,7)=n;
            
            app.UITable2.Data = app.line{2}(:,1:7);
        end
        
        %更新transf数据
        %
        function DataUpdata_transf(app,Sn,Pk,Uk,Po,Io,Uf,Us)
            app.transf{2}(app.SelectedTransf,3)=Sn;
            app.transf{2}(app.SelectedTransf,4)=Pk;
            app.transf{2}(app.SelectedTransf,5)=Uk;
            app.transf{2}(app.SelectedTransf,6)=Po;
            app.transf{2}(app.SelectedTransf,7)=Io;
            app.transf{2}(app.SelectedTransf,8)=Uf;
            app.transf{2}(app.SelectedTransf,9)=Us;
            
            app.UITable3.Data = app.transf{2};
        end

(4)保存

通过save函数生成nodedata.txt和linedata.txt分别存放节点数据和导线以及变压器信息。

 %保存数据
        function [file,path] = SaveFile_txt(app)
            [file,path] = uiputfile('*.txt','NodeData','NodeData.txt');
            filename = fullfile(path,file);
            
            if isequal(file,0) || isequal(path,0)
                disp('User clicked Cancel.')
            else
                nodedata = []
                nodepoint = []
                for i=1:app.node{1}
                    for j=1:app.node{1}
                        if app.node{2}(j,3) == i
                            nodedata = [nodedata;app.node{2}(j,3:6),app.node{2}(j,11:12),app.node{2}(j,7:10)];
                            nodepoint = [nodepoint;app.node{2}(j,1:2)];
                        end
                    end
                end
                save(filename,'nodedata',"-ascii");
                save("NodePoint.txt",'nodepoint',"-ascii");
            end
            
            [file,path] = uiputfile('*.txt','LineData','LineData.txt');
            filename = fullfile(path,file);
            if isequal(file,0) || isequal(path,0)
                disp('User clicked Cancel.')
            else
                linedata = [app.line{2},zeros(app.line{1},2);app.transf{2}];
                save(filename,'linedata',"-ascii");
            end
        end

(5)加载

通过load函数读取nodedata.txt和linedata.txt获得节点数据和导线以及变压器信息,并绘制相应图像。

function Openfile_txt(app)
            [file,path] = uigetfile('*.txt');
            filename = fullfile(path,file);
            
            if isequal(file,0) || isequal(path,0)
                disp('User clicked Cancel.')
            else
                if strcmp(file,'NodeData.txt') == 1
                    content=load(filename);
                    [m,~] = size(content);
                    app.node{1} = m;
                    app.node{2} = zeros(m,13);
                    app.node{2}(:,3:6) = content(:,1:4);
                    app.node{2}(:,7:10) = content(:,7:10);
                    app.node{2}(:,11:12) = content(:,5:6);
                    
                    content=load("NodePoint.txt");
                    [m,~] = size(content);
                    app.node{2}(:,1:2) = content;
                    for i=1:m
                        app.node{3}{i} = uiimage(app.Panel);
                        app.node{3}{i}.ImageClickedFcn = createCallbackFcn(app, @NodeClicked, true);
                        app.node{3}{i}.Position = [app.node{2}(i,1)-app.nodeimgw/2 app.node{2}(i,2)-app.nodeimgh/2 30 30];
                        app.node{3}{i}.ImageSource = 'node.png';
                    end
                    app.UITable.Data = app.node{2}(:,3:12);
                elseif strcmp(file,'LineData.txt') == 1
                    content=load(filename);
                    [m,~] = size(content);
                    i = 1;
                    while ~content(i,8)
                        i=i+1;
                        if i>m
                            break;
                        end
                    end
                    i = i - 1;
                    app.line{1} = i;
                    app.line{2} = zeros(i,7);
                    app.line{2} = content(1:i,1:7);
                    for j=1:app.line{1}                       
                        x1 = (app.node{2}(app.line{2}(j,1),1)/1003);
                        y1 = (app.node{2}(app.line{2}(j,1),2)/599);
                        x2 = (app.node{2}(app.line{2}(j,2),1)/1003);
                        y2 = (app.node{2}(app.line{2}(j,2),2)/599);
                        app.line{3}(j)=plot(app.UIAxes,[x1,x2],[y1,y2],"LineStyle","-","LineWidth",3,"Color",'b');
                        app.line{3}(j).ButtonDownFcn = createCallbackFcn(app,@LineClicked,true);
                        hold(app.UIAxes,"on");
                    end
                    app.UITable2.Data = app.line{2}(:,1:7);
                    
                    app.transf{1} = m-i;
                    app.transf{2} = zeros(m-i,9);
                    app.transf{2} = content(i+1:m,1:9);
                    for j=1:app.transf{1}
                        x1 = (app.node{2}(app.transf{2}(j,1),1)/1003);
                        y1 = (app.node{2}(app.transf{2}(j,1),2)/599);
                        x2 = (app.node{2}(app.transf{2}(j,2),1)/1003);
                        y2 = (app.node{2}(app.transf{2}(j,2),2)/599);
                        app.transf{3}(j)=plot(app.UIAxes,[x1,x2],[y1,y2],"LineStyle","-","LineWidth",3,"Color",'r');
                        app.transf{3}(j).ButtonDownFcn = createCallbackFcn(app,@TransfClicked,true);
                        hold(app.UIAxes,"on");
                    end
                    app.UITable3.Data = app.transf{2};
                    
                end
             end
        end

(6)运行潮流计算

先保存两个名为nodedata.txt和linedata.txt的文件,随后使用py.importlib.import_module调用算法程序,再打开result窗口展示运算结果。

			SaveFile_txt(app);
            obj = py.importlib.import_module('runpf');
            py.importlib.reload(obj);
            obj.runpf();
            run result_info.mlapp;

数据结构

(1)节点数据

使用matlab特有的元组,创建一个名为node的1*3元组。在node{1}中记录节点个数,每次绘制节点或删除节点时进行加一或减一;在node{2}中创建一个矩阵,矩阵初始长度为1*13,每列分别记录节点的figure横坐标、figure纵坐标、序号、节点类型、Pd、Qd、Gs、Bs、Vm、Va、Gen、Pg、Qg,在每次绘制节点或删除节点时添加一行或删除某一行;node{3}用于存放每次绘制图像时创建的实体。

(2)导线数据

同样使用元组,创建一个名为line的1*3元组。line{1}中记录导线个数,每次绘制导线或删除导线时进行加一或减一;line{2}中创建一个初始为1*7的矩阵,每列分别记录fbus、sbus、ρ、req、Dm、L、n,在每次绘制导线或删除导线时添加一行或删除某一行;line{3}用于存放每次绘制线段时创建的实体。

(3)变压器数据

同样使用元组,创建一个名为transf的1*3元组。transf{1}中记录导线个数,每次绘制导线或删除导线时进行加一或减一;transf{2}中创建一个初始为1*9的矩阵,每列分别记录fbus、sbus、Sn、Pk、Uk、Po、Io、Uf、Us,在每次绘制变压器或删除变压器时添加一行或删除某一行;transf{3}用于存放每次绘制线段时创建的实体。

(4)整数类型pen

Pen变量用于存放所选绘制图像,在选择工具时改变。

(5)选择目标

SelectedPoint、SelectedLine、SelectedTransf通过PickOn函数,使用传入的各类实体句柄确定所选目标。


版权声明:本文为qq_51594109原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>