diff --git a/@MyDaq/MyDaq.m b/@MyDaq/MyDaq.m index 02a39f3..e087782 100644 --- a/@MyDaq/MyDaq.m +++ b/@MyDaq/MyDaq.m @@ -1,871 +1,871 @@ classdef MyDaq < handle properties %Contains GUI handles Gui; %Contains Reference trace (MyTrace object) Ref; %Contains Data trace (MyTrace object) Data; %Contains Background trace (MyTrace object) Background; %Struct containing available instruments InstrList=struct(); %Struct containing MyInstrument objects Instruments=struct() %Struct containing Cursor objects Cursors=struct(); %Struct containing Cursor labels CrsLabels=struct(); %Struct containing MyFit objects Fits=struct(); %Input parser Parser; %Struct for listeners Listeners=struct(); %Sets the colors of fits, data and reference fit_color='k'; data_color='b'; ref_color='r'; %Properties for saving files base_dir; session_name; file_name; %Flag for enabling the GUI enable_gui; end properties (Dependent=true) save_dir; main_plot; open_fits; open_instrs; open_crs; instr_tags; instr_names; savefile; end methods %% Class functions %Constructor function function this=MyDaq(varargin) createParser(this); parse(this.Parser,varargin{:}); parseInputs(this); if this.enable_gui this.Gui=guihandles(eval('GuiDaq')); initGui(this); hold(this.main_plot,'on'); end initDaq(this) end function delete(this) %Deletes the MyFit objects and their listeners cellfun(@(x) delete(this.Fits.(x)), this.open_fits); cellfun(@(x) deleteListeners(this,x), this.open_fits); %Deletes the MyInstrument objects and their listeners cellfun(@(x) delete(this.Instruments.(x)), this.open_instrs); cellfun(@(x) deleteListeners(this,x), this.open_instrs); if this.enable_gui set(this.Gui.figure1,'CloseRequestFcn',''); %Deletes the figure delete(this.Gui.figure1); %Removes the figure handle to prevent memory leaks this.Gui=[]; end end %Creates parser for constructor function function createParser(this) p=inputParser; addParameter(p,'enable_gui',1); this.Parser=p; end %Sets the class variables to the inputs from the inputParser. function parseInputs(this) for i=1:length(this.Parser.Parameters) %Takes the value from the inputParser to the appropriate %property. if isprop(this,this.Parser.Parameters{i}) this.(this.Parser.Parameters{i})=... this.Parser.Results.(this.Parser.Parameters{i}); end end end %Initializes the class depending on the computer name function initDaq(this) computer_name=getenv('computername'); switch computer_name case 'LPQM1PCLAB2' initRt(this); case 'LPQM1PC18' initUhq(this); case 'LPQM1PC2' %Test case for testing on Nils' computer. otherwise error('Please create an initialization function for this computer') end %Initializes empty trace objects this.Ref=MyTrace; this.Data=MyTrace; this.Background=MyTrace; end %Sets callback functions for the GUI function initGui(this) %Close request function is set to delete function of the class set(this.Gui.figure1, 'CloseRequestFcn',... @(hObject,eventdata) closeFigure(this, hObject, ... eventdata)); %Sets callback for the edit box of the base directory set(this.Gui.BaseDir,'Callback',... @(hObject, eventdata) baseDirCallback(this, hObject, ... eventdata)); %Sets callback for the session name edit box set(this.Gui.SessionName,'Callback',... @(hObject, eventdata) sessionNameCallback(this, hObject, ... eventdata)); %Sets callback for the file name edit box set(this.Gui.FileName,'Callback',... @(hObject, eventdata) fileNameCallback(this, hObject, ... eventdata)); %Sets callback for the save data button set(this.Gui.SaveData,'Callback',... @(hObject, eventdata) saveDataCallback(this, hObject, ... eventdata)); %Sets callback for the save ref button set(this.Gui.SaveRef,'Callback',... @(hObject, eventdata) saveRefCallback(this, hObject, ... eventdata)); %Sets callback for the show data button set(this.Gui.ShowData,'Callback',... @(hObject, eventdata) showDataCallback(this, hObject, ... eventdata)); %Sets callback for the show reference button set(this.Gui.ShowRef,'Callback',... @(hObject, eventdata) showRefCallback(this, hObject, ... eventdata)); %Sets callback for the data to reference button set(this.Gui.DataToRef,'Callback',... @(hObject, eventdata) dataToRefCallback(this, hObject, ... eventdata)); %Sets callback for the LogY button set(this.Gui.LogY,'Callback',... @(hObject, eventdata) logYCallback(this, hObject, ... eventdata)); %Sets callback for the LogX button set(this.Gui.LogX,'Callback',... @(hObject, eventdata) logXCallback(this, hObject, ... eventdata)); %Sets callback for the data to background button set(this.Gui.DataToBg,'Callback',... @(hObject, eventdata) dataToBgCallback(this, hObject, ... eventdata)); %Sets callback for the ref to background button set(this.Gui.RefToBg,'Callback',... @(hObject, eventdata) refToBgCallback(this, hObject, ... eventdata)); %Sets callback for the clear background button set(this.Gui.ClearBg,'Callback',... @(hObject, eventdata) clearBgCallback(this, hObject, ... eventdata)); %Sets callback for the select trace popup menu set(this.Gui.SelTrace,'Callback',... @(hObject,eventdata) selTraceCallback(this, hObject, ... eventdata)); %Sets callback for the vertical cursor button set(this.Gui.VertCursor,'Callback',... @(hObject, eventdata) cursorButtonCallback(this, hObject,... eventdata)); %Sets callback for the horizontal cursors button set(this.Gui.HorzCursor,'Callback',... @(hObject, eventdata) cursorButtonCallback(this, hObject,... eventdata)); %Sets callback for the center cursors button set(this.Gui.CenterCursors,'Callback',... @(hObject,eventdata) centerCursorsCallback(this,hObject,... eventdata)); %Sets callback for the center cursors button set(this.Gui.CopyPlot,'Callback',... @(hObject,eventdata) copyPlotCallback(this,hObject,... eventdata)); %Initializes the AnalyzeMenu set(this.Gui.AnalyzeMenu,'Callback',... @(hObject, eventdata) analyzeMenuCallback(this, hObject,... eventdata)); set(this.Gui.AnalyzeMenu,'String',{'Select a routine...',... 'Linear Fit','Quadratic Fit','Exponential Fit',... 'Gaussian Fit','Lorentzian Fit'}); %Initializes the InstrMenu set(this.Gui.InstrMenu,'Callback',... @(hObject,eventdata) instrMenuCallback(this,hObject,... eventdata)); end %Executes when the GUI is closed function closeFigure(this,~,~) delete(this); end %Adds an instrument to InstrList. Used by initialization functions. function addInstr(this,tag,name,type,interface,address) %Usage: addInstr(this,tag,name,type,interface,address) if ~ismember(tag,this.instr_tags) this.InstrList.(tag).name=name; this.InstrList.(tag).type=type; this.InstrList.(tag).interface=interface; this.InstrList.(tag).address=address; else error(['%s is already defined as an instrument. ',... 'Please choose a different tag'],tag); end end %Gets the tag corresponding to an instrument name function tag=getTag(this,instr_name) ind=cellfun(@(x) strcmp(this.InstrList.(x).name,instr_name),... this.instr_tags); tag=this.instr_tags{ind}; end %Opens the correct instrument function openInstrument(this,tag) instr_type=this.InstrList.(tag).type; %Collects the correct inputs for creating the MyInstrument %class input_cell={this.InstrList.(tag).name,... this.InstrList.(tag).interface,... this.InstrList.(tag).address}; switch instr_type case 'RSA' this.Instruments.(tag)=MyRsa(input_cell{:},... 'gui','GuiRsa'); case 'Scope' this.Instruments.(tag)=MyScope(input_cell{:},... 'gui','GuiScope'); case 'NA' this.Instruments.(tag)=MyNa(input_cell{:},... 'gui','GuiNa'); end %Adds listeners for new data and deletion of the instrument. %These call plot functions and delete functions respectively. this.Listeners.(tag).NewData=... addlistener(this.Instruments.(tag),'NewData',... @(src, eventdata) acquireNewData(this, src, eventdata)); this.Listeners.(tag).Deletion=... addlistener(this.Instruments.(tag),'ObjectBeingDestroyed',... @(src, eventdata) deleteInstrument(this, src, eventdata)); end %Updates fits function updateFits(this) %Pushes data into fits in the form of MyTrace objects, so that %units etc follow. for i=1:length(this.open_fits) this.Fits.(this.open_fits{i}).Data=getFitData(this); end end % If vertical cursors are on, takes only data %within cursors. Note the use of copy here! This is a handle %class, so if normal assignment is used, this.Fits.Data and %this.(trace_str) will refer to the same object, causing roblems. function Trace=getFitData(this) %Finds out which trace the user wants to fit. trace_opts=get(this.Gui.SelTrace,'String'); trace_str=trace_opts{get(this.Gui.SelTrace,'Value')}; Trace=copy(this.(trace_str)); if ismember('Vert',fieldnames(this.Cursors)) ind=findCursorData(this, trace_str); Trace.x=this.(trace_str).x(ind); Trace.y=this.(trace_str).y(ind); end end %Finds data between vertical cursors in the given trace function ind=findCursorData(this, trace) curs_pos=sort([this.Cursors.Vert{1}.Location,... this.Cursors.Vert{2}.Location]); ind=(this.(trace).x>curs_pos(1) & this.(trace).x %Prints the figure to the clipboard print(newFig,'-clipboard','-dbitmap'); %Deletes the figure delete(newFig); end %% Callbacks %Callback for copying the plot to clipboard function copyPlotCallback(this,~,~) copyPlot(this); end %Callback for centering cursors function centerCursorsCallback(this, ~, ~) x_pos=mean(get(this.main_plot,'XLim')); y_pos=mean(get(this.main_plot,'YLim')); for i=1:length(this.open_crs) switch this.open_crs{i} case 'Horz' pos=y_pos; case 'Vert' pos=x_pos; end %Centers the position cellfun(@(x) set(x,'Location',pos), ... this.Cursors.(this.open_crs{i})); %Triggers the UpdateCursorBar event, which triggers %listener callback to reposition text cellfun(@(x) notify(x,'UpdateCursorBar'),... this.Cursors.(this.open_crs{i})); cellfun(@(x) notify(x,'EndDrag'),... this.Cursors.(this.open_crs{i})); end end %Callback for creating vertical cursors function cursorButtonCallback(this, hObject, ~) tag=get(hObject,'Tag'); %Gets the first four characters of the tag (Vert or Horz) type=tag(1:4); if get(hObject,'Value') set(hObject, 'BackGroundColor',[0,1,.2]); createCursors(this,type); else set(hObject, 'BackGroundColor',[0.941,0.941,0.941]); deleteCursors(this,type); end end %Callback for the instrument menu function instrMenuCallback(this,hObject,~) val=get(hObject,'Value'); if val~=1 names=get(hObject,'String'); tag=getTag(this,names(val)); else tag=''; end %If instrument is valid and not open, opens it. If it is valid %and open it changes focus to the instrument control window. if ismember(tag,this.instr_tags) && ... ~ismember(tag,this.open_instrs) openInstrument(this,tag); elseif ismember(tag,this.open_instrs) figure(this.Instruments.(tag).figure1); end end %Select trace callback function selTraceCallback(this, ~, ~) updateFits(this) end %Saves the data if the save data button is pressed. function saveDataCallback(this, ~, ~) if this.Data.validatePlot save(this.Data,'save_dir',this.save_dir,'name',... this.savefile) else error('Data trace was empty, could not save'); end end %Saves the reference if the save ref button is pressed. function saveRefCallback(this, ~, ~) if this.Data.validatePlot save(this.Ref,'save_dir',this.save_dir,'name',... this.savefile) else error('Reference trace was empty, could not save') end end %Toggle button callback for showing the data trace. function showDataCallback(this, hObject, ~) if get(hObject,'Value') set(hObject, 'BackGroundColor',[0,1,.2]); setVisible(this.Data,this.main_plot,1); else set(hObject, 'BackGroundColor',[0.941,0.941,0.941]); setVisible(this.Data,this.main_plot,0); end end %Toggle button callback for showing the ref trace function showRefCallback(this, hObject, ~) if get(hObject,'Value') set(hObject, 'BackGroundColor',[0,1,0.2]); setVisible(this.Ref,this.main_plot,1); else set(hObject, 'BackGroundColor',[0.941,0.941,0.941]); setVisible(this.Ref,this.main_plot,0); end end %Callback for moving the data to reference. function dataToRefCallback(this, ~, ~) if this.Data.validatePlot this.Ref.x=this.Data.x; this.Ref.y=this.Data.y; this.Ref.plotTrace(this.main_plot,'Color',this.ref_color); this.Ref.setVisible(this.main_plot,1); updateFits(this); set(this.Gui.ShowRef,'Value',1); set(this.Gui.ShowRef, 'BackGroundColor',[0,1,.2]); else warning('Data trace was empty, could not move to reference') end end %Callback for ref to bg button. Sends the reference to background function refToBgCallback(this, ~, ~) if this.Ref.validatePlot this.Background.x=this.Ref.x; this.Background.y=this.Ref.y; this.Background.plotTrace(this.main_plot); this.Background.setVisible(this.main_plot,1); else warning('Reference trace was empty, could not move to background') end end %Callback for data to bg button. Sends the data to background function dataToBgCallback(this, ~, ~) if this.Data.validatePlot this.Background.x=this.Data.x; this.Background.y=this.Data.y; this.Background.plotTrace(this.main_plot); this.Background.setVisible(this.main_plot,1); else warning('Data trace was empty, could not move to background') end end %Callback for clear background button. Clears the background function clearBgCallback(this, ~, ~) this.Background.x=[]; this.Background.y=[]; this.Background.setVisible(this.main_plot,0); end %Callback for LogY button. Sets the YScale to log/lin function logYCallback(this, hObject, ~) if get(hObject,'Value') set(this.main_plot,'YScale','Log'); set(hObject, 'BackGroundColor',[0,1,.2]); else set(this.main_plot,'YScale','Linear'); set(hObject, 'BackGroundColor',[0.941,0.941,0.941]); end end %Callback for LogX button. Sets the XScale to log/lin function logXCallback(this, hObject, ~) if get(hObject,'Value') set(this.main_plot,'XScale','Log'); set(hObject, 'BackGroundColor',[0,1,.2]); else set(this.main_plot,'XScale','Linear'); set(hObject, 'BackGroundColor',[0.941,0.941,0.941]); end end %Base directory callback function baseDirCallback(this, hObject, ~) this.base_dir=get(hObject,'String'); for i=1:length(this.open_fits) this.Fits.(this.open_fits{i}).save_dir=this.save_dir; end end %Callback for session name edit box. Sets the session name. function sessionNameCallback(this, hObject, ~) this.session_name=get(hObject,'String'); for i=1:length(this.open_fits) this.Fits.(this.open_fits{i}).save_dir=this.save_dir; end end %Callback for filename edit box. Sets the file name. function fileNameCallback(this, hObject,~) this.file_name=get(hObject,'String'); for i=1:length(this.open_fits) this.Fits.(this.open_fits{i}).save_name=this.file_name; end end %Callback for the analyze menu (popup menu for selecting fits). %Opens the correct MyFit object. function analyzeMenuCallback(this, hObject, ~) analyze_list=get(hObject,'String'); analyze_ind=get(hObject,'Value'); %Finds the correct fit name analyze_name=analyze_list{analyze_ind}; analyze_name=analyze_name(1:(strfind(analyze_name,' ')-1)); analyze_name=[upper(analyze_name(1)),analyze_name(2:end)]; %Sees if the fit object is already open, if it is, changes the %focus to it, if not, opens it. if ismember(analyze_name,fieldnames(this.Fits)) %Changes focus to the relevant fit window figure(this.Fits.(analyze_name).Gui.Window); elseif analyze_ind~=1 %Makes an instance of MyFit with correct parameters. this.Fits.(analyze_name)=MyFit('fit_name',analyze_name,... 'enable_plot',1,'plot_handle',this.main_plot,... 'Data',getFitData(this),'save_dir',this.save_dir,... 'save_name',this.file_name); %Sets up a listener for the Deletion event, which %removes the MyFit object from the Fits structure if it is %deleted. this.Listeners.(analyze_name).Deletion=... addlistener(this.Fits.(analyze_name),'ObjectBeingDestroyed',... @(src, eventdata) deleteFit(this, src, eventdata)); %Sets up a listener for the NewFit. Callback plots the fit %on the main plot. this.Listeners.(analyze_name).NewFit=... addlistener(this.Fits.(analyze_name),'NewFit',... @(src, eventdata) plotNewFit(this, src, eventdata)); end end %% Listener functions %Callback function for NewFit listener. Plots the fit in the %window using the plotFit function of the MyFit object function plotNewFit(this, src, ~) src.plotFit('Color',this.fit_color); updateCursors(this); end %Callback function for the NewData listener function acquireNewData(this, src, ~) this.Data=src.Trace; src.Trace.plotTrace(this.main_plot,'Color',this.data_color) updateCursors(this); updateFits(this); end %Callback function for MyInstrument ObjectBeingDestroyed listener. %Removes the relevant field from the Instruments struct and deletes %the listeners from the object function deleteInstrument(this, src, ~) %Deletes the object from the Instruments struct tag=getTag(this, src.name); if ismember(tag, this.open_instrs) this.Instruments=rmfield(this.Instruments,tag); end %Deletes the listeners from the Listeners struct deleteListeners(this, tag); end %Callback function for MyFit ObjectBeingDestroyed listener. %Removes the relevant field from the Fits struct and deletes the %listeners from the object. function deleteFit(this, src, ~) %Deletes the object from the Fits struct if ismember(src.fit_name, fieldnames(this.Fits)) this.Fits=rmfield(this.Fits,src.fit_name); end %Deletes the listeners from the Listeners struct. deleteListeners(this, src.fit_name); %Updates cursors since the fits are removed from the plot updateCursors(this); end %Listener update function for vertical cursor function vertCursorUpdate(this, src) %Finds the index of the cursor. All cursors are tagged %V1,V2,H1,H2 etc, ind is the number. ind=str2double(src.Tag(2)); %Moves the cursor labels set(this.CrsLabels.Vert{ind},'Position',[src.Location,... this.CrsLabels.Vert{ind}.Position(2),0]); %Sets the edit box displaying the location of the cursor set(this.Gui.(sprintf('EditV%d',ind)),'String',... num2str(src.Location)); %Sets the edit box displaying the difference in locations set(this.Gui.EditV2V1,'String',... num2str(this.Cursors.Vert{2}.Location-... this.Cursors.Vert{1}.Location)) end %Listener update function for horizontal cursor function horzCursorUpdate(this, src) %Finds the index of the cursor. All cursors are tagged %V1,V2,H1,H2 etc, ind is the number. ind=str2double(src.Tag(2)); %Moves the cursor labels set(this.CrsLabels.Horz{ind},'Position',... [this.CrsLabels.Horz{ind}.Position(1),... src.Location,0]); %Sets the edit box displaying the location of the cursor set(this.Gui.(sprintf('EditH%d',ind)),'String',... num2str(src.Location)); %Sets the edit box displaying the difference in locations set(this.Gui.EditH2H1,'String',... num2str(this.Cursors.Horz{2}.Location-... this.Cursors.Horz{1}.Location)); end %Function that deletes listeners from the listeners struct, %corresponding to an object of name obj_name function deleteListeners(this, obj_name) %Finds if the object has listeners in the listeners structure if ismember(obj_name, fieldnames(this.Listeners)) %Grabs the fieldnames of the object's listeners structure names=fieldnames(this.Listeners.(obj_name)); for i=1:length(names) %Deletes the listeners delete(this.Listeners.(obj_name).(names{i})); %Removes the field from the structure this.Listeners.(obj_name)=... rmfield(this.Listeners.(obj_name),names{i}); end %Removes the object's field from the structure this.Listeners=rmfield(this.Listeners, obj_name); end end %% Set functions function set.base_dir(this,base_dir) if ~strcmp(base_dir(end),'\') base_dir(end+1)='\'; end this.base_dir=base_dir; end %% Get functions %Get function from save directory function save_dir=get.save_dir(this) save_dir=[this.base_dir,datestr(now,'yyyy-mm-dd '),... this.session_name,'\']; end %Get function for the plot handles function main_plot=get.main_plot(this) if this.enable_gui main_plot=this.Gui.figure1.CurrentAxes; else main_plot=[]; end end %Get function for available instrument tags function instr_tags=get.instr_tags(this) instr_tags=fieldnames(this.InstrList); end %Get function for open fits function open_fits=get.open_fits(this) open_fits=fieldnames(this.Fits); end %Get function for open instrument tags function open_instrs=get.open_instrs(this) open_instrs=fieldnames(this.Instruments); end %Get function for instrument names function instr_names=get.instr_names(this) %Cell of strings is output, so UniformOutput must be 0. instr_names=cellfun(@(x) this.InstrList.(x).name, ... this.instr_tags,'UniformOutput',0); end %Generates appropriate file name for the save file. function savefile=get.savefile(this) if get(this.Gui.AutoName,'Value') date_time = datestr(now,'yyyy-mm-dd_HHMMSS'); else date_time=''; end savefile=[this.file_name,date_time]; end %Get function that displays names of open cursors function open_crs=get.open_crs(this) open_crs=fieldnames(this.Cursors); end end end \ No newline at end of file diff --git a/@MyG/MyG.m b/@MyG/MyG.m index 086a327..23b5474 100644 --- a/@MyG/MyG.m +++ b/@MyG/MyG.m @@ -1,145 +1,159 @@ classdef MyG < handle properties %Trace of mechanical resonance MechTrace; %Trace of calibration tone CalTrace; %Struct containing Gui handles Gui; %Struct containing variable names corresponding to Gui edits VarStruct; %Contains inputParser Parser; temp; beta; end properties (Dependent=true) var_tags; end methods function this=MyG(varargin) createVarStruct(this); createParser(this); parse(this.Parser,varargin{:}) this.Gui=guihandles(eval('GuiGCal')); this.MechTrace=this.Parser.Results.MechTrace; this.CalTrace=this.Parser.Results.CalTrace; this.beta=this.Parser.Results.beta; this.temp=this.Parser.Results.temp; initGui(this); end %Class deletion function function delete(this) set(this.Gui.figure1,'CloseRequestFcn',''); %Deletes the figure delete(this.Gui.figure1); %Removes the figure handle to prevent memory leaks this.Gui=[]; end %Creates class input parser function createParser(this) p=inputParser; validateTrace=@(x) validateattributes(x,{'MyTrace'},... {'nonempty'}); addParameter(p,'MechTrace',MyTrace(),validateTrace); addParameter(p,'CalTrace',MyTrace(),validateTrace); cellfun(@(x) addParameter(p, this.VarStruct.(x).var,... this.VarStruct.(x).default), this.var_tags); this.Parser=p; end %Creates the variable struct which contains variable names and %default values function createVarStruct(this) addVar(this,'Temp','temp',295); addVar(this,'Beta','beta',0); end %Adds a variable to the VarStruct function addVar(this,name,var,default) this.VarStruct.(name).var=var; this.VarStruct.(name).default=default; end %Initializes the GUI function initGui(this) cellfun(@(x) set(this.Gui.([x,'Edit']),'Callback',... @(hObject,~) editCallback(this,hObject)),... this.var_tags); + set(this.Gui.CopyButton,'Callback',@(~,~) copyCallback(this)); set(this.Gui.figure1, 'CloseRequestFcn',... @(~,~) closeFigure(this)); end function calcG(this) %Conditions the caltrace by doing background subtraction, then %finds the area cal_bg=mean(this.CalTrace.y(1:5),this.CalTrace.y((end-4):end)); this.CalTrace.y=this.CalTrace.y-cal_bg; cal_area=integrate(this.CalTrace); v_rms_eom=sqrt(cal_area); %Conditions the mechtrace by doing background subtraction, then %finds the area mech_bg=mean(this.MechTrace.y(1:5),this.MechTrace.y((end-4):end)); this.MechTrace.y=this.MechTrace.y-mech_bg; mech_area=integrate(this.MechTrace); v_rms_mech=sqrt(mech_area); %Finds the mechanical frequency and the fwhm [~,mech_freq]=max(this.MechTrace); - gamma_m=calcFwhm(this.MechTrace) + gamma_m=calcFwhm(this.MechTrace); q_m=mech_freq/gamma_m; + %Defines constants and finds mechanical phononon number k_b=1.38e-23; h=6.63e-34; n_m=k_b*this.temp/(h*mech_freq); + %Calculates g_0 g0=(v_rms_mech/v_rms_eom)*this.beta*mech_freq/sqrt(4*n_m); set(this.Gui.MechFreq,'String',num2str(mech_freq/1e6,4)); set(this.Gui.Q,'String',num2str(q_m,6)); set(this.Gui.Linewidth,'String',num2str(gamma_m,5)); set(this.Gui.g0,'String',num2str(g0,5)); end %The close figure function calls the deletion method. function closeFigure(this) delete(this) end %Generic editbox callback which sets the appropriate property of %the class function editCallback(this, hObject) tag_str=erase(get(hObject,'Tag'),'Edit'); var_str=this.VarStruct.(tag_str).var; this.(var_str)=str2double(get(hObject,'String')); end + + %Callback function for copying values to clipboard + function copyCallback(this) + mech_freq=get(this.Gui.MechFreq,'String'); + q_m=get(this.Gui.Q,'String'); + gamma_m=get(this.Gui.Linewidth,'String'); + g0=get(this.Gui.g0,'String'); + copy_string=sprintf('%s \t %s \t %s \t %s',... + mech_freq,q_m,gamma_m,g0); + clipboard('copy',copy_string); + end end %% Set functions methods function set.beta(this,beta) this.beta=beta; set(this.Gui.BetaEdit,'String',num2str(this.beta)); end function set.temp(this,temp) this.temp=temp; set(this.Gui.TempEdit,'String',num2str(this.temp)); end end %% Get functions methods function var_tags=get.var_tags(this) var_tags=fieldnames(this.VarStruct); end end end diff --git a/@MyTrace/MyTrace.m b/@MyTrace/MyTrace.m index 0c5344d..194f237 100644 --- a/@MyTrace/MyTrace.m +++ b/@MyTrace/MyTrace.m @@ -1,369 +1,377 @@ classdef MyTrace < handle & matlab.mixin.Copyable - properties + properties (Access=public) x=[]; y=[]; name='placeholder'; Color='b'; Marker='.'; LineStyle='-' MarkerSize=6; - Parser; name_x='x'; name_y='y'; unit_x=''; unit_y=''; save_dir=''; load_path=''; + end + + properties (GetAccess=public, SetAccess=private) %Cell that contains handles the trace is plotted in hlines={}; end + properties (Access=private) + Parser; + end + properties (Dependent=true) label_x; label_y; end - methods + methods (Access=public) function this=MyTrace(varargin) createParser(this); parse(this.Parser,varargin{:}); parseInputs(this,true); if ~ismember('load_path',this.Parser.UsingDefaults) loadTrace(this,this.load_path); end end - %Creates the input parser for the class. Includes default values - %for all optional parameters. - function createParser(this) - p=inputParser; - addParameter(p,'name','placeholder'); - addParameter(p,'x',[]); - addParameter(p,'y',[]); - addParameter(p,'Color','b'); - addParameter(p,'Marker','none'); - addParameter(p,'LineStyle','-'); - addParameter(p,'MarkerSize',6); - addParameter(p,'unit_x','x'); - addParameter(p,'unit_y','y'); - addParameter(p,'name_x','x'); - addParameter(p,'name_y','y'); - %Default save folder is the current directory upon - %instantiation - addParameter(p,'save_dir',pwd); - addParameter(p,'load_path',''); - this.Parser=p; - end - %Defines the save function for the class. Saves the data with %column headers as label_x and label_y function save(this,varargin) %Allows all options of the class as inputs for the save %function, to change the name or save directory. parse(this.Parser,varargin{:}); parseInputs(this,false); %Creates save directory if it does not exist if ~exist(this.save_dir,'dir') mkdir(this.save_dir) end %Adds the \ at the end if it was not added by the user. if ~strcmp(this.save_dir(end),'\') this.save_dir(end)=[]; end %Creates a file name out of the name of the class and the save %directory filename=[this.save_dir,this.name,'.txt']; %Creates the file fileID=fopen(filename,'w'); %MATLAB returns -1 for the fileID if the file could not be %opened if fileID==-1 error('File could not be created.'); end %Finds appropriate column width cw=max([length(this.label_y),length(this.label_x)]); if cw<9; cw=9; end %Makes a format string with the correct column width. %% makes %a % symbol in sprintf, thus if cw=14, below is %14s\t%14s\r\n. %\r\n prints a carriage return, ensuring linebreak in NotePad. fprintf(fileID,sprintf('%%%ds\t%%%ds\r\n',cw,cw),... this.label_x, this.label_y); %Saves in scientific notation with correct column width defined %above. Again if cw=14, we get %14.3e\t%14.3e\r\n fprintf(fileID,sprintf('%%%d.3e\t%%%d.3e\r\n',cw,cw),... [this.x, this.y]'); fclose(fileID); end function loadTrace(this, file_path) if ~exist(this.load_path,'file') error('File does not exist, please choose a different load path') end load_data=tdfread(file_path); this.load_path=file_path; data_labels=fieldnames(load_data); %Code for left bracket ind_start=strfind(data_labels, '0x28'); %Code for right bracket ind_stop=strfind(data_labels, '0x29'); col_name={'x','y'}; for i=1:2 if ~isempty(ind_start) && ~isempty(ind_stop) %Extracts the data labels from the file this.(sprintf('unit_%s',col_name{i}))=... data_labels{i}((ind_start{i}+4):(ind_stop{i}-1)); this.(sprintf('name_%s',col_name{i}))=... data_labels{i}(1:(ind_start{i}-2)); end %Loads the data into the trace this.(col_name{i})=load_data.(data_labels{i}); end end %Allows setting of multiple properties in one command. function setTrace(this, varargin) parse(this.Parser,varargin{:}) parseInputs(this, false); - end - - %Sets the class variables to the inputs from the inputParser. Can - %be used to reset class to default values if default_flag=true. - function parseInputs(this, default_flag) - for i=1:length(this.Parser.Parameters) - %Sets the value if there was an input or if the default - %flag is on. The default flag is used to reset the class to - %its default values. - if default_flag || ~any(ismember(this.Parser.Parameters{i},... - this.Parser.UsingDefaults)) - this.(this.Parser.Parameters{i})=... - this.Parser.Results.(this.Parser.Parameters{i}); - end - end - end + end %Plots the trace on the given axes, using the class variables to %define colors, markers, lines and labels. Takes all optional %parameters of the class as inputs. function plotTrace(this,plot_axes,varargin) - %Checks that there are axes to plot + %Checks that there are axes to plot assert(exist('plot_axes','var') && ... isa(plot_axes,'matlab.graphics.axis.Axes'),... 'Please input axes to plot in.') %Checks that x and y are the same size assert(validatePlot(this),... 'The length of x and y must be identical to make a plot') %Parses inputs without resetting to defaults parse(this.Parser,varargin{:}) parseInputs(this,false); ind=findLineInd(this, plot_axes); if ~isempty(ind) && any(ind) set(this.hlines{ind},'XData',this.x,'YData',this.y); else this.hlines{end+1}=plot(plot_axes,this.x,this.y); ind=length(this.hlines); end %Sets the correct color and label options set(this.hlines{ind},'Color',this.Color,'LineStyle',... - this.LineStyle,'Marker',this.Marker,... - 'MarkerSize',this.MarkerSize); + this.LineStyle,'Marker',this.Marker,... + 'MarkerSize',this.MarkerSize); xlabel(plot_axes,this.label_x,'Interpreter','LaTeX'); ylabel(plot_axes,this.label_y,'Interpreter','LaTeX'); set(plot_axes,'TickLabelInterpreter','LaTeX'); end %If there is a line object from the trace in the figure, this sets %it to the appropriate visible setting. function setVisible(this, plot_axes, bool) if bool - vis='on'; + vis='on'; else vis='off'; end ind=findLineInd(this, plot_axes); if ~isempty(ind) && any(ind) set(this.hlines{ind},'Visible',vis) end end - - %Finds the hline handle that is plotted in the specified axes - function ind=findLineInd(this, plot_axes) - if ~isempty(this.hlines) - ind=cellfun(@(x) ismember(x,findall(plot_axes,... - 'Type','Line')),this.hlines); - else - ind=[]; - end - end - - %Checks if the data can be plotted - function bool=validatePlot(this) - bool=~isempty(this.x) && ~isempty(this.y)... - && length(this.x)==length(this.y); - end - - %Defines addition of two MyTrace objects + %Defines addition of two MyTrace objects function sum=plus(a,b) checkArithmetic(a,b); sum=MyTrace('x',a.x,'y',a.y+b.y,'unit_x',a.unit_x,... 'unit_y',a.unit_y,'name_x',a.name_x,'name_y',a.name_y); end - + %Defines subtraction of two MyTrace objects function sum=minus(a,b) checkArithmetic(a,b); sum=MyTrace('x',a.x,'y',a.y-b.y,'unit_x',a.unit_x,... 'unit_y',a.unit_y,'name_x',a.name_x,'name_y',a.name_y); end function [max_val,max_x]=max(this) assert(validatePlot(this),['MyTrace object must contain',... ' nonempty data vectors of equal length to find the max']) [max_val,max_ind]=max(this.y); max_x=this.x(max_ind); end - + function fwhm=calcFwhm(this) assert(validatePlot(this),['MyTrace object must contain',... ' nonempty data vectors of equal length to find the fwhm']) [max_val,~]=max(this); ind1=find(this.y>max_val/2,1,'first'); ind2=find(this.y>max_val/2,1,'last'); fwhm=this.x(ind2)-this.x(ind1); end + + %Integrates the trace numerically + function area=integrate(this) + assert(validatePlot(this),['MyTrace object must contain',... + ' nonempty data vectors of equal length to integrate']) + area=trapz(this.x,this.y); + end + + %Checks if the object is empty + function bool=isempty(this) + bool=isempty(this.x) && isempty(this.y); + end + end + + methods (Access=private) + %Creates the input parser for the class. Includes default values + %for all optional parameters. + function createParser(this) + p=inputParser; + addParameter(p,'name','placeholder'); + addParameter(p,'x',[]); + addParameter(p,'y',[]); + addParameter(p,'Color','b'); + addParameter(p,'Marker','none'); + addParameter(p,'LineStyle','-'); + addParameter(p,'MarkerSize',6); + addParameter(p,'unit_x','x'); + addParameter(p,'unit_y','y'); + addParameter(p,'name_x','x'); + addParameter(p,'name_y','y'); + %Default save folder is the current directory upon + %instantiation + addParameter(p,'save_dir',pwd); + addParameter(p,'load_path',''); + this.Parser=p; + end + + %Sets the class variables to the inputs from the inputParser. Can + %be used to reset class to default values if default_flag=true. + function parseInputs(this, default_flag) + for i=1:length(this.Parser.Parameters) + %Sets the value if there was an input or if the default + %flag is on. The default flag is used to reset the class to + %its default values. + if default_flag || ~any(ismember(this.Parser.Parameters{i},... + this.Parser.UsingDefaults)) + this.(this.Parser.Parameters{i})=... + this.Parser.Results.(this.Parser.Parameters{i}); + end + end + end + %Checks if arithmetic can be done with MyTrace objects. function checkArithmetic(a,b) assert(isa(a,'MyTrace') && isa(b,'MyTrace'),... ['Both objects must be of type MyTrace to add,',... 'here they are type %s and %s'],class(a),class(b)); assert(strcmp(a.unit_x, b.unit_x) && strcmp(a.unit_y,b.unit_y),... 'The MyTrace classes must have the same units for arithmetic'); assert(length(a.x)==length(a.y) && length(a.x)==length(a.y),... 'The length of x and y must be equal for arithmetic'); assert(all(a.x==b.x),... 'The MyTrace objects must have identical x-axis for arithmetic') end - %Integrates the trace numerically - function area=integrate(this) - assert(validatePlot(this),['MyTrace object must contain',... - ' nonempty data vectors of equal length to integrate']) - area=trapz(this.x,this.y); + %Finds the hline handle that is plotted in the specified axes + function ind=findLineInd(this, plot_axes) + if ~isempty(this.hlines) + ind=cellfun(@(x) ismember(x,findall(plot_axes,... + 'Type','Line')),this.hlines); + else + ind=[]; + end end - %Checks if the object is empty - function bool=isempty(this) - bool=isempty(this.x) && isempty(this.y); + %Checks if the data can be plotted + function bool=validatePlot(this) + bool=~isempty(this.x) && ~isempty(this.y)... + && length(this.x)==length(this.y); end end %Set and get methods methods %Set function for Color. Checks if it is a valid color. function set.Color(this, Color) assert(iscolor(Color),... '%s is not a valid MATLAB default color or RGB triplet',... Color); this.Color=Color; end %Set function for Marker. Checks if it is a valid %marker style. function set.Marker(this, Marker) assert(ismarker(Marker),... '%s is not a valid MATLAB MarkerStyle',Marker); this.Marker=Marker; end %Set function for x, checks if it is a vector of doubles. function set.x(this, x) assert(isnumeric(x),... 'Data must be of class double'); this.x=x(:); end %Set function for y, checks if it is a vector of doubles. function set.y(this, y) assert(isnumeric(y),... 'Data must be of class double'); this.y=y(:); end %Set function for LineStyle, checks if input is a valid line style. function set.LineStyle(this, LineStyle) assert(isline(LineStyle),... '%s is not a valid MATLAB LineStyle',LineStyle); this.LineStyle=LineStyle; end %Set function for MarkerSize, checks if input is a positive number. function set.MarkerSize(this, MarkerSize) assert(isnumeric(MarkerSize) && MarkerSize>0,... 'MarkerSize must be a numeric value greater than zero'); this.MarkerSize=MarkerSize; end %Set function for name, checks if input is a string. function set.name(this, name) assert(ischar(name),'Name must be a string, not a %s',... class(name)); this.name=name; end %Set function for unit_x, checks if input is a string. function set.unit_x(this, unit_x) assert(ischar(unit_x),'Unit must be a string, not a %s',... class(unit_x)); this.unit_x=unit_x; end %Set function for unit_y, checks if input is a string function set.unit_y(this, unit_y) assert(ischar(unit_y),'Unit must be a string, not a %s',... class(unit_y)); this.unit_y=unit_y; end %Set function for name_x, checks if input is a string function set.name_x(this, name_x) assert(ischar(name_x),'Name must be a string, not a %s',... class(name_x)); this.name_x=name_x; end %Set function for name_y, checks if input is a string function set.name_y(this, name_y) assert(ischar(name_y),'Name must be a string, not a %s',... class(name_y)); this.name_y=name_y; end function set.load_path(this, load_path) assert(ischar(load_path),'File path must be a string, not a %s',... class(load_path)); this.load_path=load_path; end %Get function for label_x, creates label from name_x and unit_x. function label_x=get.label_x(this) label_x=sprintf('%s (%s)', this.name_x, this.unit_x); end %Get function for label_y, creates label from name_y and unit_y. function label_y=get.label_y(this) label_y=sprintf('%s (%s)', this.name_y, this.unit_y); end end end \ No newline at end of file diff --git a/GUIs/GuiGCal.fig b/GUIs/GuiGCal.fig index 1515a81..40686d3 100644 Binary files a/GUIs/GuiGCal.fig and b/GUIs/GuiGCal.fig differ diff --git a/GUIs/GuiGCal.m b/GUIs/GuiGCal.m index aea87dd..29bc089 100644 --- a/GUIs/GuiGCal.m +++ b/GUIs/GuiGCal.m @@ -1,172 +1,129 @@ function varargout = GuiGCal(varargin) %GUIGCAL MATLAB code file for GuiGCal.fig % GUIGCAL, by itself, creates a new GUIGCAL or raises the existing % singleton*. % % H = GUIGCAL returns the handle to a new GUIGCAL or the handle to % the existing singleton*. % % GUIGCAL('Property','Value',...) creates a new GUIGCAL using the % given property value pairs. Unrecognized properties are passed via % varargin to GuiGCal_OpeningFcn. This calling syntax produces a % warning when there is an existing singleton*. % % GUIGCAL('CALLBACK') and GUIGCAL('CALLBACK',hObject,...) call the % local function named CALLBACK in GUIGCAL.M with the given input % arguments. % % *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one % instance to run (singleton)". % % See also: GUIDE, GUIDATA, GUIHANDLES % Edit the above text to modify the response to help GuiGCal -% Last Modified by GUIDE v2.5 02-Nov-2017 13:50:30 +% Last Modified by GUIDE v2.5 02-Nov-2017 16:11:33 % Begin initialization code - DO NOT EDIT gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @GuiGCal_OpeningFcn, ... 'gui_OutputFcn', @GuiGCal_OutputFcn, ... 'gui_LayoutFcn', [], ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end % End initialization code - DO NOT EDIT % --- Executes just before GuiGCal is made visible. function GuiGCal_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % varargin unrecognized PropertyName/PropertyValue pairs from the % command line (see VARARGIN) % Choose default command line output for GuiGCal handles.output = hObject; % Update handles structure guidata(hObject, handles); % UIWAIT makes GuiGCal wait for user response (see UIRESUME) % uiwait(handles.figure1); % --- Outputs from this function are returned to the command line. function varargout = GuiGCal_OutputFcn(hObject, eventdata, handles) % varargout cell array for returning output args (see VARARGOUT); % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Get default command line output from handles structure varargout{1} = handles.output; -function PEomEdit_Callback(hObject, eventdata, handles) -% hObject handle to PEomEdit (see GCBO) -% eventdata reserved - to be defined in a future version of MATLAB -% handles structure with handles and user data (see GUIDATA) - -% Hints: get(hObject,'String') returns contents of PEomEdit as text -% str2double(get(hObject,'String')) returns contents of PEomEdit as a double - - % --- Executes during object creation, after setting all properties. function PEomEdit_CreateFcn(hObject, eventdata, handles) % hObject handle to PEomEdit (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end -function VPiEdit_Callback(hObject, eventdata, handles) -% hObject handle to VPiEdit (see GCBO) -% eventdata reserved - to be defined in a future version of MATLAB -% handles structure with handles and user data (see GUIDATA) - -% Hints: get(hObject,'String') returns contents of VPiEdit as text -% str2double(get(hObject,'String')) returns contents of VPiEdit as a double - - % --- Executes during object creation, after setting all properties. function VPiEdit_CreateFcn(hObject, eventdata, handles) % hObject handle to VPiEdit (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end -function TempEdit_Callback(hObject, eventdata, handles) -% hObject handle to TempEdit (see GCBO) -% eventdata reserved - to be defined in a future version of MATLAB -% handles structure with handles and user data (see GUIDATA) - -% Hints: get(hObject,'String') returns contents of TempEdit as text -% str2double(get(hObject,'String')) returns contents of TempEdit as a double - - % --- Executes during object creation, after setting all properties. function TempEdit_CreateFcn(hObject, eventdata, handles) % hObject handle to TempEdit (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end -% --- Executes on button press in pushbutton4. -function pushbutton4_Callback(hObject, eventdata, handles) -% hObject handle to pushbutton4 (see GCBO) -% eventdata reserved - to be defined in a future version of MATLAB -% handles structure with handles and user data (see GUIDATA) - - -function BetaEdit_Callback(hObject, eventdata, handles) -% hObject handle to BetaEdit (see GCBO) -% eventdata reserved - to be defined in a future version of MATLAB -% handles structure with handles and user data (see GUIDATA) - -% Hints: get(hObject,'String') returns contents of BetaEdit as text -% str2double(get(hObject,'String')) returns contents of BetaEdit as a double - - % --- Executes during object creation, after setting all properties. function BetaEdit_CreateFcn(hObject, eventdata, handles) % hObject handle to BetaEdit (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); -end +end \ No newline at end of file