|
78 | 78 | % fd = an FdData object, or, if forceChan was a cell array, an |
79 | 79 | % FdDataCollection. |
80 | 80 |
|
81 | | - % Parse force channel specification |
82 | | - if ischar(forceChan) || isnumeric(forceChan) |
83 | | - [forceChanNames, friendlyForceChanNames] = n_parseForceChan(forceChan); |
84 | | - forceChanNames = {forceChanNames}; |
85 | | - friendlyForceChanNames = {friendlyForceChanNames}; |
86 | | - elseif iscell(forceChan) |
87 | | - forceChanNames = cell(length(forceChan),1); |
88 | | - friendlyForceChanNames = cell(length(forceChan),1); |
89 | | - for i = 1:length(forceChan) |
90 | | - [forceChanNames{i}, friendlyForceChanNames{i}] = n_parseForceChan(forceChan{i}); |
91 | | - end |
92 | | - else |
93 | | - error('Invalid argument "forceChan"'); |
94 | | - end |
95 | | - |
96 | | - % Parse distance channel specification |
97 | | - if ischar(distChan) |
98 | | - distChan = str2num(distChan); |
99 | | - end |
100 | | - if isnumeric(distChan) && isscalar(distChan) |
101 | | - if distChan < 1 || distChan > 2 |
102 | | - error('Distance channel out of range.'); |
103 | | - end |
104 | | - distChanName = sprintf('Distance %d (um)', distChan); |
105 | | - else |
106 | | - error('Invalid argument "distChan".'); |
107 | | - end |
| 81 | + % Parse channel specs |
| 82 | + [forceChanNames, friendlyForceChanNames] = self.parseForceChannelSpecArg(forceChan); |
| 83 | + [distChanName, ~] = self.parseDistanceChannelSpec(distChan); |
108 | 84 |
|
109 | 85 | % Retrieve needed subset of TDMS file data |
110 | 86 | objGet = struct(); |
|
140 | 116 | error('Error retrieving data: data not found.'); |
141 | 117 | end |
142 | 118 |
|
143 | | - % Assemble FdData object containing data. |
144 | | - fd = FdData(sprintf('%s - %s, %s', ... |
145 | | - self.getTdmsProperty('name'), ... |
146 | | - friendlyForceChanNames{j}, distChanName), ... |
| 119 | + fd = self.makeFdDataObject(... |
| 120 | + [' - ' friendlyForceChanNames{j} ', ' distChanName], ... |
147 | 121 | f, d, t); |
148 | | - |
149 | | - % ... metadata |
150 | | - fd.metaData = self.tdmsStruct.Props; |
151 | | - fn = fieldnames(self.tdmsStruct.FD_Data.Props); |
152 | | - for k = 1:length(fn) |
153 | | - fd.metaData.(fn{k}) = self.tdmsStruct.FD_Data.Props.(fn{k}); |
154 | | - end |
155 | | - |
156 | | - % ... add to FdDataCollection |
157 | 122 | fdc.add(fd); |
158 | 123 | end |
159 | 124 |
|
160 | 125 | % Rectify output: just a single FdData object instead of an |
161 | | - % FdDataCollection when appropriate |
| 126 | + % FdDataCollection when appropriate. |
162 | 127 | if ~iscell(forceChan) && (fdc.length == 1) |
163 | 128 | fd = fdc.items{1}; |
164 | 129 | else |
165 | 130 | fd = fdc; |
166 | 131 | end |
167 | | - |
168 | | - % >> nested functions |
169 | | - function [fcName, friendlyFcName] = n_parseForceChan(fc) |
170 | | - if isnumeric(fc) |
171 | | - fcName = sprintf('Force Channel %d (pN)', fc-1); |
172 | | - friendlyFcName = sprintf('Force Channel %d (pN)', fc); |
173 | | - elseif ischar(fc) && length(fc) == 3 && fc(1) == 'c' |
174 | | - forceIdx = str2num(fc(2)); |
175 | | - chanIdx = 2*(forceIdx-1); |
176 | | - friendlyFcName = sprintf('Force Trap %d', forceIdx); |
177 | | - if (fc(3) == 'x') |
178 | | - % ok |
179 | | - friendlyFcName = [friendlyFcName ' - X']; |
180 | | - elseif (fc(3) == 'y') |
181 | | - chanIdx = chanIdx + 1; |
182 | | - friendlyFcName = [friendlyFcName ' - Y']; |
183 | | - else |
184 | | - error('Invalid argument "forceChan".'); |
185 | | - end |
186 | | - if chanIdx >= self.NForceChannels |
187 | | - error('Force channel index out of range.'); |
188 | | - end |
189 | | - fcName = sprintf('Force Channel %d (pN)', chanIdx); |
190 | | - friendlyFcName = [friendlyFcName ' (pN)']; |
191 | | - elseif ischar(fc) && length(fc) == 2 && fc(1) == 't' |
192 | | - forceIdx = str2num(fc(2)); |
193 | | - if forceIdx*2 > self.NForceChannels |
194 | | - error('Force trap index out of range.'); |
195 | | - end |
196 | | - fcName = sprintf('Force Trap %d (pN)', forceIdx-1); |
197 | | - friendlyFcName = sprintf('Force Trap %d (pN)', forceIdx); |
198 | | - else |
199 | | - error('Invalid argument "forceChan".'); |
200 | | - end |
201 | | - end |
202 | | - % << nested functions |
203 | 132 | end |
204 | 133 |
|
205 | | - function [fd] = getHiResFtData(self, forceChanIdx, timeRange) |
| 134 | + function [fd] = getHiResFtData(self, forceChan, timeRange) |
206 | 135 | % GETHIRESFTDATA Returns high-resolution F,t data, if available |
207 | 136 | % |
208 | 137 | % INPUT: |
209 | | - % forceChanIdx = force channel index (1-based), or a vector of |
210 | | - % indices. |
| 138 | + % forceChan = see 'getFdData'. Note that trap channels are not |
| 139 | + % allowed here. |
211 | 140 | % timeRange = if not empty (default), only force data for this time |
212 | 141 | % range is returned. |
213 | 142 | % |
|
218 | 147 | if ~self.HasHiResFtData |
219 | 148 | error('No high-resolution F,t data available.'); |
220 | 149 | end |
221 | | - if ~isnumeric(forceChanIdx) || ~isvector(forceChanIdx) |
222 | | - error('Invalid argument "forceChanIdx".'); |
223 | | - end |
224 | | - forceChanNames = cell(length(forceChanIdx),1); |
225 | | - friendlyForceChanNames = cell(length(forceChanIdx),1); |
226 | | - for i = 1:length(forceChanIdx) |
227 | | - if forceChanIdx(i) < 1 || forceChanIdx(i) > self.NForceChannels |
228 | | - error('Force channel index out of range.'); |
229 | | - end |
230 | | - forceChanNames{i} = sprintf('Force Channel %d (pN)', forceChanIdx(i)-1); |
231 | | - friendlyForceChanNames{i} = sprintf('Force Channel %d (pN)', forceChanIdx(i)); |
232 | | - end |
| 150 | + |
233 | 151 | if nargin < 3 |
234 | 152 | timeRange = []; |
235 | 153 | end |
236 | 154 |
|
| 155 | + [forceChanNames, friendlyForceChanNames] = self.parseForceChannelSpecArg(forceChan, false); |
| 156 | + |
237 | 157 | if isempty(timeRange) |
238 | 158 | subsGet = []; |
239 | 159 | else |
|
277 | 197 | error('Error retrieving data: data not found.'); |
278 | 198 | end |
279 | 199 |
|
280 | | - % Assemble FdData object containing data. |
281 | | - fd = FdData(sprintf('%s - %s (HiRes)', ... |
282 | | - self.getTdmsProperty('name'), ... |
283 | | - friendlyForceChanNames{j}), ... |
| 200 | + fd = self.makeFdDataObject(... |
| 201 | + [' - ' friendlyForceChanNames{j}], ... |
284 | 202 | f, [], t); |
285 | | - |
286 | | - % ... metadata |
287 | | - fd.metaData = self.tdmsStruct.Props; |
288 | | - fn = fieldnames(self.tdmsStruct.FD_Data.Props); |
289 | | - for m = 1:length(fn) |
290 | | - fd.metaData.(fn{m}) = self.tdmsStruct.FD_Data.Props.(fn{m}); |
291 | | - end |
292 | | - |
293 | | - % ... add to FdDataCollection |
294 | 203 | fdc.add(fd); |
295 | 204 | end |
296 | 205 |
|
|
399 | 308 |
|
400 | 309 | methods % low-level methods |
401 | 310 |
|
| 311 | + function [fd] = makeFdDataObject(self, nameSuffix, f, d, t) |
| 312 | + fd = FdData(... |
| 313 | + [self.getTdmsProperty('name') nameSuffix], ... |
| 314 | + f, d, t ... |
| 315 | + ); |
| 316 | + |
| 317 | + % Add metadata |
| 318 | + % ... file-level metadata |
| 319 | + fd.metaData = self.tdmsStruct.Props; |
| 320 | + |
| 321 | + % ... 'FD Data' group-level metadata |
| 322 | + fn = fieldnames(self.tdmsStruct.FD_Data.Props); |
| 323 | + for i = 1:length(fn) |
| 324 | + fd.metaData.(fn{i}) = self.tdmsStruct.FD_Data.Props.(fn{i}); |
| 325 | + end |
| 326 | + end |
| 327 | + |
402 | 328 | function [val] = getTdmsProperty(self, path, default, varargin) |
403 | 329 | % GETTDMSPROPERTY Get a single TDMS property value |
404 | 330 | % |
|
544 | 470 | % << nested functions |
545 | 471 | end % function listTdmsProperties |
546 | 472 |
|
| 473 | + function [tdmsChannelName, friendlyName] = parseDistanceChannelSpec(self, dc) |
| 474 | + if ischar(dc) |
| 475 | + dc = str2num(dc); |
| 476 | + end |
| 477 | + if isnumeric(dc) && isscalar(dc) |
| 478 | + if dc < 1 || dc > 2 |
| 479 | + error('Invalid distance channel specification: index out of range.'); |
| 480 | + end |
| 481 | + tdmsChannelName = sprintf('Distance %d (um)', dc); |
| 482 | + friendlyName = tdmsChannelName; |
| 483 | + else |
| 484 | + error('Invalid distance channel specification: unknown type.'); |
| 485 | + end |
| 486 | + end |
| 487 | + |
| 488 | + function [tdmsChannelName, friendlyName] = parseForceChannelSpec(self, fc, allowTrapChannel) |
| 489 | + if nargin < 3 |
| 490 | + allowTrapChannel = true; |
| 491 | + end |
| 492 | + |
| 493 | + if isnumeric(fc) |
| 494 | + % numeric fc |
| 495 | + tdmsChannelName = sprintf('Force Channel %d (pN)', fc-1); |
| 496 | + friendlyName = sprintf('Force Channel %d (pN)', fc); |
| 497 | + |
| 498 | + elseif ischar(fc) && fc(1) == 'c' && length(fc) > 2 |
| 499 | + % fc = 'c1x', 'c3y', etc. |
| 500 | + forceIdx = str2num(fc(2:end-1)); |
| 501 | + tdmsChanIdx = 2*(forceIdx-1); |
| 502 | + |
| 503 | + friendlyName = sprintf('Force Trap %d', forceIdx); |
| 504 | + if fc(end) == 'x' |
| 505 | + friendlyName = [friendlyName ' - X']; |
| 506 | + elseif fc(end) == 'y' |
| 507 | + friendlyName = [friendlyName ' - Y']; |
| 508 | + tdmsChanIdx = tdmsChanIdx + 1; |
| 509 | + else |
| 510 | + error('Invalid force channel specification "%s": malformed X/Y channel spec.', fc); |
| 511 | + end |
| 512 | + friendlyName = [friendlyName ' (pN)']; |
| 513 | + |
| 514 | + if tdmsChanIdx >= self.NForceChannels |
| 515 | + error('Invalid force channel specification "%s": channel index out of range.', fc); |
| 516 | + end |
| 517 | + tdmsChannelName = sprintf('Force Channel %d (pN)', tdmsChanIdx); |
| 518 | + |
| 519 | + elseif ischar(fc) && fc(1) == 't' && length(fc) > 1 |
| 520 | + % fc = 't1', 't3', etc. |
| 521 | + if ~allowTrapChannel |
| 522 | + error('Invalid force channel specification: trap channel is not allowed here.'); |
| 523 | + end |
| 524 | + |
| 525 | + forceIdx = str2num(fc(2:end)); |
| 526 | + if forceIdx*2 > self.NForceChannels |
| 527 | + error('Invalid force channel specification "%s": channel index out of range.', fc); |
| 528 | + end |
| 529 | + |
| 530 | + tdmsChannelName = sprintf('Force Trap %d (pN)', forceIdx-1); |
| 531 | + friendlyName = sprintf('Force Trap %d (pN)', forceIdx); |
| 532 | + |
| 533 | + else |
| 534 | + error('Invalid force channel specification "%s".', fc); |
| 535 | + end |
| 536 | + end |
| 537 | + |
| 538 | + function [tdmsChannelNames, friendlyNames] = parseForceChannelSpecArg(self, fc, allowTrapChannel) |
| 539 | + if nargin < 3 |
| 540 | + allowTrapChannel = true; |
| 541 | + end |
| 542 | + |
| 543 | + if ischar(fc) || (isnumeric(fc) && isscalar(fc)) |
| 544 | + fc = {fc}; |
| 545 | + elseif iscell(fc) |
| 546 | + % ok |
| 547 | + elseif isnumeric(fc) && isvector(fc) |
| 548 | + fc = num2cell(fc); |
| 549 | + else |
| 550 | + error('Invalid force channel specification: unknown type.'); |
| 551 | + end |
| 552 | + |
| 553 | + tdmsChannelNames = cell(length(fc),1); |
| 554 | + friendlyNames = cell(length(fc),1); |
| 555 | + for i = 1:length(fc) |
| 556 | + [tdmsChannelNames{i}, friendlyNames{i}] = self.parseForceChannelSpec(fc{i}, allowTrapChannel); |
| 557 | + end |
| 558 | + end |
| 559 | + |
547 | 560 | end |
548 | 561 |
|
549 | 562 | end |
0 commit comments