如何把PSCAD的仿真数据导到matlab中?自己写了一个matlab小程序。数据可以保存在硬盘里,想提取哪个就提取哪个,想什么时候提取就什么时候提取,还可以大批量一次性搞定。
今天分享出来,欢迎各位提出改进意见!
用到的函数
打开和关闭文件
filename=‘D:\simulation\pscad\1’;
fid=fopen(filename)
…
fclose(fid);查找数据
文件扫描——textscan()
c1=textscan(fid,’%*s%s%*s%*s%*s%s%*s%*s%*s%n%s%s%[^\n]’,‘delimiter’,’”’,‘headerlines’,6);格式转换
数字转换为字符串——num2str()
num2str(n,1)
数字转换为元胞——num2cell()
num2cell(i+n-1,1)
字符串转换为浮点数——str2double()
str2double(sequence{k(i)})+1字符串操作
字符串连接——strcat()
strcat(name_pro(n2),’_’, num1)
字符串比较——strcmp()
strcmp(name{i},str_find)数据处理
取余——rem()
rem(i-1,10)
思路
首先,需要在PSCAD中开启数据记录,并设置一个保存名称,例如data.out。在仿真中对自己想要采集的数据设置相应的output channel。例如
只有设置了输出通道output channel的数据才能被采集下来,注意一下所采集数据的维度,最好是单维度的,这个原因在后面会讲。
之后,每次运行结束后,PSCAD会在project文件所在的文件夹下生成一个后缀为.gf42的文件夹,如下图所示。仿真过程中记录的数据就保存在这个文件夹里。下次运行时生成的新的.gf42的文件夹会覆盖旧的文件,所以注意重命名。
gf42文件夹里的内容如下所示:
文件夹里的.out文件就是数据了。用记事本可以打开.out文件,但是打开后发现里面一堆的数据,数了数一共11列,第一列是时间序列。而像这样的文件可能有几十个。
那么问题来了,如何知道想找的数据在哪里呢?
好在,后缀为.infx的文档是一个关于数据内容的菜单。
经过验证,之前的.out文件中的数据与infx文件中的名称可以一一对应。
这下,有了名称、序列以及相应的数据,剩下的就是找到想要的数据,并把它们分别提取出来。
步骤
1. 从.infx文件中提取出需要的数据
我们需要的数据包括次序,名称以及维度。
利用textscan()函数可以从txt文件中提取出数据。
fid = fopen(filename); %先打开文件,filename是.infx文件的地址
c1=textscan(fid,'%*s%s%*s%*s%*s%s%*s%*s%*s%n%*s%s%*[^\n]','delimiter','"','headerlines',6);
fclose(fid);
sequence=c1{ 1};
name=c1{ 2};
dim=c1{ 3};
unit=c1{ 4};
采用” ” “作为分隔符,前6行不是我们需要的,因此要跳过。采集出来后分别存好。
2. 处理多维数据
有了名单,找到相应的数据就好办了。例如,我们要找的是数据A,我们可以从之前提取的名单里面找到A的次序编号,然后再根据一个文件里一共有11列,就能算出编号所在的是第几个文件夹里的第几列了。
然而,实际操作发现,有的数据维度是多维的,例如有的电流是三相的,三列数据共同用一个名字。这种情况下,使用之前的序列编号直接计算地址就会出错了。这时当初提取出来的维度数据就有用了。
根据维度数据,可以将实际的各个变量数据的编号计算出来,还可以顺便给它们分别命好名字。(当然,也可以从根源上解决,确保仿真的数据都是单维的)
sequence_pro=cell(sum0,1); %序号也要重新定义
i=1 ; %数据的个数
n=1; %多维数据里的次序
x=1 ; %循环的次数
%由于很多数据是多维的且没有相应的名字,所以要利用维度这个数据对多维的数据重新起名字
%就是在多维的数据的名字后面加上序号
for x=1:size(dim,1)
num=dim(x); %根据维度进行判断
if num>1 %如果该数据的维度不为1
for n=1:num %从1到最大的维度进行循环
num1=num2str(n,1); %将该序号转为字符格式,为拼接作准备
name_pro(i+n-1)=strcat(name(x),'_',num1); %在名字后面加上序号,表示多维数据内容
sequence_pro(i+n-1)=num2cell(i+n-1,1); %将序列补充完整
end
elseif num<1 %这里发现结尾的维度数据有0出现,当出现0时,说明已经处理完了
break
else
name_pro(i)=name(x); %如果是单维的数据就直接按照之前的名字命名即可
sequence_pro(i)=num2cell(i,1); %序号也是一样
end
i=i+num; %数据的个数加上维度数目
x=x+1 ; %当前名字的数据的个数已经处理完,进行下一个名字的操作
end
处理完多维数据的问题,就可以准确定位数据了。
3. 定位并提取数据
搜索名称->记录序列编号->计算所在文件夹个数和数据列数->去相应的地址中提取。
line_name=cell(size(set,2),1); %将线的名称存在数组里
Data_base=ones(length(time),1)*nan; %存储数据的矩阵预定义
%记录存储数据的数目
n3=1;
str_find=set{ 1,fig_l};
%搜索所需要的数据
n=max(size(name));
k=ones(1,1)*nan;
for i=1:n
if strcmp(name{ i},str_find) %从name数组中找相同名字的项
[b]=i; %i是name中的该项的位置
k=[k,b];
end
end
k(:,1)='';
if k(1,1)< 1 %这里想写一个错误处理,但是没成功,反正如果在这里报错,就看str_find,那个就是没找到的变量
print='未找到数据!!!';
pause;
end
%给没在一起的三相数据命名
if max(size(k))>1 %这里有一点不是很好,就是当数据被第二次使用时,依照这种方法就无法找到了,需要加上后缀才行
for i=1:max(size(k))
n2=str2double(sequence{ k(i)})+1;
num1=num2str(i);
name_pro(n2)=strcat(name_pro(n2),'_',num1); %修改三相数据的名字
end
end
%提取相应数据
for u=1:max(size(k)) % k有可能是三相数据,所以是数组
n2=str2double(sequence{ k(u)})+1;
for i=n2:n2+dim(k(u))-1 %从维度开始的序号到维度结束的序号
pick2=pick; %准备删除*号
txtn=ceil(i/10); %文件数是除以10再取整,ceil是向上取整
column=rem(i-1,10)+1; %列数是除以10再取余,这里i-1是因为当i=10时,取余为0,通过i-1再取余最后+1可以解决这个问题
pick2(pin(column))=''; %删除*号,产生提取的格式
fid=fopen(faddress{ txtn});
c1=textscan(fid,pick2,'headerlines',1);
fclose(fid);
a=c1{ 1};
Data_base=[Data_base,a]; %保存数据
line_name(n3)=name_pro(i); %保存相应数据的名称
n3=n3+1; %数据数目累加
end
end
4. 补充说明
data文件有多个,提取文档需要用到他们的地址,手动保存会很累,下面的程序可以自动生成他们的地址。
n=max(strfind(filename,'\'));
n1=max(strfind(filename,'.'));
freename=filename(n+1:n1-1); %提取自定义的存储名
headad=filename(1:n);%提取后面要用到的地址头部,一直到数据文件名前的\
%下面的循环是为了通过拼接产生地址清单,为后面的提取数据作准备
for i=1:total %循环次数为总的文件的个数,一个文件提取一次
n=num2str(i); %整数转换为字符串格式,为拼接作准备
if i<10 %1-9的文件名下划线后面有0
faddress_temp=strcat(headad,freename,'_0',n,'.out'); %拼接
else
faddress_temp=strcat(headad,freename,'_',n,'.out') ;
end
faddress(i)={ faddress_temp}; %保存地址
end
程序内容
完整的程序内容如下。
%% PSCAD_data_manage.m
%该程序可以提取所需要的PSCAD自动存储的数据
%输入要提取的变量名称,可以参照.infx
set={ '变量1','变量2','变量3','变量4'};
%输入数据存储地址
filename='D:/simulation/1/';
pick='%*f%*f%*f%*f%*f%*f%*f%*f%*f%*f%*f';
pin=[5 8 11 14 17 20 23 26 29 32];
n=max(strfind(filename,'\'));
n1=max(strfind(filename,'.'));
freename=filename(n+1:n1-1); %提取自定义的存储名
headad=filename(1:n);%提取后面要用到的地址头部,一直到数据文件名前的\
%提取数据的标题
fid = fopen(filename);
c1=textscan(fid,'%*s%s%*s%*s%*s%s%*s%*s%*s%n%*s%s%*[^\n]','delimiter','"','headerlines',6);
fclose(fid);
sequence=c1{ 1};
name=c1{ 2};
dim=c1{ 3};
unit=c1{ 4};
i= ~isnan(dim);
dim=dim(i); %去掉里面的nan项,否则无法相加
sum0=sum(dim(:)); %所有的数据条数
sum0=uint32(sum0);
name_pro=cell(sum0,1); %预定义所有的名称数组空间
sequence_pro=cell(sum0,1); %序号也要重新定义
i=1 ; %数据的个数
n=1; %多维数据里的次序
x=1 ; %循环的次数
%由于很多数据是多维的且没有相应的名字,所以要利用维度这个数据对多维的数据重新起名字
%就是在多维的数据的名字后面加上序号
for x=1:size(dim,1)
num=dim(x); %根据维度进行判断
if num>1 %如果该数据的维度不为1
for n=1:num %从1到最大的维度进行循环
num1=num2str(n,1); %将该序号转为字符格式,为拼接作准备
name_pro(i+n-1)=strcat(name(x),'_',num1); %在名字后面加上序号,表示多维数据内容
sequence_pro(i+n-1)=num2cell(i+n-1,1); %将序列补充完整
end
elseif num<1 %这里发现结尾的维度数据有0出现,当出现0时,说明已经处理完了
break
else
name_pro(i)=name(x); %如果是单维的数据就直接按照之前的名字命名即可
sequence_pro(i)=num2cell(i,1); %序号也是一样
end
i=i+num; %数据的个数加上维度数目
x=x+1 ; %当前名字的数据的个数已经处理完,进行下一个名字的操作
end
sum0=double(sum0);
%处理完标题,下面对具体数据的提取作准备
total=ceil(sum0/10); %计算总的数据存档文件个数
faddress=cell(total,1); %预定义文件的地址数组空间
%下面的循环是为了通过拼接产生地址清单,为后面的提取数据作准备
for i=1:total %循环次数为总的文件的个数,一个文件提取一次
n=num2str(i); %整数转换为字符串格式,为拼接作准备
if i<10 %1-9的文件名下划线后面有0
faddress_temp=strcat(headad,freename,'_0',n,'.out'); %拼接
else
faddress_temp=strcat(headad,freename,'_',n,'.out') ;
end
faddress(i)={ faddress_temp}; %保存地址
end
fid = fopen(faddress{ 1});
c1=textscan(fid,'%f%*[^\n]','headerlines',1);
fclose(fid);
time=c1{ 1};
%%
%之前为预定义环节,之后才是具体的提取数据
%设置一个矩阵,根据矩阵中的数字,就可以找到相应的数据名
line_name=cell(size(set,2),1); %将线的名称存在数组里
Data_base=ones(length(time),1)*nan; %存储数据的矩阵预定义
%记录存储数据的数目
n3=1;
for fig_l=1:size(set,2)
str_find=set{ 1,fig_l};
%搜索所需要的数据
n=max(size(name));
k=ones(1,1)*nan;
for i=1:n
if strcmp(name{ i},str_find) %从name数组中找相同名字的项
[b]=i; %i是name中的该项的位置
k=[k,b];
end
end
k(:,1)='';
if k(1,1)< 1 %想写错误处理,没成功,如果在这里报错,就看str_find,那个就是没找到的变量
print='未找到数据!!!';
pause;
end
%给没在一起的三相数据命名
if max(size(k))>1 %这里有一点不是很好,就是当数据被第二次使用时,依照这种方法就无法找到了,需要加上后缀才行
for i=1:max(size(k))
% n2=str2num(sequence{ k(i)})+1; %要知道次序数组里的该位置对应的次序数才能知道该项的name_pro数组里的名字
n2=str2double(sequence{ k(i)})+1;
num1=num2str(i);
name_pro(n2)=strcat(name_pro(n2),'_',num1); %修改三相数据的名字
end
end
%提取相应数据
for u=1:max(size(k)) % k有可能是三相数据,所以是数组
% n2=str2num(sequence{ k(u)})+1; %找到相应的包含有维度的数据在表格中的序列号
n2=str2double(sequence{ k(u)})+1;
for i=n2:n2+dim(k(u))-1 %从维度开始的序号到维度结束的序号
pick2=pick; %准备删除*号
txtn=ceil(i/10); %文件数是除以10再取整,ceil是向上取整
column=rem(i-1,10)+1; %列数是除以10再取余,这里i-1是因为当i=10时,取余为0,通过i-1再取余最后+1可以解决这个问题
pick2(pin(column))=''; %删除*号,产生提取的格式
% [a]=textread(faddress{ txtn},pick2,'delimiter',' ','headerlines',1);%提取数据
fid=fopen(faddress{ txtn});
c1=textscan(fid,pick2,'headerlines',1);
fclose(fid);
a=c1{ 1};
Data_base=[Data_base,a]; %保存数据
line_name(n3)=name_pro(i); %保存相应数据的名称
n3=n3+1; %数据数目累加
end
end
end
Data_base(:,1)=''; %去掉空列
如果帮到了大家,点个赞再走呗~