diff --git a/@MyAvgTrace/MyAvgTrace.m b/@MyAvgTrace/MyAvgTrace.m index 76abf59..12592e2 100644 --- a/@MyAvgTrace/MyAvgTrace.m +++ b/@MyAvgTrace/MyAvgTrace.m @@ -1,168 +1,173 @@ % Adds averaging capabilities to MyTrace % % The averaging type is 'lin' (or 'linear')/ 'exp' (or 'exponential'). % Linear averaging is a simple mean % x=\sum_{n=0}^N x_n, % exponential is an unlimited weighted sum % x=(1-exp(-1/n_avg))*\sum_{n=0}^\inf x_n exp(-n/n_avg). classdef MyAvgTrace < MyTrace properties (Access = public, SetObservable = true) % Target number of averages, when it is reached or exceeded % AveragingDone event is triggered n_avg = 1 avg_type = 'lin' end properties (GetAccess = public, SetAccess = protected, ... SetObservable = true) % Counter for the averaging function, can be reset by clearData avg_count = 0 end methods (Access = public) % Adds data to the average accumulator. When the averaging counter % reaches n_avg (or exceeds it in the exponential case), completed % is set to 'true', otherwise 'false'. % In exponential regime the averaging proceeds indefinitely so that % avg_count can exceed n_avg. % In linear regime when the averaging counter exceeds n_avg, new % data is discarded. function completed = addAverage(this, b) assert(isa(b,'MyTrace'), ['Second argument must be a ' ... 'MyTrace object']); - if isempty(this) || length(this.x)~=length(b.x) || ... + if isDataEmpty(this) || length(this.x)~=length(b.x) || ... any(this.x~=b.x) + % Initialize new data and return this.x=b.x; this.y=b.y; this.name_x=b.name_x; this.unit_x=b.unit_x; this.name_y=b.name_y; this.unit_y=b.unit_y; this.avg_count=1; completed=(this.avg_count>=this.n_avg); return end assert(length(b.y)==length(this.y), ... ['New vector of y values must be of the same', ... 'length as the exisiting y data of MyTrace in ', ... 'order to perform averanging']) switch this.avg_type case 'lin' if this.avg_count=this.n_avg); otherwise error('Averaging type %s is not supported', ... this.avg_type) end end % Provide restricted access to the trace averaging counter function resetCounter(this) this.avg_count = 0; end % Overload the method so that it reset the averaging counter in % addition to clearing the x and y values function clearData(this) this.x = []; this.y = []; resetCounter(this); end end methods (Access = protected) % Extend the info stored in trace metadata compare to MyTrace function Mdt = getMetadata(this) Mdt = getMetadata@MyTrace(this); Info = titleref(Mdt, 'Info'); addParam(Info, 'avg_type', this.avg_type, ... 'comment', 'Averaging type, linear or exponential'); addParam(Info, 'avg_count', this.avg_count, 'comment', ... 'Number of accomplished averages'); addParam(Info, 'n_avg', this.n_avg, 'comment', ... ['Target number of averages (lin) or exponential ' ... 'averaging constant (exp)']); end function setMetadata(this, Mdt) Info = titleref(Mdt, 'Info'); if ~isempty(Info) if isparam(Info, 'avg_type') this.avg_type = Info.ParamList.avg_type; end if isparam(Info, 'n_avg') this.n_avg = Info.ParamList.n_avg; end if isparam(Info, 'avg_count') this.avg_count = Info.ParamList.avg_count; end end setMetadata@MyTrace(this, Mdt); end end %% Set and get methods methods % Ensure the supplied value for averaging mode is assigned in its % standard form - lowercase and abbreviated function set.avg_type(this, val) old_val = this.avg_type; switch lower(val) case {'lin', 'linear'} this.avg_type='lin'; case {'exp', 'exponential'} this.avg_type='exp'; otherwise error(['Averaging type must be ''lin'' ' ... '(''linear'') or ''exp'' (''exponential'')']) end % Clear data if the averaging type was changed if this.avg_type ~= old_val clearData(this); end end function set.n_avg(this, val) % The number of averages should be integer not smaller than one this.n_avg = max(1, round(val)); end end end diff --git a/@MyCommCont/MyCommCont.m b/@MyCommCont/MyCommCont.m index 77f0930..6337a3e 100644 --- a/@MyCommCont/MyCommCont.m +++ b/@MyCommCont/MyCommCont.m @@ -1,176 +1,176 @@ % Communicator container. % This class provides extended functionality for communication using VISA, % tcpip and serial objects or any other objects that have a similar usage. classdef MyCommCont < handle properties (Access = public) interface = 'serial' address = 'placeholder' % Communication object Comm end methods (Access = public) function this = MyCommCont(varargin) P = MyClassParser(this); processInputs(P, this, varargin{:}); end function delete(this) % Close the connection to the device try closeComm(this); catch ME warning(['Connection could not be closed. Error: ' ... ME.message]); end % Delete the device object try delete(this.Comm); catch ME warning(['Communication object could not be deleted. ' ... 'Error: ' ME.message]); end end %% Set up communication % Create an interface object function connect(this) if ~isempty(this.Comm) % Delete the existing object before creating a new one. delete(this.Comm); end try switch lower(this.interface) % Use 'constructor' interface to create an object with % more that one parameter passed to the constructor case 'constructor' % In this case 'address' is a MATLAB command that % creates communication object when executed. % Such commands, for example, are returned by % instrhwinfo as ObjectConstructorName. this.Comm = eval(this.address); case 'visa' % visa brand is 'ni' by default this.Comm = visa('ni', this.address); case 'tcpip' % Works only with default socket. Use 'constructor' % if socket or other options need to be specified this.Comm = tcpip(this.address); case 'serial' this.Comm = serial(this.address); otherwise error(['Unknown interface ''' this.interface ... ''', a communication object is not created.'... ' Valid interfaces are ''constructor'', ' ... '''visa'', ''tcpip'' and ''serial''']) end configureCommDefault(this); catch ME warning(ME.message); % Create a dummy this.Comm = serial('placeholder'); end end % Set larger buffer sizes and longer timeout than the MATLAB default function configureCommDefault(this) comm_props = properties(this.Comm); if ismember('OutputBufferSize',comm_props) this.Comm.OutputBufferSize = 1e7; % bytes end if ismember('InputBufferSize',comm_props) this.Comm.InputBufferSize = 1e7; % bytes end if ismember('Timeout',comm_props) - this.Comm.Timeout = 5; % s + this.Comm.Timeout = 10; % s end end function bool = isopen(this) try bool = strcmp(this.Comm.Status, 'open'); catch warning('Cannot access the communicator Status property'); bool = false; end end % Opens the device if it is not open. Does not throw error if % device is already open for communication with another object, but % tries to close existing connections instead. function openComm(this) try fopen(this.Comm); catch if isa(this.Comm, 'serial') % Try to find and close all the serial objects % connected to the same port instr_list = instrfind('Port', this.Comm.Port); else % Try to find and close all the devices with the same % VISA resource name instr_list = instrfind('RsrcName', this.Comm.RsrcName); end fclose(instr_list); fopen(this.Comm); warning(['Multiple instrument objects of ' ... 'address %s exist'], this.address); end end function closeComm(this) fclose(this.Comm); end %% Communication % Write textual command function writeString(this, str) try fprintf(this.Comm, str); catch ME try % Attempt re-opening communication openComm(this); fprintf(this.Comm, str); catch rethrow(ME); end end end % Query textual command function result = queryString(this, str) try result = query(this.Comm, str); catch ME try % Attempt re-opening communication openComm(this); result = query(this.Comm, str); catch rethrow(ME); end end end end end diff --git a/@MyDaq/MyDaq.mlapp b/@MyDaq/MyDaq.mlapp index 146681d..98407c4 100644 Binary files a/@MyDaq/MyDaq.mlapp and b/@MyDaq/MyDaq.mlapp differ diff --git a/Utility functions/splitFilename.m b/Utility functions/splitFilename.m index 918752a..51e1d62 100644 --- a/Utility functions/splitFilename.m +++ b/Utility functions/splitFilename.m @@ -1,32 +1,33 @@ % Split filename into name and extension (if present), applying some more % elaborate procedure to determine the real extension than that used % in fileparts() function [name, ext] = splitFilename(filename) filename_split = regexp(filename, '\.', 'split'); if length(filename_split) == 1 % No extension found name = filename; ext = ''; return end % A candidate for the extension ext = filename_split{end}; - if ~isempty(ext) && ~any(isspace(ext)) && length(ext)<4 + if ~isempty(ext) && ~any(isspace(ext)) && length(ext)<4 && ... + ~all(ismember(ext(2:end), '0123456789')) % ext is actual extension % Add a point to conform with the convention of fileparts() ext = ['.' ext]; name = strjoin(filename_split(1:end-1), '.'); else % ext is not an actual extension name = filename; ext = ''; end end