Skip to content

Commit 9517e6d

Browse files
committed
Refactor channel specs in TWOMDataFile
Centralize code for parsing force channel specs in TWOMDataFile. This greatly simplifies code elsewhere, and allows for unifying the arguments of the 'getFdData' and 'getHiResFtData' methods.
1 parent 9d0d1b6 commit 9517e6d

File tree

1 file changed

+118
-105
lines changed

1 file changed

+118
-105
lines changed

DataClasses/TWOMDataFile.m

Lines changed: 118 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -78,33 +78,9 @@
7878
% fd = an FdData object, or, if forceChan was a cell array, an
7979
% FdDataCollection.
8080

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);
10884

10985
% Retrieve needed subset of TDMS file data
11086
objGet = struct();
@@ -140,74 +116,27 @@
140116
error('Error retrieving data: data not found.');
141117
end
142118

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], ...
147121
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
157122
fdc.add(fd);
158123
end
159124

160125
% Rectify output: just a single FdData object instead of an
161-
% FdDataCollection when appropriate
126+
% FdDataCollection when appropriate.
162127
if ~iscell(forceChan) && (fdc.length == 1)
163128
fd = fdc.items{1};
164129
else
165130
fd = fdc;
166131
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
203132
end
204133

205-
function [fd] = getHiResFtData(self, forceChanIdx, timeRange)
134+
function [fd] = getHiResFtData(self, forceChan, timeRange)
206135
% GETHIRESFTDATA Returns high-resolution F,t data, if available
207136
%
208137
% 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.
211140
% timeRange = if not empty (default), only force data for this time
212141
% range is returned.
213142
%
@@ -218,22 +147,13 @@
218147
if ~self.HasHiResFtData
219148
error('No high-resolution F,t data available.');
220149
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+
233151
if nargin < 3
234152
timeRange = [];
235153
end
236154

155+
[forceChanNames, friendlyForceChanNames] = self.parseForceChannelSpecArg(forceChan, false);
156+
237157
if isempty(timeRange)
238158
subsGet = [];
239159
else
@@ -277,20 +197,9 @@
277197
error('Error retrieving data: data not found.');
278198
end
279199

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}], ...
284202
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
294203
fdc.add(fd);
295204
end
296205

@@ -399,6 +308,23 @@
399308

400309
methods % low-level methods
401310

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+
402328
function [val] = getTdmsProperty(self, path, default, varargin)
403329
% GETTDMSPROPERTY Get a single TDMS property value
404330
%
@@ -544,6 +470,93 @@
544470
% << nested functions
545471
end % function listTdmsProperties
546472

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+
547560
end
548561

549562
end

0 commit comments

Comments
 (0)