diff --git a/Fit classes/@MyOpticalLorentzianFit/MyOpticalLorentzianFit.m b/Fit classes/@MyOpticalLorentzianFit/MyOpticalLorentzianFit.m index 3d37a1b..24de7f5 100644 --- a/Fit classes/@MyOpticalLorentzianFit/MyOpticalLorentzianFit.m +++ b/Fit classes/@MyOpticalLorentzianFit/MyOpticalLorentzianFit.m @@ -1,91 +1,102 @@ % Lorenzian fit with additional capabilities for the calibration of optical % linewidth classdef MyOpticalLorentzianFit < MyLorentzianFit properties (GetAccess = public, SetAccess = protected) RefCursors MyCursor end methods (Access = public) function this = MyOpticalLorentzianFit(varargin) this@MyLorentzianFit(varargin{:}); if ~isempty(this.Axes) % Add two vertical reference cursors to set the frequency % scale xlim = this.Axes.XLim; x1 = xlim(1)+0.2*(xlim(2)-xlim(1)); x2 = xlim(2)-0.2*(xlim(2)-xlim(1)); this.RefCursors = ... [MyCursor(this.Axes, ... 'orientation', 'vertical', ... 'position', x1, ... 'Label','Ref 1', 'Color', [0, 0, 0.6]), ... MyCursor(this.Axes, 'orientation', 'vertical', ... 'position', x2, ... 'Label','Ref 2', 'Color', [0, 0, 0.6])]; end end function delete(this) if ~isempty(this.RefCursors) delete(this.RefCursors); end end function centerCursors(this) % Center the range cursors centerCursors@MyFit(this); % Center the ref cursors if ~isempty(this.Axes) && ~isempty(this.RefCursors) ... && all(isvalid(this.RefCursors)) xlim = this.Axes.XLim; x1 = xlim(1)+0.2*(xlim(2)-xlim(1)); x2 = xlim(2)-0.2*(xlim(2)-xlim(1)); this.RefCursors(1).value = x1; this.RefCursors(2).value = x2; end end end methods (Access = protected) function createUserParamList(this) addUserParam(this, 'line_spacing', ... 'title', 'Reference line spacing (MHz)', ... 'editable', 'on', ... 'default', 1); addUserParam(this, 'line_no', ... 'title', 'Number of reference lines', ... 'editable', 'on', ... 'default', 1); addUserParam(this, 'lw', ... 'title', 'Linewidth (MHz)', ... 'editable', 'off'); + addUserParam(this, 'eta_oc', ... + 'title', '\eta overcoupled', ... + 'editable', 'off'); + addUserParam(this, 'eta_uc', ... + 'title', '\eta undercoupled', ... + 'editable', 'off'); end function calcUserParams(this) raw_lw = this.param_vals(2); if ~isempty(this.RefCursors) % Get the reference spacing from the position of cursors xmin = min(this.RefCursors.value); xmax = max(this.RefCursors.value); ref_spacing = xmax - xmin; else % Otherwise the reference spacing is the entire data range ref_spacing = this.Data.x(1)-this.Data.x(end); end this.lw = raw_lw*this.line_spacing*this.line_no/ref_spacing; + a = this.param_vals(1); + d = this.param_vals(4); + R_min = 1 + 2*a/pi/raw_lw/d; + this.eta_oc = (1 + sqrt(R_min))/2; + this.eta_uc = (1 - sqrt(R_min))/2; end end end diff --git a/Fit classes/@MySpringShiftFit/MySpringShiftFit.m b/Fit classes/@MySpringShiftFit/MySpringShiftFit.m new file mode 100644 index 0000000..7963b7e --- /dev/null +++ b/Fit classes/@MySpringShiftFit/MySpringShiftFit.m @@ -0,0 +1,127 @@ +classdef MySpringShiftFit < MyFitParamScaling + + methods (Access = public) + function this = MySpringShiftFit(varargin) + this@MyFitParamScaling( ... + 'fit_name', 'Optomechanical spring shift', ... + 'fit_function', 'e*4*(x-c)*b/2/((x-c)^2+(b/2)^2)^2 + 1/pi*a*b/2/((x-c)^2+(b/2)^2)+d', ... + 'fit_tex', '$$e\frac{4(x-c)b/2}{((x-c)^2+(b/2)^2)^2} + \frac{a}{\pi}\frac{b/2}{(x-c)^2+(b/2)^2}+d$$', ... + 'fit_params', {'a','b','c','d','e'}, ... + 'fit_param_names', {'Absorption amplitude','Width','Center','Offset', 'OM shift amplitude'}, ... + varargin{:}); + end + end + + methods (Access = protected) + + function calcInitParams(this) + ind = this.data_selection; + + x = this.Data.x(ind); + y = this.Data.y(ind); + + this.lim_upper=[Inf,Inf,Inf,Inf,Inf]; + this.lim_lower=[-Inf,0,-Inf,-Inf,0]; + + % Finds peaks on the positive signal (max 1 peak) + rng_x = max(x)-min(x); + try + [~, locs(1), widths(1), proms(1)] = findpeaks(y, x,... + 'MinPeakDistance', rng_x/2, 'SortStr', 'descend',... + 'NPeaks', 1); + catch ME + warning(ME.message) + + proms(1) = 0; + end + + % Finds peaks on the negative signal (max 1 peak) + try + [~,locs(2),widths(2),proms(2)] = findpeaks(-y, x,... + 'MinPeakDistance', rng_x/2, 'SortStr', 'descend',... + 'NPeaks', 1); + catch ME + warning(ME.message) + + proms(2) = 0; + end + + if proms(1)==0 && proms(2)==0 + warning(['No peaks were found in the data, giving ' ... + 'default initial parameters to fit function']) + + this.param_vals = [1,1,1,1]; + this.lim_lower = -[Inf,0,Inf,Inf]; + this.lim_upper = [Inf,Inf,Inf,Inf]; + return + end + + %If the prominence of the peak in the positive signal is + %greater, we adapt our limits and parameters accordingly, + %if negative signal has a greater prominence, we use this + %for fitting. + if proms(1)>proms(2) + ind=1; + p_in(4)=min(y); + else + ind=2; + p_in(4)=max(y); + proms(2)=-proms(2); + end + + p_in(2)=widths(ind); + + %Calculates the amplitude, as when x=c, the amplitude + %is 2a/(pi*b) + p_in(1)=proms(ind)*pi*p_in(2)/2; + p_in(3)=locs(ind); + + this.param_vals = p_in; + this.lim_lower(2)=0.01*p_in(2); + this.lim_upper(2)=100*p_in(2); + end + + function genSliderVecs(this) + genSliderVecs@MyFit(this); + + try + + %We choose to have the slider go over the range of + %the x-values of the plot for the center of the + %Lorentzian. + this.slider_vecs{3}=... + linspace(this.Fit.x(1),this.Fit.x(end),101); + %Find the index closest to the init parameter + [~,ind]=... + min(abs(this.param_vals(3)-this.slider_vecs{3})); + %Set to ind-1 as the slider goes from 0 to 100 + set(this.Gui.(sprintf('Slider_%s',... + this.fit_params{3})),'Value',ind-1); + catch + end + end + end + + methods (Access = protected) + function sc_vals = scaleFitParams(~, vals, scaling_coeffs) + [mean_x,std_x,mean_y,std_y]=scaling_coeffs{:}; + + sc_vals(1)=vals(1)/(std_y*std_x); + sc_vals(2)=vals(2)/std_x; + sc_vals(3)=(vals(3)-mean_x)/std_x; + sc_vals(4)=(vals(4)-mean_y)/std_y; + sc_vals(5)=vals(5) / std_y / std_x^2; + end + + %Converts scaled coefficients to real coefficients + function vals = unscaleFitParams(~, sc_vals, scaling_coeffs) + [mean_x,std_x,mean_y,std_y]=scaling_coeffs{:}; + + vals(1)=sc_vals(1)*std_y*std_x; + vals(2)=sc_vals(2)*std_x; + vals(3)=sc_vals(3)*std_x+mean_x; + vals(4)=sc_vals(4)*std_y+mean_y; + vals(5)=sc_vals(5) * std_y * std_x^2; + end + end +end \ No newline at end of file