diff --git a/@MyInstrument/MyInstrument.m b/@MyInstrument/MyInstrument.asv similarity index 79% copy from @MyInstrument/MyInstrument.m copy to @MyInstrument/MyInstrument.asv index 99a2d32..24720b1 100644 --- a/@MyInstrument/MyInstrument.m +++ b/@MyInstrument/MyInstrument.asv @@ -1,305 +1,310 @@ -classdef MyInstrument < dynamicprops - - properties (SetAccess=protected, GetAccess=public) - name=''; - interface=''; - address=''; - %Logical for whether gui is enabled - enable_gui=false; - %Contains the GUI handles - Gui; - %Contains the device object - Device; - %Input parser for class constructor - Parser; - %Contains a list of the commands available for the instrument as - %well as the default values and input requirements - CommandList; - %Parses commands using an inputParser object - CommandParser; - %Trace object for storing data - Trace=MyTrace(); - end - - properties (Dependent=true) - command_names; - command_no; - end - - events - NewData; - end - - methods (Access=public) - function this=MyInstrument(name, interface, address, varargin) - createParser(this); - parse(this.Parser,name,interface,address,varargin{:}); - - %Loads parsed variables into class properties - this.name=this.Parser.Results.name; - this.interface=this.Parser.Results.interface; - this.address=this.Parser.Results.address; - this.enable_gui=~ismember('gui',this.Parser.UsingDefaults); - - %If a gui input is given, load the gui - if this.enable_gui - %Loads the gui from the input gui string - this.Gui=guihandles(eval(this.Parser.Results.gui)); - %Sets figure close function such that class will know when - %figure is closed - set(this.Gui.figure1, 'CloseRequestFcn',... - @(hObject,eventdata) closeFigure(this, hObject, ... - eventdata)); - end - end - - function delete(this) - %Removes close function from figure, prevents infinite loop - if this.enable_gui - set(this.Gui.figure1,'CloseRequestFcn',''); - %Deletes the figure handles - structfun(@(x) delete(x), this.Gui); - %Removes the figure handle to prevent memory leaks - this.Gui=[]; - end - - %Closes the connection to the device - closeDevice(this); - %Deletes the device object - delete(this.Device); - clear('this.Device'); - end - - %Clears data from trace to save memory. - function clearData(this) - this.Trace.x=[]; - this.Trace.y=[]; - end - - %Writes properties to device. Can take multiple inputs. With the - %option init_device, the function writes default to all the - %available writeable parameters. - function writeProperty(this, varargin) - %Parses the inputs using the CommandParser - parse(this.CommandParser, varargin{:}); - - if ~this.CommandParser.Results.write_all_defaults - %Finds the writeable commands that are supplied by the user - ind=~ismember(this.CommandParser.Parameters,... - this.CommandParser.UsingDefaults); - %Creates a list of commands to be executed - exec=this.CommandParser.Parameters(ind); - else - exec=this.CommandParser.Parameters; - %Removes write_all_defaults from the list of commands to be - %executed - exec(strcmp(exec,'write_all_defaults'))=[]; - end - - for i=1:length(exec) - %Creates the write command using the right string spec - write_command=[this.CommandList.(exec{i}).command,... - ' %',this.CommandList.(exec{i}).str_spec]; - %Gets the value to write to the device - this.(exec{i})=this.CommandParser.Results.(exec{i}); - command=sprintf(write_command, this.(exec{i})); - %Sends command to device - fprintf(this.Device, command); - end - end - - %Wrapper for writeProperty that opens the device - function writePropertyHedged(this, varargin) - this.openDevice(); - try - this.writeProperty(varargin{:}); - catch - disp('Error while writing the properties:'); - disp(varargin); - end - this.readAll(); - closeDevice(this); - end - - function result=readProperty(this, varargin) - result=struct(); - ind=cellfun(@(x) contains(this.CommandList.(x).access,'r'),... - varargin); - - exec=varargin(ind); - - if any(~ind) - disp('Some specified properties are write-only:') - non_exec=varargin(~ind); - disp(non_exec{:}); - end - - - for i=1:length(exec) - %Creates the correct read command - read_command=[this.CommandList.(exec{i}).command,'?']; - - %Reads the property from the device and stores it in the - %correct place - res_str = query(this.Device,read_command); - if strcmp(this.CommandList.(exec{i}).attributes{1},'string') - result.(exec{i})= res_str(1:(end-1)); - else - result.(exec{i})= str2double(res_str); - end - end - end - - function result = readPropertyHedged(this, varargin) - this.openDevice(); - try - result = this.readProperty(varargin{:}); - catch - disp('Error while reading the properties:'); - disp(varargin); - end - this.closeDevice(); - end - - % Execute all the read commands and update corresponding properties - function readAll(this) - ind=cellfun(@(x) contains(this.CommandList.(x).access,'r'),... - this.command_names); - result=readProperty(this, this.command_names{ind}); - res_names=fieldnames(result); - for i=1:length(res_names) - this.(res_names{i})=result.(res_names{i}); - end - end - - end - - methods (Access=private) - function createParser(this) - p=inputParser; - addRequired(p,'name',@ischar); - addRequired(p,'interface',@ischar); - addRequired(p,'address',@ischar); - addParameter(p,'gui','placeholder',@ischar); - this.Parser=p; - end - end - - methods (Access=protected) - %Triggers event for acquired data - function triggerNewData(this) - notify(this,'NewData') - end - - %Checks if the connection to the device is open - function bool=isopen(this) - bool=strcmp(this.Device.Status, 'open'); - end - - %Adds a command to the CommandList - function addCommand(this, tag, command, varargin) - p=inputParser; - addRequired(p,'tag',@ischar); - addRequired(p,'command',@ischar); - addParameter(p,'default','placeholder'); - addParameter(p,'attributes','placeholder',@iscell); - addParameter(p,'str_spec','d',@ischar); - %If the write flag is on, it means this command can be used to - %write a parameter to the device - addParameter(p,'access','rw',@ischar); - addParameter(p,'conv_factor',1,@isnumeric); - parse(p,tag,command,varargin{:}); - - %Adds the command to be sent to the device - this.CommandList.(tag).command=command; - this.CommandList.(tag).access=p.Results.access; - - write_flag=contains(p.Results.access,'w'); -% read_flag=contains(p.Results.access,'r'); - - %Adds a default value and the attributes the inputs must have - %and creates a new property in the class - if write_flag - %Adds the string specifier to the list - this.CommandList.(tag).str_spec=p.Results.str_spec; - %Adds the default value - this.CommandList.(tag).default=p.Results.default; - %Adds the necessary attributes for the input to the command - this.CommandList.(tag).attributes=p.Results.attributes; - %Adds a conversion factor for displaying the value - this.CommandList.(tag).conv_factor=p.Results.conv_factor; - %Adds a property to the class corresponding to the tag - addprop(this,tag); - end - end - - %Creates inputParser using the command list - function createCommandParser(this) - %Use input parser - %Requires input of the appropriate class - p=inputParser; - p.StructExpand=0; - %Flag for whether the command should initialize the device with - %defaults - addParameter(p, 'write_all_defaults',false,@islogical); - - for i=1:this.command_no - %Adds optional inputs for each command, with the - %appropriate default value from the command list and the - %required attributes for the command input. - addParameter(p, this.command_names{i},... - this.CommandList.(this.command_names{i}).default),... - @(x) validateattributes(x,... - this.CommandList.(this.command_names{i}).attributes{1:end}); - end - this.CommandParser=p; - end - - %Connects to the device if it is not connected - function openDevice(this) - if ~isopen(this) - try - fopen(this.Device); - catch - try - instr_list=instrfind('RemoteHost',this.address); - fclose(instr_list); - fopen(this.Device); - warning('Multiple instrument objects of address %s exist',... - this.address); - catch - error('Could not open device') - end - end - end - end - - %Closes the connection to the device - function closeDevice(this) - if isopen(this) - try - fclose(this.Device); - catch - - error('Could not close device') - end - end - end - - %Close figure callback simply calls delete function for class - function closeFigure(this,~,~) - delete(this); - end - end - - %% Get functions - methods - function command_names=get.command_names(this) - command_names=fieldnames(this.CommandList); - end - - function command_no=get.command_no(this) - command_no=length(this.command_names); - end - end +classdef MyInstrument < dynamicprops + + properties (SetAccess=protected, GetAccess=public) + name=''; + interface=''; + address=''; + %Logical for whether gui is enabled + enable_gui=false; + %Contains the GUI handles + Gui; + %Contains the device object + Device; + %Input parser for class constructor + Parser; + %Contains a list of the commands available for the instrument as + %well as the default values and input requirements + CommandList; + %Parses commands using an inputParser object + CommandParser; + %Trace object for storing data + Trace=MyTrace(); + end + + properties (Dependent=true) + command_names; + command_no; + end + + events + NewData; + end + + methods (Access=public) + function this=MyInstrument(name, interface, address, varargin) + createParser(this); + parse(this.Parser,name,interface,address,varargin{:}); + + %Loads parsed variables into class properties + this.name=this.Parser.Results.name; + this.interface=this.Parser.Results.interface; + this.address=this.Parser.Results.address; + this.enable_gui=~ismember('gui',this.Parser.UsingDefaults); + + %If a gui input is given, load the gui + if this.enable_gui + %Loads the gui from the input gui string + this.Gui=guihandles(eval(this.Parser.Results.gui)); + %Sets figure close function such that class will know when + %figure is closed + set(this.Gui.figure1, 'CloseRequestFcn',... + @(hObject,eventdata) closeFigure(this, hObject, ... + eventdata)); + end + end + + function delete(this) + %Removes close function from figure, prevents infinite loop + if this.enable_gui + set(this.Gui.figure1,'CloseRequestFcn',''); + %Deletes the figure handles + structfun(@(x) delete(x), this.Gui); + %Removes the figure handle to prevent memory leaks + this.Gui=[]; + end + + %Closes the connection to the device + closeDevice(this); + %Deletes the device object + delete(this.Device); + clear('this.Device'); + end + + %Clears data from trace to save memory. + function clearData(this) + this.Trace.x=[]; + this.Trace.y=[]; + end + + %Writes properties to device. Can take multiple inputs. With the + %option all, the function writes default to all the + %available writeable parameters. + function writeProperty(this, varargin) + %Parses the inputs using the CommandParser + parse(this.CommandParser, varargin{:}); + + % Finds the writeable commands that are supplied by the user + % and creates a list of commands to be executed + exec={}; + for x = this.command_names + % Condition for adding a command to the execution list: + % The command has a write mode and either it was supplied a + % new value or the 'all' option is true + if this.CommandList.(x).write_flag &&... + (~ismember(x, this.CommandParser.UsingDefaults) ... + || this.CommandParser.Results.all) + exec={exec,x}; + elseif ~this.CommandList.(x).write_flag &&... + ~ismember(x, this.CommandParser.UsingDefaults) + % issue a warning if try to write a read-only command + warning('%s is a read-only command',x); + end + end + + for i=1:length(exec) + %Creates the write command using the right string spec + write_command=[this.CommandList.(exec{i}).command,... + ' %',this.CommandList.(exec{i}).str_spec]; + %Gets the value to write to the device + this.(exec{i})=this.CommandParser.Results.(exec{i}); + command=sprintf(write_command, this.(exec{i})); + %Sends command to device + fprintf(this.Device, command); + end + end + + % Wrapper for writeProperty that opens and closes the device + function writePropertyHedged(this, varargin) + this.openDevice(); + try + this.writeProperty(varargin{:}); + catch + warning('Error while writing the properties:'); + disp(varargin); + end + this.readProperty('all'); + this.closeDevice(); + end + + function result=readProperty(this, varargin) + result = struct(); + read_all_flag = any(strcmp('all',varargin)); + + exec={}; + if read_all_flag + for x = this.command_names + if this.CommandList.(x).read_flag + exec={exec,x}; + end + end + else + for x = varargin + % Condition for adding a command to the execution list: + % The command has a read mode and either it was mentioned + % in the input or 'all' option is specified + if contains(this.CommandList.(x).access,'r') &&... + (any(strcmp(varargin, x)) || read_all_flag) + exec={exec,x}; + end + end + end + + for i=1:length(exec) + %Creates the correct read command + read_command=[this.CommandList.(exec{i}).command,'?']; + %Reads the property from the device and stores it in the + %correct place + res_str = query(this.Device,read_command); + if strcmp(this.CommandList.(exec{i}).attributes{1},'string') + result.(exec{i})= res_str(1:(end-1)); + else + result.(exec{i})= str2double(res_str); + end + end + end + + % Wrapper for readProperty that opens and closes the device + function result = readPropertyHedged(this, varargin) + this.openDevice(); + try + result = this.readProperty(varargin{:}); + catch + warning('Error while reading the properties:'); + disp(varargin); + end + this.closeDevice(); + end + + end + + methods (Access=private) + function createParser(this) + p=inputParser; + addRequired(p,'name',@ischar); + addRequired(p,'interface',@ischar); + addRequired(p,'address',@ischar); + addParameter(p,'gui','placeholder',@ischar); + this.Parser=p; + end + end + + methods (Access=protected) + %Triggers event for acquired data + function triggerNewData(this) + notify(this,'NewData') + end + + %Checks if the connection to the device is open + function bool=isopen(this) + bool=strcmp(this.Device.Status, 'open'); + end + + %Adds a command to the CommandList + function addCommand(this, tag, command, varargin) + p=inputParser; + addRequired(p,'tag',@ischar); + addRequired(p,'command',@ischar); + addParameter(p,'default','placeholder'); + addParameter(p,'attributes','placeholder',@iscell); + addParameter(p,'str_spec','d',@ischar); + %If the write flag is on, it means this command can be used to + %write a parameter to the device + addParameter(p,'access','rw',@ischar); + addParameter(p,'conv_factor',1,@isnumeric); + parse(p,tag,command,varargin{:}); + + %Adds the command to be sent to the device + this.CommandList.(tag).command=command; + this.CommandList.(tag).access=p.Results.access; + + this.CommandList.(tag).write_flag=contains(p.Results.access,'w'); + this.CommandList.(tag).read_flag=contains(p.Results.access,'r'); + + %Adds a default value and the attributes the inputs must have + %and creates a new property in the class + if this.CommandList.(tag).write_flag + %Adds the string specifier to the list + this.CommandList.(tag).str_spec=p.Results.str_spec; + %Adds the default value + this.CommandList.(tag).default=p.Results.default; + %Adds the necessary attributes for the input to the command + this.CommandList.(tag).attributes=p.Results.attributes; + %Adds a conversion factor for displaying the value + this.CommandList.(tag).conv_factor=p.Results.conv_factor; + %Adds a property to the class corresponding to the tag + if ~isprop(this,tag) + addprop(this,tag); + end + end + end + + %Creates inputParser using the command list + function createCommandParser(this) + %Use input parser + %Requires input of the appropriate class + p=inputParser; + p.StructExpand=0; + %Flag for whether the command should initialize the device with + %defaults + addParameter(p, 'all',false,@islogical); + + for i=1:this.command_no + %Adds optional inputs for each command, with the + %appropriate default value from the command list and the + %required attributes for the command input. + addParameter(p, this.command_names{i},... + this.CommandList.(this.command_names{i}).default),... + @(x) validateattributes(x,... + this.CommandList.(this.command_names{i}).attributes{1:end}); + end + this.CommandParser=p; + end + + %Connects to the device if it is not connected + function openDevice(this) + if ~isopen(this) + try + fopen(this.Device); + catch + try + instr_list=instrfind('RemoteHost',this.address); + fclose(instr_list); + fopen(this.Device); + warning('Multiple instrument objects of address %s exist',... + this.address); + catch + error('Could not open device') + end + end + end + end + + %Closes the connection to the device + function closeDevice(this) + if isopen(this) + try + fclose(this.Device); + catch + + error('Could not close device') + end + end + end + + %Close figure callback simply calls delete function for class + function closeFigure(this,~,~) + delete(this); + end + end + + %% Get functions + methods + function command_names=get.command_names(this) + command_names=fieldnames(this.CommandList); + end + + function command_no=get.command_no(this) + command_no=length(this.command_names); + end + end end \ No newline at end of file diff --git a/@MyInstrument/MyInstrument.m b/@MyInstrument/MyInstrument.m index 99a2d32..50890b2 100644 --- a/@MyInstrument/MyInstrument.m +++ b/@MyInstrument/MyInstrument.m @@ -1,305 +1,311 @@ classdef MyInstrument < dynamicprops properties (SetAccess=protected, GetAccess=public) name=''; interface=''; address=''; %Logical for whether gui is enabled enable_gui=false; %Contains the GUI handles Gui; %Contains the device object Device; %Input parser for class constructor Parser; %Contains a list of the commands available for the instrument as %well as the default values and input requirements CommandList; %Parses commands using an inputParser object CommandParser; %Trace object for storing data Trace=MyTrace(); end properties (Dependent=true) command_names; command_no; end events NewData; end methods (Access=public) function this=MyInstrument(name, interface, address, varargin) createParser(this); parse(this.Parser,name,interface,address,varargin{:}); %Loads parsed variables into class properties this.name=this.Parser.Results.name; this.interface=this.Parser.Results.interface; this.address=this.Parser.Results.address; this.enable_gui=~ismember('gui',this.Parser.UsingDefaults); %If a gui input is given, load the gui if this.enable_gui %Loads the gui from the input gui string this.Gui=guihandles(eval(this.Parser.Results.gui)); %Sets figure close function such that class will know when %figure is closed set(this.Gui.figure1, 'CloseRequestFcn',... @(hObject,eventdata) closeFigure(this, hObject, ... eventdata)); end end function delete(this) %Removes close function from figure, prevents infinite loop if this.enable_gui set(this.Gui.figure1,'CloseRequestFcn',''); %Deletes the figure handles structfun(@(x) delete(x), this.Gui); %Removes the figure handle to prevent memory leaks this.Gui=[]; end %Closes the connection to the device closeDevice(this); %Deletes the device object delete(this.Device); clear('this.Device'); end %Clears data from trace to save memory. function clearData(this) this.Trace.x=[]; this.Trace.y=[]; end %Writes properties to device. Can take multiple inputs. With the - %option init_device, the function writes default to all the + %option all, the function writes default to all the %available writeable parameters. function writeProperty(this, varargin) %Parses the inputs using the CommandParser parse(this.CommandParser, varargin{:}); - - if ~this.CommandParser.Results.write_all_defaults - %Finds the writeable commands that are supplied by the user - ind=~ismember(this.CommandParser.Parameters,... - this.CommandParser.UsingDefaults); - %Creates a list of commands to be executed - exec=this.CommandParser.Parameters(ind); - else - exec=this.CommandParser.Parameters; - %Removes write_all_defaults from the list of commands to be - %executed - exec(strcmp(exec,'write_all_defaults'))=[]; + + % Finds the writeable commands that are supplied by the user + % and creates a list of commands to be executed + exec={}; + for x = this.command_names + % Condition for adding a command to the execution list: + % The command has a write mode and either it was supplied a + % new value or the 'all' option is true + if this.CommandList.(x).write_flag &&... + (~ismember(x, this.CommandParser.UsingDefaults) ... + || this.CommandParser.Results.all) + exec={exec,x}; + elseif ~this.CommandList.(x).write_flag &&... + ~ismember(x, this.CommandParser.UsingDefaults) + % issue a warning if try to write a read-only command + warning('%s is a read-only command',x); + end end for i=1:length(exec) %Creates the write command using the right string spec write_command=[this.CommandList.(exec{i}).command,... ' %',this.CommandList.(exec{i}).str_spec]; %Gets the value to write to the device this.(exec{i})=this.CommandParser.Results.(exec{i}); command=sprintf(write_command, this.(exec{i})); %Sends command to device fprintf(this.Device, command); end end - %Wrapper for writeProperty that opens the device + % Wrapper for writeProperty that opens and closes the device function writePropertyHedged(this, varargin) this.openDevice(); try this.writeProperty(varargin{:}); catch - disp('Error while writing the properties:'); + warning('Error while writing the properties:'); disp(varargin); end - this.readAll(); - closeDevice(this); + this.readProperty('all'); + this.closeDevice(); end function result=readProperty(this, varargin) - result=struct(); - ind=cellfun(@(x) contains(this.CommandList.(x).access,'r'),... - varargin); - - exec=varargin(ind); + result = struct(); + read_all_flag = any(strcmp('all',varargin)); - if any(~ind) - disp('Some specified properties are write-only:') - non_exec=varargin(~ind); - disp(non_exec{:}); + exec={}; + if read_all_flag + for x = this.command_names + if this.CommandList.(x).read_flag + exec={exec,x}; + end + end + else + for x = varargin + % Selecs the commands from the input list taht have + % read access + if this.CommandList.(x).read_flag &&... + any(strcmp(this.command_names, x)) + exec={exec,x}; + else + warning('%s is not a valid read command', x); + end + end end - for i=1:length(exec) %Creates the correct read command read_command=[this.CommandList.(exec{i}).command,'?']; - %Reads the property from the device and stores it in the %correct place res_str = query(this.Device,read_command); if strcmp(this.CommandList.(exec{i}).attributes{1},'string') result.(exec{i})= res_str(1:(end-1)); else result.(exec{i})= str2double(res_str); end end end - + + % Wrapper for readProperty that opens and closes the device function result = readPropertyHedged(this, varargin) this.openDevice(); try result = this.readProperty(varargin{:}); catch - disp('Error while reading the properties:'); + warning('Error while reading the properties:'); disp(varargin); end this.closeDevice(); end - % Execute all the read commands and update corresponding properties - function readAll(this) - ind=cellfun(@(x) contains(this.CommandList.(x).access,'r'),... - this.command_names); - result=readProperty(this, this.command_names{ind}); - res_names=fieldnames(result); - for i=1:length(res_names) - this.(res_names{i})=result.(res_names{i}); - end - end - end methods (Access=private) function createParser(this) p=inputParser; addRequired(p,'name',@ischar); addRequired(p,'interface',@ischar); addRequired(p,'address',@ischar); addParameter(p,'gui','placeholder',@ischar); this.Parser=p; end end methods (Access=protected) %Triggers event for acquired data function triggerNewData(this) notify(this,'NewData') end %Checks if the connection to the device is open function bool=isopen(this) bool=strcmp(this.Device.Status, 'open'); end %Adds a command to the CommandList function addCommand(this, tag, command, varargin) p=inputParser; addRequired(p,'tag',@ischar); addRequired(p,'command',@ischar); addParameter(p,'default','placeholder'); addParameter(p,'attributes','placeholder',@iscell); addParameter(p,'str_spec','d',@ischar); %If the write flag is on, it means this command can be used to %write a parameter to the device addParameter(p,'access','rw',@ischar); addParameter(p,'conv_factor',1,@isnumeric); parse(p,tag,command,varargin{:}); %Adds the command to be sent to the device this.CommandList.(tag).command=command; this.CommandList.(tag).access=p.Results.access; - write_flag=contains(p.Results.access,'w'); -% read_flag=contains(p.Results.access,'r'); + this.CommandList.(tag).write_flag=contains(p.Results.access,'w'); + this.CommandList.(tag).read_flag=contains(p.Results.access,'r'); %Adds a default value and the attributes the inputs must have %and creates a new property in the class - if write_flag + if this.CommandList.(tag).write_flag %Adds the string specifier to the list this.CommandList.(tag).str_spec=p.Results.str_spec; %Adds the default value this.CommandList.(tag).default=p.Results.default; %Adds the necessary attributes for the input to the command this.CommandList.(tag).attributes=p.Results.attributes; %Adds a conversion factor for displaying the value this.CommandList.(tag).conv_factor=p.Results.conv_factor; %Adds a property to the class corresponding to the tag - addprop(this,tag); + if ~isprop(this,tag) + addprop(this,tag); + end end end %Creates inputParser using the command list function createCommandParser(this) %Use input parser %Requires input of the appropriate class p=inputParser; p.StructExpand=0; %Flag for whether the command should initialize the device with %defaults - addParameter(p, 'write_all_defaults',false,@islogical); + addParameter(p, 'all',false,@islogical); for i=1:this.command_no %Adds optional inputs for each command, with the %appropriate default value from the command list and the %required attributes for the command input. addParameter(p, this.command_names{i},... this.CommandList.(this.command_names{i}).default),... @(x) validateattributes(x,... this.CommandList.(this.command_names{i}).attributes{1:end}); end this.CommandParser=p; end %Connects to the device if it is not connected function openDevice(this) if ~isopen(this) try fopen(this.Device); catch try instr_list=instrfind('RemoteHost',this.address); fclose(instr_list); fopen(this.Device); warning('Multiple instrument objects of address %s exist',... this.address); catch error('Could not open device') end end end end %Closes the connection to the device function closeDevice(this) if isopen(this) try fclose(this.Device); catch error('Could not close device') end end end %Close figure callback simply calls delete function for class function closeFigure(this,~,~) delete(this); end end %% Get functions methods function command_names=get.command_names(this) command_names=fieldnames(this.CommandList); end function command_no=get.command_no(this) command_no=length(this.command_names); end end end \ No newline at end of file diff --git a/@MyNa/MyNa.m b/@MyNa/MyNa.asv similarity index 95% copy from @MyNa/MyNa.m copy to @MyNa/MyNa.asv index dbeb6df..4a9bce7 100644 --- a/@MyNa/MyNa.m +++ b/@MyNa/MyNa.asv @@ -1,215 +1,211 @@ -classdef MyNa < MyInstrument - properties (SetAccess=protected, GetAccess=public) - ifbw; % IF bandwidth - start_freq; - stop_freq; - cent_freq; - span; - power; % probe power - trace_no; % number of traces - enable_out; % switch the output signal on/off - average_no; - point_no; % number of points in the sweep - sweep_type; % linear or log sweep - disp_type; % windows arrangement at the display, e.g 'D1' - active_trace = -1; % manipulating with active traces seems unavoidable - % for selecting the data format. -1 stands for unknown - cont_trig; - - % measurement parameters for the traces 1-2, e.g. 'S21' - meas_par1; - meas_par2; - - % data formats for the traces 1-2, options: - % 'PHAS', 'SLIN', 'SLOG', 'SCOM', 'SMIT', 'SADM', 'MLOG', 'MLIN', 'PLIN', 'PLOG', 'POL' - form1 = 'MLOG'; - form2 = 'PHAS'; - - data1 = struct(); - data2 = struct(); - end - - methods - function this=MyNa(name, interface, address, varargin) - this@MyInstrument(name, interface, address,varargin{:}); - createCommandList(this); - createCommandParser(this); - - switch interface - case 'TCPIP' - connectTCPIP(this); - end - - %Tests if device is working. - try - openDevice(this); - closeDevice(this); - catch - error(['Failed to open communications with device.',... - ' Check that the address and interface is correct.',... - ' Currently the address is %s and the interface is ',... - '%s.'],this.address,this.interface) - end - end - - % Command attributes are {class, attributtes} accepted by - % validateattributes() - function createCommandList(this) - addCommand(this,... - 'cent_freq','SENS1:FREQ:CENT %d', 'default',1.5e6,... - 'attributes',{{'numeric'}},'write_flag',true); - addCommand(this,... - 'start_freq','SENS1:FREQ:START %d', 'default',1e6,... - 'attributes',{{'numeric'}},'write_flag',true); - addCommand(this,... - 'stop_freq','SENS1:FREQ:STOP %d', 'default',2e6,... - 'attributes',{{'numeric'}},'write_flag',true); - addCommand(this,... - 'span','SENS1:FREQ:SPAN %d', 'default',1e6,... - 'attributes',{{'numeric'}},'write_flag',true); - addCommand(this,... - 'ifbw','SENS1:BAND %d', 'default',100,... - 'attributes',{{'numeric'}},'write_flag',true); - addCommand(this,... - 'point_no','SENS1:SWE:POIN %i', 'default',1000,... - 'attributes',{{'numeric'},{'integer'}},'write_flag',true); - addCommand(this,... - 'average_no','SENS1:AVER:COUN %i', 'default',0,... - 'attributes',{{'numeric'},{'integer'}},'write_flag',true); - addCommand(this,... - 'trace_no','CALC1:PAR:COUN %i', 'default',1,... - 'attributes',{{'numeric'},{'integer'}},'write_flag',true); - addCommand(this,... - 'sweep_type','SENS1:SWE:TYPE %s', 'default','LIN',... - 'attributes',{{'string'}},'write_flag',true); - addCommand(this,... - 'enable_out','OUTP %d', 'default',0,... - 'attributes',{{'logical'}},'write_flag',true); - addCommand(this,... - 'power','SOUR:POW:LEV:IMM:AMPL %d', 'default',-10,... - 'attributes',{{'numeric'}},'write_flag',true); - addCommand(this,... - 'disp_type','DISP:WIND1:SPL %s', 'default','D1',... - 'attributes',{{'string'}},'write_flag',true); - addCommand(this,... - 'cont_trig',':INIT1:CONT %s', 'default','OFF',... - 'attributes',{{'string'}},'write_flag',true); - - % Parametric commands - % Measurement parameters for traces, i can be extended to 4 - for i = 1:2 - i_str = num2str(i); - addCommand(this,... - ['meas_par',i_str],['CALC1:PAR',i_str,':DEF %s'],... - 'default','S21',... - 'attributes',{{'string'}},'write_flag',true); - end - end - - % Execute all the write commands with default values - function writeAllDefaults(this) - for i=1:this.command_no - if this.CommandList.(this.command_names{i}).write_flag - write(this.Device, ... - sprintf(this.CommandList.(this.command_names{i}).command,... - this.CommandList.(this.command_names{i}).default)); - this.(this.command_names{i})=... - this.CommandList.(this.command_names{i}).default; - end - end - end - - % Execute all the read commands and update corresponding properties - function readAll(this) - result=readProperty(this, this.command_names{:}); - res_names=fieldnames(result); - for i=1:length(res_names) - this.(res_names{i})=result.(res_names{i}); - end - end - - function writePropertyHedged(this, varargin) - this.openDevice(); - try - this.writeProperty(varargin{:}); - catch - disp('Error while writing the properties:'); - disp(varargin); - end - this.readAll(); - closeDevice(this); - end - - function result = readPropertyHedged(this, varargin) - this.openDevice(); - try - result = this.readProperty(varargin{:}); - catch - disp('Error while reading the properties:'); - disp(varargin); - end - this.closeDevice(); - end - - function readTrace(this, nTrace) - this.writeActiveTrace(nTrace); - dtag = sprintf('data%i', nTrace); - freq_str = strsplit(query(this.Device,'SENS1:FREQ:DATA?'),','); - data_str = strsplit(query(this.Device,'CALC1:DATA:FDAT?'),','); - this.(dtag).x = str2double(freq_str); - this.(dtag).y = str2double(data_str(1:2:end)); - this.(dtag).y2 = str2double(data_str(2:2:end)); - end - - function writeActiveTrace(this, nTrace) - fprintf(this.Device, sprintf('CALC1:PAR%i:SEL',nTrace)); - this.active_trace = nTrace; - end - - function writeTraceFormat(this, nTrace, fmt) - this.writeActiveTrace(nTrace); - n_str = num2str(nTrace); - this.(['form',n_str]) = fmt; - fprintf(this.Device, sprintf('CALC1:FORM %s', fmt)); - end - - function singleSweep(this) - this.openDevice(); - % Set the triger source to be remote control - fprintf(this.Device,':TRIG:SOUR BUS'); - % Start a sweep cycle - fprintf(this.Device,':TRIG:SING'); - % Wait for the sweep to end - query(this.Device,'*OPC?'); - this.closeDevice(); - end - - function startContSweep(this) - this.openDevice(); - this.writeProperty('cont_trig', 'ON'); - % Set the triger source to be remote control - fprintf(this.Device,':TRIG:SOUR BUS'); - % Start a sweep cycle - fprintf(this.Device,':TRIG'); - this.closeDevice(); - end - - function abortSweep(this) - this.openDevice(); - fprintf(this.Device,':ABOR'); - this.closeDevice(); - end - - function connectTCPIP(this) - buffer = 1000 * 1024; - visa_brand = 'ni'; - visa_address_rsa = sprintf('TCPIP0::%s::inst0::INSTR',... - this.address); - this.Device=visa(visa_brand, visa_address_rsa,... - 'InputBufferSize', buffer,... - 'OutputBufferSize', buffer); - set(this.Device,'InputBufferSize',1e6); - set(this.Device,'Timeout',10); - end - end -end +classdef MyNa < MyInstrument + properties (SetAccess=protected, GetAccess=public) + enable_out; % switch the output signal on/off + point_no; % number of points in the sweep + sweep_type; % linear or log sweep + disp_type; % windows arrangement at the display, e.g 'D1' + active_trace = -1; % manipulating with active traces seems unavoidable + % for selecting the data format. -1 stands for unknown + cont_trig; + + % measurement parameters for the traces 1-2, e.g. 'S21' + meas_par1; + meas_par2; + + % data formats for the traces 1-2, options: + % 'PHAS', 'SLIN', 'SLOG', 'SCOM', 'SMIT', 'SADM', 'MLOG', 'MLIN', 'PLIN', 'PLOG', 'POL' + form1 = 'MLOG'; + form2 = 'PHAS'; + + data1 = struct(); + data2 = struct(); + end + + methods + function this=MyNa(name, interface, address, varargin) + this@MyInstrument(name, interface, address,varargin{:}); + createCommandList(this); + createCommandParser(this); + + switch interface + case 'TCPIP' + connectTCPIP(this); + end + + %Tests if device is working. + try + openDevice(this); + closeDevice(this); + catch + error(['Failed to open communications with device.',... + ' Check that the address and interface is correct.',... + ' Currently the address is %s and the interface is ',... + '%s.'],this.address,this.interface) + end + end + + % Command attributes are {class, attributtes} accepted by + % validateattributes() + function createCommandList(this) + addCommand(this,... + 'cent_freq','SENS1:FREQ:CENT %d', 'default',1.5e6,... + 'attributes',{{'numeric'}},'write_flag',true); + addCommand(this,... + 'start_freq','SENS1:FREQ:START %d', 'default',1e6,... + 'attributes',{{'numeric'}},'write_flag',true); + addCommand(this,... + 'stop_freq','SENS1:FREQ:STOP %d', 'default',2e6,... + 'attributes',{{'numeric'}},'write_flag',true); + addCommand(this,... + 'span','SENS1:FREQ:SPAN %d', 'default',1e6,... + 'attributes',{{'numeric'}},'write_flag',true); + % IF bandwidth + addCommand(this,... + 'ifbw','SENS1:BAND %d', 'default',100,... + 'attributes',{{'numeric'}},'write_flag',true); + addCommand(this,... + 'point_no','SENS1:SWE:POIN %i', 'default',1000,... + 'attributes',{{'numeric'},{'integer'}},'write_flag',true); + % number of averages + addCommand(this,... + 'average_no','SENS1:AVER:COUN %i', 'default',0,... + 'attributes',{{'numeric'},{'integer'}},'write_flag',true); + % number of traces + addCommand(this,... + 'trace_no','CALC1:PAR:COUN %i', 'default',1,... + 'attributes',{{'numeric'},{'integer'}},'write_flag',true); + addCommand(this,... + 'sweep_type','SENS1:SWE:TYPE %s', 'default','LIN',... + 'attributes',{{'string'}},'write_flag',true); + addCommand(this,... + 'enable_out','OUTP %d', 'default',0,... + 'attributes',{{'logical'}},'write_flag',true); + % probe power + addCommand(this,... + 'power','SOUR:POW:LEV:IMM:AMPL %d', 'default',-10,... + 'attributes',{{'numeric'}},'write_flag',true); + addCommand(this,... + 'disp_type','DISP:WIND1:SPL %s', 'default','D1',... + 'attributes',{{'string'}},'write_flag',true); + addCommand(this,... + 'cont_trig',':INIT1:CONT %s', 'default','OFF',... + 'attributes',{{'string'}},'write_flag',true); + + % Parametric commands + % Measurement parameters for traces, i can be extended to 4 + for i = 1:2 + i_str = num2str(i); + addCommand(this,... + ['meas_par',i_str],['CALC1:PAR',i_str,':DEF %s'],... + 'default','S21',... + 'attributes',{{'string'}},'write_flag',true); + end + end + + % Execute all the write commands with default values + function writeAllDefaults(this) + for i=1:this.command_no + if this.CommandList.(this.command_names{i}).write_flag + write(this.Device, ... + sprintf(this.CommandList.(this.command_names{i}).command,... + this.CommandList.(this.command_names{i}).default)); + this.(this.command_names{i})=... + this.CommandList.(this.command_names{i}).default; + end + end + end + + % Execute all the read commands and update corresponding properties + function readAll(this) + result=readProperty(this, this.command_names{:}); + res_names=fieldnames(result); + for i=1:length(res_names) + this.(res_names{i})=result.(res_names{i}); + end + end + + function writePropertyHedged(this, varargin) + this.openDevice(); + try + this.writeProperty(varargin{:}); + catch + disp('Error while writing the properties:'); + disp(varargin); + end + this.readAll(); + closeDevice(this); + end + + function result = readPropertyHedged(this, varargin) + this.openDevice(); + try + result = this.readProperty(varargin{:}); + catch + disp('Error while reading the properties:'); + disp(varargin); + end + this.closeDevice(); + end + + function readTrace(this, nTrace) + this.writeActiveTrace(nTrace); + dtag = sprintf('data%i', nTrace); + freq_str = strsplit(query(this.Device,'SENS1:FREQ:DATA?'),','); + data_str = strsplit(query(this.Device,'CALC1:DATA:FDAT?'),','); + this.(dtag).x = str2double(freq_str); + this.(dtag).y = str2double(data_str(1:2:end)); + this.(dtag).y2 = str2double(data_str(2:2:end)); + end + + function writeActiveTrace(this, nTrace) + fprintf(this.Device, sprintf('CALC1:PAR%i:SEL',nTrace)); + this.active_trace = nTrace; + end + + function writeTraceFormat(this, nTrace, fmt) + this.writeActiveTrace(nTrace); + n_str = num2str(nTrace); + this.(['form',n_str]) = fmt; + fprintf(this.Device, sprintf('CALC1:FORM %s', fmt)); + end + + function singleSweep(this) + this.openDevice(); + % Set the triger source to be remote control + fprintf(this.Device,':TRIG:SOUR BUS'); + % Start a sweep cycle + fprintf(this.Device,':TRIG:SING'); + % Wait for the sweep to end + query(this.Device,'*OPC?'); + this.closeDevice(); + end + + function startContSweep(this) + this.openDevice(); + this.writeProperty('cont_trig', 'ON'); + % Set the triger source to be remote control + fprintf(this.Device,':TRIG:SOUR BUS'); + % Start a sweep cycle + fprintf(this.Device,':TRIG'); + this.closeDevice(); + end + + function abortSweep(this) + this.openDevice(); + fprintf(this.Device,':ABOR'); + this.closeDevice(); + end + + function connectTCPIP(this) + buffer = 1000 * 1024; + visa_brand = 'ni'; + visa_address_rsa = sprintf('TCPIP0::%s::inst0::INSTR',... + this.address); + this.Device=visa(visa_brand, visa_address_rsa,... + 'InputBufferSize', buffer,... + 'OutputBufferSize', buffer); + set(this.Device,'InputBufferSize',1e6); + set(this.Device,'Timeout',10); + end + end +end diff --git a/@MyNa/MyNa.m b/@MyNa/MyNa.m index dbeb6df..691d1e7 100644 --- a/@MyNa/MyNa.m +++ b/@MyNa/MyNa.m @@ -1,215 +1,192 @@ +% The class for communication with Agilent E5061B Network Analyzer classdef MyNa < MyInstrument properties (SetAccess=protected, GetAccess=public) - ifbw; % IF bandwidth - start_freq; - stop_freq; - cent_freq; - span; - power; % probe power - trace_no; % number of traces - enable_out; % switch the output signal on/off - average_no; - point_no; % number of points in the sweep - sweep_type; % linear or log sweep - disp_type; % windows arrangement at the display, e.g 'D1' active_trace = -1; % manipulating with active traces seems unavoidable % for selecting the data format. -1 stands for unknown - cont_trig; - - % measurement parameters for the traces 1-2, e.g. 'S21' - meas_par1; - meas_par2; % data formats for the traces 1-2, options: - % 'PHAS', 'SLIN', 'SLOG', 'SCOM', 'SMIT', 'SADM', 'MLOG', 'MLIN', 'PLIN', 'PLOG', 'POL' + % 'PHAS', 'SLIN', 'SLOG', 'SCOM', 'SMIT', 'SADM', 'MLOG', 'MLIN', + %'PLIN', 'PLOG', 'POL' form1 = 'MLOG'; form2 = 'PHAS'; data1 = struct(); data2 = struct(); end methods function this=MyNa(name, interface, address, varargin) this@MyInstrument(name, interface, address,varargin{:}); createCommandList(this); createCommandParser(this); switch interface case 'TCPIP' connectTCPIP(this); end %Tests if device is working. try openDevice(this); closeDevice(this); catch error(['Failed to open communications with device.',... ' Check that the address and interface is correct.',... ' Currently the address is %s and the interface is ',... '%s.'],this.address,this.interface) end end % Command attributes are {class, attributtes} accepted by % validateattributes() function createCommandList(this) addCommand(this,... 'cent_freq','SENS1:FREQ:CENT %d', 'default',1.5e6,... - 'attributes',{{'numeric'}},'write_flag',true); + 'attributes',{{'numeric'}}); addCommand(this,... 'start_freq','SENS1:FREQ:START %d', 'default',1e6,... - 'attributes',{{'numeric'}},'write_flag',true); + 'attributes',{{'numeric'}}); addCommand(this,... 'stop_freq','SENS1:FREQ:STOP %d', 'default',2e6,... - 'attributes',{{'numeric'}},'write_flag',true); + 'attributes',{{'numeric'}}); addCommand(this,... 'span','SENS1:FREQ:SPAN %d', 'default',1e6,... - 'attributes',{{'numeric'}},'write_flag',true); + 'attributes',{{'numeric'}}); + % IF bandwidth addCommand(this,... 'ifbw','SENS1:BAND %d', 'default',100,... - 'attributes',{{'numeric'}},'write_flag',true); + 'attributes',{{'numeric'}}); + % number of points in the sweep addCommand(this,... 'point_no','SENS1:SWE:POIN %i', 'default',1000,... - 'attributes',{{'numeric'},{'integer'}},'write_flag',true); + 'attributes',{{'numeric'},{'integer'}}); + % number of averages addCommand(this,... 'average_no','SENS1:AVER:COUN %i', 'default',0,... - 'attributes',{{'numeric'},{'integer'}},'write_flag',true); + 'attributes',{{'numeric'},{'integer'}}); + % number of traces addCommand(this,... 'trace_no','CALC1:PAR:COUN %i', 'default',1,... - 'attributes',{{'numeric'},{'integer'}},'write_flag',true); + 'attributes',{{'numeric'},{'integer'}}); + % linear or log sweep addCommand(this,... 'sweep_type','SENS1:SWE:TYPE %s', 'default','LIN',... - 'attributes',{{'string'}},'write_flag',true); + 'attributes',{{'string'}}); + % switch the output signal on/off addCommand(this,... 'enable_out','OUTP %d', 'default',0,... - 'attributes',{{'logical'}},'write_flag',true); + 'attributes',{{'logical'}}); + % probe power [dB] addCommand(this,... 'power','SOUR:POW:LEV:IMM:AMPL %d', 'default',-10,... - 'attributes',{{'numeric'}},'write_flag',true); + 'attributes',{{'numeric'}}); + % windows arrangement at the display, e.g 'D1' addCommand(this,... 'disp_type','DISP:WIND1:SPL %s', 'default','D1',... - 'attributes',{{'string'}},'write_flag',true); + 'attributes',{{'string'}}); + % Continuous sweep triggering 'ON'/'OFF' addCommand(this,... 'cont_trig',':INIT1:CONT %s', 'default','OFF',... - 'attributes',{{'string'}},'write_flag',true); + 'attributes',{{'string'}}); - % Parametric commands - % Measurement parameters for traces, i can be extended to 4 + % Parametric commands for traces, i can be extended to 4 for i = 1:2 + % measurement parameters for the traces 1-2, e.g. 'S21' i_str = num2str(i); addCommand(this,... ['meas_par',i_str],['CALC1:PAR',i_str,':DEF %s'],... 'default','S21',... 'attributes',{{'string'}},'write_flag',true); end end % Execute all the write commands with default values function writeAllDefaults(this) for i=1:this.command_no if this.CommandList.(this.command_names{i}).write_flag write(this.Device, ... sprintf(this.CommandList.(this.command_names{i}).command,... this.CommandList.(this.command_names{i}).default)); this.(this.command_names{i})=... this.CommandList.(this.command_names{i}).default; end end end % Execute all the read commands and update corresponding properties function readAll(this) result=readProperty(this, this.command_names{:}); res_names=fieldnames(result); for i=1:length(res_names) this.(res_names{i})=result.(res_names{i}); end end - function writePropertyHedged(this, varargin) - this.openDevice(); - try - this.writeProperty(varargin{:}); - catch - disp('Error while writing the properties:'); - disp(varargin); - end - this.readAll(); - closeDevice(this); - end - - function result = readPropertyHedged(this, varargin) - this.openDevice(); - try - result = this.readProperty(varargin{:}); - catch - disp('Error while reading the properties:'); - disp(varargin); - end - this.closeDevice(); - end - function readTrace(this, nTrace) this.writeActiveTrace(nTrace); dtag = sprintf('data%i', nTrace); freq_str = strsplit(query(this.Device,'SENS1:FREQ:DATA?'),','); data_str = strsplit(query(this.Device,'CALC1:DATA:FDAT?'),','); this.(dtag).x = str2double(freq_str); + % In the returned string there is in general 2 values for each + % frequency point. In the Smith data format this can be used to + % transfer magnitude and phase of the signal in one trace. With + % MLOG, MLIN and PHAS format settings every 2-nd element should + % be 0 this.(dtag).y = str2double(data_str(1:2:end)); this.(dtag).y2 = str2double(data_str(2:2:end)); end function writeActiveTrace(this, nTrace) fprintf(this.Device, sprintf('CALC1:PAR%i:SEL',nTrace)); this.active_trace = nTrace; end function writeTraceFormat(this, nTrace, fmt) this.writeActiveTrace(nTrace); n_str = num2str(nTrace); this.(['form',n_str]) = fmt; fprintf(this.Device, sprintf('CALC1:FORM %s', fmt)); end function singleSweep(this) this.openDevice(); % Set the triger source to be remote control fprintf(this.Device,':TRIG:SOUR BUS'); % Start a sweep cycle fprintf(this.Device,':TRIG:SING'); - % Wait for the sweep to end + % Wait for the sweep to finish (the command returns 1) when it + % happens query(this.Device,'*OPC?'); this.closeDevice(); end function startContSweep(this) this.openDevice(); this.writeProperty('cont_trig', 'ON'); % Set the triger source to be remote control fprintf(this.Device,':TRIG:SOUR BUS'); % Start a sweep cycle fprintf(this.Device,':TRIG'); this.closeDevice(); end function abortSweep(this) this.openDevice(); fprintf(this.Device,':ABOR'); this.closeDevice(); end function connectTCPIP(this) buffer = 1000 * 1024; visa_brand = 'ni'; visa_address_rsa = sprintf('TCPIP0::%s::inst0::INSTR',... this.address); this.Device=visa(visa_brand, visa_address_rsa,... 'InputBufferSize', buffer,... 'OutputBufferSize', buffer); set(this.Device,'InputBufferSize',1e6); set(this.Device,'Timeout',10); end end end