Mercurial > hg > ltpda
comparison m-toolbox/classes/@ao/fromDatafile.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0afece42f48 |
---|---|
1 % FROMDATAFILE Construct an ao from filename AND parameter list | |
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
3 % | |
4 % FUNCTION: fromDatafile | |
5 % | |
6 % DESCRIPTION: Construct an ao from filename AND parameter list | |
7 % | |
8 % CALL: a = fromFilenameAndPlist(a, pli) | |
9 % | |
10 % PARAMETER: a: empty ao-object | |
11 % pli: plist-object (must contain the filename) | |
12 % | |
13 % VERSION: $Id: fromDatafile.m,v 1.51 2011/10/12 20:30:51 mauro Exp $ | |
14 % | |
15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
16 | |
17 function a = fromDatafile(ain, pli) | |
18 | |
19 utils.helper.msg(utils.const.msg.PROC1, 'constructing from filename and/or plist'); | |
20 | |
21 VERSION = '$Id: fromDatafile.m,v 1.51 2011/10/12 20:30:51 mauro Exp $'; | |
22 | |
23 % get AO info | |
24 mi = ao.getInfo('ao', 'From ASCII File'); | |
25 | |
26 % Set the method version string in the minfo object | |
27 mi.setMversion([VERSION '-->' mi.mversion]); | |
28 | |
29 % Get filename | |
30 file_name = find(pli, 'filename'); | |
31 file_path = find(pli, 'filepath'); | |
32 | |
33 [filePath, fileName, ext] = fileparts(file_name); | |
34 | |
35 % Add the file extenstion to the fileName | |
36 fileName = strcat(fileName, ext); | |
37 | |
38 % Define the path of the | |
39 if ~isempty(file_path) && ~isempty(filePath) | |
40 % Do nothing because we will use filePath | |
41 elseif ~isempty(file_path) | |
42 filePath = file_path; | |
43 elseif ~isempty(filePath) | |
44 % Do nothing because we will use filePath | |
45 else | |
46 filePath = pwd(); | |
47 end | |
48 | |
49 absolutePathname = fullfile(filePath, fileName); | |
50 | |
51 % Check if the abolute Pathname exist | |
52 if ~exist(absolutePathname, 'file') | |
53 absolutePathname = fileName; | |
54 end | |
55 | |
56 %%%%%%%%%% Get default parameter list %%%%%%%%%% | |
57 dpl = ao.getDefaultPlist('From ASCII File'); | |
58 pl = applyDefaults(dpl, pli); | |
59 | |
60 pl = pset(pl, 'filename', fileName); | |
61 pl = pset(pl, 'filepath', filePath); | |
62 | |
63 data_type = find(pl, 'type'); | |
64 columns = find(pl, 'columns'); | |
65 maxLines = find(pl, 'maxlines'); | |
66 comment_char = find(pl, 'comment_char'); | |
67 delimiter = find(pl, 'delimiter'); | |
68 use_fs = find(pl, 'fs'); | |
69 a = []; | |
70 orig_col = columns; % necessary for the history | |
71 t0 = find(pl, 't0'); | |
72 | |
73 %%%% | |
74 if strcmpi(data_type, 'cdata') | |
75 use_fs = 1; | |
76 end | |
77 | |
78 %%%%%%%%%% read file %%%%%%%%%% | |
79 [fid,msg] = fopen (absolutePathname, 'r'); | |
80 if (fid < 0) | |
81 error ('### can not open file: %s \n### error msg: %s', absolutePathname, msg); | |
82 end | |
83 | |
84 | |
85 try | |
86 | |
87 %%%%%%%%%% create scan format: '%f %f %f %f %f %*[^\n]' %%%%%%%%%% | |
88 scan_format = ''; | |
89 read_col = 0; | |
90 | |
91 %%%%%%%%%% Read first comment and empty lines %%%%%%%%%% | |
92 while ~feof(fid) | |
93 fidPos = ftell(fid); | |
94 fline = fgetl(fid); | |
95 % check if there was an error reading the file | |
96 [errmsg, errnum] = ferror(fid); | |
97 if errnum ~= 0 | |
98 error('### an error happened reading the first part of the file: %s', errmsg) | |
99 end | |
100 if fline == -1 | |
101 % we hit the end of file | |
102 error('### the file is empty!') | |
103 end | |
104 fline = strtrim(fline); | |
105 if ~isempty(fline) && ~(~isempty(comment_char) && strncmp(fline, comment_char, numel(comment_char))) | |
106 fseek(fid, fidPos, 'bof'); | |
107 break; | |
108 end | |
109 end | |
110 | |
111 %%%%%%%%%% Get/Count max number of lines %%%%%%%%%% | |
112 if isempty(maxLines) | |
113 maxLines = numLines(fid); | |
114 utils.helper.msg(utils.const.msg.PROC2, 'Counting lines: %d', maxLines); | |
115 end | |
116 | |
117 %%%%%%%%%% Check max number of columns %%%%%%%%%% | |
118 maxColumns = numCols(fid, delimiter); | |
119 if isempty(columns) && strcmpi(data_type, 'cdata') | |
120 columns = 1:maxColumns; | |
121 orig_col = columns; | |
122 end | |
123 if maxColumns < max(columns) | |
124 error('### The file doesn''t have more than [%d] columns. But you want to read the column [%d].', maxColumns, max(columns)); | |
125 end | |
126 | |
127 %%%%%%%%%% Check number of columns %%%%%%%%%% | |
128 if isempty(columns) && ~strcmpi(data_type, 'cdata') | |
129 error('### Please specify at least one column number to read the data file.'); | |
130 end | |
131 | |
132 %%% preallocate data array | |
133 f_data = zeros(maxLines, numel(unique(columns))); | |
134 | |
135 %%% check if using robust read: 'yes'/'no' or true/false or 'true'/'false' | |
136 robust = utils.prog.yes2true(find(pl, 'Robust')); | |
137 | |
138 if robust | |
139 f_data = robustRead(fid, f_data, columns, orig_col); | |
140 else | |
141 | |
142 %%% Based on skipping the not used columns we have to transform the columns. | |
143 %%% We must transform the columns [ 2 5 2 6 5 7] to [ 1 2 1 3 2 4] | |
144 %%% In each loop we have to replace the corresponding value. In the first loop | |
145 %%% the first minimum, in the second loop the second minimum, ... with the | |
146 %%% current loop number. | |
147 sort_col = sort(columns); | |
148 for jj = 1:max(columns) | |
149 if ismember(jj, columns) | |
150 scan_format = [scan_format '%n']; | |
151 read_col = read_col + 1; | |
152 replace = min(sort_col); | |
153 | |
154 columns (columns == replace) = read_col; | |
155 sort_col(sort_col == replace) = []; | |
156 else | |
157 scan_format = [scan_format '%*n']; | |
158 end | |
159 end | |
160 scan_format = [deblank(scan_format) '%*[^\n]']; | |
161 | |
162 %%%%%%%%%% Read data %%%%%%%%%% | |
163 readlines = min(50000, maxLines); | |
164 nlines = 0; | |
165 | |
166 %%% read file to end | |
167 while ~feof(fid) && nlines < maxLines | |
168 | |
169 if isempty(comment_char) && isempty(delimiter) | |
170 C = textscan(fid, scan_format, readlines); | |
171 elseif isempty(comment_char) && ~isempty(delimiter) | |
172 C = textscan(fid, scan_format, readlines, 'Delimiter', delimiter); | |
173 elseif ~isempty(comment_char) && isempty(delimiter) | |
174 C = textscan(fid, scan_format, readlines, 'CommentStyle', comment_char); | |
175 else | |
176 C = textscan(fid, scan_format, readlines, 'CommentStyle', comment_char, 'Delimiter', delimiter); | |
177 end | |
178 | |
179 if isempty(C{1}) && nlines == 0 | |
180 error('\n### There are no data.\n### Did you use the right comment character?\n### The current comment character is: [%s]\n### Use a parameter list with the parameter:\n### plist(''comment_char'', ''%%'')', comment_char); | |
181 end | |
182 | |
183 f_data(nlines+1:nlines+size(C{1},1),:) = cell2mat(C); | |
184 nlines = nlines + length(C{1}); | |
185 | |
186 utils.helper.msg(utils.const.msg.PROC2, 'read %09d lines of %09d', nlines, maxLines); | |
187 end | |
188 | |
189 %%% get only the data we want | |
190 if size(f_data,1) > nlines | |
191 f_data = f_data(1:nlines, :); | |
192 end | |
193 end | |
194 | |
195 catch ME | |
196 % An error occurred during the scan | |
197 fclose(fid); | |
198 rethrow(ME); | |
199 end | |
200 | |
201 % The scan was successful | |
202 fclose(fid); | |
203 | |
204 | |
205 %%%%%%%%%% Create for each column pair the data object %%%%%%%%%% | |
206 | |
207 % This is a list of keys which support multiple values. We need to | |
208 % process the history plist to account for this so that the hisotry of a | |
209 % single object only contains the value that the user intended that | |
210 % object to get. | |
211 % TODO: find a nicer way to specify this? | |
212 keys = {'name', 'description', 'xunits', 'yunits', 't0'}; | |
213 | |
214 if isempty(use_fs) | |
215 | |
216 %%%%%%%%%% The numbers in columns must be even %%%%%%%%%% | |
217 if length(columns) == 1 | |
218 if ~strcmp(data_type, 'cdata') | |
219 error('A single column file with no sample rate set can only be used to build a cdata AO'); | |
220 end | |
221 else | |
222 if mod(length(columns),2) ~= 0 | |
223 error('### The numbers in columns must be even or you forgot to specify the ''fs'' parameter'); | |
224 end | |
225 end | |
226 | |
227 N = length(columns)/2; | |
228 for lauf = 1:N | |
229 | |
230 data_x_axes = f_data(:, columns(lauf*2-1)); | |
231 data_y_axes = f_data(:, columns(lauf*2)); | |
232 | |
233 % create data object corresponding to the parameter list | |
234 ao_data = []; | |
235 switch lower(data_type) | |
236 case 'tsdata' | |
237 ao_data = tsdata(data_x_axes, data_y_axes); | |
238 case 'fsdata' | |
239 ao_data = fsdata(data_x_axes, data_y_axes); | |
240 case 'cdata' | |
241 error('### This should not happen!'); | |
242 case 'xydata' | |
243 ao_data = xydata(data_x_axes, data_y_axes); | |
244 otherwise | |
245 error('### unknown data type ''%s''', data_type); | |
246 end | |
247 aa = ao(ao_data); | |
248 | |
249 % set up the history plist for this object | |
250 plhist = pl.processForHistory(N, lauf, keys); | |
251 plhist.pset('columns', [orig_col(lauf*2-1) orig_col(lauf*2)]); | |
252 | |
253 | |
254 % Add history | |
255 aa.addHistory(mi, plhist, [], []); | |
256 | |
257 a = [a aa]; | |
258 | |
259 end | |
260 | |
261 %%%%%%%%%% Create for each column AND fs a data object %%%%%%%%%% | |
262 else % isempty(use_fs) | |
263 | |
264 N = length(columns); | |
265 for lauf = 1:N | |
266 | |
267 data_y_axes = f_data(:, columns(lauf)); | |
268 | |
269 % create data object corresponding to the parameter list | |
270 ao_data = []; | |
271 switch lower(data_type) | |
272 case 'tsdata' | |
273 ao_data = tsdata(data_y_axes, use_fs); | |
274 case 'fsdata' | |
275 ao_data = fsdata(data_y_axes, use_fs); | |
276 case 'cdata' | |
277 % Special case for cdata-objects. | |
278 % Is the user specify some columns then he will get for each | |
279 % column an AO. If don't specify a columns then he will all data | |
280 % in a single AO. | |
281 if isempty(pl.find('columns')) | |
282 % Create only one AO with all data | |
283 a = ao(f_data); | |
284 a.name = fileName; | |
285 a.addHistory(mi, pl, [], []); | |
286 break | |
287 else | |
288 % Create for each column a single AO | |
289 ao_data = cdata(data_y_axes); | |
290 end | |
291 case 'xydata' | |
292 ao_data = xydata(data_y_axes); | |
293 otherwise | |
294 error('### unknown data type ''%s''', data_type); | |
295 end | |
296 aa = ao(ao_data); | |
297 | |
298 % set up the history plist for this object | |
299 plhist = pl.processForHistory(N, lauf, keys); | |
300 plhist.pset('columns', orig_col(lauf)); | |
301 | |
302 | |
303 % Add history | |
304 aa.addHistory(mi, plhist, [], []); | |
305 | |
306 a = [a aa]; | |
307 | |
308 end | |
309 | |
310 end | |
311 | |
312 % for tsdata and fsdata we support setting the t0 | |
313 if any(strcmpi(data_type, {'tsdata', 'fsdata'})) | |
314 a.setT0(t0); | |
315 end | |
316 | |
317 % set xunits if we don't have a cdata | |
318 if ~strcmpi(data_type, 'cdata') | |
319 xunits = pl.find('xunits'); | |
320 if isempty(xunits) | |
321 if strcmpi(data_type, 'tsdata') | |
322 xunits = 's'; | |
323 elseif strcmpi(data_type, 'fsdata') | |
324 xunits = 'Hz'; | |
325 else | |
326 % do nothing | |
327 end | |
328 end | |
329 a.setXunits(xunits); | |
330 end | |
331 | |
332 % set yunits | |
333 a.setYunits(pl.find('yunits')); | |
334 | |
335 % Set object properties | |
336 a.setObjectProperties(pl); | |
337 | |
338 end | |
339 | |
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
341 % Local Functions % | |
342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
343 | |
344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
345 % | |
346 % FUNCTION: numLines | |
347 % | |
348 % SYNTAX: count = numLines(fid); | |
349 % | |
350 % DESCRIPTION: Returns the number of lines in an ASCII file. This method | |
351 % doesn't change the position of the file identifier (fid) | |
352 % | |
353 % HISTORY: 02-08-2002 Peter Acklam, CSSM post | |
354 % Creation. | |
355 % | |
356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
357 | |
358 function lines = numLines(fid) | |
359 | |
360 fidPos = ftell(fid); | |
361 block = []; | |
362 lines = 0; % number of lines in file | |
363 nlchr = uint8(sprintf('\n')); % newline chr as uint8 | |
364 bsize = 4 * 256 * 8192; % block size to read | |
365 | |
366 while ~feof(fid) | |
367 block = fread(fid, bsize, '*uint8'); | |
368 lines = lines + sum(block == nlchr); | |
369 end | |
370 if ~isempty(block) % in case file is empty | |
371 lines = lines + double(block(end) ~= nlchr); | |
372 end | |
373 fseek(fid, fidPos, 'bof'); | |
374 end | |
375 | |
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
377 % | |
378 % FUNCTION: numCols | |
379 % | |
380 % SYNTAX: count = numCols(fid); | |
381 % | |
382 % DESCRIPTION: Returns the number of columns in an ASCII file. This method | |
383 % doesn't change the position of the file identifier (fid) | |
384 % | |
385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
386 | |
387 function ncols = numCols(fid, delimiter) | |
388 | |
389 fidPos = ftell(fid); | |
390 line = fgetl(fid); | |
391 if ischar(line) | |
392 if nargin == 1 || isempty(delimiter) | |
393 C = textscan(line, '%s'); | |
394 else | |
395 C = textscan(line, '%s', 'Delimiter', delimiter); | |
396 end | |
397 C = C{1}; | |
398 ncols = numel(C); | |
399 else | |
400 ncols = 0; | |
401 end | |
402 fseek(fid, fidPos, 'bof'); | |
403 end | |
404 | |
405 | |
406 % A robust and slow data reader | |
407 function f_data = robustRead(fid, f_data, columns, orig_cols) | |
408 | |
409 cols = unique(columns); | |
410 ocols = unique(orig_cols); | |
411 Nline = 1; | |
412 while ~feof(fid) | |
413 % read and parse line | |
414 tokens = sscanf(fgets(fid), '%f'); | |
415 % parse tokens | |
416 if ~isempty(tokens) | |
417 f_data(Nline, cols) = tokens(ocols); | |
418 if mod(Nline, 1000) == 0 | |
419 utils.helper.msg(utils.const.msg.PROC2, 'lines read: %d', Nline); | |
420 end | |
421 Nline = Nline + 1; | |
422 end | |
423 end | |
424 | |
425 % drop empty lines | |
426 f_data = f_data(1:Nline-1, :); | |
427 | |
428 end |