Reading data from ASCII file

530 ビュー (過去 30 日間)
Pratyush Manocha
Pratyush Manocha 2020 年 5 月 17 日
コメント済み: Pratyush Manocha 2020 年 5 月 19 日
Hi,
I have an ASCII file with data corresponding to several runs of a simulation. I want to plot all the runs in the same plot for comparison purposes and know that I have to import the data as a matrix to begin with any other processing. However, I have been facing problems with importing the data. I have attached the file here for reference purposes.
This was my take on solving this problem:
1. Using textscan
fidi = fopen('data.txt');
D=textscan(fidi, '%u %u');
E = cell2mat(D);
However, this returned empty cells as is shown by the following command:
whos E
Name Size Bytes Class Attributes
E 0x2 0 uint32
2. Using textread
fid = 'data.txt';
B = textread(fid, '%f %f');
This returned the following errors:
Error using dataread
Number of outputs must match the number of unskipped input fields.
Error in textread (line 171)
[varargout{1:nlhs}]=dataread('file',varargin{:}); %#ok<REMFF1>
Then I changed the code to this:
[B,C]=textread(fid, '%f %f');
Which in turn returned the following errors:
Error using dataread
Trouble reading floating point number from file (row 1, field 1) ==> vds Id(M1)\n
Error in textread (line 171)
[varargout{1:nlhs}]=dataread('file',varargin{:}); %#ok<REMFF1>
3. Using spcread
B=spcread(fid);
This gave the following error:
Undefined function or variable 'spcread'.
4. Using importdata
I had limited success with this, but this was as far as I could go...
A=importdata(fid);
This gave me a 1x1 struct file with a 101x2 double comprising of the first 101 lines of the text file and a 2x1 cell with the first two header lines.
I then removed all the header files which did import the entire data, albeit without all headers and would require splitting into multiple matrices to be able to plot all of the runs in one graph (because if I recall correctly, plot function doesn't support dot indexing for variables of the form A.data) like so (output taken from a commercial spice simulator):
Could someone help me import the data properly so that I can move to plotting the curves?

採用された回答

Stephen23
Stephen23 2020 年 5 月 18 日
編集済み: Stephen23 2020 年 5 月 18 日
Importing the entire file data as character, converting to string, spltting that string into multiple little strings, and then finally converting those many little strings to numeric is convoluted, an inefficient use of memory (because on each of those conversions you duplicate the data in MATLAB memory), and involves multiple data type conversions (also inefficient).
The most efficient way to import the data is to get the importing routine to directly convert the data to numeric, for example very simply using textscan (no data duplication required):
opt = {'CollectOutput',true};
hdr = {};
out = {};
[fid,msg] = fopen('data.txt','rt');
assert(fid>=3,msg) % ensure the file opened correctly.
fgetl(fid); % read and ignore the very first line.
while ~feof(fid)
hdr{end+1} = fgetl(fid);
out(end+1) = textscan(fid,'%f%f',opt{:});
end
fclose(fid);
Giving all eleven groups of data:
>> size(out)
ans =
1 11
Take a quick look at the imported data:
>> out{1}
ans =
0 0
0.1 1.3168e-10
0.2 1.3725e-10
0.3 1.4305e-10
0.4 1.4907e-10
0.5 1.5532e-10
0.6 1.6183e-10
... lots more lines here
9.6 5.8922e-09
9.7 6.1318e-09
9.8 6.3811e-09
9.9 6.6406e-09
10 6.9106e-09
>> out{11}
ans =
0 0
0.1 0.00020176
0.2 0.00038716
0.3 0.00055754
0.4 0.00071407
0.5 0.00085781
0.6 0.00098973
0.7 0.0011107
0.8 0.0012214
0.9 0.0013227
1 0.0014152
1.1 0.0014994
... lots more lines here
9.2 0.0027014
9.3 0.0027099
9.4 0.0027185
9.5 0.002727
9.6 0.0027355
9.7 0.002744
9.8 0.0027525
9.9 0.0027611
10 0.0027696
Converting the intermediate header data to numeric is trickier because some of them include SI prefixes (e.g. '500m' for 0.5) but one easy approach is to download my FEX submission sip2num and do something like this:
>> mat = cell2mat(cellfun(@sip2num,strrep(hdr(:),'Inf',''),'uni',0))
mat =
0 1 11
0.5 2 11
1 3 11
1.5 4 11
2 5 11
2.5 6 11
3 7 11
3.5 8 11
4 9 11
4.5 10 11
5 11 11
  5 件のコメント
J. Alex Lee
J. Alex Lee 2020 年 5 月 18 日
This answer indeed looks better. I didn't realize textscan can be used this way...it fails out gracefully by just not continuing and keeping file pointer where it is.
Pratyush Manocha
Pratyush Manocha 2020 年 5 月 18 日
It all makes sense now. Thanks a lot! I'll accept your answer as the best answer.

サインインしてコメントする。

その他の回答 (1 件)

J. Alex Lee
J. Alex Lee 2020 年 5 月 17 日
It would have been helpful to know these things in advance (you hinted at the first, but say it explicitly)
  1. Data contains multiple header rows for multiple sets of data
  2. Each data set is exactly 101 data points long
Without having known the 2nd detail, here's a script that will split your data - maybe there's more elegant ways (certainly much better ones knowing the exact length of all data sets)
fc = string(fileread('data.txt'));
flines = split(fc,newline);
% remove empty lines
flines(flines=="") = [];
HeaderMask = contains(flines,"Step");
HeaderIdx = find(HeaderMask);
% pad the indices with "ghost" line after last line
HeaderIdx(end+1) = length(flines)+1;
NSets = length(HeaderIdx) - 1;
hdrs = flines(HeaderMask)
for i = NSets:-1:1
tmp = flines(HeaderIdx(i)+1:HeaderIdx(i+1)-1);
tmp = str2double(split(tmp,char(9)));
data{i,1} = tmp;
hdrs(i,1) = flines(HeaderIdx(i));
end
  8 件のコメント
J. Alex Lee
J. Alex Lee 2020 年 5 月 18 日
In this case, in my inefficient process of reading in the text data into a string, Matlab showed the tab character as a right-arrow in the command line. But as Stephen's answer indicates, I guess you don't necessarily need to know that since textscan can figure it out.
You could also copy-paste the character and do
double(' ')
Pratyush Manocha
Pratyush Manocha 2020 年 5 月 19 日
I see. Thanks for clarifying!

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeText Data Preparation についてさらに検索

製品


リリース

R2018b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by