classdef ArmCavityBafflePDAnalyzer < handle
    % Welcome to the ArmCavityBafflePDAnalyzer class! It is designed to
    % facilitate analysis of scatter in LIGO Fabry-Perot arm cavity. This
    % introduction will teach you how to use this tool. For more analysis
    % information, go to <a href="https://dcc.ligo.org/LIGO-T1800224">LIGO-T1800224</a>.
    %
    %   1. General help
    %   Run '<a href="matlab:help ArmCavityBafflePDAnalyzer">help ArmCavityBafflePDAnalyzer</a>' in command window to see the
    %   brief description of how to use this tool
    %   Run '<a href="matlab:doc ArmCavityBafflePDAnalyzer">doc ArmCavityBafflePDAnalyzer</a>' to see the summary page (very useful)
    %   Run 'help functionName' to see the detailed description of the
    %   function named by 'functionName'.
    %
    %   2. Data structure
    %   The input data should be organized in these two formats: <a href="matlab:help struct">struct</a> or <a href="matlab:help cell">cell</a>
    %   Struct data represents a consecutive time series
    %   Cell of struct data represents many sections of consecutive time
    %   series (the file name of section data often have '_section' appended)
    %   Please follow this convention to ease analysis and avoid debugging!
    %
    %   3. Nomenclature
    %   The data pulled from nds server has these identiers of interest:
    %       a. Interferometer (L1)
    %       b. Response type (lock(SS) or alignment(ADS)) or purpose
    %       c. Period (O2)
    %       d. Data processing (minTrend, MA120)
    %       e. Data structure (section)
    %   Example nomenclature:
    %       'L1_SS_O2_minTrend': 
    %       all steady-state (SS) raw data in entire O2 with minute-trend
    %       sampling 
    %       'L1_ADS_O2LSD_MA120_section': 
    %       all transient (ADS) data filtered by moving-average of 120
    %       seconds in sections of O2 longest stable duration (2/25/17 -
    %       6/6/17) 
    %
    %   4. Examples
    %   Declare an analyzer called 'm' that loads data from 'filename':
    %       m = ArmCavityBafflePDAnalyzer('data', filename);
    %   Execute functions named by 'functionName':
    %       m.functionName;
    %   Execute my analysis in <a href="https://dcc.ligo.org/LIGO-T1800224">LIGO-T1800224</a>:
    %       m.main; (will take some time to finish)
    %
    % Please let me know if you still have any trouble.
    % Thank you,
    % Wenxuan Jia (LIGO SURF '18), Anamaria Effler, Valera Frolov
    % 2018/6/12 - 2018/8/19
    % Go GO LIGO!
    
    properties(SetAccess = public, GetAccess = public)
        
        dat;% data loaded into this analyzer
        channelNames;% channel names loaded into this analyzer
        fileName;% name of the file loaded into this analyzer
        
        %logical indices
        
        lockIndex;% logical index of lock
        finalIndex;% final logical index of steady-state period
        ADSIndex;% final logical index of transient period
        
        %baffle structure
        
        ITMX;%ITMX baffle structure
        ETMX;%ETMX baffle structure
        ITMY;%ITMY baffle structure
        ETMY;%ETMY baffle structure
        
        %PD parameter
        
        rPD = 5.64; %[mm], radius of PD
        responsivity = 0.47; %[A/W], responsivity of PD
        transimpedence = 20*1000; %[V/A], transimpedence of PD
        PDgain = 1; %[-], analog gain (default 1)
        
        rTM = 170.1; %[mm], radius of test mass
        
        L_c = 3994.5; %[mm], Cavity length in O2
  
        G_c = 250;%[-], FP cavity buildup in O2
        
        %fieldPositionViewer parameter
        
        boxSize = 20;%[mm] size of the box in viewer
        res = 1;%[mm] resolution of the box in viewer
        
        drivealign;% O2 drivealign combination info
        O2SSpos;% O2 Steady-state beam positions
        O2SSpostime;% O2 period of Steady-state beam positions
        

    end
    
    
    methods
        %% Constructor  
        function m = ArmCavityBafflePDAnalyzer(varargin)
            % Wenxuan Jia, LIGO SURF '18
            % Input ('data', filename) to load data from file
            % Input ('dat', dat, 'channelNames', channelNames) to load from
            % workspace
            
            %help ArmCavityBafflePDAnalyzer;
            
            addpath('figure', 'O2data');
            addpath('IFOBuilder', 'IFOmains');%, 'IFOBuilder/FOGPrime13Toolbox');
            
            if(m.argHas('data', varargin))
                datafile = varargin{m.argHas('data', varargin)+1};
                m.loadData(datafile);
                fprintf('\n Data loaded from: %s\n', m.fileName);
                fprintf('\n Channels loaded:\n\n');
                m.printChannels;
            end
            
            if(m.argHas('dat', varargin))
                m.dat = varargin{m.argHas('dat', varargin)+1};
                m.fileName = 'Workspace';
                fprintf('\n Data loaded from: %s\n', m.fileName);
            end
            
            if(m.argHas('channelNames', varargin))
                m.channelNames = varargin{m.argHas('channelNames', varargin)+1};
                m.fileName = 'Workspace';
                fprintf('\n Channels loaded:\n\n');
                m.printChannels;
            end
            
            set(0,'defaulttextinterpreter','latex')
            set(groot, 'defaultAxesTickLabelInterpreter','latex'); 
            set(groot, 'defaultLegendInterpreter','latex');
            set(0,'defaultfigureposition',[400 300 600 400]);

            % PD VOLTS channel offset in O2 (minus it to get true volt)
            % 
            if(~isempty(m.fileName) && strcmp(m.fileName(1:2),'H1'))
                % H1 O2 offset measured from period when ifo is down
                % (12/23/16 - 1/3/17)
                m.ITMX.PD1.off = -0.0115;
                m.ITMX.PD2.off = -0.0019;
                m.ITMX.PD3.off = -0.0050;
                m.ITMX.PD4.off = -0.0027;
                
                m.ETMX.PD1.off = -0.0160;
                m.ETMX.PD2.off = -0.0117;
                m.ETMX.PD3.off = -0.0011;
                m.ETMX.PD4.off = -0.0007;

                m.ITMY.PD1.off = -0.0101;
                m.ITMY.PD2.off = 0.0015;
                m.ITMY.PD3.off = -0.0145;
                m.ITMY.PD4.off = -0.0171;

                m.ETMY.PD1.off = -0.004;
                m.ETMY.PD2.off = -0.004;
                m.ETMY.PD3.off = -0.006;
                m.ETMY.PD4.off = -0.0015;
                
            else
                % L1 O2 offset
                m.ITMX.PD1.off = -0.00533;
                m.ITMX.PD2.off = -0.0023;
                m.ITMX.PD3.off = -0.0017;
                m.ITMX.PD4.off = -0.0017;

                m.ETMX.PD1.off = 0.0031;
                m.ETMX.PD2.off = 0.0017;
                m.ETMX.PD3.off = 0.0026;
                m.ETMX.PD4.off = 0.003;

                m.ITMY.PD1.off = -0.0031;
                m.ITMY.PD2.off = -0.0028;
                m.ITMY.PD3.off = -0.00666;
                m.ITMY.PD4.off = -0.0035;

                m.ETMY.PD1.off = 0.0009;
                m.ETMY.PD2.off = -0.006;
                m.ETMY.PD3.off = 0.0046;
                m.ETMY.PD4.off = 0.0085;
            end
            
            
            % PD local positions in O2 baffle
            % left hole (viewing from ETMX)
            m.ITMX.PD1.x = -149.6; m.ITMX.PD1.y =  160.7;
            m.ITMX.PD2.x =  149.6; m.ITMX.PD2.y =  440.3;
            m.ITMX.PD3.x =  430.0; m.ITMX.PD3.y =  151.4;
            m.ITMX.PD4.x =  149.6; m.ITMX.PD4.y = -137.2;
            % right hole
            m.ETMX.PD1.x =  149.6; m.ETMX.PD1.y =  160.7;
            m.ETMX.PD2.x = -149.6; m.ETMX.PD2.y =  440.3;
            m.ETMX.PD3.x = -430.0; m.ETMX.PD3.y =  151.4;
            m.ETMX.PD4.x = -149.6; m.ETMX.PD4.y = -137.2;
            % right hole
            m.ITMY.PD1.x =  149.6; m.ITMY.PD1.y =  160.7;
            m.ITMY.PD2.x = -149.6; m.ITMY.PD2.y =  440.3;
            m.ITMY.PD3.x = -430.0; m.ITMY.PD3.y =  151.4;
            m.ITMY.PD4.x = -149.6; m.ITMY.PD4.y = -137.2;
            % left hole
            m.ETMY.PD1.x = -149.6; m.ETMY.PD1.y =  160.7;
            m.ETMY.PD2.x =  149.6; m.ETMY.PD2.y =  440.3;
            m.ETMY.PD3.x =  430.0; m.ETMY.PD3.y =  151.4;
            m.ETMY.PD4.x =  149.6; m.ETMY.PD4.y = -137.2;
            % PD radial positions
            m.ITMX.PD1.r = sqrt(m.ITMX.PD1.x^2 + m.ITMX.PD1.y^2);
            m.ITMX.PD2.r = sqrt(m.ITMX.PD2.x^2 + m.ITMX.PD2.y^2);
            m.ITMX.PD3.r = sqrt(m.ITMX.PD3.x^2 + m.ITMX.PD3.y^2);
            m.ITMX.PD4.r = sqrt(m.ITMX.PD4.x^2 + m.ITMX.PD4.y^2);
            m.ETMX.PD1.r = sqrt(m.ETMX.PD1.x^2 + m.ETMX.PD1.y^2);
            m.ETMX.PD2.r = sqrt(m.ETMX.PD2.x^2 + m.ETMX.PD2.y^2);
            m.ETMX.PD3.r = sqrt(m.ETMX.PD3.x^2 + m.ETMX.PD3.y^2);
            m.ETMX.PD4.r = sqrt(m.ETMX.PD4.x^2 + m.ETMX.PD4.y^2);
            m.ITMY.PD1.r = sqrt(m.ITMY.PD1.x^2 + m.ITMY.PD1.y^2);
            m.ITMY.PD2.r = sqrt(m.ITMY.PD2.x^2 + m.ITMY.PD2.y^2);
            m.ITMY.PD3.r = sqrt(m.ITMY.PD3.x^2 + m.ITMY.PD3.y^2);
            m.ITMY.PD4.r = sqrt(m.ITMY.PD4.x^2 + m.ITMY.PD4.y^2);
            m.ETMY.PD1.r = sqrt(m.ETMY.PD1.x^2 + m.ETMY.PD1.y^2);
            m.ETMY.PD2.r = sqrt(m.ETMY.PD2.x^2 + m.ETMY.PD2.y^2);
            m.ETMY.PD3.r = sqrt(m.ETMY.PD3.x^2 + m.ETMY.PD3.y^2);
            m.ETMY.PD4.r = sqrt(m.ETMY.PD4.x^2 + m.ETMY.PD4.y^2);
            % solid angle (assume constant)
            m.ITMX.PD1.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMX.PD1.r/1000)^2);
            m.ITMX.PD2.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMX.PD2.r/1000)^2);
            m.ITMX.PD3.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMX.PD3.r/1000)^2);
            m.ITMX.PD4.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMX.PD4.r/1000)^2);
            m.ETMX.PD1.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMX.PD1.r/1000)^2);
            m.ETMX.PD2.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMX.PD2.r/1000)^2);
            m.ETMX.PD3.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMX.PD3.r/1000)^2);
            m.ETMX.PD4.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMX.PD4.r/1000)^2);
            m.ITMY.PD1.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMY.PD1.r/1000)^2);
            m.ITMY.PD2.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMY.PD2.r/1000)^2);
            m.ITMY.PD3.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMY.PD3.r/1000)^2);
            m.ITMY.PD4.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ITMY.PD4.r/1000)^2);
            m.ETMY.PD1.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMY.PD1.r/1000)^2);
            m.ETMY.PD2.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMY.PD2.r/1000)^2);
            m.ETMY.PD3.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMY.PD3.r/1000)^2);
            m.ETMY.PD4.omega = (pi*(m.rPD/1000)^2)/(m.L_c^2+(m.ETMY.PD4.r/1000)^2);
            % zenith angle (assume constant)
            m.ITMX.PD1.theta = atan(m.ITMX.PD1.r/1000/m.L_c);
            m.ITMX.PD2.theta = atan(m.ITMX.PD2.r/1000/m.L_c);
            m.ITMX.PD3.theta = atan(m.ITMX.PD3.r/1000/m.L_c);
            m.ITMX.PD4.theta = atan(m.ITMX.PD4.r/1000/m.L_c);
            m.ETMX.PD1.theta = atan(m.ETMX.PD1.r/1000/m.L_c);
            m.ETMX.PD2.theta = atan(m.ETMX.PD2.r/1000/m.L_c);
            m.ETMX.PD3.theta = atan(m.ETMX.PD3.r/1000/m.L_c);
            m.ETMX.PD4.theta = atan(m.ETMX.PD4.r/1000/m.L_c);
            m.ITMY.PD1.theta = atan(m.ITMY.PD1.r/1000/m.L_c);
            m.ITMY.PD2.theta = atan(m.ITMY.PD2.r/1000/m.L_c);
            m.ITMY.PD3.theta = atan(m.ITMY.PD3.r/1000/m.L_c);
            m.ITMY.PD4.theta = atan(m.ITMY.PD4.r/1000/m.L_c);
            m.ETMY.PD1.theta = atan(m.ETMY.PD1.r/1000/m.L_c);
            m.ETMY.PD2.theta = atan(m.ETMY.PD2.r/1000/m.L_c);
            m.ETMY.PD3.theta = atan(m.ETMY.PD3.r/1000/m.L_c);
            m.ETMY.PD4.theta = atan(m.ETMY.PD4.r/1000/m.L_c);
            
            %Beam position from DRIVEALIGN in O2(to mm)
            %formula (in mm):
            %ETM spot (x, y) : (ETM Yaw* Eyaw2x, (Pitch* Epitch2y) + Epitchoffset)
            %ITM spot (x, y) : (ITM Yaw* Iyaw2x, (Pitch* Ipitch2y) + Ipitchoffset)
            if(~isempty(m.fileName) && strcmp(m.fileName(1:2),'H1'))
                
            else
                m.ITMX.DRyaw2x = 3.65; 
                m.ETMX.DRyaw2x = 3.5;
                m.ITMY.DRyaw2x = 3.65; 
                m.ETMY.DRyaw2x = 3.5;
                m.ITMX.DRpitch2y = -4.5; 
                m.ETMX.DRpitch2y = -4.5;
                m.ITMY.DRpitch2y = -4.5; 
                m.ETMY.DRpitch2y = -4.5;

                m.ITMX.DRyoff = 3.5; 
                m.ETMX.DRyoff = 3.5; 
                m.ITMY.DRyoff = 3.5; 
                m.ETMY.DRyoff = 3.5; 
            end
            
            %Beam position from INMON in O2 (to mm)
            %formula (in mm):
            %ETMX spot (dx, dy) : ( YAW3/(Y3CLKGAIN*ADSGAIN) * IMyaw2x , PIT3/(P3CLKGAIN*ADSGAIN) * IMpitch2y )
            %ETMY spot (dx, dy) : ( YAW4/(Y4CLKGAIN*ADSGAIN) * IMyaw2x , PIT4/(P4CLKGAIN*ADSGAIN) * IMpitch2y )
            if(~isempty(m.fileName) && strcmp(m.fileName(1:2),'H1'))
                
            else
                m.ETMX.IMyaw2x = -720;
                m.ETMX.IMpitch2y = 980;
                m.ETMY.IMyaw2x = -760;
                m.ETMY.IMpitch2y = 950;
            end

            
            
            %SIS
            m.ITMX.SIS.x = [];
            m.ITMX.SIS.E = [];
            m.ITMX.SIS.r = [];
            m.ITMX.SIS.r2P = [];
            m.ITMX.SIS.r2NP = [];
            
            m.ETMX.SIS.x = [];
            m.ETMX.SIS.E = [];
            m.ETMX.SIS.r = [];
            m.ETMX.SIS.r2P = [];
            m.ETMX.SIS.r2NP = [];
            
            m.ITMY.SIS.x = [];
            m.ITMY.SIS.E = [];
            m.ITMY.SIS.r = [];
            m.ITMY.SIS.r2P = [];
            m.ITMY.SIS.r2NP = [];
            
            m.ETMY.SIS.x = [];
            m.ETMY.SIS.E = [];
            m.ETMY.SIS.r = [];
            m.ETMY.SIS.r2P = [];
            m.ETMY.SIS.r2NP = [];
            
            %Power map around it
            m.ITMX.PDPowerMap = [];
            m.ETMX.PDPowerMap = [];
            m.ITMY.PDPowerMap = [];
            m.ETMY.PDPowerMap = [];

        end
        
        
        
        %% main
        function main(m)
        %MAIN The main function for my SURF project (<a href="https://dcc.ligo.org/LIGO-T1800224">LIGO-T1800224</a>)
        %   .main
        %   execute all of my analyses (will take some time)
        %
        %   See also INTROTOFPCAVITY DEMOPHASEMAPONSIS DEMOPDAVERAGINGONSIS
        %   CALIBPD CALIBBRDF STEADYSTATESCATTERINO2 RUNSIS GETSISR2P
        %   GETSISBRDF SISVIEWER COMPARESSBRDF GETDRIVEALIGNCOMBODURATIONS
        %   BEAMPOSITIONINO2SSVIEWER DEMOO2LOCKPOSITIONSONSIS
        %   STEADYSTATESCATTERINO2LSD CHANVIEWER DEMOBOTHBEAMPOSITIONSONSIS
        %   TRANSIENTSCATTERVIEWER TESTMODELSIGMAWITHNUMOFTRAINEDDATA
        
            m.introToFPCavity;
            
            m.demoPhasemapOnSIS;
            
            m.demoPDAveragingOnSIS;
            
            % steady-state scatter
            m.loadData('L1_O2_minTrend.mat');
            m.calibPD;
            m.calibBRDF
            m.steadyStateScatterInO2;
            
            m.runSIS('arm','X');
            m.runSIS('arm','Y');
            m.getSISr2P;
            m.getSISBRDF;
            m.SISViewer('2D');
            m.SISViewer('3D');
            m.SISViewer('PD');
            m.SISViewer('baffle');
            
            m.loadData('L1_SS_O2_minTrend_section.mat');
            m.compareSSBRDF;
            
            m.getDriveAlignComboDurations;
            m.beamPositioninO2SSViewer;
            m.demoO2LockPositionsOnSIS;
            
            m.loadData('L1_SS_O2LSD_section.mat');
            m.steadyStateScatterInO2LSD;
            
            %transient scatter
            m.loadData('L1_ADS25W_O2_MA120_section.mat');
            
            %show sample transient data on 03/29/2017
            m.chanViewer('BRDF*ITMX_PD+BEAM_POSITION_ETMX','n', m.whichCellInDatHasGPSTime(m.utc2gps('29-Mar-2017')));
            
            %show three transiences that don't reproduce
            m.chanViewer('BRDF*ETMY_PD+BEAM_POSITION_ETMY','n', ...
                [m.whichCellInDatHasGPSTime(m.utc2gps('03-Mar-2017'))...
                m.whichCellInDatHasGPSTime(m.utc2gps('21-Mar-2017'))...
                m.whichCellInDatHasGPSTime(m.utc2gps('09-Apr-2017'))]);

            m.demoBothBeamPositionsOnSIS;

            for baffle = {'ITMX','ETMX','ITMY','ETMY'}
                bf = baffle{1};
                m.transientScatterViewer(bf, 's');
                m.transientScatterViewer(bf, 'a');
            end
            
            %regression on LSD
            m.numberOfTerms;
            
            m.loadData('L1_ADS25W_O2LSD_MA120_section.mat');
            m.testModelSigmaWithNumOfTrainedData;
            
            %regression on all O2
            m.loadData('L1_ADS25W_O2_MA120_section.mat');
            m.testModelSigmaWithNumOfTrainedData;
            
            %O3 scatter
            m.runSIS('arm','X', 'ETMdat','O3');
            m.runSIS('arm','Y', 'ETMdat','O3');
            m.SISViewer('2D');
            m.SISViewer('PD');
        end
        % main function for my SURF project (LIGO-T1800224)

        
        
        %% Toolbox
        
        function loadData(m, datafile)
        %LOADDATA Load data from data file
        %   .loadData(datafile) get datafile in ./O2data/
        %                       supports * alias
            
            datadir = './O2data/';
            files = dir([datadir, datafile]);
            i = 1;
            if(isempty(files))
                error('\n\n No data found with filename ''%s''!!!\n\n', datafile);
                
            elseif(length(files) > 1)
                fprintf('\n More than one data found with filename ''%s'':\n', datafile);
                for j = 1:length(files)
                    fprintf('    %d: %s\n', j, files(j).name);
                end
                fprintf('\n');
                i = input(' Please choose the one by index: ');
                
            end
            eval(['load ./O2data/' files(i).name]);
            m.fileName = files(i).name;
            m.dat = dat; %#ok<CPROPLC>
            m.channelNames = channelNames; %#ok<CPROPLC>
        end
        %load data from datafile in ./O2data/
        
        function saveData(m, dataName)
        %SAVEDATA Save the data in this analyzer to ./O2data/
        %   .save save data with the same name loaded
        %
        %   .saveData(dataName) dataName is the one will be saved
        %
        %   If the data is cell, you can have option to choose
        %   concatenating them to a struct.
            dat = m.dat;
            channelNames = m.channelNames;
            
            if(~exist('dataName')) %#ok<*EXIST>
                dataName = m.fileName;
            end
            
            if(dataName(end-3:end) == '.mat')
                dataName = dataName(1:end-4);
            end
            
            if(contains(dataName, '_section'))
                sid = strfind(dataName, '_section');
                dataName(sid:sid+7) = [];
            end
            
            if(iscell(m.dat))
                eval(['save ./O2data/' dataName '_section.mat dat channelNames']);
                fprintf('\n Channels extracted to ''%s'' succeeded:\n', [dataName '_section.mat']);
                m.printChannels(channelNames);
                d = dat;
                flag = input('Concatenate m.dat to struct? (Y/N): ', 's');
                if(flag == 'Y' || flag == 'y')
                    dat = d{1};
                    for i = 2:length(d)
                        for j = 1:length(dat)
                            dat(j).data = [dat(j).data; d{i}(j).data];
                        end
                    end
                    dat = rmfield(dat,'start');
                    dat = rmfield(dat,'duration');

                    eval(['save ./O2data/' dataName '.mat dat channelNames']);

                    fprintf('\n Channels extracted to ''%s'' succeeded:\n\n', [dataName '.mat']);
                end
                
            else
                eval(['save ./O2data/' dataName '.mat dat channelNames']);
                fprintf('\n Channels extracted to ''%s'' succeeded:\n', [dataName '.mat']);
                m.printChannels(channelNames);

            end

            
        end
        % save data to the dataName.mat
        %if dataName not inputted, then it is the fileName of the object
        
        function extractDataFromSection(m, chanName, dataName)
        %EXTRACTDATAFROMSECTION Extract channels from cell data
        %   .extractDataFromSection(chanName, dataName) 
        %   save channels specified by chanName to a file named dataName
        %   
        %   See also WHICHCHAN
            chans = m.whichChan(chanName)';
            dat = m.dat;
            channelNames = m.channelNames;
            
            if(dataName(end-3:end) == '.mat')
                dataName = dataName(1:end-4);
            end
            
            if(contains(dataName, '_section'))
                sid = strfind(dataName, '_section');
                dataName(sid:sid+7) = [];
            end

            for n = 1:length(dat)

                L = length(m.channelNames);
                for j = L:-1:1
                    if(~ismember(j, chans))
                        dat{n}(j) = [];
                    end
                end
                
            end
            
            for j = L:-1:1
                if(~ismember(j, chans))
                    channelNames(j) = [];
                end

            end
            

            eval(['save ./O2data/' dataName '_section.mat dat channelNames']);
            fprintf('\n Channels extracted to ''%s'' succeeded:\n', [dataName '_section.mat']);
            m.printChannels(channelNames);
            
            flag = input('Concatenate m.dat to struct? (Y/N): ','s');
            if ~(~isempty(flag) && (flag == 'y' || flag == 'Y'))
                return;
            end
            
            
            d = dat;
            
            dat = d{1};
            for i = 2:length(d)
                for j = 1:length(dat)
                    dat(j).data = [dat(j).data; d{i}(j).data];
                end
            end
            dat = rmfield(dat,'start');
            dat = rmfield(dat,'duration');
            
            eval(['save ./O2data/' dataName '.mat dat channelNames']);
            
            fprintf('\n Channels extracted to ''%s'' succeeded:\n\n', [dataName '.mat']);
            
        end
        % extract data channel from cells of m.dat to a cell or struct mat 
        
        function unionDataFile(m, varargin)
        %UNIONDATAFILE Union two datafiles and save it to one
        %Prerequisite: the data at the same channel must be the same
        %   .unionDataFile('file1','name')
        %   union data from the data in this analyzer with 'file1.mat' and
        %   save it in 'name.mat'
        %
        %   .unionDataFile('file1','file2','name')
        %   union data from 'file1.mat' and 'file2.mat' and save it to
        %   'name.mat'
        
            if(length(varargin) == 2)
                name2 = [varargin{1} '.mat'];
                eval(['load ./O2data/' varargin{1} '.mat']);
                dat1 = m.dat;
                channelNames1 = m.channelNames;
                name1 = m.fileName;
            elseif(length(varargin) == 3)
                eval(['load ./O2data/' varargin{1} '.mat']);
                dat1 = dat;  %#ok<NODEF>
                channelNames1 = channelNames;  %#ok<NODEF>
                name1 = [varargin{1} '.mat'];
                eval(['load ./O2data/' varargin{2} '.mat']);
                name2 = [varargin{2} '.mat'];
            end
                
            exChan = [];
            for i = 1:length(channelNames1)
                if(~contains(channelNames1{i}, channelNames)) 
                    exChan = [exChan i];
                end
            end
            
            channelNames = [channelNames; channelNames1(exChan)];
            
            if(isstruct(dat))
                dat = [dat dat1(exChan)];
            else
                for n = 1:length(m.dat)
                    dat{n} = [dat{n} dat1{n}(exChan)];
                end
            end
                
            eval(['save ./O2data/' varargin{end} '.mat dat channelNames']);
            fprintf('\n Union of ''%s'' and ''%s'' succeeded:\n\n', name1, name2);
            m.printChannels(channelNames);
        end
        % union two data files (note the length of them should be the same)
        
        function printChannels(m, channelNames)
        % PRINTCHANNELS Print channels
        %   .printChannels
        %   print channels loaded to this analyzer
        %
        %   .printChannels(channelNames)
        %   print channelNames in a neat format
            switch nargin
                case 1
                    for i = 1:length(m.channelNames)
                        fprintf('    %s\n', m.channelNames{i});
                    end
                    fprintf('\n\n');
                case 2
                    for i = 1:length(channelNames)
                        fprintf('    %s\n', channelNames{i});
                    end
                    fprintf('\n\n');
            end
        end
        %print out m.channelNames
        
        function chanNum = whichChan(m, name)
        %WHICHCHAN Returns the index of channels specified by name
        %   .whichChan(name) 
        %   returns 1-D vector of channel indices specified by name.
        %   smart search is used with the help of these symbols:
        %   *: use * for alias
        %   +: use + to union signal channels
        %   E.g.: 
        %   'PD_1' return all channels whose name contains 'PD_1'
        %   'ITMX*PD_1' union channels with name 'ITMX' and 'PD_1'
        %   'ITMX*PD_1+ITMX*PD_2' union channels of 'ITMX*PD_1' and
        %   'ITMX*PD_2'
            if(isempty(m.channelNames))
                error('\n\n No channel names loaded!!!\n\n');
                
            end
            chanNum = [];

            plusloc = strfind(name, '+');
            wordsWithAsterisk = cell(1, length(plusloc)+1);

            %divide name to many words with asterisk in it
            in = [0, plusloc, length(name)+1];
            if(isempty(plusloc))
                wordsWithAsterisk{1} = name;
            else
                for j = 1:length(plusloc)+1
                    wordsWithAsterisk{j} = name((in(j)+1):(in(j+1)-1));
                end
            end

            %find each one of wordsWithAsterisk and divide it to many words based on *
            words = cell(1, length(wordsWithAsterisk));

            for i = 1:length(wordsWithAsterisk)
                starloc = strfind(wordsWithAsterisk{i}, '*');
                in = [0, starloc, length(wordsWithAsterisk{i})+1];
                if(isempty(starloc))
                    words{i}{1} = wordsWithAsterisk{i};
                else
                    words{i} = cell(1,length(starloc)+1);
                    for j = 1:length(starloc)+1
                        words{i}{j} = wordsWithAsterisk{i}((in(j)+1):(in(j+1)-1));
                    end
                end
            end

            %find corresponding channel number in words
            for k = 1:length(words)
                for j = 1:length(words{k})
                    tempChanNum{k}{j} = []; 
                    for i = 1:length(m.channelNames)
                       if(~isempty(strfind(m.channelNames{i}, words{k}{j})))
                           tempChanNum{k}{j} = [tempChanNum{k}{j}, i];
                       end
                    end            
                end
            end

            %find intersections of each vector in tempChanNum
            % (this can be done in previous loop, but I seperate for the sake of
            % clarity)
            for k = 1:length(tempChanNum)
                if(length(tempChanNum{k}) > 1)
                    for j = 2:length(tempChanNum{k})
                        tempChanNum{k}{1} = intersect(tempChanNum{k}{1}, tempChanNum{k}{j});
                    end
                end
                chanNum = sort(union(chanNum, tempChanNum{k}{1}));
            end

            if(isempty(chanNum))
                fprintf('\n No such channel with name: ''%s''!!!\n', name);
                return
        %     elseif(length(chanNum) ~= 1)
        %         fprintf('\n');
        %         fprintf('The channel name: ''%s'' refers to more than one channel\n', name);
        %         chanNum = -1;
        %         return

            end
        end
        % returns indices of ‘channels’ specified by ‘name’ 
             
        function timeUnit = getTimeUnit(m, rate) %#ok<*INUSL>
        %GETTIMEUNIT Get the char array of the time unit
        %   timeUnit = .getTimeUnit(rate)
        %   return the char array ('second','month'...) of double rate
            switch round(1/rate)
                case 1
                    timeUnit = 'second';
                case 60
                    timeUnit = 'minute';
                case 3600
                    timeUnit = 'hour';
                case 86400
                    timeUnit = 'day';
                otherwise
                    fprintf('\n Unit incorrect! \n\n');
                    timeUnit = [];
            end
        end
        %get time unit for the data
          
        function [me, sd] = getMeanSD(m, data, index)
        %GETMEANSD Get the mean and standard deviation with correct sig fig
        %   [m,sd] = .getMeanSD(data)
        %   get mean and sd from array data with correct sig fig
        %   
        %   [m,sd] = .getMeanSD(data, index)
        %   get mean and sd from array data(index) with correct sig fig
            switch nargin
                case 2
                    sd = round(std(data),1,'significant');
                    if(sd > 0)
                        me = round(mean(data)/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    else
                        me = mean(data);
                    end

                case 3
                    sd = round(std(data(index)),1,'significant');
                    if(sd > 0)
                        me = round(mean(data(index))/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    else
                        me = mean(data(index));
                    end

                otherwise
                    fprintf('\n\n Wrong number of inputa!! \n');
            end

        end
        % find mean and standard deviation of ‘data’ vector and round it 
        %with correct sig figs (sd only has 1 sig fig and limits mean’s precision). 
        % If index is provided, it will find mean&sd from ‘data(index)’

        function time = gps2utc(m, t, precisionOrts, te)
        %GPS2UTC Convert GPS time arrays to UTC time char arrays
        %   time = .gps2utc(t)
        %   Convert GPS time array t to time in a format: 14-Sep-2015 09:50
        %
        %   time = .gps2utc(t, 'format')
        %   Convert GPS time array t to time in a format specified
        %   'format' could be 'year','month','day','hour','minute','second'
        %
        %   time = .gps2utc(t, ts, te)
        %   Convert GPS time array t to time in a format based on start
        %   time ts and end time te (all in seconds!!!)
            temp = datestr(datetime('01-Jan-2016 00:00:00')+seconds(t-1135641617));
            [row, col] = size(temp); 
            switch nargin
                case 2
                    if row == 1
                        time = temp(1, 1:11);
                    else
                        for i = 1:row
                            time{i} = ['\begin{tabular}{c} ' temp(i, 1:11) ' \\ ' temp(i, 12:17) '\end{tabular}']; 
                        end
                    end
                case 3
                    precision = precisionOrts;
                    for i = 1:row
                        switch precision
                            case 'year'
                                time{i} = temp(i, 8:11); %#ok<*AGROW>
                            case 'month'
                                time{i} = ['\begin{tabular}{c} ' temp(i, 4:6) ' \\ ' temp(i, 8:11) '\end{tabular}'];
                            case 'day'
                                time{i} = ['\begin{tabular}{c} ' temp(i, 1:6) ' \\ ' temp(i, 8:11) '\end{tabular}'];
                            case 'hour'
                                time{i} = temp(i, 13:end);
                            case 'minute'
                                time{i} = temp(i, 1:17);
                            case 'second'
                                time{i} = temp(i, 13:end);
                            otherwise
                                error('\n\n Wrong input arguments!!!\n');
                        end
                    end
                case 4
                    ts = precisionOrts;
                    delta = (te-ts)/10;
                    if(delta > 3600*24*365)
                        precision = 'year';
                    elseif(delta > 3600*24*30)
                        precision = 'month';
                    elseif(delta > 3600*24)
                        precision = 'day';
                    elseif(delta > 3600)
                        precision = 'hour';
                    elseif(delta > 60)
                        precision = 'minute';
                    else
                        precision = 'second';
                    end
                    for i = 1:row
                    switch precision
                            case 'year'
                                time{i} = temp(i, 8:11);
                            case 'month'
                                time{i} = temp(i, 4:11);
                            case 'day'
                                time{i} = temp(i, 1:11);
                            case 'hour'
                                time{i} = [temp(i, 1:11) '\newline' temp(i, 12:14)];
                            case 'minute'
                                time{i} = [temp(i, 1:11) '\newline' temp(i, 12:17)];
                            case 'second'
                                time{i} = [temp(i, 1:11) '\newline' temp(i, 12:end)];

                    end
                    end

            end
        end
        % convert gps time ‘t’ to utc time
        % if precision (‘year’ to ‘second’) is given, then ‘time’ output is 
        %in that scale
        % if te is provided, then the the precision is automatically found 
        %by te - precisionOrts

        function time = utc2gps(m, t)% 14-Sep-2015 09:50:45
        %UTC2GPS Convert one UTC char array t to GPS time
        %   time = .utc2gps('14-Sep-2015')
        %   Convert UTC time 14-Sep-2015 00:00:00 to GPS time
        %
        %   time = .utc2gps('14-Sep-2015 09')
        %   Convert UTC time 14-Sep-2015 09:00:00 to GPS time. Always have
        %   00 trailed

            if(length(t) == 11)
                t = [t ' 00:00:00'];
            elseif(length(t) == 14)
                t = [t ':00:00'];
            elseif(length(t) == 17)
                t = [t ':00'];
            elseif(length(t) ~= 20)
                error('UTC time format should be like 14-Sep-2015 (09:50:45) !!!');
                
            end
            try
                time = seconds(datetime(t) - datetime('01-Jan-2016 00:00:00')) + 1135641617;
            catch
                error('UTC time format should be like 14-Sep-2015 (09:50:45) !!!');

            end
        end
        % convert utc time ‘t’ to gps time

        function alpha = getTransparentAlpha(m, img, color)
        %GETTRANSPARENTALPHA Returns alpha array that is transparent if the
        %(i,j) pixel has [r g b] == ‘color’
        %   alpha = .getTransparentAlpha(img, color)
        %   Make alpha(i,j) = 0 if img(i,j) has color [r g b] = color
            
            [w,l,d] = size(img); %#ok<*ASGLU>
            alpha = ones(w,l)*255;
            for i = 1:w
                for j = 1:l
                    if(all([img(i,j,1) img(i,j,2) img(i,j,3)] == color))
                        alpha(i,j) = 0;
                    end
                end
            end
            alpha = uint8(alpha);
        end
        % make the (i, j) pixel in ‘img’ that has [r g b] == ‘color’ transparent 
        %(the corresponding alpha(i, j) = 0)
        
        function makeImgColorTransparent(m,filename,color) 
        %MAKEIMGCOLORTRANSPARENT Load image and make its color transparent
        %   .makeImgColorTransparent(filename,color)
        %   load the image from filename and convert its color to
        %   transparent (alpha = 0), and save it
        %   Modify the condition to set color range and customize
        
            [img, map, alphachannel] = imread(filename);
            [w,l,d] = size(img); %#ok<*ASGLU>
            alpha = ones(w,l)*255;
            for i = 1:w
                for j = 1:l
                    if(all([img(i,j,1) img(i,j,2) img(i,j,3)] == color))
                    %if(sum([img(i,j,1) img(i,j,2) img(i,j,3)]) >= 700)
                    %if(img(i,j,1) > 230 && img(i,j,2) > 230 && img(i,j,3) > 230)
                        img(i,j,1) = 255;
                        img(i,j,2) = 255;
                        img(i,j,3) = 255;
                        alpha(i,j) = 0;
                    end
                end
            end
            alpha = uint8(alpha);
            
            figure
            %image(img, 'AlphaData', m.getTransparentAlpha(img, [255 255 255]));
            image(img, 'AlphaData', alpha);
            %imwrite(img, [filename(1:end-3) 'png'], 'png','Alpha',alpha);
            imwrite(img, ['hat_a' 'png'], 'png','Alpha',alpha);
        end
        % make loaded image transparent at certain color and save it
        
        function out = addChar(m, str, char1, char2)
        %ADDCHAR Add char2 in front of each char1 in str
        %   out = .addChar(str, char1, char2)
        %   find location of ‘char1’ in the ‘str’ and add ‘char2’ in front of each 
        %   ‘char1’ in ‘str’ and output as ‘out’
        %   Very useful in latex formatting when you need to add \ before _
            if(~ischar(char1) || ~ischar(char2))
                fprintf('\n\n Input character array!!! \n\n');
            end
            if(iscell(str))
                str = str{1};
            end
            loc = strfind(str, char1);
            loc = [1 loc length(str)+1];
            out = [];
            for i = 1:length(loc)-1
                out = [out str(loc(i):loc(i+1)-1)];
                if(i < length(loc)-1)
                    out = [out char2];
                end
            end
        end
        % find location of ‘char1’ in the ‘str’ and add ‘char2’ in front of each 
        %‘char1’ in ‘str’ and output as ‘out’
        
        function out = biliInterp(m,X,Y,Z,x,y)
        %BILIINTERP Bilinear interpolation of value (x,y) in Z(X,Y)
        %   out = .biliInterp(X,Y,Z,x,y)
        %   find bilinear interpolation of the (x,y) in the function Z(X,Y)
        %   X,Y are vectors and Z is a 2D array
            imin = 1;
            imax = length(X);
            i = ceil((imin+imax)/2);
            while(imax-imin > 1)
                if(x < X(i))
                    imax = i;
                    i = ceil((imin+imax)/2);
                elseif(x > X(i))
                    imin = i;
                    i = ceil((imin+imax)/2);
                else
                    if(i == 1)
                        imax = i+1;
                        imin = i;
                    else
                        imax = i;
                        imin = i-1;
                    end
                end
            end
            if(X(imax) < x || X(imin) > x)
                error('\n\n x goes out of bound!!!\n\n');
                
            else
                xmin = X(imin);
                xmax = X(imax);
            end

            jmin = 1;
            jmax = length(Y);
            j = ceil((jmin+jmax)/2);
            while(jmax-jmin > 1)
                if(y < Y(j))
                    jmax = j;
                    j = ceil((jmin+jmax)/2);
                elseif(y > Y(j))
                    jmin = j;
                    j = ceil((jmin+jmax)/2);
                else
                    if(j == 1)
                        jmax = j+1;
                        jmin = j;
                    else
                        jmax = j;
                        jmin = j-1;
                    end
                end
            end
            if(Y(jmax) < y || Y(jmin) > y)
                error('\n\n y goes out of bound!!!\n\n');
                
            else
                ymin = Y(jmin);
                ymax = Y(jmax);
            end

            out = [xmax-x x-xmin]*[Z(jmin, imin), Z(jmax, imin); Z(jmin, imax), Z(jmax,imax)]*[ymax-y;y-ymin]...
                /((xmax-xmin)*(ymax-ymin));

        end
        % find bilinear interpolation of the (x,y) in the function Z(X,Y)
                
        function pos = plotboxpos(m, h)
        %PLOTBOXPOS Returns the position of the plotted axis region
        %
        % pos = .plotboxpos(h)
        %
        % This function returns the position of the plotted region of an axis,
        % which may differ from the actual axis position, depending on the axis
        % limits, data aspect ratio, and plot box aspect ratio.  The position is
        % returned in the same units as the those used to define the axis itself.
        % This function can only be used for a 2D plot.  
        %
        % Input variables:
        %
        %   h:      axis handle of a 2D axis (if ommitted, current axis is used).
        %
        % Output variables:
        %
        %   pos:    four-element position vector, in same units as h

        % Copyright 2010 Kelly Kearney

            % Check input

            if nargin < 1
                h = gca;
            end

            if ~ishandle(h) || ~strcmp(get(h,'type'), 'axes')
                error('Input must be an axis handle');
            end

            % Get position of axis in pixels

            currunit = get(h, 'units');
            set(h, 'units', 'pixels');
            axisPos = get(h, 'Position');
            set(h, 'Units', currunit);

            % Calculate box position based axis limits and aspect ratios

            darismanual  = strcmpi(get(h, 'DataAspectRatioMode'),    'manual');
            pbarismanual = strcmpi(get(h, 'PlotBoxAspectRatioMode'), 'manual');

            if ~darismanual && ~pbarismanual

                pos = axisPos;

            else

                xlim = get(h, 'XLim');
                ylim = get(h, 'YLim');

                % Deal with axis limits auto-set via Inf/-Inf use

                if any(isinf([xlim ylim]))
                    hc = get(h, 'Children');
                    hc(~arrayfun( @(h) isprop(h, 'XData' ) & isprop(h, 'YData' ), hc)) = [];
                    xdata = get(hc, 'XData');
                    if iscell(xdata)
                        xdata = cellfun(@(x) x(:), xdata, 'uni', 0);
                        xdata = cat(1, xdata{:});
                    end
                    ydata = get(hc, 'YData');
                    if iscell(ydata)
                        ydata = cellfun(@(x) x(:), ydata, 'uni', 0);
                        ydata = cat(1, ydata{:});
                    end
                    isplotted = ~isinf(xdata) & ~isnan(xdata) & ...
                                ~isinf(ydata) & ~isnan(ydata);
                    xdata = xdata(isplotted);
                    ydata = ydata(isplotted);
                    if isempty(xdata)
                        xdata = [0 1];
                    end
                    if isempty(ydata)
                        ydata = [0 1];
                    end
                    if isinf(xlim(1))
                        xlim(1) = min(xdata);
                    end
                    if isinf(xlim(2))
                        xlim(2) = max(xdata);
                    end
                    if isinf(ylim(1))
                        ylim(1) = min(ydata);
                    end
                    if isinf(ylim(2))
                        ylim(2) = max(ydata);
                    end
                end

                dx = diff(xlim);
                dy = diff(ylim);
                dar = get(h, 'DataAspectRatio');
                pbar = get(h, 'PlotBoxAspectRatio');

                limDarRatio = (dx/dar(1))/(dy/dar(2));
                pbarRatio = pbar(1)/pbar(2);
                axisRatio = axisPos(3)/axisPos(4);

                if darismanual
                    if limDarRatio > axisRatio
                        pos(1) = axisPos(1);
                        pos(3) = axisPos(3);
                        pos(4) = axisPos(3)/limDarRatio;
                        pos(2) = (axisPos(4) - pos(4))/2 + axisPos(2);
                    else
                        pos(2) = axisPos(2);
                        pos(4) = axisPos(4);
                        pos(3) = axisPos(4) * limDarRatio;
                        pos(1) = (axisPos(3) - pos(3))/2 + axisPos(1);
                    end
                elseif pbarismanual
                    if pbarRatio > axisRatio
                        pos(1) = axisPos(1);
                        pos(3) = axisPos(3);
                        pos(4) = axisPos(3)/pbarRatio;
                        pos(2) = (axisPos(4) - pos(4))/2 + axisPos(2);
                    else
                        pos(2) = axisPos(2);
                        pos(4) = axisPos(4);
                        pos(3) = axisPos(4) * pbarRatio;
                        pos(1) = (axisPos(3) - pos(3))/2 + axisPos(1);
                    end
                end
            end

            % Convert plot box position to the units used by the axis

            hparent = get(h, 'parent');
            hfig = ancestor(hparent, 'figure'); % in case in panel or similar
            currax = get(hfig, 'currentaxes');

            temp = axes('Units', 'Pixels', 'Position', pos, 'Visible', 'off', 'parent', hparent);
            set(temp, 'Units', currunit);
            pos = get(temp, 'position');
            delete(temp);

            set(hfig, 'currentaxes', currax);
        end
        %PLOTBOXPOS Returns the position of the plotted axis region
        % Copyright 2010 Kelly Kearney
                
        function id = argHas(m, key, input)
        %ARGHAS Return the index of the char key in cell array input(varargin)
        %   id = .argHas(key, input)
        %   return the index id of the key in cell array input(varargin)
        %   id = 0 if ~contains(key, input)
        %   Usually used to check varargin:
        %     if(m.argHas('key', varargin))
        %         key = varargin{m.argHas('key', varargin)+1};
        %     end
            id = 0;
            for i = 1:length(input)
                if(isequal(key, input{i}) && ischar(input{i}))
                    id = i;
                    return
                end
            end
            
        end
        % check if varargin has key and return the index of it. Otherwise
        % it returns 0
         
        function num = whichCellInDatHasGPSTime(m,time)
        %WHICHCELLINDATHASGPSTIME Find the first cell in .dat that has
        %the start > GPS time
        %PREREQUISITE: cell data loaded
        %
        %   num = .whichCellInDatHasGPSTime(time)
        %   return first cell number num that has the start > GPS time
            for i = 1:length(m.dat)
                %if(m.dat{i}(1).start <= time && m.dat{i}(1).start+m.dat{i}(1).duration >= time)
                if(m.dat{i}(1).start >= time)
                num = i;
                return
                end
            end
        end
        % return the number of cell in m.dat that has such GPS time point
        
        function out = countInteractionTerms(m,k,p)
        %COUNTINTERACTIONTERMS Count interactions terms in p-dimensional
        %polynomials that has total order <= k (Yang Hui's triangle)
        %   out = .countInteractionTerms(k,p)
        %   return counts out from vector k and p
            order = k;
            for i = 1:length(order)
                N = 1; %intercept term
                for k = 1:order(i)
                    for j = 1:min(p,k)
                        N = N + nchoosek(k-1,j-1)*nchoosek(p,j);
                    end
                
                end
                out(i) = N;
            end
        end
        %Count interactions terms in p-dimensional
        %polynomials that has total order < k (Pascal triangle)
        
        function R = Rmn(m, rho, m_in, n_in)
        %RMN Get the radial polynomial Rmn(rho) given the integer m, n and
        %vector rho
        %   R = .Rmn(rho, m, n)
        %   Return the function Rmn(rho) that has equal length of rho
            m = m_in;
            n = n_in;
            if(~(floor(m) == m && m >= 0))
                error('\n\n m is not nonpositive integer\n\n');
            end
            if(~(floor(n) == n && n >= 0))
                error('\n\n n is not nonpositive integer\n\n');
            end
            if(n < m)
                error('\n\n n must be >= m\n\n');
            end
            if(mod(n-m, 2))
                error('\n\n n-m must be even\n\n');
            end
            if(max(max(rho)) > 1 || min(min(rho)) < 0)
                error('\n\n rho must be [0,1] \n\n');
            end
            [row, col] = size(rho);
            R = zeros(row, col);
            for i = 1:row
                for j = 1:col
                    for k = 0:1:(n-m)/2
                        R(i,j) = R(i,j)+ ((-1)^k*factorial(n-k))*rho(i,j)^(n-2*k)/...
                            (factorial(k)*factorial((n+m)/2-k)*factorial((n-m)/2-k));
                    end
                end
            end


        end
        %Get Radial polynomial Rmn(rho) for Zernike
        
        function Z = Zmn(m, m_in, n_in, rho_in, phi_in)
        %ZMN Get the Zernike polynomial Zmn(rho, phi) given the integer m,n
        %and vector rho, phi. The result is plotted as well
        %   Z = .Zmn(m_in, n_in, rho_in, phi_in)
        %   Return the 2D array Zmn(rho, phi)
        
            m = m_in;
            n = n_in;
            if(min(rho_in) ~= 0)
                error('\\n\n vector ''rho'' must start from 0!!!\n\n');
            end
            rho = rho_in;
            if(nargin == 4)
                phi = phi_in;
            else
                phi = 0:(2*pi/(length(rho)-1)):2*pi;
            end
            %normalize rho
            Rho = max(rho);
            rho = rho/Rho;
            [rho, phi] = meshgrid(rho, phi);
            if(m < 0)
                Z = Rho*Rmn(rho, -m, n).*sin(m*phi);
            else
                Z = Rho*Rmn(rho, m, n).*cos(m*phi);
            end

            figure
            surf(rho.*cos(phi) , rho.*sin(phi) , Z ,'edgecolor','none')
            colormap('jet')
            caxis([min(min(Z)) max(max(Z))]);

        %     xlim([min(currx(indx1)) max(currx(indx1))]);
        %     ylim([min(curry(indy1)) max(curry(indy1))]);
        %     xlabel('mm')
        %     ylabel('mm')
        %     title('PD1: map');
            c = colorbar;
        %     c.Label.String = 'dB';
            c.TickLabelInterpreter = 'latex';
            c.Label.Interpreter = 'latex';
            box on

            view([0 90]);


        end
        %Get Zernike polynomial Zmn(rho, phi)
        
        function [duration, startTime] = getTimeMoreThanDurations(m, indices, time)%sec
        %GETTIMEMORETHANDURATIONS Get the start time (GPS) and durations
        %from input indices
        %   [duration, startTime] = .getTimeMoreThanDurations(indices)
        %   Given the logical indices of the .dat, find the startTime and
        %   duration of each consecutive 1111 in indices
        %
        %   [duration, startTime] = .getTimeMoreThanDurations(indices, time)
        %   Find the startTime and duration of each consecutive 1111 in
        %   indices that are longer than time (in seconds!!!)

            if(isempty(m.dat))
                error('\n\n No data loaded!!!\n\n');
            end
            
            L = length(indices);
            duration = [];
            startIndex = [];

            switch nargin
                case 2
                    i = 1;
                    while(i <= L)
                        if(indices(i))
                            i0 = i;
                            count = 1;
                            i = i+1;

                            while(i <= L && indices(i))
                                count = count+1;
                                i = i+1;
                            end
                            duration = [duration count]; 
                            startIndex = [startIndex, i0]; 
                        end
                        i = i+1;
                    end
                case 3
                    i = 1;
                    while(i <= L)
                        if(indices(i))
                            i0 = i;
                            count = 1;
                            i = i+1;

                            while(i <= L && indices(i))
                                count = count+1;
                                i = i+1;
                            end
                            if(count*round(1/m.dat(1).rate) >= time)
                                startIndex = [startIndex, i0]; 
                                duration = [duration count]; 
                            end
                        end
                        i = i+1;
                    end
                otherwise
                    fprintf('\n\n Not enough input arguments!!! \n');
            end
            duration = duration*round(1/m.dat(1).rate);
            t = 0:round(1/m.dat(1).rate):m.dat(1).duration-round(1/m.dat(1).rate);
            t = t + m.dat(1).start;
            startTime = t(startIndex);
        end
        % get length (time in seconds) of consecutive 1’s in ‘indices’
        % if ‘time’ is given, then the function only returns 
        %durations > ‘time’ (always in seconds)
        
        function T = getMAFilterTime(m, data)
        %GETMAFILTERTIME Get the automatic time for MA filtering on
        %data(NOT READY)
        %   Not ready yet (Welcome to write by yourself)
            toPlot = true;
            
%             if(iscell(m.dat))
%                 Fs = (m.dat{1}(1).rate);
%             elseif(isstruct(m.at))
%                 Fs = (m.dat(1).rate);
%             else
%                 fprintf('\n\n No data loaded!!!\n\n');
%                 return
%             end
            Fs = 1;
            
            Y = fft(data);
            L = length(data);
            P2 = abs(Y/L);
            P1 = P2(1:L/2+1);
            P1(2:end-1) = 2*P1(2:end-1);
            f = Fs*(0:(L/2))/L;
            if(toPlot)
                figure
                plot(f,P1)
                title('Single-Sided Amplitude Spectrum of X(t)')
                xlabel('$f$ (Hz)')
                ylabel('$|P1(f)|$')
                grid on
            end
            
            
            T = floor((2)/f(P1 == max(P1(f>0.0075))));
            
            
        end
        % needs to be modified to find correct time automatically
               
        function getDriveAlignComboDurations(m, logicIndex)
        %GETDRIVEALIGNCOMBODURATIONS Get unique drivealign combos and beam
        %positions from .dat for steady-state analysis
        %PREREQUISITE: O2 data loaded
        %
        %   .getDriveAlignComboDurations
        %   Go through each *TM*_DRIVEALIGN_P/Y2L and print out a nice
        %   summary table
        %
        %   .getDriveAlignComboDurations(logicIndex)
        %   PREREQUISITE: struct data loaded
        %   Apply logicIndex to m.dat
        
            %     stableIndices = m.searchStableIndex(name, transientTime); %input time in seconds
            %     stableIndex = stableIndices.index{1};
            %     for i = 2:length(stableIndices.index)
            %         stableIndex = stableIndex&(stableIndices.index{i});
            %     end
            %     stableIndex = m.removeTransienceFromIndex(stableIndex, transientTime);
            
            if(isempty(m.dat))
                error('\n\n No data loaded!!!\n\n');
            end
            
            ITMXYawChan = m.whichChan('SUS-ITMX_L2_DRIVEALIGN_Y2L_GAIN');
            ETMXYawChan = m.whichChan('SUS-ETMX_L2_DRIVEALIGN_Y2L_GAIN');
            ITMYYawChan = m.whichChan('SUS-ITMY_L2_DRIVEALIGN_Y2L_GAIN');
            ETMYYawChan = m.whichChan('SUS-ETMY_L2_DRIVEALIGN_Y2L_GAIN');
            ITMXPitchchan = m.whichChan('SUS-ITMX_L2_DRIVEALIGN_P2L_GAIN');
            ETMXPitchchan = m.whichChan('SUS-ETMX_L2_DRIVEALIGN_P2L_GAIN');
            ITMYPitchchan = m.whichChan('SUS-ITMY_L2_DRIVEALIGN_P2L_GAIN');
            ETMYPitchchan = m.whichChan('SUS-ETMY_L2_DRIVEALIGN_P2L_GAIN');
            
            ITMXxCh = m.whichChan('BEAM_POSITION_ITMX_x');
            ITMXyCh = m.whichChan('BEAM_POSITION_ITMX_y');
            ETMXxCh = m.whichChan('BEAM_POSITION_ETMX_x');
            ETMXyCh = m.whichChan('BEAM_POSITION_ETMX_y');
            ITMYxCh = m.whichChan('BEAM_POSITION_ITMY_x');
            ITMYyCh = m.whichChan('BEAM_POSITION_ITMY_y');
            ETMYxCh = m.whichChan('BEAM_POSITION_ETMY_x');
            ETMYyCh = m.whichChan('BEAM_POSITION_ETMY_y');
            
%             fprintf('\n\nDrivealign combinations table:\n\n');
%             fprintf(['              ITMXyaw    ITMXpitch   ETMXyaw   ETMXpitch'...  
%                 '   ITMYyaw   ITMYpitch   ETMYyaw   ETMYpitch\n']);
            
            fprintf('\n\n Beam positions table:\n\n');
            fprintf(['              ITMX_x    ITMX_y   ETMX_x   ETMX_y'...  
                '   ITMY_x   ITMY_y   ETMY_x   ETMY_y\n']);
            
            
            fprintf('--------------------------------------------------------------------------------------\n');
                     
            combo = {};
            
            %prepare for the SIS2DViewer through O2
            pos.ITMX.x = [];
            pos.ITMX.y = [];
            pos.ETMX.x = [];
            pos.ETMX.y = [];
            pos.ITMY.x = [];
            pos.ITMY.y = [];
            pos.ETMY.x = [];
            pos.ETMY.y = [];
            lgd = {};

            if(isstruct(m.dat))
                index = 1:length(logicIndex);
                index = index(logicIndex);

                t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;
                
                cutofftime = [];
                
                for i = 1:length(index)

                    ITMXyaw = m.dat(ITMXYawChan).data(index(i));
                    ETMXyaw = m.dat(ETMXYawChan).data(index(i));
                    ITMYyaw = m.dat(ITMYYawChan).data(index(i));
                    ETMYyaw = m.dat(ETMYYawChan).data(index(i));
                    ITMXpitch = m.dat(ITMXPitchchan).data(index(i));
                    ETMXpitch = m.dat(ETMXPitchchan).data(index(i));
                    ITMYpitch = m.dat(ITMYPitchchan).data(index(i));
                    ETMYpitch = m.dat(ETMYPitchchan).data(index(i));

                    if(isempty(combo) || ...
                        ~all([ITMXyaw, ITMXpitch, ETMXyaw, ETMXpitch, ITMYyaw, ITMYpitch, ETMYyaw, ETMYpitch]== combo{end}))

                        combo = [combo,{[ITMXyaw, ITMXpitch, ETMXyaw, ETMXpitch, ITMYyaw, ITMYpitch, ETMYyaw, ETMYpitch]}];
                        fprintf('%s:   % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f\n',...
                        m.gps2utc(t(index(i))),...
                        ITMXyaw,ITMXpitch,ETMXyaw,ETMXpitch,ITMYyaw,ITMYpitch,ETMYyaw,ETMYpitch);
                        
                        pos.ITMX.x = [pos.ITMX.x m.dat(ITMXxCh).data(index(i))];
                        pos.ITMX.y = [pos.ITMX.y m.dat(ITMXyCh).data(index(i))];
                        pos.ETMX.x = [pos.ETMX.x m.dat(ETMXxCh).data(index(i))];
                        pos.ETMX.y = [pos.ETMX.y m.dat(ETMXyCh).data(index(i))];
                        pos.ITMY.x = [pos.ITMY.x m.dat(ITMYxCh).data(index(i))];
                        pos.ITMY.y = [pos.ITMY.y m.dat(ITMYyCh).data(index(i))];
                        pos.ETMY.x = [pos.ETMY.x m.dat(ETMYxCh).data(index(i))];
                        pos.ETMY.y = [pos.ETMY.y m.dat(ETMYyCh).data(index(i))];
                    
                        cutofftime = [cutofftime t(index(i))];
                        
                        tstart = m.gps2utc(t(index(i)));
                        
                        lgd = [lgd [tstart(4:6) tstart(1:2) '-']];

                    end

                end
            elseif(iscell(m.dat))
                dat = {};
                istart = 1;
                for i = 1:length(m.dat)
                    
                    ITMXyaw = mean(m.dat{i}(ITMXYawChan).data);
                    ETMXyaw = mean(m.dat{i}(ETMXYawChan).data);
                    ITMYyaw = mean(m.dat{i}(ITMYYawChan).data);
                    ETMYyaw = mean(m.dat{i}(ETMYYawChan).data);
                    ITMXpitch = mean(m.dat{i}(ITMXPitchchan).data);
                    ETMXpitch = mean(m.dat{i}(ETMXPitchchan).data);
                    ITMYpitch = mean(m.dat{i}(ITMYPitchchan).data);
                    ETMYpitch = mean(m.dat{i}(ETMYPitchchan).data);
                    
                    if(isempty(combo) || ...
                    ~all([ITMXyaw, ITMXpitch, ETMXyaw, ETMXpitch, ITMYyaw, ITMYpitch, ETMYyaw, ETMYpitch]== combo{end}))
                
                        pos.ITMX.x = [pos.ITMX.x mean(m.dat{i}(ITMXxCh).data)];
                        pos.ITMX.y = [pos.ITMX.y mean(m.dat{i}(ITMXyCh).data)];
                        pos.ETMX.x = [pos.ETMX.x mean(m.dat{i}(ETMXxCh).data)];
                        pos.ETMX.y = [pos.ETMX.y mean(m.dat{i}(ETMXyCh).data)];
                        pos.ITMY.x = [pos.ITMY.x mean(m.dat{i}(ITMYxCh).data)];
                        pos.ITMY.y = [pos.ITMY.y mean(m.dat{i}(ITMYyCh).data)];
                        pos.ETMY.x = [pos.ETMY.x mean(m.dat{i}(ETMYxCh).data)];
                        pos.ETMY.y = [pos.ETMY.y mean(m.dat{i}(ETMYyCh).data)];
                        
                        tstart = m.gps2utc(m.dat{i}(1).start);
                        
                        lgd = [lgd [tstart(4:6) tstart(1:2) '-']];
                        
                        combo = [combo,{[ITMXyaw, ITMXpitch, ETMXyaw, ETMXpitch, ITMYyaw, ITMYpitch, ETMYyaw, ETMYpitch]}];
                        
%                         fprintf('%s:   % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f      % 5.2f\n',...
%                         m.gps2utc(m.dat{i}(1).start),...
%                         ITMXyaw,ITMXpitch,ETMXyaw,ETMXpitch,ITMYyaw,ITMYpitch,ETMYyaw,ETMYpitch);
                        
                        fprintf('%s:  % 5.2f     % 5.2f    % 5.2f    % 5.2f    % 5.2f    % 5.2f    % 5.2f    % 5.2f\n',...
                        m.gps2utc(m.dat{i}(1).start),... 
                        pos.ITMX.x(end),pos.ITMX.y(end),pos.ETMX.x(end),pos.ETMX.y(end),pos.ITMY.x(end),pos.ITMY.y(end),pos.ETMY.x(end),pos.ETMY.y(end));
                    
                        if(i==248)% i == 248 is the section after the end of LSD
                            
                            tend = m.gps2utc(m.dat{i-1}(1).start);
%                             if(m.dat{istart}(1).start > 1169942417)%2/1/17
%                                 temp{1} = m.dat(istart:i-1);
%                                 dat = [dat temp];
%                             end
                            dat = m.dat(istart:i-1);
                            channelNames = m.channelNames;
                            save(['./O2data/O2SS_LSD_section.mat'], 'dat', 'channelNames'); %#ok<*NBRAK>
                        end
                        istart = i;
                    end
                    
                end
                
                
            end
            fprintf('\n\n');
            m.O2SSpos = pos;
            m.O2SSpostime = lgd;
        end
        % get unique drive align parameters combo in the O2 and print out 
        %as a nice table
        % load SS_O2 data
        
        function getPDPowerMapWithBeamPos(m, baffle, currx, curry, PTM)
        %GETPDPOWERMAPWITHBEAMPOS Infer beam positions solely from
        %simulation (SIS). This will be useful if SIS could have better
        %resolution
            PDx = -m.boxSize:m.res:m.boxSize;
            PDy = -m.boxSize:m.res:m.boxSize;
            fprintf('Start radial integration\n')
            PDPowerMap = cell(1,4);
            for p = 1:4
                PDPowerMap{p} = zeros(length(PDx), length(PDy));
                for i = 1:length(PDx)
                    for j = 1:length(PDy)
                        PDPowerMap{p}(i,j) = m.getAvgRadialIntegration(currx, curry, PTM, ...
                            sqrt((m.coord{p}(1)-PDx(i))^2+(m.coord{p}(2)-PDy(j))^2)-m.rPD, m.rPD*2);
                    end
                end
                fprintf('Integration done for PD %d\n', p);
            end
            eval(['m.' baffle '.PDPowerMap = PDPowerMap']);
        end
        % find the PD power distribution if beam position moves by m.boxSize
        % purely infer from SIS, which can't predict mm scale scatter

        
        
        %% Static Interferometer Simulation (SIS)
        
        function clearSIS(m, baffle) 
        %CLEARSIS Clear SIS result stored in .*TM* struct
        %   .clearSIS
        %   clear SIS results from all 4 baffles
        %
        %   .clearSIS(baffle)
        %   clear SIS from baffle like 'ITMX' or {'ITMX','ETMX'}
            if(~exist('baffle')) 
                baffle = {'ITMX','ETMX','ITMY','ETMY'};
            end
            
            
            for baf = baffle
                bf = baf{1};
                eval(['f = fields(m.' bf '.SIS);']);
                for i = 1:numel(f)
                    eval(['m.' bf '.SIS.(f{i}) = [];']);
                end
            end
        end
        % clear m.*TM*.SIS. fields
        
        function runSIS(m, varargin) % distance in m !!!
        %RUNSIS Run Static Interferometer Simulation built by Hiro Yamamoto
        %and store results in .*TM*.SIS.x (in m!!!)and .*TM*.SIS.E structs
        %   .runSIS('arm',arm)
        %   Run FP cavity simulation of arm ('X' or 'Y')
        %
        %   .runSIS('arm',arm, 'ETMdat', 'O3')
        %   Use O3 phasemap for simulation
        %
        %   .runSIS('arm',arm, 'power', power)
        %   Specify power on the ITM
        %
        %   .runSIS('arm',arm, 'Aperture', Aperture)
        %   Set size of test mass (0.326 for realistic or 0.45 for nill)
        %
        %   .runSIS('arm',arm, 'ITMx', ITM_x, 'ITMy',ITM_y)
        %   Set beam position on ITM (in m!!!): (ITM_x,ITM_y). Default are zeros
        %
        %   .runSIS('arm',arm, 'ETMx', ETM_x, 'ETMy',ETM_y)
        %   Set beam position on ETM (in m!!!): (ETM_x,ETM_y). Default are zeros
        %
        %   .runSIS('arm',arm, 'ifo', 'LHO' ...)
        %   Run simulation on LHO arm cavity
        %
        %   See also FPIFOV FFTIFO
        
        
        
            %get Hiro's simulation
            if(m.argHas('arm',varargin))
                arm = varargin{m.argHas('arm',varargin)+1};
            end
            
            if(m.argHas('ITMx',varargin))
                varargin{m.argHas('ITMx',varargin)+1} = -varargin{m.argHas('ITMx',varargin)+1};
            end
            if(m.argHas('ETMx',varargin))
                varargin{m.argHas('ETMx',varargin)+1} = -varargin{m.argHas('ETMx',varargin)+1};
            end
            
            if(arm == 'X')
                [E2ITM, xITM, E2ETM, xETM] = fpscat( varargin{:} );
                m.ITMX.SIS.E = E2ITM;
                m.ITMX.SIS.x = xITM;
                m.ETMX.SIS.E = E2ETM;
                m.ETMX.SIS.x = xETM;
            elseif(arm == 'Y')
                [E2ITM, xITM, E2ETM, xETM] = fpscat( varargin{:} );
                m.ITMY.SIS.E = E2ITM;
                m.ITMY.SIS.x = xITM;
                m.ETMY.SIS.E = E2ETM;
                m.ETMY.SIS.x = xETM;
            else
                error('\n\n No such baffle !!!\n\n');
            end
            m.getSISr2P(varargin{:});
            m.getSISBRDF(varargin{:});
        end
        % Static Interferometer Simulation
        % Copyright 2018 Hiroaki Yamamoto
        
        function getSISr2P(m, varargin)
        %GETSISR2P Get power on PD with respect to radial distance from SIS
        %simulation results
        %PREREQUISITE: SIS simulated (runSIS)
        %
        %   .getSISr2P
        %   Radial integrate SIS results on all baffles (if they have SIS
        %   data
        %
        %   .getSISr2P('arm',arm)
        %   Only integrate on one arm like 'X' (default is 'XY')
        %
        %   .getSISr2P('res',res)
        %   Set integration resolution of radial distance (default is
        %   m.res = 1 [mm]
        %
        %   See also RUNSIS BILIINTERP
        
            if(~isempty(varargin) && m.argHas('res',varargin))
                dr = varargin{m.argHas('res',varargin)+1};
            else
                dr = m.res; %mm
            end
            ds = 5;%mm
            
            if(m.argHas('arm',varargin))
                arm_in = varargin{m.argHas('arm',varargin)+1};
            else
                arm_in = 'XY';
            end
            
            for arm = arm_in
                
                for baffle = {'ITM', 'ETM'}
                    bf = [baffle{1} arm];
                    if(eval(['~isempty(m.' bf '.SIS.E)']))
                        fprintf('Radially integrating %s\n', bf)
                        eval(['x = m.' bf '.SIS.x * 1000;'])% convert to mm
                        y = x;
                        eval(['E = m.' bf '.SIS.E;'])
                        Pdensity = abs(E).^2; % W/m^2
                        Pdensity = Pdensity/10^(6); %convert to W/mm^2
                        %P = P./max(max(P));

                        %find center of profile (x0, y0)
                        [~,xmaxid] = max(max(Pdensity));
                        [~,ymaxid] = max(Pdensity(:, xmaxid));
                        x0 = x(xmaxid);
                        y0 = y(ymaxid);

                        rmax = min(min(max(x)-x0, abs(x0-min(x))) , min(max(y)-y0, abs(y0-min(y))));


    %                     srange = 5:-0.01:0.01;
    %                     for ds = srange
    %                     for r = 200
                        r2Pdensity = [];
                        for r = 0:dr:floor(rmax)
                            if(r == 0)
                                dtheta = 2*pi;
                            else
                                dtheta = ds/r;
                            end
                            poweratr = [];
                            for theta = 0:dtheta:2*pi
                                poweratr = [poweratr, m.biliInterp(x-x0, y-y0, Pdensity, r*cos(theta), r*sin(theta)) ];
                            end

                            r2Pdensity = [r2Pdensity, mean(poweratr)];
                        end


    %                     figure
    %                     plot(srange, r2P./r2P(end))
    %                     hold on
    %                     set(gca, 'XDir','reverse')
    %                     grid on
    %                     xlabel('Arc length (mm)')
    %                     ylabel('Radial integration result difference')
    %                     title(['Integration resolution test at r = ' int2str(r) ' mm.'])

                        % get actual power in W
                        ddr = 0.001; % interpolate the r2Pdensity
                        rrange = 0:ddr:floor(rmax);
                        r2Pdensity = interp1(0:dr:rmax, r2Pdensity, rrange);
                        P_2pir_dr = r2Pdensity.*(2*pi*rrange*ddr);
                        P_2pir_dr(1) = P_2pir_dr(1) + r2Pdensity(1)*pi*ddr^2;
                        %fprintf('Arm power on test mass: %g kW\n', sum(P_2pir_dr(1:round(((m.rTM)-rrange(1))/ddr+1)))/1000);
                        fprintf('Power buildup in FP cavity: %g kW\n', sum(P_2pir_dr)/1000);


                        r2P = [];
                        deltaid = 2*m.rPD/ddr;
                        for r = (m.rPD+rrange(1)):dr:(rrange(end) - m.rPD)
                            startid = round(((r-m.rPD)-rrange(1))/ddr+1);
                            Patr = sum(P_2pir_dr(startid:startid+deltaid));
                            r2P = [r2P (Patr/((r+m.rPD)^2 - (r-m.rPD)^2))*m.rPD^2];



                        end
                        %normalize r2P with arm cavity buildup
                        r2NP = r2P/sum(P_2pir_dr);


                        eval(['m.' bf '.SIS.r =  (m.rPD+rrange(1)):dr:(rrange(end) - m.rPD);'])
                        %eval(['m.' bf '.SIS.r =  rrange;'])
                        eval(['m.' bf '.SIS.r2NPdensity = r2Pdensity/max(r2Pdensity);'])
                        eval(['m.' bf '.SIS.r2P = r2P;'])
                        eval(['m.' bf '.SIS.r2NP = r2NP;'])
                    end
                end
            end
            
        end
        % get 2D SIS profile (P v. r)
        
        function getSISBRDF(m, varargin)
        %GETSISBRDF Get BRDF measured by PD with respect to zenith angle 
        %from SIS results
        %PREREQUISITE: SIS simulated (runSIS) and radial integration done
        %(getSISr2P)
        %
        %   .getSISBRDF
        %   Radial integrate SIS results on all baffles (if they have SIS
        %   data
        %
        %   .getSISBRDF('arm',arm)
        %   Only integrate on one arm like 'X' (default is 'XY')
        %
        %   .getSISBRDF('res',res)
        %   Set integration resolution of radial distance (default is
        %   m.res = 1 [mm]
        %
        %   See also GETSISR2P RUNSIS
            if(~isempty(varargin) && m.argHas('res',varargin))
                dr = varargin{m.argHas('res',varargin)+1};
            else
                dr = m.res; %mm
            end
            ds = 5;%mm
            
            if(m.argHas('arm',varargin))
                arm_in = varargin{m.argHas('arm',varargin)+1};
            else
                arm_in = 'XY';
            end
            
            for arm = arm_in
                
                for baffle = {'ITM', 'ETM'}
                    bf = [baffle{1} arm];

                    %Compute BRDF from power measured on PD (10 mm
                    %averaging)
                    if(eval(['~isempty(m.' bf '.SIS.r) && ~isempty(m.' bf '.SIS.r2NP)']))
                        
                        eval(['R = m.' bf '.SIS.r/1000;']);% m
                        eval(['r2NP = m.' bf '.SIS.r2NP;'])
                        theta = atan(R/m.L_c);
                        omega = pi*(m.rPD/1000)^2./(m.L_c^2 + (R).^2);
                        BRDF = r2NP./omega;
                        
                        eval(['m.' bf '.SIS.theta = theta;'])
                        eval(['m.' bf '.SIS.BRDF = BRDF;'])
                        
                        
                    %Compute BRDF with 1 mm resolution (different from PD read-out)
%                     if(eval(['~isempty(m.' bf '.SIS.x) && ~isempty(m.' bf '.SIS.E)']))
%                         fprintf('Computing BRDF of %s\n', bf)
%                         eval(['x = m.' bf '.SIS.x * 1000;'])% convert to mm
%                         y = x;
%                         eval(['E = m.' bf '.SIS.E;'])
%                         Pdensity = abs(E).^2; % W/m^2
%                         Pdensity = Pdensity/10^(6); %convert to W/mm^2
% 
%                         %find center of profile (x0, y0)
%                         [~,xmaxid] = max(max(Pdensity));
%                         [~,ymaxid] = max(Pdensity(:, xmaxid));
%                         x0 = x(xmaxid);
%                         y0 = y(ymaxid);
% 
%                         rmax = min(min(max(x)-x0, abs(x0-min(x))) , min(max(y)-y0, abs(y0-min(y))));
%                         r2Pdensity = [];
%                         for r = 0:dr:floor(rmax)
%                             if(r == 0)
%                                 dtheta = 2*pi;
%                             else
%                                 dtheta = ds/r;
%                             end
%                             poweratr = [];
%                             for theta = 0:dtheta:2*pi
%                                 poweratr = [poweratr, m.biliInterp(x-x0, y-y0, Pdensity, r*cos(theta), r*sin(theta)) ];
%                             end
% 
%                             r2Pdensity = [r2Pdensity, mean(poweratr)];
%                         end
% 
% 
%     %                     figure
%     %                     plot(srange, r2P./r2P(end))
%     %                     hold on
%     %                     set(gca, 'XDir','reverse')
%     %                     grid on
%     %                     xlabel('Arc length (mm)')
%     %                     ylabel('Radial integration result difference')
%     %                     title(['Integration resolution test at r = ' int2str(r) ' mm.'])
% 
%                         % get actual power in W
%                         ddr = 0.001; % interpolate the r2Pdensity
%                         rrange = 0:ddr:floor(rmax);
%                         r2Pdensity = interp1(0:dr:rmax, r2Pdensity, rrange);
%                         P_2pir_dr = r2Pdensity.*(2*pi*rrange*ddr);
%                         P_2pir_dr(1) = P_2pir_dr(1) + r2Pdensity(1)*pi*ddr^2;
%                         %fprintf('Arm power on test mass: %g kW\n', sum(P_2pir_dr(1:round(((m.rTM)-rrange(1))/ddr+1)))/1000);
%                         %fprintf('Power buildup in FP cavity: %g kW\n', sum(P_2pir_dr)/1000);
% 
%                         theta = atan(rrange/1000/m.L_c);
%                         omega = 2*pi*rrange/1000*ddr/1000./(m.L_c^2 + (rrange/1000).^2);
%                         BRDF = P_2pir_dr./(omega.*sum(P_2pir_dr));
% 
%                         eval(['m.' bf '.SIS.theta = theta;'])
%                         eval(['m.' bf '.SIS.BRDF = BRDF;'])

                    end
                end
            end
            
        end
        % get 2D SIS profile (BRDF v. theta)
        
        
        
        %% Opearating data channel ('MY:WXJ-')
        
        %----Clear channels----
        function clearChan(m, key)
        %CLEARCHAN Clear channels with name key
        %PREREQUISITE: data loaded
        %
        %   .clearChan(key)
        %   Remove channels specified by .whichChan(key)
        %
        %   See also WHICHCHAN
            ch = m.whichChan(key);
            if(iscell(m.dat))
                for i = 1:length(m.dat)
                    m.dat{i}(ch) = [];
                    
                end
            elseif(isstruct(m.dat))
                m.dat(ch) = [];
                
            end
            m.channelNames(ch) = [];
            fprintf('\n Channels after clearing %s:\n\n', key);
            m.printChannels;
        end
        
        %----Moving-average filter----%
        
        function MAfilter(m, keyword, span)  
        %MAFILTER Apply moving-average filter on data and append to .dat
        %PREREQUISITE: data loaded
        %
        %   .MAfilter
        %   Prompted to filter PD and ADS error data with span (in seconds!!!)
        %
        %   .MAfilter(key, span)
        %   MA filter all channels specified by .whichChan(key) with span
        %   (in seconds!!!)
        %
        %   See also WHICHCHAN SMOOTH MAFILTERPDDATA MAFILTERADSDATA
            
            if(isempty(m.dat) || isempty(m.channelNames))
                error('\n\n No data loaded!!\n')
            end
            
            if(nargin == 1)
                span = input('MA filter PD data with span (Enter 1 if not filter): ');
                m.MAfilterPDData(span);

                span = input('MA filter ADS error data with span (Enter 1 if not filter): ');
                m.MAfilterADSData(span);
            else
                chan = m.whichChan(keyword);
                if(iscell(m.dat))
                    span = span/round(1/m.dat{1}(1).rate);
                elseif(isstruct(m.dat))
                    span = span/round(1/m.dat(1).rate);
                end
                
                for i = 1:length(chan)
                   ch = chan(i);
                   chName = m.channelNames{ch};

                   if(iscell(m.dat))
                       for j = 1:length(m.dat)
                           data = smooth(m.dat{j}(ch).data, span);


                           m.dat{j} = [m.dat{j} m.dat{j}(end)];
                           %put data in new channel
                           m.dat{j}(end).data = data(ceil(span/2):floor(end-span/2));
                           m.dat{j}(end).start = m.dat{j}(end).start + ceil(span/2);
                           m.dat{j}(end).duration = length(m.dat{j}(end).data);
                       end
                   elseif(isstruct(m.dat))
                       data = smooth(m.dat(ch).data, span);
                       m.dat = [m.dat m.dat(end)];
                       %put data in new channel
                       m.dat(end).data = data(ceil(span/2):floor(end-span/2));
                       m.dat(end).start = m.dat(end).start + ceil(span/2);
                       m.dat(end).duration = length(m.dat(end).data);

                   end

    %                if(ch < length(m.channelNames))
    %                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch);m.channelNames(ch+1:end)];
    %                else
    %                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch)];
    %                end

                   m.channelNames = [m.channelNames;m.channelNames(end)];
                   m.channelNames{end} = [chName '_MA' int2str(span)];

                end
                
                
                
                
            end
            
            fprintf('\n Channels after moving-average filter:\n\n');
            m.printChannels;
            
        end
        % MA filter these things
        
        function MAfilterPDData(m, span)
        %MAFILTERPDDATA Apply moving-average filter on PD BRDF and append
        %to .dat
        %PREREQUISITE: BRDF data computed
        %
        %   .MAfilterPDData(span)
        %   Prompted to filter PD data with span (in seconds!!!)
        %
        %   See also SMOOTH CALIBBRDF
        
            if(isempty(m.dat) || isempty(m.channelNames))
                error('\n\n No data loaded!!\n')
            end
            if(iscell(m.dat))
                span = span/round(1/m.dat{1}(1).rate);
            elseif(isstruct(m.dat))
                span = span/round(1/m.dat(1).rate);
            end
            
            PDchan = m.whichChan('BRDF');
            
            for i = 1:length(PDchan)
               ch = PDchan(i);
               chName = m.channelNames{ch};
               
               if(iscell(m.dat))
                   for j = 1:length(m.dat)
                       data = smooth(m.dat{j}(ch).data, span);
                       
                       
                       m.dat{j} = [m.dat{j} m.dat{j}(end)];
                       %put data in new channel
                       m.dat{j}(end).data = data(ceil(span/2):floor(end-span/2));
                       m.dat{j}(end).start = m.dat{j}(end).start + ceil(span/2);
                       m.dat{j}(end).duration = length(m.dat{j}(end).data);
                   end
               elseif(isstruct(m.dat))
                   data = smooth(m.dat(ch).data, span);
                   m.dat = [m.dat m.dat(end)];
                   %put data in new channel
                   m.dat(end).data = data(ceil(span/2):floor(end-span/2));
                   m.dat(end).start = m.dat(end).start + ceil(span/2);
                   m.dat(end).duration = length(m.dat(end).data);

               end
             
%                if(ch < length(m.channelNames))
%                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch);m.channelNames(ch+1:end)];
%                else
%                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch)];
%                end

               m.channelNames = [m.channelNames;m.channelNames(end)];
               m.channelNames{end} = [chName '_MA' int2str(span)];

            end
            
            
            
        end
        % MA filter PDdata with with span specified
        
        function MAfilterADSData(m, span)
        %MAFILTERADSDATA Apply moving-average filter on INMON and append
        %to .dat
        %PREREQUISITE: ASC-ADS*DOF_INMON channel loaded
        %
        %   .MAfilterADSData(span)
        %   Prompted to filter INMON error signal with span (in seconds!!!)
        %
        %   See also SMOOTH
        
            if(isempty(m.dat) || isempty(m.channelNames))
                error('\n\n No data loaded!!\n')
            end
            
            if(iscell(m.dat))
                span = span/round(1/m.dat{1}(1).rate);
            elseif(isstruct(m.dat))
                span = span/round(1/m.dat(1).rate);
            end
            
            ADSchan = m.whichChan('ASC-ADS*DOF_INMON');
            
            for i = 1:length(ADSchan)
               ch = ADSchan(i);
               chName = m.channelNames{ch};
               
               if(iscell(m.dat))
                   for j = 1:length(m.dat)
                       data = smooth(m.dat{j}(ch).data, span);
                       
                       
                       m.dat{j} = [m.dat{j} m.dat{j}(end)];
                       %put data in new channel
                       m.dat{j}(end).data = data(ceil(span/2):floor(end-span/2));
                       m.dat{j}(end).start = m.dat{j}(end).start + ceil(span/2);
                       m.dat{j}(end).duration = length(m.dat{j}(end).data);
                   end
               elseif(isstruct(m.dat))
                   data = smooth(m.dat(ch).data, span);
                   m.dat = [m.dat m.dat(end)];
                   %put data in new channel
                   m.dat(end).data = data(ceil(span/2):floor(end-span/2));
                   m.dat(end).start = m.dat(end).start + ceil(span/2);
                   m.dat(end).duration = length(m.dat(end).data);
                   
%                    % change power channel data size
%                    m.dat(pwrchan).data = m.dat(pwrchan).data(ceil(span/2):floor(end-span/2));
%                    m.dat(pwrchan).start = m.dat(pwrchan).start + ceil(span/2);
%                    m.dat(pwrchan).duration = length(m.dat(pwrchan).data);

               end
             
               m.channelNames = [m.channelNames;m.channelNames(end)];
               m.channelNames{end} = [chName '_MA' int2str(span)];

            end
            
                % change power channel data size
%             for j = 1:length(m.dat)
%                m.dat{j}(pwrchan).data = m.dat{j}(pwrchan).data(ceil(span/2):floor(end-span/2));
%                m.dat{j}(pwrchan).start = m.dat{j}(pwrchan).start + ceil(span/2);
%                m.dat{j}(pwrchan).duration = length(m.dat{j}(pwrchan).data);
%             end
            
        end
        % MA filter ADS error with span specified
        
        %----Calibrate beam position----%
        function calibrate(m)
        %CALIBRATE Calibrate data and append to .dat
        %PREREQUISITE: required channels loaded
        %
        %   .calibrate
        %   Calibrate PD VOLTS or POWER channel to power [W] or BRDF and
        %   calibrate DRIVEALIGN and INMON signal to position [mm]
        %
        %   See also CALIBPD CALIBBRDF CALIBDRIVEALIGN CALIBINMON
            
            flag = input('Calibrate PD power (Y/N): ','s');
            if(~isempty(flag) && (flag == 'Y' || flag == 'y'))
                m.calibPD;
            else
                fprintf('Didn''t calibrate PD power\n')
            end
            
            flag = input('Calibrate PD BRDF (Y/N): ','s');
            if(~isempty(flag) && (flag == 'Y' || flag == 'y'))
                m.calibBRDF;
            else
                fprintf('Didn''t calibrate BRDF\n')
            end
            
            flag = input('Calibrate DRIVEALIGN (Y/N): ','s');
            if(~isempty(flag) && (flag == 'Y' || flag == 'y'))
                m.calibDRIVEALIGN;
            else
                fprintf('Didn''t calibrate DRIVEALIGN\n')
            end
            
            flag = input('Calibrate INMON (Y/N): ','s');
            if(~isempty(flag) && (flag == 'Y' || flag == 'y'))
                m.calibINMON;
            else
                fprintf('Didn''t calibrate INMON\n')
            end

            
            fprintf('\n Channels after calibration:\n\n');
            m.printChannels;
        end
        %calibrate these things
        
        function calibPD(m)
        %CALIBPD Calibrate PD channels to W and append to .dat
        %PREREQUISITE: AOS-*BAFFLEPD*VOLTS/POWER channels,
        %LSC-POP_A_LF_OUTPUT channels loaded
        %
        %   .calibPD
        %   Calibrate PD VOLTS or POWER channel to W with formula:
        %   power = (VOLTS-offset)/(responsivity*transimpedence*gain) or
        %   power = (POWER*2-offset)/(responsivity*transimpedence*gain)
            
            for baffle = {'ITMX','ETMX','ITMY','ETMY'}
                bf = baffle{1};
                for pd = 1:4
                    %pch = m.whichChan(['AOS*' bf '_BAFFLEPD_' int2str(pd) '_POWER']);
                    pch = [];
                    vch = m.whichChan(['AOS*' bf '_BAFFLEPD_' int2str(pd) '_VOLTS']);
                    if(~isempty(pch) || ~isempty(vch))
                        if(iscell(m.dat))
                            for i = 1:length(m.dat)            
                                m.dat{i} = [m.dat{i} m.dat{i}(end)];
                                eval(['offset = m.' bf '.PD' int2str(pd) '.off;'])
                                if(~isempty(vch))
                                    m.dat{i}(end).data = (m.dat{i}(vch).data-offset)/(m.responsivity*m.transimpedence*m.PDgain);
                                elseif(~isempty(pch))
                                    m.dat{i}(end).data = (m.dat{i}(pch).data*2-offset)/(m.responsivity*m.transimpedence*m.PDgain);
                                end
                            end
                        elseif(isstruct(m.dat))
                            m.dat = [m.dat m.dat(end)];
                            eval(['offset = m.' bf '.PD' int2str(pd) '.off;'])
                            if(~isempty(vch))
                                m.dat(end).data = (m.dat(vch).data-offset)/(m.responsivity*m.transimpedence*m.PDgain);
                            elseif(~isempty(pch))
                                m.dat(end).data = (m.dat(pch).data*2-offset)/(m.responsivity*m.transimpedence*m.PDgain);
                            end
                        end
                        m.channelNames = [m.channelNames; ['MY:WXJ-PDPOWER_' bf '_PD_' int2str(pd)]];

                    end


                end
            end

        end
        % calibrate beam position from BAFFLEPD_VOLTS (POWER) channels

        function calibBRDF(m)
        %CALIBBRDF Calibrate PD channels to BRdF and append to .dat
        %PREREQUISITE: PD power calibrated
        %
        %   .calibBRDF
        %   Calibrate PD power to BRDF with formula:
        %   BRDF = PD_POWER/(omega*POP_A/2*m.G_c)
        %
        %   See also CALIBPD
            
            pwrch = m.whichChan('POP_A_LF_OUTPUT');
            
            if (isempty(m.whichChan('WXJ-PDPOWER')))
                m.calibPD;
            end
            
            for baffle = {'ITMX','ETMX','ITMY','ETMY'}
                bf = baffle{1};
                for pd = 1:4
                    ch = m.whichChan(['WXJ-PDPOWER_' bf '_PD_' int2str(pd)]);
                    if(~isempty(ch))
                        if(iscell(m.dat))
                            for i = 1:length(m.dat)            
                                    m.dat{i} = [m.dat{i} m.dat{i}(end)];
                                    p_s = m.dat{i}(ch).data;
                                    p_i = (m.dat{i}(pwrch).data/2)*m.G_c;
                                    eval(['omega = m.' bf '.PD' int2str(pd) '.omega;'])
                                    m.dat{i}(end).data = p_s./(p_i*omega);

                            end
                        
                        elseif(isstruct(m.dat))
                            m.dat = [m.dat m.dat(end)];
                            p_s = m.dat(ch).data;
                            p_i = (m.dat(pwrch).data/2)*m.G_c;
                            eval(['omega = m.' bf '.PD' int2str(pd) '.omega;'])
                            m.dat(end).data = p_s./(p_i*omega);
                        end
                        m.channelNames = [m.channelNames; ['MY:WXJ-BRDF_' bf '_PD_' int2str(pd)]];
                        
                    end


                end
            end
                
            
        end
        % calibrate beam position from WXJ-PDPOWER channels
        
        function calibDRIVEALIGN(m)
        %CALIBDRIVEALIGN Calibrate DRIVEALIGN channels and append to .dat
        %PREREQUISITE: SUS-*L2_DRIVEALIGN channels loaded
        %
        %   .calibDRIVEALIGN
        %   Calibrate DRIVEALIGN signal to position [mm] with formula (in mm!!!):
        %   ETM spot (x, y) : (ETM Yaw* Eyaw2x, (Pitch* Epitch2y) + Epitchoffset)
        %   ITM spot (x, y) : (ITM Yaw* Iyaw2x, (Pitch* Ipitch2y) + Ipitchoffset)

            
            bafflelist = {'ITMX','ETMX','ITMY','ETMY'};
            
            
            for baffle = bafflelist
                bf = baffle{1};

                if(~isempty(m.whichChan([bf '*DRIVEALIGN'])))
                    if(iscell(m.dat))

                        for i = 1:length(m.dat)
                            eval(['x = m.' bf '.DRyaw2x * m.dat{i}(m.whichChan(''' bf '*DRIVEALIGN_Y2L'')).data;']);
                            eval(['y = m.' bf '.DRpitch2y * m.dat{i}(m.whichChan(''' bf '*DRIVEALIGN_P2L'')).data+m.' bf '.DRyoff;']);
                            m.dat{i} = [m.dat{i} m.dat{i}(end)];
                            m.dat{i}(end).data = x;

                            m.dat{i} = [m.dat{i} m.dat{i}(end)];
                            m.dat{i}(end).data = y;


                        end
                    elseif(isstruct(m.dat))
                        eval(['x = m.' bf '.DRyaw2x * m.dat(m.whichChan(''' bf '*DRIVEALIGN_Y2L'')).data;']);
                        eval(['y = m.' bf '.DRpitch2y * m.dat(m.whichChan(''' bf '*DRIVEALIGN_P2L'')).data+m.' bf '.DRyoff;']);
                        m.dat = [m.dat m.dat(end)];
                        m.dat(end).data = x;

                        m.dat = [m.dat m.dat(end)];
                        m.dat(end).data = y;
                        
                    end
                    m.channelNames = [m.channelNames;['MY:WXJ-BEAM_POSITION_' bf '_x']];
                    m.channelNames = [m.channelNames;['MY:WXJ-BEAM_POSITION_' bf '_y']];

                end

            end
            
                
            
        end
        % calibrate beam position from DRIVEALIGN channels

        function calibINMON(m) 
        %CALIBINMON Calibrate INMON channels and append to .dat
        %use DRIVERALIGN channel but not calibDRIVEALIGN function
        %PREREQUISITE: SUS-*L2_DRIVEALIGN channels, ASC-ADS_GAIN channel, 
        %ASC-ADS*OSC_CLKGAIN channels, ASC-ADS*DOF_INMON channels loaded
        %
        %   .calibINMON
        %   Calibrate INMON signal to position [mm] with formula (in mm!!!):
        %   ETM_x : INMON*IMyaw2x./(ADS_GAIN.*CLKGAIN) + DRIVEALIGN's x
        %   ETM_y : INMON*IMpitch2y./(ADS_GAIN.*CLKGAIN) + + DRIVEALIGN's y
            
            if(isempty(m.dat) || isempty(m.channelNames))
                error('\n\n No data loaded!!\n')
            end
            
            adschan = m.whichChan('ADS_GAIN');
            
            if(length(adschan) ~= 1)
                error('\n\n Specify correct channel!!!\n');
            end
            
            for baffle = {'ETMX','ETMY'}
                bf = baffle{1};
                
                %yaw to x
                if(bf == 'ETMX')
                    errchan = m.whichChan('YAW3_DOF_INMON');
                    clkchan = m.whichChan('YAW3_OSC_CLKGAIN');
                elseif(bf == 'ETMY')
                    errchan = m.whichChan('YAW4_DOF_INMON');
                    clkchan = m.whichChan('YAW4_OSC_CLKGAIN');
                end
               
                if(iscell(m.dat))
                   for j = 1:length(m.dat)
                       data = m.dat{j}(errchan).data;
                       adsGain = m.dat{j}(adschan).data;
                       clkGain = m.dat{j}(clkchan).data;
                       eval(['x = m.' bf '.DRyaw2x * m.dat{j}(m.whichChan(''' bf '*DRIVEALIGN_Y2L'')).data;']);
                       m.dat{j} = [m.dat{j} m.dat{j}(end)];
                       %put data in new channel
                       eval(['m.dat{j}(end).data = data*m.' bf '.IMyaw2x./(adsGain.*clkGain);']);
                       m.dat{j}(end).data = m.dat{j}(end).data + x;
                   end
                elseif(isstruct(m.dat))
                   data = m.dat(errchan).data;
                   adsGain = m.dat(adschan).data;
                   eval(['x = m.' bf '.DRyaw2x * m.dat(m.whichChan(''' bf '*DRIVEALIGN_Y2L'')).data;']);
                   m.dat = [m.dat m.dat(end)];
                   %put data in new channel
                   eval(['m.dat(end).data = data*m.' bf '.IMyaw2x./(adsGain.*clkGain);']);
                   m.dat(end).data = m.dat(end).data + x;
                end
                m.channelNames = [m.channelNames; ['MY:WXJ-ADS_BEAM_POSITION_' bf '_x']];

                
                %pitch to y
                if(bf == 'ETMX')
                    errchan = m.whichChan('PIT3_DOF_INMON');
                    clkchan = m.whichChan('PIT3_OSC_CLKGAIN');
                elseif(bf == 'ETMY')
                    errchan = m.whichChan('PIT4_DOF_INMON');
                    clkchan = m.whichChan('PIT4_OSC_CLKGAIN');
                end
               
                if(iscell(m.dat))
                   for j = 1:length(m.dat)
                       data = m.dat{j}(errchan).data;
                       adsGain = m.dat{j}(adschan).data;
                       clkGain = m.dat{j}(clkchan).data;
                       eval(['y = m.' bf '.DRpitch2y * m.dat{j}(m.whichChan(''' bf '*DRIVEALIGN_P2L'')).data+m.' bf '.DRyoff;']);
                       m.dat{j} = [m.dat{j} m.dat{j}(end)];
                       %put data in new channel
                       eval(['m.dat{j}(end).data = data*m.' bf '.IMpitch2y./(adsGain.*clkGain);']);
                       m.dat{j}(end).data = m.dat{j}(end).data + y;
                   end
                elseif(isstruct(m.dat))
                   data = m.dat(errchan).data;
                   adsGain = m.dat(adschan).data;
                   eval(['y = m.' bf '.DRpitch2y * m.dat(m.whichChan(''' bf '*DRIVEALIGN_P2L'')).data+m.' bf '.DRyoff;']);

                   m.dat = [m.dat m.dat(end)];
                   %put data in new channel
                   eval(['m.dat(end).data = data*m.' bf '.IMpitch2y./(adsGain.*clkGain);']);
                   m.dat(end).data = m.dat(end).data + y;
                end
                m.channelNames = [m.channelNames; ['MY:WXJ-ADS_BEAM_POSITION_' bf '_y']];

                
                
            end
            
            
        end
        % calibrate beam position from DRIVEALIGN and INMON channels
        
       
        
        %% Logical indexing
        
        function stableIndex = searchStableIndex(m, name, time, sigma)
        %SEARCHSTABLEINDEX Search the stable period of channel(s) and
        %return the logical index that corresponds to those periods
        %PREREQUISITE: struct data loaded
        %
        %   id = .searchStableIndex(name, time)
        %   search the channel(s) specified name and find periods longer
        %   than time (in seconds!!!) with constant value
        %   if only one channel, then 'id' is just a 1-D logical vector.
        %   Else, the ‘id’ has two fields: double* ‘chan’ has channel numbers
        %   , ‘index’ has cells containing logical indices
        %
        %   id = .searchStableIndex(name, time, sigma)
        %   search the channel(s) specified name and find periods longer
        %   than time (in seconds!!!) with variation < sigma
        %   See also WHICHCHAN
            if(isempty(m.channelNames) || isempty(m.dat))
                error('\n\n No data or channel names loaded!!!\n\n');
            end
            chan = m.whichChan(name);
            stableIndex = [];

            switch nargin
                case 3
                    if(isempty(chan))
                        error('\n\n No such channel! \n');
                    elseif(length(chan)==1)
                        data = m.dat(chan).data;

                        %quick search of only 1 time unit[
                %         temp = max(data)+1; %filler value
                %         stableIndex = (data - [temp; data(1:end-1)])==(data - [data(2:end); temp])&(~(logical(diff([data; temp]))));
                        stableIndex = false(1, length(data));
                        j = 1;
                        while(j<length(data))
                            if(data(j) == data(j+1))
                                start = j;
                                j = j+1;
                                while(j < length(data) && data(j) == data(j+1))
                                    j = j+1;
                                end
                                if(j-start+1 < time*m.dat(1).rate)
                                    stableIndex(start:j) = false;
                                else
                                    stableIndex(start:j) = true;
                                end
                            else
                                stableIndex(j) = false;

                            end
                            j = j+1;      
                        end


                    else
                        stableIndex = struct();
                        stableIndex.chan = chan;
                        stableIndex.index = cell(1, length(chan));
                        for i = 1:length(chan)
                            data = m.dat(chan(i)).data;
                            %quick search of only 1 time unit[
                %         temp = max(data)+1; %filler value
                %         stableIndex = (data - [temp; data(1:end-1)])==(data - [data(2:end); temp])&(~(logical(diff([data; temp]))));
                            stableIndex.index{i} = false(1, length(data));
                            j = 1;
                            while(j<length(data))
                                if(data(j) == data(j+1))
                                    start = j;
                                    j = j+1;
                                    while(j < length(data) && data(j) == data(j+1))
                                        j = j+1;
                                    end
                                    if(j-start+1 < time*m.dat(1).rate)
                                        stableIndex.index{i}(start:j) = false;
                                    else
                                        stableIndex.index{i}(start:j) = true;
                                    end
                                else
                                    stableIndex.index{i}(j) = false;

                                end
                                j = j+1;      
                            end

                        end
                    end
                case 4
                    if(isempty(chan))
                        error('\n\n No such channel! \n');
                    elseif(length(chan)==1)
                        data = m.dat(chan).data;

                        %quick search of only 1 time unit[
                %         temp = max(data)+1; %filler value
                %         stableIndex = (data - [temp; data(1:end-1)])==(data - [data(2:end); temp])&(~(logical(diff([data; temp]))));
                        stableIndex = false(1, length(data));
                        j = 1;
                        while(j<length(data))
                            if(abs(data(j) - data(j+1))<=sigma)
                                start = j;
                                j = j+1;
                                while(j < length(data) && abs(data(j) - data(j+1))<=sigma)
                                    j = j+1;
                                end
                                if(j-start+1 < time*m.dat(1).rate)
                                    stableIndex(start:j) = false;
                                else
                                    stableIndex(start:j) = true;
                                end
                            else
                                stableIndex(j) = false;

                            end
                            j = j+1;      
                        end


                    else
                        stableIndex = struct();
                        stableIndex.chan = chan;
                        stableIndex.index = cell(1, length(chan));
                        for i = 1:length(chan)
                            data = m.dat(chan(i)).data;
                            %quick search of only 1 time unit[
                %         temp = max(data)+1; %filler value
                %         stableIndex = (data - [temp; data(1:end-1)])==(data - [data(2:end); temp])&(~(logical(diff([data; temp]))));
                            stableIndex.index{i} = false(1, length(data));
                            j = 1;
                            while(j<length(data))
                                if(abs(data(j) - data(j+1))<=sigma)
                                    start = j;
                                    j = j+1;
                                    while(j < length(data) && abs(data(j) - data(j+1))<=sigma)
                                        j = j+1;
                                    end
                                    if(j-start+1 < time*m.dat(1).rate)
                                        stableIndex.index{i}(start:j) = false;
                                    else
                                        stableIndex.index{i}(start:j) = true;
                                    end
                                else
                                    stableIndex.index{i}(j) = false;

                                end
                                j = j+1;      
                            end

                        end
                    end
                otherwise
                    fprintf('\n\n Not enough input!!!n');
            end

        end
        % put time in seconds
        % finds the logical indices of data channel with ‘name’ specified 
        %that has duration longer than ‘time’. 
        % define sigma if the signal is not exactly flat with known disturbance ‘sigma’

        function lockIndex = getLockIndex(m, high) %time in seconds
        %GETLOCKINDEX Get the logical index when LOCK_STATE channel is at
        %defined value and save it to .lockIndex property
        %PREREQUISITE: struct data loaded
        %
        %   .getLockIndex
        %   Get logical index when LOCK_STATE == 2000 (interferometer is
        %   locked) and save it to .lockIndex property
        %
        %   .getLockIndex(value)
        %   Get logical index when LOCK_STATE == value and save it to 
        %   .lockIndex property
        %
        %   id = .getLockIndex
        %   Get logical index when LOCK_STATE == 2000 (interferometer is
        %   locked), save it to .lockIndex property and return it
        %
        %   id = .getLockIndex(value)
        %   same as the previous function with value defined
            if(isempty(m.dat))
                error('\n\n No data loaded!!!\n\n');
            end
            switch nargin
                case 1
                    lockIndex = m.dat(m.whichChan('STATE')).data == 2000;
                    m.lockIndex = lockIndex;
                case 2
                    lockIndex = m.dat(m.whichChan('STATE')).data == high;
                    if(high == 2000)
                        m.lockIndex = lockIndex;
                    end
                otherwise
                    fprintf('\n\n Wrong inputs \n');
            end
            
            

        end
        % get lock index that is locked in  'L1:GRD-ISC_LOCK_STATE_N' channel. 
        % If ‘high’ is not specified, then it will select 2000
        
        function index = removeTransienceFromIndex(m, index, transientTime) %time in seconds
        %REMOVETRANSIENCEFROMINDEX Remove the transience from the logical
        %index by shrinking its consecutive 1 (on both sides!)
        %PREREQUISITE: struct data loaded
        %
        %   out = .removeTransienceFromIndex(index, transientTime)
        %   Shrink the width of 1 on both sides of index by transientTime
        %   (in second!!!) 
        
        
            if(isempty(m.dat))
                error('\n\n No data loaded!!!\n\n');
            end
            %index has 00011110011, 1 means on and 0 means off
            %shrink width of 1 (or expand width of 0) by N == transientTime/tStep
            %expansion of 0 is chosen in this method
            tStep = 1/m.dat(1).rate; %in second
            N = ceil(transientTime/tStep);

            tempIndex = diff(double(index));

            for i = 1:length(tempIndex)
                if(tempIndex(i) == 1)
                    j = 1;
                    while(j <= N && j+i <= length(index))
                        index(i+j) = 0;
                        j = j+1; 
                    end
                elseif(tempIndex(i) == -1)
                    j = 0;
                    while(j < N && i-j >= 1)
                        index(i-j) = 0;
                        j = j+1;
                    end
                end
            end

        end
        % index has 00011110011, 1 means on and 0 means off
        % shrink width of 1 (or expand width of 0) on both sides by N == transientTime/tStep
        % expansion of 0 is chosen in this method
        
        function index = addTransienceToIndex(m, index, transientTime) %time in seconds
        %ADDTRANSIENCETOINDEX Add the transience to the logical
        %index by expanding its consecutive 1 (on both sides!)
        %PREREQUISITE: struct data loaded
        %
        %   out = .addTransienceToIndex(index, transientTime)
        %   Expand the width of 1 on both sides of index by transientTime
        %   (in second!!!) 
        
            if(isempty(m.dat))
                error('\n\n No data loaded!!!\n\n');
            end
            % index has 00011110011, 1 means on and 0 means off
            % expand the width of 1 (or shrink width of 0) by N == transientTime/tStep
            % expansion of 1 is chosen in this method
            tStep = 1/m.dat(1).rate; %in second
            N = ceil(transientTime/tStep);

            tempIndex = diff(double(index));

            for i = 1:length(tempIndex)
                if(tempIndex(i) == -1)
                    j = 1;
                    while(j <= N && j+i <= length(index))
                        index(i+j) = 1;
                        j = j+1; 
                    end
                elseif(tempIndex(i) == 1)
                    j = 0;
                    while(j < N && i-j >= 1)
                        index(i-j) = 1;
                        j = j+1;
                    end
                end
            end

        end
        % index has 00011110011, 1 means on and 0 means off
        % expand the width of 1 (or shrink width of 0) by N == transientTime/tStep
        % expansion of 1 is chosen in this method
        
        function index = addTransienceToRightOfIndex(m, index, transientTime) %time in seconds
        %ADDTRANSIENCETORIGHTOFINDEX Add the transience to the logical
        %index by expanding its consecutive 1 at the right
        %PREREQUISITE: struct data loaded
        %
        %   out = .addTransienceToRightOfIndex(index, transientTime)
        %   Append 1 to the right sides of index (1111) by transientTime
        %   (in second!!!) 
            if(isempty(isempty(m.dat)))
                error('\n\n No data loaded!!!\n\n');
            end

            tStep = 1/m.dat(1).rate; %in second
            N = ceil(transientTime/tStep);

            tempIndex = diff(double(index));

            for i = 1:length(tempIndex)
                if(tempIndex(i) == -1)
                    j = 1;
                    while(j <= N && j+i <= length(index))
                        index(i+j) = 1;
                        j = j+1; 
                    end
%                 elseif(tempIndex(i) == 1)
%                     j = 0;
%                     while(j < N && i-j >= 1)
%                         index(i-j) = 1;
%                         j = j+1;
%                     end
                end
            end

        end
        % index has 00011110011, 1 means on and 0 means off
        % expand the width of 1 at the right (or shrink width of 0) by N == transientTime/tStep
        % expansion of 1 is chosen in this method
        
        function index = addTransienceToLeftOfIndex(m, index, transientTime) %time in seconds
        %ADDTRANSIENCETOLEFTOFINDEX Add the transience to the logical
        %index by expanding its consecutive 1 at the left
        %PREREQUISITE: struct data loaded
        %
        %   out = .addTransienceToLeftOfIndex(index, transientTime)
        %   Append 1 to the left sides of index (1111) by transientTime
        %   (in second!!!) 
            if(isempty(isempty(m.dat)))
                error('\n\n No data loaded!!!\n\n');
            end

            tStep = 1/m.dat(1).rate; %in second
            N = ceil(transientTime/tStep);

            tempIndex = diff(double(index));

            for i = 1:length(tempIndex)
%                 if(tempIndex(i) == -1)
%                     j = 1;
%                     while(j <= N && j+i <= length(index))
%                         index(i+j) = 1;
%                         j = j+1; 
%                     end
                if(tempIndex(i) == 1)
                    j = 0;
                    while(j < N && i-j >= 1)
                        index(i-j) = 1;
                        j = j+1;
                    end
                end
            end

        end
        % index has 00011110011, 1 means on and 0 means off
        % expand the width of 1 at the left (or shrink width of 0) by N == transientTime/tStep
        % expansion of 1 is chosen in this method

        function index = removePeaksFromIndex(m, data, threshold, transientTime) 
        %REMOVEPEAKSFROMINDEX Remove the peaks in input data that are
        %higher than the threshold and shorter than the transientTime (in
        %seconds!) by setting the corresponding logical index to 0
        %PREREQUISITE: struct data loaded
        %
        %   out = .removePeaksFromIndex(data, threshold, transientTime) 
        %   Search peaks in data that has value higher than threshold and
        %   last for a time longer than transientTime (in second!) Set the
        %   logical index to 0
            if(isempty(isempty(m.dat)))
                error('\n\n No data loaded!!!\n\n');
            end
            %index has 00011110011, 1 means on and 0 means off
            %zero all 1 if the consecutive length is < N == transientTime/tStep
            tStep = 1/m.dat(1).rate; %in second
            N = ceil(transientTime/tStep);
            L = length(data);
            index = true(1, L);

            i = 1;
            while(i <= L)
                if(data(i) > threshold)
                    i0 = i;
                    count = 1;
                    i = i+1;

                    while(i <= L && data(i) > threshold)
                        count = count+1;
                        i = i+1;
                    end

                    if(count <= N)
                        index(i0:(i0+count-1)) = false;
                    end
                end
                i = i+1;
            end



        end
        % time in seconds
        % ‘transientTime’ in seconds
        % remove the sudden weird peaks with duration <= ‘transientTime’
        % return the 
        % index has 111111111111, 1 means on and 0 means off
        % zero all 1 if the consecutive length is < N == transientTime/tStep
        
        function getO2FinalIndex(m, varargin)
        %GETO2FINALINDEX Get the steady-state logical index of O2 data and
        %save it to .finalIndex
        %PREREQUISITE: struct data loaded (O2_minute.mat)
        %
        %   .getO2FinalIndex 
        %   Get the steady-state logical index of O2 data by the following
        %   criteria:
        %   1. Interferometer is locked (LOCK_STATE == 2000(L1) or 600(H1))
        %   2. Interferometer is at low-noise mode (OBSERVATION_READY == 1)
        %   3. The beam position is fixed (DRIVEALIGN signals are constant)
        %   %(4. The power in PRC is stable (POP_A < 3 W))
        %   5. 1 hr transience is removed at the beginning and end of each
        %   index mentioned above
        %
        %   .getO2FinalIndex('lockValue', value)
        %   Set the lock index value by yourself (default is determind by
        %   input data file name (L1 or H1).
        %
        %   .getO2FinalIndex('transientTime', value)
        %   Set the transient time by yourself (in seconds!) (default is
        %   3600)
        %
        %   See also GETLOCKINDEX SEARCHSTABLEINDEX
        %   REMOVETRANSIENCEFROMINDEX 
        
            if(isempty(m.dat))
                error('\n\n No data loaded!!!\n\n');
            end
            
            if(m.argHas('lockValue', varargin))
                lockValue = varargin{find(contains(cellfun(@num2str,varargin,'un',0), 'lockValue'))+1};
            else
                if(strcmp(m.fileName(1:2), 'L1'))
                    lockValue = 2000;
                elseif(strcmp(m.fileName(1:2), 'H1'))
                    lockValue = 600;
                end
            end
            
            if(any(contains(cellfun(@num2str,varargin,'un',0), 'transientTime')))
                transientTime = varargin{find(contains(cellfun(@num2str,varargin,'un',0), 'transientTime'))+1};
            else
                transientTime = 3600;
            end
                     
            %filter indices
            alignStableIndices = m.searchStableIndex('DRIVEALIGN', transientTime); %input time in seconds
            alignStableIndex = alignStableIndices.index{1};
            for i = 2:length(alignStableIndices.index)
                alignStableIndex = alignStableIndex&(alignStableIndices.index{i});
            end
            alignStableIndex = m.removeTransienceFromIndex(alignStableIndex, transientTime);

            %powerStableIndex = m.searchStableIndex('POP_A*_OUTPUT', transientTime, 3);
            %powerStableIndex = powerStableIndices.index;
%             for i = 2:length(powerStableIndices.index)
%                 powerStableIndex = powerStableIndex&(powerStableIndices.index{i});
%             end

            scienceIndex = m.removeTransienceFromIndex(m.dat(m.whichChan('READY')).data == 1, transientTime);
            lockIndex = m.removeTransienceFromIndex(m.getLockIndex(lockValue), transientTime); 
            %combine everything
            m.finalIndex = alignStableIndex & scienceIndex' & lockIndex';  %#ok<*PROPLC>
            
        end
        % get final index that filters the data in O2 that satisfies requirement
        
        function getO2ADSIndex(m, varargin)
        %GETO2ADSINDEX Get the transient logical index of O2 data and
        %save it to .ADSIndex
        %PREREQUISITE: struct data loaded (O2_minute.mat)
        %
        %   .getO2ADSIndex 
        %   Get the transient logical index of O2 data by the following
        %   criteria:
        %   1. The lock duration is longer than 2 hour
        %   2. Get the period when the LOCK_STATE rises from 1000 to 2000
        %   (when the alignment happens) from locks satisfied by 1.
        %
        %   .getO2FinalIndex('transientTime', value)
        %   Set the transient time by yourself (default is 3600, which  
        %   filters locks longer than 2*3600 = 2 hour)
        %
        %   See also ADDTRANSIENCETOLEFTOFINDEX REMOVETRANSIENCEFROMINDEX
        
            if(isempty(isempty(m.dat)))
                error('\n No data loaded!!!\n\n');
            end
            if(~isstruct(m.dat))
                error('\n Please load struct data!!!\n\n');
            end
            
            if(any(contains(cellfun(@num2str,varargin,'un',0), 'transientTime')))
                duration = varargin{find(contains(cellfun(@num2str,varargin,'un',0), 'transientTime'))+1};
            else
                duration = 3600; %sample half an hour of time
            end
            
            t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate; 
            
            lock = m.dat(m.whichChan('LOCK_STATE')).data;
            id =  (lock == 2000);
            duration = 3600;
            id = m.removeTransienceFromIndex(id, duration);
            id = m.addTransienceToLeftOfIndex(id, duration);
            
            i = 1;
            L = length(id);
            startIndex = [];
            while(i <= L)
                if(id(i))
                    i0 = i;
                    count = 1;
                    i = i+1;

                    while(i <= L && id(i))
                        count = count+1;
                        i = i+1;
                    end
                    
                    startIndex = [startIndex, i0]; 
                end
                i = i+1;
            end
            id = false(length(id),1);
            for start = startIndex
                j = start;
                while(j >= 1 && lock(j) > 1000)
                    id(j) = true;
                    j = j-1;
                end
                id(start:start+duration/(round(1/m.dat(1).rate))) = true;
                
            end
            
            m.ADSIndex = id;
        end
        % get ADS index
        
        function [lowPowerIndex, highPowerIndex] = getSectionADSErrorIndex(m, varargin)
        %GETSECTIONADSERRORINDEX Return the logical index of low-power(10W)
        %alignment and high-power(25W) alignment in O2 section data
        %PREREQUISITE: cell data extracted from .ADSIndex loaded 
        %(like O2ADS_rawdata_section.mat)
        %
        %   [lowPowerIndex, highPowerIndex] = getSectionADSErrorIndex('n',n) 
        %   Get the two alignment logical indices of the n-th cell by the 
        %   following criteria:
        %   lowPowerIndex
        %   1. LOCK_STATE < 1200
        %   2. Non-zero constant CLKGAIN
        %   3. Non-zero constant ADSGAIN
        %
        %   See also ADDTRANSIENCETOLEFTOFINDEX REMOVETRANSIENCEFROMINDEX
        
            if(isempty(isempty(m.dat)))
                error('\n\n No data loaded!!!\n\n');
            end
            
            if(any(contains(cellfun(@num2str,varargin,'un',0), 'n')))
                n = varargin{find(contains(cellfun(@num2str,varargin,'un',0), 'n'))+1};
            else
                error('\n\n Please specify which section of data to use !\n\n');
            end
            
            if(m.dat{n}(m.whichChan('ADS_GAIN')).data(1) ~= 0 || m.dat{n}(m.whichChan('ADS_GAIN')).data(1) ~= 0)
                fprintf('\n\n Number %d doesn''t have 10W transience\n\n',n);
%                 lowPowerIndex = [];
%                 highPowerIndex = [];
%                 return
            end
            
            adsGain = m.dat{n}(m.whichChan('ADS_GAIN')).data;
            
            lowIndex = (m.dat{n}(m.whichChan('LOCK_STATE')).data < 1200);
            lowPowerIndex = (adsGain == max(adsGain(lowIndex)));
            temp = m.dat{n}(m.whichChan('CLKGAIN')).data;
            lowPowerIndex = lowPowerIndex & temp == max(temp(lowIndex));
            lowPowerIndex = lowPowerIndex & lowIndex;
            
            highIndex = (m.dat{n}(m.whichChan('LOCK_STATE')).data > 1200);
            highPowerIndex = (adsGain == max(adsGain(highIndex)));
            highPowerIndex = highPowerIndex & temp == max(temp(highIndex));
            highPowerIndex = highPowerIndex & highIndex;
            
%             temp1 = diff([m.dat{n}(m.whichChan('ADS_GAIN')).data; realmax]);
%             temp2 = diff([realmax; m.dat{n}(m.whichChan('ADS_GAIN')).data]);
%             ADSGAINId = (temp1 == 0) | (temp2 == 0);
%             ADSGAINId = m.dat{n}(m.whichChan('ADS_GAIN')).data.*double(ADSGAINId) ~= 0;
%                         
%             temp1 = diff([m.dat{n}(m.whichChan('CLKGAIN')).data; realmax]);
%             temp2 = diff([realmax; m.dat{n}(m.whichChan('CLKGAIN')).data]);
%             CLKGAINId = (temp1 == 0) | (temp2 == 0);
%             CLKGAINId = m.dat{n}(m.whichChan('CLKGAIN')).data.*double(CLKGAINId) ~= 0;
%             
%             powerIndex = ADSGAINId & CLKGAINId;
%             
%             lowPowerIndex = powerIndex & (m.dat{n}(m.whichChan('LOCK_STATE')).data < 1200);
%             highPowerIndex = powerIndex & (m.dat{n}(m.whichChan('LOCK_STATE')).data > 1200);
            
%             i = 1;
%             while(i <= length(lowPowerIndex))
%                 if(lowPowerIndex(i))
%                     for j = i:min(i+n*m.dat(1).rate, length(lowPowerIndex))
%                         lowPowerIndex(j) = true;
%                     end
%                     i = i+n*m.dat(1).rate;
%                 end
%                 i = i+1;
%             end
                       
        end
        % get 10W and 25W ADS error data from sections of cell* m.dat
        
        
                
        %% Viewers
        
        function PDViewer(m, baffle, varargin) 
        %PDVIEWER Create a well formatted viewer of PD channel data
        %PREREQUISITE: Data loaded
        %
        %   .PDViewer(baffle)
        %   View the PD channel data on 'baffle' (like 'ITMX')
        %
        %   .PDViewer(baffle, 't', name)
        %   View the PD data on 'baffle' (like 'ITMX') with big title
        %   'name'
        %
        %   .PDViewer(baffle, 'l', index)
        %   View the PD data on 'baffle' selected by logical 'index'
        %   (only work for struct data loaded)
        %
        %   .PDViewer(baffle, 'semilogy' ...)
        %   Change the y axis to log-scale
        %
        %   See also WHICHCHAN 
            if(isempty(m.channelNames) || isempty(m.dat))
                error('\n\n No data or channel names loaded!!!\n\n');
            end

            markersize = 3;
            fontsize = 15;

            set(0,'defaultfigureposition',[100 400 1150 450]); %set window size and location
            

            
            %set(gca,'TickLabelInterpreter', 'tex');
            
            t = [];            
            if(iscell(m.dat))
                PDdata = cell(1,4);
                for i = 1:length(m.dat)
                    for pd = 1:4
                        %PDdata{pd} = [PDdata{pd}; m.dat{i}(m.whichChan(['WXJ-PDPOWER_' baffle '_PD_' int2str(pd)])).data];
                        PDdata{pd} = [PDdata{pd}; m.dat{i}(m.whichChan(['WXJ-BRDF_' baffle '_PD_' int2str(pd)])).data];
                        temp = 0:round(1/m.dat{i}(1).rate):(m.dat{i}(1).duration - round(1/m.dat{i}(1).rate));
                        
                    end
                    t = [t temp+m.dat{i}(1).start];
                end
                
                
            elseif(isstruct(m.dat))
                t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;
                if(m.argHas('l',varargin))
                    index = varargin{m.argHas('l',varargin)+1};
                else 
                    index = [];
                end
                PDdata = cell(1,4);
                for i = 1:4
                    PDdata{i} = m.dat(m.whichChan(['WXJ-BRDF_' baffle '_PD_' int2str(i)])).data;
                    %PDdata{i} = m.dat(m.whichChan(['PDPOWER_' baffle '_PD_' int2str(i)])).data;
                    if(~isempty(index))
                        PDdata{i} = PDdata{i}(index);
                    end
                end
                if(~isempty(index))
                    t = t(index);
                end
                
            end

            figure
            s1 = subplot(1,2,1);
            
            if(m.argHas('semilogy',varargin))
                semilogy(t, PDdata{1}, 'r.', 'MarkerSize', markersize);
                hold on
                semilogy(t, PDdata{4}, 'k.', 'MarkerSize', markersize);
                ylow1 = 1e-5;
            else
                plot(t, PDdata{1}, 'r.', 'MarkerSize', markersize);
                hold on
                plot(t, PDdata{4}, 'k.', 'MarkerSize', markersize);
                ylow1 = 0;
            end
            hold off
            %ylabel(['L1:AOS-' baffle '\_BAFFLEPD\_*\_POWER'])
            ylabel('BRDF [sr$^{-1}$]')
            %ylabel('Power [W]')
            title([m.fileName(1:2) ': ' baffle ' PD1, 4']);
            grid on
%             xlim([t(1) t(end)])
%             ylow1 = min([0, min(PDdata{1}), min(PDdata{4})]);
%             yhigh1 = max(max(PDdata{1}), max(PDdata{4}));
%             ylow1 = 0;
%             yhigh1 = 3.76;
%             ylim([ylow1 yhigh1])
            axis tight
            temp = ylim;
            
            yhigh1 = temp(2)+0.5e-4;
            %yhigh1 = 1.064e-3+0.5e-4;
            ylim([ylow1 yhigh1])
            xticklabels(m.gps2utc(xticks, 'month'));
            legend('PD1', 'PD4', 'Location', 'best')
            set(gca, 'FontSize', fontsize)

            s2 = subplot(1,2,2);

            if(m.argHas('semilogy',varargin))
                semilogy(t, PDdata{2}, 'g.', 'MarkerSize', markersize);
                hold on
                semilogy(t, PDdata{3}, 'b.', 'MarkerSize', markersize);
                ylow2 = 1e-7;
            else
                plot(t, PDdata{2}, 'g.', 'MarkerSize', markersize);
                hold on
                plot(t, PDdata{3}, 'b.', 'MarkerSize', markersize);
                ylow2 = 0;
            end
            
            hold off
            title([m.fileName(1:2) ': ' baffle ' PD2, 3']);
            grid on
            xlim([t(1) t(end)])
            ylow2 = min([0, min(PDdata{2}), min(PDdata{3})]);
            yhigh2 = max(max(PDdata{2}), max(PDdata{3}));
            %ylow2 = -0.001;
            %yhigh2 = 4e-5;
            ylim([ylow2 yhigh2])
            xticklabels(m.gps2utc(xticks, 'month'));
            legend('PD2', 'PD3', 'Location', 'best')
            set(gca, 'FontSize', fontsize)


               

            s1p = get(s1, 'Position');
            s2p = get(s2, 'Position');
            s1x = s1p(1)+s1p(3);
            s2x = s2p(1);
            s1y = s1p(2);
            s2y = s2p(2)+s2p(4)*(0-ylow2)/(yhigh2 - ylow2);
            annotation('line', [s1x s2x], [s1y+0.01 s2y+0.01], 'Linewidth', 0.75);
            s1y = s1p(2) + s1p(4)*(yhigh2)/yhigh1;
            s2y = s2p(2)+s2p(4);
            annotation('line', [s1x s2x], [s1y s2y], 'Linewidth', 0.75);

            if(m.argHas('t',varargin)) 
                titleAxe = axes('Position',[0.01 0.93 0.2 0.05]);
                set(gca,'xtick',[]);
                set(gca,'ytick',[]);
                axis off
                text(0, 0.5, varargin{m.argHas('t',varargin)+1}, 'FontSize', 18);
            end

            %print([baffle ' allPD.png'],'-dpng','-r600');
            set(0,'defaultfigureposition',[400 200 600 500]); %set window size and location
        end
        % PDdata is filtered with index
        % give 2 subplots of the PDdata (PD 1,4 and 2.3). If index is given, then it only 
        %plots data(index)
        
        function PDDataViewer(m, PDdata, t, baffle, name) 
        %PDDATAVIEWER Create a well formatted viewer of loaded PD data
        %
        %   .PDDataViewer(PDdata, t, baffle)
        %   View the loaded 'PDdata' (1x4 cell) on 'baffle' (like 'ITMX')
        %
        %   .PDDataViewer(PDdata, t, baffle, name)
        %   View the loaded 'PDdata' (1x4 cell) on 'baffle' (like 'ITMX')
        %   with a big title 'name'
        
            markersize = 3;
            fontsize = 15;

            set(0,'defaultfigureposition',[400 200 1150 450]); %set window size and location
            

            figure
            %set(gca,'TickLabelInterpreter', 'tex');

            s1 = subplot(1,2,1);

            plot(t, PDdata{1}, 'r.', 'MarkerSize', markersize);
            hold on
            plot(t, PDdata{4}, 'k.', 'MarkerSize', markersize);
            hold off
            %ylabel([baffle ' PD measurement [-]'])
            ylabel('BRDF [sr$^{-1}$]')
            title([baffle ' PD 1,4']);
            grid on
%             xlim([t(1) t(end)])
%             ylow1 = min([0, min(PDdata{1}), min(PDdata{4})]);
%             yhigh1 = max(max(PDdata{1}), max(PDdata{4}));
%             ylow1 = 0;
%             yhigh1 = 3.76;
%             ylim([ylow1 yhigh1])
            axis tight
            temp = ylim;
            ylow1 = temp(1);
            yhigh1 = temp(2);
            xticklabels(m.gps2utc(xticks, 'month'));
            legend('PD1', 'PD4', 'Location', 'best')
            set(gca, 'FontSize', fontsize)

            s2 = subplot(1,2,2);

            plot(t, PDdata{2}, 'g.', 'MarkerSize', markersize);
            hold on
            plot(t, PDdata{3}, 'b.', 'MarkerSize', markersize);
            hold off
            title([baffle ' PD 2,3']);
            grid on
%             xlim([t(1) t(end)])
%             ylow2 = min([0, min(PDdata{2}), min(PDdata{3})]);
%             yhigh2 = max(max(PDdata{2}), max(PDdata{3}));
%             ylow2 = -0.001;
%             yhigh2 = 0.11;
%             ylim([ylow2 yhigh2])
            axis tight
            temp = ylim;
            ylow2 = temp(1);
            yhigh2 = temp(2);
            xticklabels(m.gps2utc(xticks, 'month'));
            legend('PD2', 'PD3', 'Location', 'best')
            set(gca, 'FontSize', fontsize)


            
            s1p = get(s1, 'Position');
            s2p = get(s2, 'Position');
            s1x = s1p(1)+s1p(3);
            s2x = s2p(1);
            s1y = s1p(2);
            s2y = s2p(2)+s2p(4)*(0-ylow2)/(yhigh2 - ylow2);
            annotation('line', [s1x s2x], [s1y+0.01 s2y+0.01], 'Linewidth', 0.75);
            s1y = s1p(2) + s1p(4)*(yhigh2)/yhigh1;
            s2y = s2p(2)+s2p(4);
            annotation('line', [s1x s2x], [s1y s2y], 'Linewidth', 0.75);
            
            if(exist('name')) 
                titleAxe = axes('Position',[0.01 0.95 0.2 0.05]);
                set(gca,'xtick',[]);
                set(gca,'ytick',[]);
                axis off
                text(0, 0.5, name, 'FontSize', 18);
            end

            %print([baffle ' allPD.png'],'-dpng','-r600');
            set(0,'defaultfigureposition',[400 200 600 500]); %set window size and location
        end
        % PDdata is filtered with index
        % give 2 subplots of the PDdata (PD 1,4 and 2.3). If index is given, then it only 
        %plots data(index)
        
        function chanViewer(m, keyword, varargin)
        %CHANVIEWER Fast viewer of channel data with flexible choices
        %PREREQUISITE: data loaded
        %
        %   .chanViewer(keyword)
        %   Plot all data of channels specified by keyword
        %
        %   .chanViewer(keyword, 'month')
        %   Change the xticks to month in UTC time
        %
        %   .chanViewer(keyword, 'day')
        %   Change the xticks to day in UTC time
        %
        %   .chanViewer(keyword, 'GPS')
        %   Change the xticks to GPS time
        %
        %   .chanViewer(keyword, 'p', plotSpecifier)
        %   Plot all data with styles of 'plotSpecifier' (dault is '-')
        %
        %   .chanViewer(keyword, 'n', n)
        %   Only plot data in n-th cell (must load cell data, of course!)
        %   n can be an array to plot multiple cell data together!
        %
        %   .chanViewer(keyword, 'l', index)
        %   Only plot data(index), mostly for struct data
        %
        %   .chanViewer(keyword, 'MA', span)
        %   Apply a moving-average filter to data plotted. Span is in
        %   seconds!!
        %
        %   .chanViewer(keyword, 'dB')
        %   Set the y-axis in decibel
        %
        %   .chanViewer(keyword, 'fontsize', size)
        %   Set the font size of the plot
        %
        %   .chanViewer(keyword, 't', title)
        %   Add a big 'title' at top-left of the viewer
        %
        %   .chanViewer(keyword, 'm', '10W')
        %   Only plot 10W-alignment periods (need to load correct cell data
        %   like O2ADS_rawdata_section.mat (default is none)
        %
        %   .chanViewer(keyword, 'm', '25W')
        %   Only plot 25W-alignment periods (need to load correct cell data
        %   like O2ADS_rawdata_section.mat (default is none)
        %
        %   .chanViewer(keyword, 'displayStats', true)
        %   Display the mean and average of data plotted (default is false)
        %
        %   See also WHICHCHAN GPS2UTC GETSECTIONADSERRORINDEX SMOOTH


            if(isempty(m.channelNames) || isempty(m.dat))
                error('\n\n No data or channel names loaded!!!\n\n');
            end
            
            textBoxDim = [0.15 0.6 0.3 0.3];
            markersize = 5;
            noUTC = false;
            GPS = false;
            
            if(m.argHas('displayStats',varargin))
                displayStats = varargin{m.argHas('displayStats',varargin)+1};
            else
                displayStats = false;
            end
            
            
            if(m.argHas('month',varargin))
                xtickscale = 'month';
            elseif(m.argHas('second',varargin))
                xtickscale = 'second';
            elseif(m.argHas('GPS',varargin))
                GPS = true;
            else
                noUTC = true;
            end
            
            
            if(m.argHas('p',varargin))
                plotSpecifier = varargin{m.argHas('p',varargin)+1};
            else
                plotSpecifier = '-';
            end
            
            if(m.argHas('n',varargin))
                n = varargin{m.argHas('n',varargin)+1};
            else
                n = [];
            end
            
            if(m.argHas('l',varargin))
                index = varargin{m.argHas('l',varargin)+1};
            else
                index = [];
%                 if(isstruct(m.dat))
%                     index = true(1,length(m.dat(1).data));
%                 else
%                     if(~isempty(n))
%                         index = true(1, length(m.dat{n}(1).data));
%                     else
%                         index = [];
%                         for i = 1:length(m.dat)
%                             index = [index, true(1, length(m.dat{i}(1).data))];
%                         end
%                     end
%                 end
            end
            
            
            if(m.argHas('m',varargin))
                mode = varargin{m.argHas('m',varargin)+1};
            else
                mode = 'none';
            end
            
            if(m.argHas('t',varargin))
                tx = varargin{m.argHas('t',varargin)+1};
            else
                tx = '';
            end
            
            if(m.argHas('MA',varargin))
                MA = varargin{m.argHas('MA',varargin)+1};
                if(iscell(m.dat))
                    MA = MA/round(1/m.dat{1}(1).rate);
                elseif(isstruct(m.dat))
                    MA = MA/round(1/m.dat(1).rate);
                end
            else
                MA = [];
            end
            
            
            
            
            switch mode
                case '10W'
                    if(~isempty(n))
                        [l,h] = m.getSectionADSErrorIndex('n',n);
                        index = l;
                    else
                        index = [];
                        for i = 1:length(m.dat)
                            [l,h] = m.getSectionADSErrorIndex('n',i);
                            index = [index; l];
                        end
                    end
                case '25W'
                    if(~isempty(n))
                        [l,h] = m.getSectionADSErrorIndex('n',n);
                        index = h;
                    else
                        index = [];
                        for i = 1:length(m.dat)
                            [l,h] = m.getSectionADSErrorIndex('n',i);
                            index = [index; h];
                        end
                    end
%                 case 'ss'
%                     if(~isempty(n))
%                         [l,h] = m.getSectionADSErrorIndex('n',n);
%                         h(1:end-600) = false;
%                         index = h;
%                     else
%                         index = [];
%                         for i = 1:length(m.dat)
%                             [l,h] = m.getSectionADSErrorIndex('n',i);
%                             h(1:end-600) = false;
%                             index = [index; h];
%                         end
%                     end
                otherwise
            end
                    
            
%             commaloc = strfind(keyword, ',');
%             words = cell(1, length(commaloc)+1);
% 
%             %divide name to many words with asterisk in it
%             in = [0, commaloc, length(keyword)+1];
%             if(isempty(commaloc))
%                 words{1} = keyword;
%             else
%                 for j = 1:length(commaloc)+1
%                     words{j} = keyword((in(j)+1):(in(j+1)-1));
%                 end
%             end
%             
%             N = length(words);
%             allchan = cell(1,N);
%             for i = 1:N
%                 allchan{i} = m.whichChan(words{i});
%             end
            
            
            

            channels = m.whichChan(keyword);
            N = length(channels);
            

            figure
            str = cell(1,N);
            for i = 1:N
                if(N>1)
                    ha(i) = subplot(ceil(N/2), 2, i);
                end
                data = [];
                time = [];

                if(isempty(n))

                    if(isstruct(m.dat))
                        time = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;
                        %time = time(index);
                        data = m.dat(channels(i)).data;
                        rate = m.dat(1).rate;
                    elseif(iscell(m.dat))
                        for j = 1:length(m.dat)
                            time = [time, m.dat{j}(1).start:(1/m.dat{j}(1).rate):(m.dat{j}(1).start+m.dat{j}(1).duration-1)];
                            data = [data; m.dat{j}(channels(i)).data];
                        end
                        rate = m.dat{1}(1).rate;
                    end
                    if(~isempty(index))
                        time = time(logical(index));
                        data = data(logical(index));
                    end
                    if(~isempty(MA))
                        data = smooth(data, MA);
                    end

                    if(m.argHas('dB', varargin))
                        data = db(data);
                    end
                    if(noUTC)
                        plot((1:length(data))/rate, data, plotSpecifier, 'MarkerSize', markersize);
                    else
                        plot(time, data, plotSpecifier, 'MarkerSize', markersize);
                    end

                    datamin = min(data);
                    datamax = max(data);

                else
                    datamin = [];
                    datamax = [];
                    legendItem = {};
                    for j = 1:length(n)
                        if(isstruct(m.dat))
                            time = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;
                            %time = time(index);
                            data = m.dat(channels(i)).data;
                            datamin = min(data);
                            datamax = max(data);
                            rate = m.dat(1).rate;
                        elseif(iscell(m.dat))
                            time = m.dat{n(j)}(1).start + (1:length(m.dat{n(j)}(1).data))./m.dat{n(j)}(1).rate;
                            %time = time(index);
                            data = m.dat{n(j)}(channels(i)).data;
                            if(~isempty(datamin))
                                datamin = min(datamin, min(data));
                                datamax = max(datamax, max(data));
                            else
                                datamin = min(data);
                                datamax = max(data);
                            end
                            rate = m.dat{1}(1).rate;
                        end
                        if(~isempty(index))
                            time = time(logical(index));
                            data = data(logical(index));
                        end
                        if(~isempty(MA))
                            data = smooth(data, MA);
                        end

                        if(m.argHas('dB', varargin))
                            data = db(data);
                        end

                        if(noUTC)
                            plot((1:length(data))/rate, data, plotSpecifier, 'MarkerSize', markersize);
                        else
                            plot(time, data, plotSpecifier, 'MarkerSize', markersize);
                        end
                        hold on

                        legendItem = [legendItem, m.gps2utc(m.dat{n(j)}(1).start)];
                        %legendItem = [legendItem, int2str(n(j))];

                    end

                    if(length(n) > 1)
                        legend(legendItem, 'Location','best');
                    end

                end

                hold off

                if(datamin < datamax)
                    %ylim([datamin, datamax]);
                end

                chName = m.channelNames{channels(i)};
                %ylabel(m.addChar(chName(8:min(-10*ceil(N/2)+55+8,length(chName))), '_', '\'));
                %length of channel names on y axis (ylabel)
                ylabel(m.addChar(chName(8:min(29,length(chName))), '_', '\'));
                %ylabel(m.addChar(chName, '_', '\'));
                %title(m.addChar(chName, '_', '\'));
                %ylabel('BRDF [sr$^{-1}$]')
                %ylabel('BRDF [dB]')
                grid on

                if(m.argHas('fontsize',varargin))
                    set(gca, 'fontsize', varargin{m.argHas('fontsize',varargin)+1});
                end

                if(noUTC)
                    xlabel('Time [s]');
                    %xlim([0, length(data)]);
                else
                    xlabel('Time (GPS)');
                    if(~GPS)
                        xlabel('')
                        xticklabels(m.gps2utc(xticks, xtickscale));
                    end
                    %xlim([min(time), max(time)]);
                end
                axis tight
                [avg, sd] = m.getMeanSD(data);
                str{i} = {sprintf('mean = %g', avg), sprintf('sd = %g',sd)};

            end
            drawnow;
            if(displayStats)
                if(N>1) 
                    pos = arrayfun(@m.plotboxpos, ha, 'uni', 0);
                    dim = cellfun(@(x) x.*[1 1 1 1], pos, 'uni',0);
                    for i = 1:N
                        annotation('textbox',  dim{i}, 'String', str{i}, 'FitBoxToText','on');
                    end

                else
                    annotation('textbox', textBoxDim, 'String', {sprintf('mean = %g', avg), sprintf('sd = %g',sd)}, 'FitBoxToText', 'on');

                end
            end
                
            
            titleAxe = axes('Position',[0.01 0.95 0.2 0.05]);
            set(gca,'xtick',[]);
            set(gca,'ytick',[]);
            axis off
            text(0, 0.5, tx, 'FontSize', 18);


        end
        % plot all data with channel that contains keyword 
        %(support alias by * and union by +)
        % if ‘index’ is inputted, the function only plots indices specified by ‘index’
        % displays mean and sd as well
        % can work with cell* dat

        function fieldPositionViewer(m, baffle, varargin)
        %FIELDPOSITIONVIEWER The 2D field distribution viewer on baffle
        %with various display choices
        %PREREQUISITE: struct data loaded
        %
        %   .fieldPositionViewer(baffle)
        %   View the 2D field distribution on 'baffle' (like 'ITMX')
        %
        %   .fieldPositionViewer(baffle, 't', titleName)
        %   Add the big 'titleName' at the top-left of the viewer
        %
        %   .fieldPositionViewer(baffle, 'mode', 'time series')
        %   Add time series plot of PD data from .dat (default is 'none')
        %
        %   .fieldPositionViewer(baffle, 'mode', 'relative power')
        %   Add relative magnitude plot of PD data from .dat
        %
        %   .fieldPositionViewer(baffle, 'mode', 'power map')
        %   Add a closed-look box of powermap in the area around PD
        %
        %   See also RUNSIS
            set(0,'defaultfigureposition',[400 30 672 606]); %set window size and location

            if(m.argHas('mode',varargin))
                mode = varargin{m.argHas('mode',varargin)+1};
            end
            figure

            %% SIS profile
            vertR = 13.56*25.4/2;%mm LIGO-D1200322-v4
            horiR = 13.54*25.4/2;%mm LIGO-D1200322-v4

            beamAxe = axes('Position',[0 0 1 1]); %#ok<*NASGU>

        %     %calibration plot
        %     plot(beamAxe, [-vertR/2,vertR/2], [0 0]);
        %     hold on
        %     plot(beamAxe, [0 0], [-vertR/2,vertR/2]);
        %     theta = 0:0.1:2*pi;
        %     plot(beamAxe, vertR*cos(theta), vertR*sin(theta)); 

        %     r = 30; %mm, Gaussian radius

            %get beam positions
            if(baffle(1) == 'I')
                opposite = ['E' baffle(2:4)];
            elseif(baffle(1) == 'E')
                opposite = ['I' baffle(2:4)];
            else        
                error('\n\n Wrong name for baffle\n');
            end


        %     pitch = dat(m.whichChan([opposite '*P2L_GAIN'])).data(1);
        %     yaw = dat(m.whichChan([opposite '*Y2L_GAIN'])).data(1);
        %     x = yaw*3.5; % x offset, 3.5 is only for ETM, but let's use it for now
        %     y = pitch*(-4.5); % y offset, -4.5 is only for ETM, but let's use it for now

            x = 0;
            y = 0;
         
            if(eval(['isempty(m.' baffle '.SIS.E) || isempty(m.' baffle '.SIS.x)']))
                m.runSIS('arm',baffle(end));
            end

            
            
            
            
            eval(['currx = m.' baffle '.SIS.x*1000;']);% mm
            eval(['curry = m.' baffle '.SIS.x*1000;']);
            
            %Normalize
            eval(['PTM = abs(m.' baffle '.SIS.E).^2;']);%Power density
            PTM = PTM*(mean(diff(currx))/1000)^2;   %#ok<NODEF>
            PTM = PTM/sum(sum(PTM))/m.ITMX.PD1.omega;
            
            [~,xmaxid] = max(max(PTM));
            [~,ymaxid] = max(PTM(:, xmaxid));
            eval(['x = round(m.' baffle '.SIS.x(xmaxid)*1000); y = round(m.' baffle '.SIS.x(ymaxid)*1000); ']);

            surf(currx , curry , db(PTM),'edgecolor','none')
            colormap('jet')

            caxis([db(min(min(PTM))) db(max(max(PTM)))])

            view([0 90])

        %     theta = 0:0.001:2*pi;
        %     plot(beamAxe, r*cos(theta)+x, r*sin(theta)+y, 'r', 'MarkerSize', 10); 
        %     hold on
        
            %text(-vertR*0.78, -vertR*0.5, [sprintf('xoffset = %d mm\n', x) sprintf('yoffset = %d mm\n', y)],'Color','k');
            
            if(all(bf == 'ITMX') || all(bf == 'ETMY'))
                xlim([-170*1.2, 502*1.2]);%set the scale correctly
            else
                xlim([-502*1.2, 170*1.2]);%set the scale correctly
            end

            ylim([-170*1.2,436*1.2]);
            hold off
            axis off   
            %% background baffle image picture
            imageAxe = axes('Position',[0 0 1 1]); %x, y, width, height


            if(all(bf == 'ITMX') || all(bf == 'ETMY'))
                filename = 'Skin left hole.png'; %D1003371. D1200677
            else
                filename = 'Skin right hole.png'; %D1100476, D1003374
            end

            [img, map, alphachannel] = imread(filename);
            image(img, 'AlphaData', m.getTransparentAlpha(img, [255 255 255]));

            if(m.argHas('t', varargin)) 
                %hold on
                xlimit = xlim;
                ylimit = ylim;
                text(xlimit(1)+10, ylimit(1)+25, varargin{m.argHas('t', varargin)+1}, 'FontSize', 32);
            end
            set(gca,'xtick',[])
            set(gca,'ytick',[])
            axis off

            %saveas(gcf, [baffle ' power distribution.png'])
            %print(['./figure/' baffle ' power distribution.png'],'-dpng','-r600');
            
            if(~exist('mode') || strcmp(mode, 'none'))
                return
            end
            %% index specified? 
            if(strcmp(mode, 'time series') || strcmp(mode, 'relative power'))
                if(isempty(m.channelNames) || isempty(m.dat))
                    error('\n\n No data or channel names loaded!!!\n\n');
                end
                t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;

                if(m.argHas('l', varargin))
                    index = varargin{m.argHas('l', varargin)+1};
                    for i = 1:4
                        PDdata{i} = m.dat(m.whichChan([baffle '_BAFFLEPD_' int2str(i) '_POWER'])).data;
                        PDdata{i} = PDdata{i}(index);
                    end
                    t = t(index);
                else
                    
                    for i = 1:4
                        PDdata{i} = m.dat(m.whichChan([baffle '_BAFFLEPD_' int2str(i) '_POWER'])).data;
                    end
                end

            end  
            %% select mode
            PDAxeWidth = 0.2; %width of the PD data
            switch mode

                case 'time series'
                    %% 'time series'
                    %PD1 data
                    PD1Axe = axes('Position',[0.08 0.53 PDAxeWidth PDAxeWidth]);
                    plot(PD1Axe, t, PDdata{1});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{1}),1,'significant');
                    avg = round(mean(PDdata{1})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD1: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);

                    %PD2 data
                    PD2Axe = axes('Position',[0.43 0.65 PDAxeWidth PDAxeWidth]);
                    plot(PD2Axe, t, PDdata{2});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{2}),1,'significant');
                    avg = round(mean(PDdata{2})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD2: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);

                    %PD3 data
                    PD3Axe = axes('Position',[0.78 0.27 PDAxeWidth PDAxeWidth]);
                    plot(PD3Axe, t, PDdata{3});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{3}),1,'significant');
                    avg = round(mean(PDdata{3})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD3: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);


                    %PD4 data
                    PD4Axe = axes('Position',[0.5 0.02 PDAxeWidth PDAxeWidth]);
                    plot(PD4Axe, t, PDdata{4});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{4}),1,'significant');
                    avg = round(mean(PDdata{4})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD4: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);         
                case 'relative power'
                    %% 'relative power'

        %             %color setting
        %             red = [1 0 0];
        %             blue = [0 0 1];
        %             green = [0 1 0];
        %             black = [0 0 0];
        %             fading = 0.1; % [0, 1] smaller the fader

                    barWidth = 0.9;
                    fontSize = 9;

                    avg = zeros(1,4);
                    sd = zeros(1,4);

                    for i = 1:4
                        sd(i) = round(std(PDdata{i}),1,'significant');
                        avg(i) = round(mean(PDdata{i})/10^floor(log10(sd(i))),0)*10^floor(log10(sd(i)));
                    end

                    %PD1 bar graph
                    PD1Axe = axes('Position',[0.05 0.53 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'r');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'w', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD1');
                    s = sprintf('%g\n± %g', avg(1), sd(1));
                    text(1:length(avg),avg,[s; blanks(length(s)); blanks(length(s)); blanks(length(s))],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);

                    %PD2 bar graph
                    PD2Axe = axes('Position',[0.4 0.65 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'w');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'g', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'w', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD2');
                    s = sprintf('%g\n± %g', avg(2), sd(2));
                    text(1:length(avg),avg,[blanks(length(s)); s; blanks(length(s)); blanks(length(s))],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);

                    %PD3 bar graph
                    PD3Axe = axes('Position',[0.78 0.27 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'w');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'b', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'w', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD3');
                    s = sprintf('%g\n± %g', avg(3), sd(3));
                    text(1:length(avg),avg,[blanks(length(s)); blanks(length(s)); s; blanks(length(s))],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);


                    %PD4 bar graph
                    PD4Axe = axes('Position',[0.48 0.02 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'w');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'k', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD4');
                    s = sprintf('%g\n± %g', avg(4), sd(4));
                    text(1:length(avg),avg,[blanks(length(s)); blanks(length(s)); blanks(length(s)); s],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);
                case 'power map'
                    %% map by local positions

        %             indx1 = currx > (c1(1)-window/2) & currx < (c1(1)+window/2);
        %             indx2 = currx > (c2(1)-window/2) & currx < (c2(1)+window/2);
        %             indx3 = currx > (c3(1)-window/2) & currx < (c3(1)+window/2);
        %             indx4 = currx > (c4(1)-window/2) & currx < (c4(1)+window/2);
        %             indy1 = curry > (c1(2)-window/2) & currx < (c1(2)+window/2);
        %             indy2 = curry > (c2(2)-window/2) & currx < (c2(2)+window/2);
        %             indy3 = curry > (c3(2)-window/2) & currx < (c3(2)+window/2);
        %             indy4 = curry > (c4(2)-window/2) & currx < (c4(2)+window/2);

        %             clow14 = min([min(min(db(PTM(indy1, indx1)))), min(min(db(PTM(indy4, indx4))))]);
        %             
        %             clow23 = min([min(min(db(PTM(indy2, indx2)))), min(min(db(PTM(indy3, indx3))))]);
        %             
        %             chigh14 = max([max(max(db(PTM(indy1, indx1)))), max(max(db(PTM(indy4, indx4))))]);
        %             
        %             chigh23 = max([max(max(db(PTM(indy2, indx2)))), max(max(db(PTM(indy3, indx3))))]);
        %             
        %             %PD1 map            
        %             PD1Axe = axes('Position',[0.08 0.57 PDAxeWidth/0.7 PDAxeWidth]);
        %             surf(currx(indx1) , curry(indy1) , db(PTM(indy1, indx1)),'edgecolor','none')
        %             colormap('jet')
        %             caxis([clow14 chigh14])
        %             view([0 90])
        %             xlim([min(currx(indx1)) max(currx(indx1))]);
        %             ylim([min(curry(indy1)) max(curry(indy1))]);
        %             %xlabel('mm')
        %             ylabel('mm')
        %             title('PD1: map');
        %             c = colorbar;
        %             c.Label.String = 'dB';
        %             c.TickLabelInterpreter = 'latex';
        %             c.Label.Interpreter = 'latex';
        %             box on
        %             grid on
        %             %set(gca,'xtick',[]);
        % 
        %             %PD2 data
        %             PD2Axe = axes('Position',[0.5 0.69 PDAxeWidth/0.7 PDAxeWidth]);
        %             surf(currx(indx2) , curry(indy2) , db(PTM(indy2, indx2)),'edgecolor','none')
        %             colormap('jet')
        %             caxis([clow23 chigh23])
        %             view([0 90])
        %             xlim([min(currx(indx2)) max(currx(indx2))]);
        %             ylim([min(curry(indy2)) max(curry(indy2))]);
        %             %xlabel('mm')
        %             ylabel('mm')
        %             title('PD2: map');    
        %             c = colorbar;
        %             c.Label.String = 'dB';
        %             c.TickLabelInterpreter = 'latex';
        %             c.Label.Interpreter = 'latex';
        %             box on
        %             grid on
        %             %set(gca,'xtick',[]);
        % 
        %             %PD3 data
        %             PD3Axe = axes('Position',[0.50 0.40 PDAxeWidth/0.7 PDAxeWidth]);
        %             surf(currx(indx3) , curry(indy3) , db(PTM(indy3, indx3)),'edgecolor','none')
        %             colormap('jet')
        %             caxis([clow23 chigh23])
        %             view([0 90])
        %             xlim([min(currx(indx3)) max(currx(indx3))]);
        %             ylim([min(curry(indy3)) max(curry(indy3))]);
        %             %xlabel('mm')
        %             ylabel('mm')
        %             title('PD3: map');
        %             c = colorbar;
        %             c.Label.String = 'dB';
        %             c.TickLabelInterpreter = 'latex';
        %             c.Label.Interpreter = 'latex';
        %             box on
        %             grid on
        %             %set(gca,'xtick',[]);
        % 
        % 
        %             %PD4 data
        %             PD4Axe = axes('Position',[0.52 0.07 PDAxeWidth/0.7 PDAxeWidth]);
        %             surf(currx(indx4) , curry(indy4) , db(PTM(indy4, indx4)),'edgecolor','none')
        %             colormap('jet')
        %             caxis([clow14 chigh14])
        %             view([0 90])
        %             xlim([min(currx(indx4)) max(currx(indx4))]);
        %             ylim([min(curry(indy4)) max(curry(indy4))]);
        %             %xlabel('mm')
        %             ylabel('mm')
        %             title('PD4: map');            
        %             c = colorbar;
        %             c.Label.String = 'dB';
        %             c.TickLabelInterpreter = 'latex';
        %             c.Label.Interpreter = 'latex';
        %             box on
        %             grid on
        %             %set(gca,'xtick',[]);
                    %% map by radial integration

                    PDx = -m.boxSize:m.res:m.boxSize + x;
                    PDy = -m.boxSize:m.res:m.boxSize + y;
                    
                    if(eval(['isempty(m.' baffle '.PDPowerMap)']))
                        m.getPDPowerMapWithBeamPos(baffle, currx, curry, PTM);
                    end
                    
                    eval(['PDPowerMap = m.' baffle '.PDPowerMap;']);


                    clow14 = min([min(min(db(PDPowerMap{1}))), min(min(db(PDPowerMap{4})))]); %#ok<USENS>
                    clow23 = min([min(min(db(PDPowerMap{2}))), min(min(db(PDPowerMap{3})))]);
                    chigh14 = max([max(max(db(PDPowerMap{1}))), max(max(db(PDPowerMap{4})))]);
                    chigh23 = max([max(max(db(PDPowerMap{2}))), max(max(db(PDPowerMap{3})))]);

                    
                    %PD1 map            
                    PD1Axe = axes('Position',[0.08 0.57 PDAxeWidth/0.7 PDAxeWidth]);
                    surf(PDx , PDy , db(PDPowerMap{1}'),'edgecolor','none')
                    colormap('jet')
                    caxis([clow14 chigh14])
                    view([0 90])
                    xlim([min(PDx) max(PDx)]);
                    ylim([min(PDy) max(PDy)]);
                    %xlabel('mm')
                    ylabel('mm')
                    title('PD1: map');
                    c = colorbar;
                    c.Label.String = 'dB';
                    c.TickLabelInterpreter = 'latex';
                    c.Label.Interpreter = 'latex';
                    box on
                    grid on
                    %set(gca,'xtick',[]);

                    %PD2 data
                    PD2Axe = axes('Position',[0.5 0.69 PDAxeWidth/0.7 PDAxeWidth]);
                    surf(PDx , PDy , db(PDPowerMap{2}'),'edgecolor','none')
                    colormap('jet')
                    caxis([clow23 chigh23])
                    view([0 90])
                    xlim([min(PDx) max(PDx)]);
                    ylim([min(PDy) max(PDy)]);
                    %xlabel('mm')
                    ylabel('mm')
                    title('PD2: map');    
                    c = colorbar;
                    c.Label.String = 'dB';
                    c.TickLabelInterpreter = 'latex';
                    c.Label.Interpreter = 'latex';
                    box on
                    grid on
                    %set(gca,'xtick',[]);

                    %PD3 data
                    PD3Axe = axes('Position',[0.50 0.40 PDAxeWidth/0.7 PDAxeWidth]);
                    surf(PDx , PDy , db(PDPowerMap{3}'),'edgecolor','none')
                    colormap('jet')
                    caxis([clow23 chigh23])
                    view([0 90])
                    xlim([min(PDx) max(PDx)]);
                    ylim([min(PDy) max(PDy)]);
                    %xlabel('mm')
                    ylabel('mm')
                    title('PD3: map');
                    c = colorbar;
                    c.Label.String = 'dB';
                    c.TickLabelInterpreter = 'latex';
                    c.Label.Interpreter = 'latex';
                    box on
                    grid on
                    %set(gca,'xtick',[]);


                    %PD4 data
                    PD4Axe = axes('Position',[0.52 0.07 PDAxeWidth/0.7 PDAxeWidth]);
                    surf(PDx , PDy , db(PDPowerMap{4}'),'edgecolor','none')
                    colormap('jet')
                    caxis([clow14 chigh14])
                    view([0 90])
                    xlim([min(PDx) max(PDx)]);
                    ylim([min(PDy) max(PDy)]);
                    %xlabel('mm')
                    ylabel('mm')
                    title('PD4: map');            
                    c = colorbar;
                    c.Label.String = 'dB';
                    c.TickLabelInterpreter = 'latex';
                    c.Label.Interpreter = 'latex';
                    box on
                    grid on
                    %set(gca,'xtick',[]);

            end
            %saveas(gcf, [baffle ' power distribution2.png'])
            %print(['./figure/' baffle ' power distribution2.png'],'-dpng','-r600');

            %% post process
            set(0,'defaultfigureposition',[400 200 600 500]); %set window size and location
        end
        % get field distribution map of baffle (‘*TM*’)
        % 4 modes: ‘time series’, ‘relative power’ (these two need to load data first)
        %	      ‘power map’, ‘none’ (these don’t)
        
        function transientScatterViewer(m, varargin)
        %TRANSIENTSCATTERVIEWER View the transient scatter data with
        %respect to beam positions
        %PREREQUISITE: MA-filtered cell data loaded (like
        %'ADS25W_O2_MA120_section.mat')
        %
        %   .transientScatterViewer(bf, 's')
        %   View the transient scatter on 'baffle' (like 'ITMX') with only
        %   the start point of each alignment
        %
        %   .transientScatterViewer(bf, 'a')
        %   View the transient scatter on 'baffle' (like 'ITMX') with all
        %   alignment paths
        %
        %   .transientScatterViewer(bf, 'a', 't', titleName)
        %   Add the big 'titleName' at the top-left of the viewer
        
            if(isempty(m.dat) || isempty(m.channelNames))
                fprintf('\n\n No data loaded!!! \n\n');
            end
            
            bf = varargin{1};
            mode = varargin{2};
            
            set(0,'defaultfigureposition',[50 50 900 800]);
            
            %colorbar stuff
            colorRes = 1000;
            colTable = jet;
            cr = interp1(1:(colorRes-1)/(length(colTable(:,1))-1):colorRes, colTable(:,1), 1:colorRes);
            cg = interp1(1:(colorRes-1)/(length(colTable(:,2))-1):colorRes, colTable(:,2), 1:colorRes);
            cb = interp1(1:(colorRes-1)/(length(colTable(:,3))-1):colorRes, colTable(:,3), 1:colorRes);
            
            PDdata = cell(1,4);
            x = [];
            y = [];
            
%             %calibration coeff from Anamaria
%             switch baffle(end)
%                 case 'X'
%                     pynum = 3;
%                     p2l = 0.98 *1000;% cts to mm
%                     y2l = -0.72 *1000;
%                 case 'Y'
%                     pynum = 4;
%                     p2l = 0.95 *1000;
%                     y2l = -0.76 *1000;
%             end
            
            switch mode
                case 's'
                    for n = 1:length(m.dat)
                        for i = 1:4
                            PDdata{i} = [PDdata{i}  m.dat{n}(m.whichChan(['BRDF_' bf '_PD_' int2str(i)])).data(1)];
                        end
                        
                        x = [x m.dat{n}(m.whichChan(['ADS_BEAM_POSITION_ETM' bf(end) '_x'])).data(1)];
                        y = [y m.dat{n}(m.whichChan(['ADS_BEAM_POSITION_ETM' bf(end) '_y'])).data(1)];
                        
                    end
                    markerSize = 10;
                    
                case 'a'
                    %for n = 1:79
                    for n = 1:length(m.dat)
                        for i = 1:4
                            PDdata{i} = [PDdata{i}; m.dat{n}(m.whichChan(['BRDF_' bf '_PD_' int2str(i)])).data(1:min(3000,m.dat{n}(1).duration))];
                        end
                       
                        x = [x; m.dat{n}(m.whichChan(['ADS_BEAM_POSITION_ETM' bf(end) '_x'])).data(1:min(3000,m.dat{n}(1).duration))];
                        y = [y; m.dat{n}(m.whichChan(['ADS_BEAM_POSITION_ETM' bf(end) '_y'])).data(1:min(3000,m.dat{n}(1).duration))];
                    end
                    
                    markerSize = 2;
            end

 
            figure
            pdToPlot = [1 4];
            L = length(pdToPlot);
            for i = 1:L
                eval(['currPD = PDdata{' int2str(pdToPlot(i)) '};']);
                subplot(ceil(L/2),2,i);
                da = max(currPD); 
                xiao = min(currPD);
%                 for j = 1:length(currPD)
%                     if(xiao > 0)
% %                             id = floor(1+(colorRes-1)*(log(currPD{i}(j))-log(xiao))/(log(da)-log(xiao)));
%                         id = floor(1+(colorRes-1)*(log10(currPD(j))-log10(xiao))/(log10(da)-log10(xiao)));
%                     else
%                         id = floor(1+(colorRes-1)*(currPD(j)-xiao)/(da-xiao));
%                     end
%                     plot(x(j), y(j), 'o', 'MarkerSize',markerSize, 'MarkerEdgeColor','none','MarkerFaceColor',[cr(id) cg(id) cb(id)]);
%                     hold on
%                 end
                scatter(x,y,markerSize,db(currPD),'filled')
                xlim([min(x) max(x)])
                ylim([min(y) max(y)])
                grid on
                xlabel(['$x$ on ETM' bf(end) ' [mm]'])
                ylabel(['$y$ on ETM' bf(end) ' [mm]'])
                colormap('jet')                    
                if(xiao > 0)
%                     c = colorbar('TicksMode','manual','Ticks',[xiao,10^(log10(xiao)+(log10(da)-log10(xiao))/4),...
%                         10^(log10(xiao)+(log10(da)-log10(xiao))/2),...
%                         10^(log10(xiao)+(log10(da)-log10(xiao))*3/4),da],'TickLabels',...
%                         {sprintf('%.2s',xiao), sprintf('%.2s',10^(log10(xiao)+(log10(da)-log10(xiao))/4)),...
%                         sprintf('%.2s',10^(log10(xiao)+(log10(da)-log10(xiao))/2)),...
%                         sprintf('%.2s',10^(log10(xiao)+(log10(da)-log10(xiao))*3/4)),...
%                         sprintf('%.2s',da)});
                    c = colorbar;
                    %c.Label.String = 'BRDF [sr$^{-1}$]';
                    c.Label.String = 'BRDF [dB]';
                else
                    c = colorbar('Ticks',[xiao, xiao+(da-xiao)/4, xiao+(da-xiao)/2,...
                        xiao+(da-xiao)*3/4, da],'TickLabels',...
                        {sprintf('%.2s',xiao), sprintf('%.2s',xiao+(da-xiao)/4),...
                        sprintf('%.2s',xiao+(da-xiao)/2), sprintf('%.2s',xiao+(da-xiao)*3/4), sprintf('%.2s',da)});
                    %c.Label.String = 'BRDF [sr$^{-1}$]';
                    c.Label.String = 'BRDF [dB]';
                end
                c.TickLabelInterpreter = 'latex';
                c.Label.Interpreter = 'latex';
                title([bf ' PD' int2str(pdToPlot(i))])
                set(gca,'FontSize',14)
                box on
                temp = xlim;
                xticks(ceil(temp(1)):1:floor(temp(2)))
                temp = ylim;
                yticks(ceil(temp(1)):1:floor(temp(2)))
            end
            
            if(m.argHas('t', varargin))
                titleAxe = axes('Position',[0.07 0.95 0.2 0.05]);
                set(gca,'xtick',[]);
                set(gca,'ytick',[]);
                axis off
                text(0, 0.5, varargin{m.argHas('t', varargin)+1}, 'FontSize', 18);
            end
                
            
            set(0,'defaultfigureposition',[400 300 600 400]);
        end
        % View the alignment path of PD measurement in color.
        % load MA filtered sectioned data view
        % mode: 's': scatter data (only get the start of each section)
        %       'a': all path in the section
        
        function SISViewer(m, varargin)
        %SISVIEWER View plot of SIS in this object
        %PREREQUISITE: SIS run
        %
        %   .SISViewer
        %   plot the 2D (BRDF v. radius) SIS profile on all baffles
        %
        %   .SISViewer('ITMX')
        %   plot the 2D (BRDF v. radius) SIS profile on 'ITMX' baffles
        %
        %   .SISViewer({'ITMX', 'ETMX'})
        %   plot the 2D (BRDF v. radius) SIS profile on the cell list of
        %   baffles
        %
        %   .SISViewer(... , '2D')
        %   plot the 2D radial SIS BRDF [1/sr] profile
        %
        %   .SISViewer(... , '3D')
        %   plot the 3D SIS BRDF [dB] profile
        %
        %   .SISViewer(... , 'PD')
        %   plot the radial SIS BRDF [dB] profile at PD locations (±10 mm)
        %
        %   .SISViewer(... , 'baffle')
        %   plot the 2D SIS BRDF [dB] profile received on baffles (view
        %   from the other side of the arm cavity)
        %
        %   See also RUNSIS
        
        
            baffle = {'ITMX','ETMX','ITMY','ETMY'};
            if(isempty(varargin))
                baffle = {'ITMX','ETMX','ITMY','ETMY'};
            elseif(iscell(varargin{1}))
                baffle = varargin{1};
            elseif(length(varargin{1}) == 4)
                baffle = varargin(1);
            end
            
            mode = '2D';
            if(m.argHas('2D', varargin))
                mode = '2D';
            elseif(m.argHas('3D', varargin))
                mode = '3D';
            elseif(m.argHas('PD', varargin))
                mode = 'PD';
            elseif(m.argHas('baffle', varargin))
                mode = 'baffle';
            end
            
            for bf = baffle
                bf = bf{1}; %#ok<FXSET>
                
                switch mode
                    
                    case '2D'
                        set(0,'defaultfigureposition',[400 300 600 400]);
                        figure
                        eval(['semilogy(m.' bf '.SIS.r, m.' bf '.SIS.BRDF);']);
                        axis tight
                        %xlim([170.1/1000/3994.5 1.8e-4])
                        xlim([0 700])
                        %xlim([0 1.8e-4])

                        temp = ylim;


                        grid on
                        %xlabel('Zenith angle [rad]');
                        ylabel('BRDF [sr$^{-1}$]');
                        xlabel('Radius [mm]');
                        %ylabel('BRDF [dB]');
                        title(bf)
                        %legend('O2','O3', 'PD1','PD2','PD3','PD4')
                        set(gca,'FontSize',14)
                        
                        
                    case '3D'
                        
                        eval(['currx = m.' bf '.SIS.x*1000;']);% mm
                        eval(['curry = m.' bf '.SIS.x*1000;']);
                        eval(['PTM = abs(m.' bf '.SIS.E).^2;']);%Power density
                        P = PTM*(mean(diff(currx))/1000)^2;  
                        BRDF = P/sum(sum(P))/((mean(diff(currx))/1000)^2/3994.5^2);
                        BRDF = db(BRDF);
                        
                        figure
                        surf(currx , curry , BRDF,'edgecolor','none')
                        %set(gca, 'ZScale', 'log');
                        %set(gca,'colorscale','log')
                        %zticks('')
                        xlabel('[mm]')
                        ylabel('[mm]')
                        zlabel('BRDF [dB]')
                        axis tight
                        colormap('jet')
                        caxis([min(min(BRDF)) max(max(BRDF))])
                        c = colorbar;
                        %c.Ruler.Scale = 'log';
                        %c.Ruler.MinorTick = 'on';  
                        c.Label.String = 'BRDF [dB]';
                        c.TickLabelInterpreter = 'latex';
                        c.Label.Interpreter = 'latex';
                        

                    case 'PD'
                        
                        set(0,'defaultfigureposition',[400 300 280 240]);
                        figure
                        eval(['plot(m.' bf '.SIS.r, db(m.' bf '.SIS.BRDF));']);
                        grid on
%                         xlo = min(m.ITMX.PD1.theta,m.ITMX.PD4.theta)-2.5e-6;
%                         xhi = max(m.ITMX.PD1.theta,m.ITMX.PD4.theta)+2.5e-6;
                        xlo = min(m.ITMX.PD1.r,m.ITMX.PD4.r)-10;
                        xhi = max(m.ITMX.PD1.r,m.ITMX.PD4.r)+10;
                        axis tight
                        xlim([xlo xhi]) 
                        temp = ylim;
                        hold on
                        pHandle = [];
                        eval(['pHandle(1) = plot([m.' bf '.PD1.r, m.' bf '.PD1.r], [temp(1) temp(2)], ''r--'');']);
                        eval(['pHandle(2) = plot([m.' bf '.PD2.r, m.' bf '.PD2.r], [temp(1) temp(2)], ''g--'');']);
                        eval(['pHandle(3) = plot([m.' bf '.PD3.r, m.' bf '.PD3.r], [temp(1) temp(2)], ''b--'');']);
                        eval(['pHandle(4) = plot([m.' bf '.PD4.r, m.' bf '.PD4.r], [temp(1) temp(2)], ''k--'');']);
                        set(gca,'FontSize',14)
                        ylabel('BRDF [dB]')

                        figure
                        eval(['plot(m.' bf '.SIS.r, db(m.' bf '.SIS.BRDF));']);
                        grid on
%                         xlo = min(m.ITMX.PD2.theta,m.ITMX.PD3.theta)-2.5e-6;
%                         xhi = max(m.ITMX.PD2.theta,m.ITMX.PD3.theta)+2.5e-6;
                        xlo = min(m.ITMX.PD2.r,m.ITMX.PD3.r)-10;
                        xhi = max(m.ITMX.PD2.r,m.ITMX.PD3.r)+10;
                        axis tight
                        xlim([xlo xhi]) 
                        temp = ylim;
                        hold on
                        pHandle = [];
                        eval(['pHandle(1) = plot([m.' bf '.PD1.r, m.' bf '.PD1.r], [temp(1) temp(2)], ''r--'');']);
                        eval(['pHandle(2) = plot([m.' bf '.PD2.r, m.' bf '.PD2.r], [temp(1) temp(2)], ''g--'');']);
                        eval(['pHandle(3) = plot([m.' bf '.PD3.r, m.' bf '.PD3.r], [temp(1) temp(2)], ''b--'');']);
                        eval(['pHandle(4) = plot([m.' bf '.PD4.r, m.' bf '.PD4.r], [temp(1) temp(2)], ''k--'');']);
                        set(gca,'FontSize',14)
                        legend(pHandle, 'PD1','PD2','PD3','PD4')

                        
                    case 'baffle'
                        set(0,'defaultfigureposition',[400 30 672 606]); %set window size and location
                        figure

                        vertR = 13.56*25.4/2;%mm LIGO-D1200322-v4
                        horiR = 13.54*25.4/2;%mm LIGO-D1200322-v4

                        beamAxe = axes('Position',[0 0 1 1]); %#ok<*NASGU>

                    %     %calibration plot
                    %     plot(beamAxe, [-vertR/2,vertR/2], [0 0]);
                    %     hold on
                    %     plot(beamAxe, [0 0], [-vertR/2,vertR/2]);
                    %     theta = 0:0.1:2*pi;
                    %     plot(beamAxe, vertR*cos(theta), vertR*sin(theta)); 

                    %     r = 30; %mm, Gaussian radius

                        x = 0;
                        y = 0;
                        eval(['currx = m.' bf '.SIS.x*1000;']);% mm
                        eval(['curry = m.' bf '.SIS.x*1000;']);
                        eval(['PTM = abs(m.' bf '.SIS.E).^2;']);%Power density
                        P = PTM*(mean(diff(currx))/1000)^2;   
                        BRDF = P/sum(sum(P))/((mean(diff(currx))/1000)^2/3994.5^2);
                        BRDF = db(BRDF);

                        [~,xmaxid] = max(max(BRDF));
                        [~,ymaxid] = max(BRDF(:, xmaxid));
                        eval(['x = round(m.' bf '.SIS.x(xmaxid)*1000); y = round(m.' bf '.SIS.x(ymaxid)*1000); ']);

                        surf(currx , curry , BRDF,'edgecolor','none')
                        colormap('jet')

                        caxis([(min(min(BRDF))) (max(max(BRDF)))])

                        view([0 90])

                    %     theta = 0:0.001:2*pi;
                    %     plot(beamAxe, r*cos(theta)+x, r*sin(theta)+y, 'r', 'MarkerSize', 10); 
                    %     hold on

                        %text(-vertR*0.78, -vertR*0.5, [sprintf('xoffset = %d mm\n', x) sprintf('yoffset = %d mm\n', y)],'Color','k');
                        if(all(bf == 'ITMX') || all(bf == 'ETMY'))
                            xlim([-170*1.2, 502*1.2]);%set the scale correctly
                        else
                            xlim([-502*1.2, 170*1.2]);%set the scale correctly
                        end
                        
                        ylim([-170*1.2,436*1.2]);
                        hold off
                        axis off   

                        imageAxe = axes('Position',[0 0 1 1]); %x, y, width, height
                        
                        
                        if(all(bf == 'ITMX') || all(bf == 'ETMY'))
                            filename = 'Skin left hole.png'; %D1003371. D1200677
                        else
                            filename = 'Skin right hole.png'; %D1100476, D1003374
                        end
                        
                        [img, map, alphachannel] = imread(filename);
                        image(img, 'AlphaData', m.getTransparentAlpha(img, [255 255 255]));
                        
                        xlimit = xlim;
                        ylimit = ylim;
                        text(xlimit(1)+10, ylimit(1)+30, bf, 'FontSize', 32);

                        set(gca,'xtick',[])
                        set(gca,'ytick',[])
                        axis off
                        %saveas(gcf, [baffle ' power distribution.png'])
                        %print(['./figure/' baffle ' power distribution.png'],'-dpng','-r600');
                                        
                end
                
            end
            
            
            
       
            set(0,'defaultfigureposition',[400 300 600 400]);
        end
        % Get Power-radial distance 2D plot from SIS 
        % mode: 
        % empty: 2D radial
        % '3D'
        % 'PD': radial near PD
        %'baffle': on baffle
        
        function beamPositioninO2SSViewer(m)
        %BEAMPOSITIONINO2SSVIEWER View the beam positions during locks of
        %O2
        %PREREQUISITE: .getDriveAlignComboDurations run
        %
        %   .beamPositioninO2SSViewer
        %   Plot the steady-state beam positions
        %
        %   See also GETDRIVEALIGNCOMBODURATIONS
            
            pos = m.O2SSpos;
            figure
            i = 1;
            for baffle = {'ITMX','ETMX','ITMY','ETMY'}
                bf = baffle{1};
                subplot(2,2,i);
                %set(0,'defaultfigureposition',[400 300 400 400]);
                eval(['plot(pos.' bf '.x, pos.' bf '.y, ''ro'')']);
                hold on
                axis square
                grid on
                plot(10*cos(0:0.01:2*pi), 10*sin(0:0.01:2*pi), 'Color', '[0.15 0.15 0.15]','LineStyle','--')
                plot(8*cos(0:0.01:2*pi), 8*sin(0:0.01:2*pi), 'Color', '[0.15 0.15 0.15]','LineStyle','--')
                plot(6*cos(0:0.01:2*pi), 6*sin(0:0.01:2*pi), 'Color', '[0.15 0.15 0.15]','LineStyle','--')
                plot(4*cos(0:0.01:2*pi), 4*sin(0:0.01:2*pi), 'Color', '[0.15 0.15 0.15]','LineStyle','--')
                plot(2*cos(0:0.01:2*pi), 2*sin(0:0.01:2*pi), 'Color', '[0.15 0.15 0.15]','LineStyle','--')
                xlabel('x [mm]')
                ylabel('y [mm]')
                %title([bf ' beam position in O2 locks'])
                title(bf)
                set(gca,'FontSize',12)
                i = i+1;
            end
            
            
        end
        %View O2 steady state beam positions (using m.O2SSpos)

        
                
        %% Steady-state (lock) scatter
        
        function introToFPCavity(m) %#ok<*MANU>
        %INTROTOFPCAVITY Plot transmittance and reflectance of FP cavity
        %with respect to mirror properties
        %   .introToFPCavity
        %   Make these introduction plots
        
            set(0,'defaultfigureposition',[400 300 350 310]);
            %reflectance/transmittance
            R1s = [0.9 0.99 0.999];
            R2s = [0.9 0.99 0.999];
            T1s = 1-R1s;
            T2s = 1-R2s;
            
            kL = -0.1:0.0001:0.1;
            cos2kL = -1:0.01:1;
                   
            figure
            lgd = {};
            for i = 1:length(R1s)
                R1 = R1s(i);
                R2 = R2s(i);
                T_FP = (1-R1)*(1-R2)./(1-2*sqrt(R1*R2)*cos(2*kL)+R1*R2);
                plot(kL, T_FP)
                hold on
                lgd = [lgd ['$R = ' num2str(R1s(i)) '$']];
            end
            legend(lgd,'location','northwest');
            hold off
            grid on
            xlabel('$kL$')
            ylabel('$T_{FP}$')
            %title(['$R_1 = ' num2str(R1) '; R_2 = ' num2str(R2) '$'])
            axis tight
            ylim([0 1]);
            
            figure
            lgd = {};
            for i = 1:length(R1s)
                R1 = R1s(i);
                R2 = R2s(i);
                R_FP = (R1-2*sqrt(R1*R2)*cos(2*kL)+R2)./(1-2*sqrt(R1*R2)*cos(2*kL)+R1*R2);
                plot(kL, R_FP)
                hold on
                lgd = [lgd ['$R = ' num2str(R1s(i)) '$']];
            end
            legend(lgd,'location','southwest');
            hold off
            grid on
            xlabel('$kL$')
            ylabel('$R_{FP}$')
            %title(['$R_1 = ' num2str(R1) '; R_2 = ' num2str(R2) '$'])
            axis tight
            ylim([0 1]);
            
            figure
            lgd = {};
            for i = 1:length(R1s)
                R1 = R1s(i);
                R2 = R2s(i);
                T_FP = (1-R1)*(1-R2)./(1-2*sqrt(R1*R2)*cos2kL+R1*R2);
                plot(cos2kL, T_FP)
                hold on
                lgd = [lgd ['$R = ' num2str(R1s(i)) '$']];
            end
            hold off
            grid on
            legend(lgd);
            xlabel('cos$(2kL)$')
            ylabel('$T_{FP}$')
            %title(['$R_1 = ' num2str(R1) '; R_2 = ' num2str(R2) '$'])
            axis tight
            ylim([0 1]);
            
            figure
            for i = 1:length(R1s)
                R1 = R1s(i);
                R2 = R2s(i);
                R_FP = (R1-2*sqrt(R1*R2)*cos2kL+R2)./(1-2*sqrt(R1*R2)*cos2kL+R1*R2);
                plot(cos2kL, R_FP)
                hold on
            end
            grid on
            xlabel('cos$(2kL)$')
            ylabel('$R_{FP}$')
            title(['$R_1 = ' num2str(R1) '; R_2 = ' num2str(R2) '$'])
            axis tight
            ylim([0 1]);

            
            
            
            set(0,'defaultfigureposition',[400 300 600 400]);

        end
        % plot FP transmittance and reflectance
        
        function demoPhasemapOnSIS(m, varargin) 
        %DEMOPHASEMAPONSIS Plot the simulation w/o phasemap and finite mirror
        %size to demo the effect of their diffractions
        %PREREQUISITE: have demoSISPhasemap.mat in folder
        %
        %   .demoPhasemapOnSIS
        %   plot scatter BRDF on all 4 baffles
        %
        %   .demoPhasemapOnSIS('PD')
        %   plot scatter BRDF on all 4 baffles along with PD measurements
            
            load demoSISPhasemap
            
            if(m.argHas('PD', varargin))
                plotPD = true;
            else
                plotPD = false;
            end
            
            
            for arm = 'XY'
                for baffle = {'ITM', 'ETM'}
                    bf = [baffle{1} arm];
                    set(0,'defaultfigureposition',[400 300 600 400]);
                    figure
                    eval(['semilogy(nominal.' bf '.SIS.r, nominal.' bf '.SIS.BRDF);']);
                    hold on
                    eval(['semilogy(finite.' bf '.SIS.r, finite.' bf '.SIS.BRDF);']);
                    eval(['semilogy(m.' bf '.SIS.r, m.' bf '.SIS.BRDF);']);
                    axis tight
                    %xlim([170.1/1000/3994.5 1.8e-4])
                    xlim([0 700])
                    %xlim([0 1.8e-4])

                    temp = ylim;

                    
                    pHandle = [];

                    if(plotPD)
%                         eval(['pHandle(1) = plot([m.' bf '.PD1.theta, m.' bf '.PD1.theta], [3.5329e9, min(nominal.' bf '.SIS.BRDF)], ''r--'');']);
%                         eval(['pHandle(2) = plot([m.' bf '.PD2.theta, m.' bf '.PD2.theta], [3.5329e9, min(nominal.' bf '.SIS.BRDF)], ''g--'');']);
%                         eval(['pHandle(3) = plot([m.' bf '.PD3.theta, m.' bf '.PD3.theta], [3.5329e9, min(nominal.' bf '.SIS.BRDF)], ''b--'');']);
%                         eval(['pHandle(4) = plot([m.' bf '.PD4.theta, m.' bf '.PD4.theta], [3.5329e9, min(nominal.' bf '.SIS.BRDF)], ''k--'');']);

                        eval(['pHandle(1) = plot([m.' bf '.PD1.r, m.' bf '.PD1.r], [temp(1), temp(2)], ''r--'');']);
                        eval(['pHandle(2) = plot([m.' bf '.PD2.r, m.' bf '.PD2.r], [temp(1), temp(2)], ''g--'');']);
                        eval(['pHandle(3) = plot([m.' bf '.PD3.r, m.' bf '.PD3.r], [temp(1), temp(2)], ''b--'');']);
                        eval(['pHandle(4) = plot([m.' bf '.PD4.r, m.' bf '.PD4.r], [temp(1), temp(2)], ''k--'');']);
                    end
                    
                    grid on
                    %xlabel('Zenith angle [rad]');
                    ylabel('BRDF [sr$^{-1}$]');
                    xlabel('Radius [mm]');
                    %ylabel('BRDF [dB]');
                    hold off
                    title(bf)
                    legend('Nominal in arm','Finite mirror size','Phasemap','location','northeast')
                    %legend('O2','O3', 'PD1','PD2','PD3','PD4')
                    set(gca,'FontSize',14)
                    
                    if(plotPD)
                        set(0,'defaultfigureposition',[400 300 280 240]);
                        figure
                        eval(['semilogy(nominal.' bf '.SIS.r, nominal.' bf '.SIS.BRDF);']);
                        hold on
                        eval(['semilogy(finite.' bf '.SIS.r, finite.' bf '.SIS.BRDF);']);
                        eval(['semilogy(m.' bf '.SIS.r, m.' bf '.SIS.BRDF);']);

                        
                        grid on
                        xlo = min(m.ITMX.PD1.theta,m.ITMX.PD4.theta)-2.5e-6;
                        xhi = max(m.ITMX.PD1.theta,m.ITMX.PD4.theta)+2.5e-6;
                        xlo = min(m.ITMX.PD1.r,m.ITMX.PD4.r)-10;
                        xhi = max(m.ITMX.PD1.r,m.ITMX.PD4.r)+10;
                        axis tight
                        xlim([xlo xhi]) 
                        temp = ylim;
                        
                        pHandle = [];
                        eval(['pHandle(1) = plot([m.' bf '.PD1.r, m.' bf '.PD1.r], [temp(1) temp(2)], ''r--'');']);
                        eval(['pHandle(2) = plot([m.' bf '.PD2.r, m.' bf '.PD2.r], [temp(1) temp(2)], ''g--'');']);
                        eval(['pHandle(3) = plot([m.' bf '.PD3.r, m.' bf '.PD3.r], [temp(1) temp(2)], ''b--'');']);
                        eval(['pHandle(4) = plot([m.' bf '.PD4.r, m.' bf '.PD4.r], [temp(1) temp(2)], ''k--'');']);
                        set(gca,'FontSize',14)



                        figure
                        eval(['semilogy(nominal.' bf '.SIS.r, nominal.' bf '.SIS.BRDF);']);
                        hold on
                        eval(['semilogy(finite.' bf '.SIS.r, finite.' bf '.SIS.BRDF);']);
                        eval(['semilogy(m.' bf '.SIS.r, m.' bf '.SIS.BRDF);']);

                        pHandle = [];
                        grid on
                        xlo = min(m.ITMX.PD2.theta,m.ITMX.PD3.theta)-2.5e-6;
                        xhi = max(m.ITMX.PD2.theta,m.ITMX.PD3.theta)+2.5e-6;
                        xlo = min(m.ITMX.PD2.r,m.ITMX.PD3.r)-10;
                        xhi = max(m.ITMX.PD2.r,m.ITMX.PD3.r)+10;
                        axis tight
                        xlim([xlo xhi]) 
                        temp = ylim;

                        eval(['pHandle(1) = plot([m.' bf '.PD1.r, m.' bf '.PD1.r], [temp(1) temp(2)], ''r--'');']);
                        eval(['pHandle(2) = plot([m.' bf '.PD2.r, m.' bf '.PD2.r], [temp(1) temp(2)], ''g--'');']);
                        eval(['pHandle(3) = plot([m.' bf '.PD3.r, m.' bf '.PD3.r], [temp(1) temp(2)], ''b--'');']);
                        eval(['pHandle(4) = plot([m.' bf '.PD4.r, m.' bf '.PD4.r], [temp(1) temp(2)], ''k--'');']);
                        set(gca,'FontSize',14)
                    end
                end
            end
        end
        % Plot the simulation w/o phasemap and finite mirror
        
        function demoPDAveragingOnSIS(m, varargin) 
        %DEMOPDAVERAGINGONSIS Plot the simulation w/o PD averaging (10 mm)
        %PREREQUISITE: have demoPDAveragingOnSIS.mat in folder
        %
        %   .demoPDAveragingOnSIS
        %   plot scatter BRDF on all 4 baffles
            
            load demoPDAveragingOnSIS
            
            for arm = 'XY'
                for baffle = {'ITM', 'ETM'}
                    bf = [baffle{1} arm];

                    set(0,'defaultfigureposition',[400 300 280 240]);
                    figure
                    eval(['plot(raw.' bf '.SIS.theta, db(raw.' bf '.SIS.BRDF));']);
                    hold on
                    eval(['plot(pdavg.' bf '.SIS.theta, db(pdavg.' bf '.SIS.BRDF));']);

                    grid on
                    xlo = min(m.ITMX.PD1.theta,m.ITMX.PD4.theta)-2.5e-6;
                    xhi = max(m.ITMX.PD1.theta,m.ITMX.PD4.theta)+2.5e-6;
%                     xlo = min(m.ITMX.PD1.r,m.ITMX.PD4.r)-10;
%                     xhi = max(m.ITMX.PD1.r,m.ITMX.PD4.r)+10;
                    axis tight
                    xlim([xlo xhi]) 
                    temp = ylim;

                    pHandle = [];
                    eval(['pHandle(1) = plot([m.' bf '.PD1.theta, m.' bf '.PD1.theta], [temp(1) temp(2)], ''r--'');']);
                    eval(['pHandle(2) = plot([m.' bf '.PD2.theta, m.' bf '.PD2.theta], [temp(1) temp(2)], ''g--'');']);
                    eval(['pHandle(3) = plot([m.' bf '.PD3.theta, m.' bf '.PD3.theta], [temp(1) temp(2)], ''b--'');']);
                    eval(['pHandle(4) = plot([m.' bf '.PD4.theta, m.' bf '.PD4.theta], [temp(1) temp(2)], ''k--'');']);
                    set(gca,'FontSize',14)
                    xlabel('Zenith angle [rad]')
                    ylabel('BRDF [dB]')



                    figure
                    eval(['plot(raw.' bf '.SIS.theta, db(raw.' bf '.SIS.BRDF));']);
                    hold on
                    eval(['plot(pdavg.' bf '.SIS.theta, db(pdavg.' bf '.SIS.BRDF));']);

                    pHandle = [];
                    grid on
                    xlo = min(m.ITMX.PD2.theta,m.ITMX.PD3.theta)-2.5e-6;
                    xhi = max(m.ITMX.PD2.theta,m.ITMX.PD3.theta)+2.5e-6;
%                     xlo = min(m.ITMX.PD2.r,m.ITMX.PD3.r)-10;
%                     xhi = max(m.ITMX.PD2.r,m.ITMX.PD3.r)+10;
                    axis tight
                    xlim([xlo xhi]) 
                    temp = ylim;
                    eval(['pHandle(1) = plot([m.' bf '.PD1.theta, m.' bf '.PD1.theta], [temp(1) temp(2)], ''r--'');']);
                    eval(['pHandle(2) = plot([m.' bf '.PD2.theta, m.' bf '.PD2.theta], [temp(1) temp(2)], ''g--'');']);
                    eval(['pHandle(3) = plot([m.' bf '.PD3.theta, m.' bf '.PD3.theta], [temp(1) temp(2)], ''b--'');']);
                    eval(['pHandle(4) = plot([m.' bf '.PD4.theta, m.' bf '.PD4.theta], [temp(1) temp(2)], ''k--'');']);
                    
%                     eval(['pHandle(1) = plot([m.' bf '.PD1.r, m.' bf '.PD1.r], [temp(1) temp(2)], ''r--'');']);
%                     eval(['pHandle(2) = plot([m.' bf '.PD2.r, m.' bf '.PD2.r], [temp(1) temp(2)], ''g--'');']);
%                     eval(['pHandle(3) = plot([m.' bf '.PD3.r, m.' bf '.PD3.r], [temp(1) temp(2)], ''b--'');']);
%                     eval(['pHandle(4) = plot([m.' bf '.PD4.r, m.' bf '.PD4.r], [temp(1) temp(2)], ''k--'');']);
                    set(gca,'FontSize',14)
                    legend('Original BRDF','Measured BRDF')

                end
            end
        end
        % Plot the simulation w/o PD averaging
        
        function demoO2LockPositionsOnSIS(m)
        %DEMOO2LOCKPOSITIONSONSIS Plot all simulations with beam positions in
        %O2 to compare the difference from them
        %PREREQUISITE have SISwithO2SSPositions.mat in the directory
        %
        %   .demoO2LockPositionsOnSIS
        %   Plot all simulations together
            
            load SISwithO2SSPositions
            
            for baffle = {'ITMX','ETMX','ITMY','ETMY'}
                bf = baffle{1};
                if(bf(end)=='X')
                    pcav = 100846;
                else
                    pcav = 108600;
                end
                set(0,'defaultfigureposition',[400 300 600 400]);
                figure
                for i = 1:N
                    
                    eval(['semilogy(pos.' bf '.r{i}, pos.' bf '.r2P{i}/pcav/6.2630e-12, ''DisplayName'', ''lgd{i}'');']);
                    hold on
                end
                eval(['R = pos.' bf '.r{i};']);
                eval(['BRDF = pos.' bf '.r2P{i}/pcav/6.2630e-12;']);
                grid on
                xlabel('Radial distance [mm]');
                ylabel('BRDF [sr$^{-1}$]');
                xlim([min(R) max(R)])
                ylim([min(BRDF) max(BRDF)])
                
                %style = {'r.', 'g.', 'b.', 'k.'};
                rcell = {};
                Pcell = {};
                dPcell = {};

%                     for pd = 1:4
%                         eval(['xbch = m.whichChan(''BEAM_POSITION_' bf '_x'');'])
%                         eval(['ybch = m.whichChan(''BEAM_POSITION_' bf '_y'');'])
%                         eval(['pdpwrch = m.whichChan(''PDPOWER_' bf '_PD' int2str(pd) ''');']);
%                         r = [];
%                         nmlzdP = [];
%                         dnmlzdP = [];
%                         for i = 1:length(m.dat)
%                             xb = mean(m.dat{i}(xbch).data);
%                             yb = mean(m.dat{i}(ybch).data);
%                             eval(['r = [r sqrt((m.' bf '.PD' int2str(pd) '.x - xb)^2 + (m.' bf '.PD' int2str(pd) '.y - yb)^2)];']);
%                             temp = (m.dat{i}(pdpwrch).data./(m.dat{i}(powerch).data/2*2*450/pi));
%                             nmlzdP = [nmlzdP mean(temp)];
%                             dnmlzdP = [dnmlzdP std(temp)];
%                             
%                         end
%                         rcell = [rcell r];
%                         Pcell = [Pcell nmlzdP];
%                         dPcell = [dPcell dnmlzdP];
%                         pHandle(pd) = errorbar(r,nmlzdP,dnmlzdP, style{pd});
%                     end
%                     legend(pHandle, 'PD1','PD2','PD3','PD4')
%                     title([bf ' steady-state PD data in entire O2'])
                pHandle = [];
                pHandle(1) = plot([m.ITMX.PD1.r, m.ITMX.PD1.r], [max(BRDF), min(BRDF)], 'r--');
                pHandle(2) = plot([m.ITMX.PD2.r, m.ITMX.PD2.r], [max(BRDF), min(BRDF)], 'g--');
                pHandle(3) = plot([m.ITMX.PD3.r, m.ITMX.PD3.r], [max(BRDF), min(BRDF)], 'b--');
                pHandle(4) = plot([m.ITMX.PD4.r, m.ITMX.PD4.r], [max(BRDF), min(BRDF)], 'k--');
                if(exist('lgd')) 
                    legend(lgd,'Location','northeast');
                end
                title([bf ' BRDF Estimation for beam positions in O2'])
                

                set(0,'defaultfigureposition',[400 300 280 240]);
                diff = 10; % 'diff'-factor difference in yaxis
                figure
                for i = 1:N
                    
                    %eval(['semilogy(pos.' bf '.r{i}, pos.' bf '.r2P{i});']);
                    eval(['plot(pos.' bf '.r{i}, db(pos.' bf '.r2P{i}/pcav/6.2630e-12));']);
                    hold on
                end
                grid on
%                     errorbar(rcell{1}, Pcell{1}, dPcell{1}, style{1});
%                     errorbar(rcell{4}, Pcell{4}, dPcell{4}, style{4});
%                     xlim([floor(min(min(rcell{1}), min(rcell{4}))) ceil(max(max(rcell{1}), max(rcell{4})))])

                xlo = min(m.ITMX.PD1.r,m.ITMX.PD4.r)-10;
                xhi = max(m.ITMX.PD1.r,m.ITMX.PD4.r)+10;
%                 eval(['xlo = min(min(pos.' bf '.r{:}))-10;']);
%                 eval(['xhi = max(max(pos.' bf '.r{:}))+10;']);
                ymid = (db(max(BRDF(R>=xlo & R<=xhi)))+db(min(BRDF(R>=xlo & R<=xhi))))/2;
                %ylo = db2mag(ymid - db(diff)/2);
                %yhi = db2mag(ymid + db(diff)/2);
                ylo = (ymid - db(diff)/2);
                yhi = (ymid + db(diff)/2);
                plot([m.ITMX.PD1.r, m.ITMX.PD1.r], [yhi,ylo], 'r--')
                plot([m.ITMX.PD4.r, m.ITMX.PD4.r], [yhi,ylo], 'k--')
                xlim([xlo xhi]);
                ylim([ylo yhi]);
                ylabel('BRDF [dB]')


                figure
                for i = 1:N
                    
                    %eval(['semilogy(pos.' bf '.r{i}, pos.' bf '.r2P{i});']);
                    eval(['plot(pos.' bf '.r{i}, db(pos.' bf '.r2P{i}/pcav/6.2630e-12));']);
                    hold on
                end
                
                grid on

%                     errorbar(rcell{2}, Pcell{2}, dPcell{2}, style{2});
%                     errorbar(rcell{3}, Pcell{3}, dPcell{3}, style{3});
%                     xlim([floor(min(min(rcell{2}), min(rcell{3}))) ceil(max(max(rcell{2}), max(rcell{3})))])
                xlo = min(m.ITMX.PD2.r,m.ITMX.PD3.r)-10;
                xhi = max(m.ITMX.PD2.r,m.ITMX.PD3.r)+10;
                ymid = (db(max(BRDF(R>=xlo & R<=xhi)))+db(min(BRDF(R>=xlo & R<=xhi))))/2;
                %ylo = db2mag(ymid - db(diff)/2);
                %yhi = db2mag(ymid + db(diff)/2);
                ylo = (ymid - db(diff)/2);
                yhi = (ymid + db(diff)/2);
                plot([m.ITMX.PD2.r, m.ITMX.PD2.r], [yhi,ylo], 'g--')
                plot([m.ITMX.PD3.r, m.ITMX.PD3.r], [yhi,ylo], 'b--')
                xlim([xlo xhi]);
                ylim([ylo yhi]);
            end
            

        end
        % Plot all simulations with beam positions in O2 to compare the difference from them
        
        function steadyStateScatterInO2(m, baffle)
        %STEADYSTATESCATTERINO2 Plot steady-state scatter in O2
        %PREREQUISITE: struct data loaded (like O2_minTrend.mat)
        %               
        %   .steadyStateScatterInO2
        %   plot the O2 steady-state scatter measured on all 4 baffles
        %
        %   .steadyStateScatterInO2('ITMX')
        %   only plot the ITMX baffle PD steady-state measurements
        %
        %   .steadyStateScatterInO2({'ITMX','ITMY'})
        %   plot PD scatter on designated baffle cell list
        %
        %   See also GETO2FINALINDEX PDVIEWER
        
            if(~exist('baffle'))
                baffle = {'ITMX','ETMX','ITMY','ETMY'};
            end
            
            if(~iscell(baffle))
                
                baffle = {baffle};
                
            end
            
            
            if(isempty(m.channelNames) || isempty(m.dat))
                error('\n\n No data or channel names loaded!!!\n\n');
            end

            %t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;

            if(isempty(m.finalIndex))
                m.getO2FinalIndex;
            end
            for i = 1:length(baffle)
                m.PDViewer(baffle{i}, 'l',m.finalIndex);
            end

            % m.beamPositionViewer(baffle, 'relative power', baffle, finalIndex);
            % m.chanViewer(['C-P*IN+PR2+SUS*' baffle(2:4)], finalIndex);
        end
        % check the stability of data in O2. Plot range is entire O2
        
        function compareSSBRDF(m)
        %COMPARESSBRDF Compare simulation with O2 SS scatter measurements
        %PREREQUISITE: SS_O2_minTrend_section.mat loaded
        %
        %   .compareSSBRDF
        %   compare SS scatter on all baffles
        
            for arm = 'XY'
                
%                 if(eval(['isempty(m.ITM' arm '.SIS.BRDF)']))
%                     ITM_x = mean(m.dat{1}(m.whichChan(['ITM' arm '_x'])).data)/1000;
%                     ITM_y = mean(m.dat{1}(m.whichChan(['ITM' arm '_y'])).data)/1000;
%                     ETM_x = mean(m.dat{1}(m.whichChan(['ETM' arm '_x'])).data)/1000;
%                     ETM_y = mean(m.dat{1}(m.whichChan(['ETM' arm '_y'])).data)/1000;
%                     %m.runSIS('arm', arm, 'ITMx',ITM_x,'ITMy',ITM_y,'ETMx',ETM_x,'ETMy',ETM_y);
%                     m.runSIS('arm', arm);% assume same pattern
%                 end
                
                for baffle = {'ITM', 'ETM'}
                    bf = [baffle{1} arm];
                    set(0,'defaultfigureposition',[400 300 600 400]);
                    figure
                    eval(['theta_s = m.' bf '.SIS.theta;']);
                    eval(['BRDF_s = m.' bf '.SIS.BRDF;']);
                    r_s = tan(theta_s)*m.L_c*1000; %mm
                    plot(r_s, db(BRDF_s));
                    %semilogy(theta_s, BRDF_s);
                    hold on
                    grid on
                    %xlabel('Zenith angle [rad]');
                    xlabel('Radius [mm]');
                    %ylabel('BRDF [sr$^{-1}$]');
                    ylabel('BRDF [dB]');
                    
                    style = {'r.', 'g.', 'b.', 'k.'};
                    pHandle = [];
                    thetacell = {};
                    BRDFcell = {};
                    dBRDFcell = {};
                    rcell = {};
                    for pd = 1:4
                        eval(['xbch = m.whichChan(''BEAM_POSITION_' bf '_x'');'])
                        eval(['ybch = m.whichChan(''BEAM_POSITION_' bf '_y'');'])
                        pdch = m.whichChan(['WXJ-BRDF_' bf '_PD_' int2str(pd)]);
                        theta = [];
                        BRDF = [];
                        dBRDF = [];
                        r = [];
                        for i = 1:length(m.dat)
                            xb = mean(m.dat{i}(xbch).data);
                            yb = mean(m.dat{i}(ybch).data);
                            eval(['r = [r sqrt((m.' bf '.PD' int2str(pd) '.x - xb)^2 + (m.' bf '.PD' int2str(pd) '.y - yb)^2)];']);
                            eval(['theta = [theta m.' bf '.PD' int2str(pd) '.theta];']);
                            BRDF = [BRDF mean(m.dat{i}(pdch).data)];
                            dBRDF = [dBRDF std(m.dat{i}(pdch).data)];
                            
                        end
                        thetacell = [thetacell theta];
                        BRDFcell = [BRDFcell BRDF];
                        dBRDFcell = [dBRDFcell dBRDF];
                        rcell = [rcell r];
                        %pHandle(pd) = errorbar(theta,BRDF,dBRDF, style{pd});
                        pHandle(pd) = errorbar(r,db(BRDF),db(BRDF-dBRDF) - db(BRDF),db(BRDF+dBRDF) - db(BRDF), style{pd});
                    end
                    hold off
                    legend(pHandle, 'PD1','PD2','PD3','PD4')
                    %title([bf ' steady-state PD data in ' m.fileName(14:24)])
                    title([bf ' steady-state PD BRDF in entire O2'])
                    axis tight
                    %xlim([atan(170/1000/m.L_c), 1.8e-4])
                    xlim([0, 700])
                    set(gca, 'fontsize',14)
                    
                    
                    
                    set(0,'defaultfigureposition',[400 300 280 240]);
                    figure
                    %semilogy(theta_s, BRDF_s);
                    plot(r_s, db(BRDF_s))
                    hold on
                    grid on
                    pHandle = [];
                    %errorbar(thetacell{1}, BRDFcell{1}, dBRDFcell{1}, style{1});
                    %errorbar(thetacell{4}, BRDFcell{4}, dBRDFcell{4}, style{4});
                    pHandle(1) = errorbar(rcell{1}, db(BRDFcell{1}), db(BRDFcell{1}-dBRDFcell{1}) - db(BRDFcell{1}), db(BRDFcell{1}+dBRDFcell{1}) - db(BRDFcell{1}), style{1});
                    pHandle(2) = errorbar(rcell{4}, db(BRDFcell{4}), db(BRDFcell{4}-dBRDFcell{4}) - db(BRDFcell{4}), db(BRDFcell{4}+dBRDFcell{4}) - db(BRDFcell{4}),style{4});
                    axis tight
                    %xlim([min(min(thetacell{1}), min(thetacell{4}))-1e-6 max(max(thetacell{1}), max(thetacell{4}))+1e-6])
                    xlim([min(min(rcell{1}), min(rcell{4}))-1 max(max(rcell{1}), max(rcell{4}))+1])
                    %ylabel('BRDF [dB]')
                    %xlabel('Radius [mm]')
                    %xlabel('Zenith angle [rad]')
                    legend(pHandle,'PD1','PD4', 'location','best')
                    
                    figure
                    %semilogy(theta_s, BRDF_s);
                    plot(r_s, db(BRDF_s));
                    hold on
                    grid on
                    pHandle = [];
                    %errorbar(thetacell{2}, BRDFcell{2}, dBRDFcell{2}, style{2});
                    %errorbar(thetacell{3}, BRDFcell{3}, dBRDFcell{3}, style{3});
                    pHandle(1) = errorbar(rcell{2}, db(BRDFcell{2}), db(BRDFcell{2}-dBRDFcell{2}) - db(BRDFcell{2}), db(BRDFcell{2}+dBRDFcell{2}) - db(BRDFcell{2}),style{2});
                    pHandle(2) = errorbar(rcell{3}, db(BRDFcell{3}), db(BRDFcell{3}-dBRDFcell{3}) - db(BRDFcell{3}), db(BRDFcell{3}+dBRDFcell{3}) - db(BRDFcell{3}), style{3});
                    axis tight
                    %xlim([min(min(thetacell{2}), min(thetacell{3}))-1e-6 max(max(thetacell{2}), max(thetacell{3}))+1e-6])
                    xlim([min(min(rcell{2}), min(rcell{3}))-1 max(max(rcell{2}), max(rcell{3}))+1])
                    legend(pHandle, 'PD2','PD3', 'location','best')
                end
            end
            set(0,'defaultfigureposition',[400 300 600 400]);
        end
        % compare steady-state BRDF
        % load O2 sectioned data to see
        
        function steadyStateScatterInO2LSD(m, baffle)
        %STEADYSTATESCATTERINO2LSD Plot steady-state scatter in O2 LSD
        %(2/25/17 - 6/6/17)
        %PREREQUISITE: SS_O2LSD_section.mat loaded
        %               
        %   .steadyStateScatterInO2LSD
        %   plot the O2 LSD steady-state scatter measured on all 4 baffles
        %
        %   .steadyStateScatterInO2('ITMX')
        %   only plot the ITMX baffle PD steady-state LSD measurements
        %
        %   .steadyStateScatterInO2({'ITMX','ITMY'})
        %   plot PD scatter on designated baffle cell list
        %
        %   See also GETMEANSD
        
            if(~exist('baffle'))
                baffle = {'ITMX','ETMX','ITMY','ETMY'};
            end
            
            if(~iscell(baffle))
                
                baffle = {baffle};
                
            end

            onlyShowPD14 = false;
            set(0,'defaultfigureposition',[200 100 970 600])
            
            O2ts = 1164499217;
            O2te = 1187654418;

            %create drivealign, which has two fields:
            %.gain: {[yaw, pitch]_1, [yaw, pitch]_2 ....}
            %.index:  {[2,3,4...(which has combo [yaw, pitch]_1)], [5,6...], ...}
            % they have the same lengths
            
            for bf = baffle
                bf = bf{1}; %#ok<FXSET>

                t = [];
                y1 = [];
                y2 = [];
                y3 = [];
                y4 = [];
                dy1 = [];
                dy2 = [];
                dy3 = [];
                dy4 = [];
                figure
                for j = 1:length(m.dat)
                    temp = m.dat{j};
                    PD1 = temp(m.whichChan(['BRDF_' bf '_PD_1'])).data;
                    PD2 = temp(m.whichChan(['BRDF_' bf '_PD_2'])).data;
                    PD3 = temp(m.whichChan(['BRDF_' bf '_PD_3'])).data;
                    PD4 = temp(m.whichChan(['BRDF_' bf '_PD_4'])).data;
%                     %normalize PD* data
%                     PWR = temp(m.whichChan('PWR_IN_OUTPUT')).data;
%                     PRC = temp(m.whichChan('PRC_GAIN')).data;
%                     PD1 = PD1./(PWR.*PRC/2);
%                     PD2 = PD2./(PWR.*PRC/2);
%                     PD3 = PD3./(PWR.*PRC/2);
%                     PD4 = PD4./(PWR.*PRC/2);
                    %get mean and sd of each PD
                    [m1, sd1] = m.getMeanSD(PD1);
                    [m2, sd2] = m.getMeanSD(PD2);
                    [m3, sd3] = m.getMeanSD(PD3);
                    [m4, sd4] = m.getMeanSD(PD4);
                    %get duration
                    ts = temp(1).start;
                    te = temp(1).start+length(temp(1).data)/temp(1).rate;
                    %plot values
            %         fi = fill([ts te te ts],[m1+sd1 m1+sd1 m1-sd1 m1-sd1],[1 0.8 0.8]);
            %         fi.FaceColor = [1 0.8 0.8];       % make the filled area pink
            %         fi.EdgeColor = 'none'; 
                    errorbar([ts, te], m1*ones(1,2), [sd1,sd1], 'Color','r');
                    hold on

                    if(~onlyShowPD14)
                        errorbar([ts, te], m2*ones(1,2), [sd2,sd2], 'Color','g');
                        errorbar([ts, te], m3*ones(1,2), [sd3,sd3], 'Color','b');

                    end
                    errorbar([ts, te], m4*ones(1,2), [sd4,sd4], 'Color','k');
                    t = [t ts te];
                    y1 = [y1 m1 m1];
                    y2 = [y2 m2 m2];
                    y3 = [y3 m3 m3];
                    y4 = [y4 m4 m4];
                    dy1 = [dy1 sd1 sd1];
                    dy2 = [dy2 sd1 sd1];
                    dy3 = [dy3 sd1 sd1];
                    dy4 = [dy4 sd1 sd1];

                end
                %linear fit
                N = length(t);
                %Compute slope k:
                k1 = (N*sum(t.*y1) - sum(t)*sum(y1))/(N*sum(t.^2) - (sum(t))^2);
                k2 = (N*sum(t.*y2) - sum(t)*sum(y2))/(N*sum(t.^2) - (sum(t))^2);
                k3 = (N*sum(t.*y3) - sum(t)*sum(y3))/(N*sum(t.^2) - (sum(t))^2);
                k4 = (N*sum(t.*y4) - sum(t)*sum(y4))/(N*sum(t.^2) - (sum(t))^2);
                %Compute intercept b:
                b1 = (sum(t.^2)*sum(y1) - sum(t)*sum(t.*y1))/(N*sum(t.^2) - (sum(t))^2);
                b2 = (sum(t.^2)*sum(y2) - sum(t)*sum(t.*y2))/(N*sum(t.^2) - (sum(t))^2);
                b3 = (sum(t.^2)*sum(y3) - sum(t)*sum(t.*y3))/(N*sum(t.^2) - (sum(t))^2);
                b4 = (sum(t.^2)*sum(y4) - sum(t)*sum(t.*y4))/(N*sum(t.^2) - (sum(t))^2);    
                %plot linear fits
                plot([t(1) t(end)], [k1*t(1)+b1 k1*t(end)+b1], 'r--');

                if(~onlyShowPD14)
                    plot([t(1) t(end)], [k2*t(1)+b2 k2*t(end)+b2], 'g--');
                    plot([t(1) t(end)], [k3*t(1)+b3 k3*t(end)+b3], 'b--');
                end
                plot([t(1) t(end)], [k4*t(1)+b4 k4*t(end)+b4], 'k--');
                %uncertainties of the slope
                dkdy = (N*t - sum(t))/(N*sum(t.^2) - (sum(t))^2);
                dk1 = round(sqrt(sum((dkdy.*dy1).^2)), 1, 'significant');
                dk2 = round(sqrt(sum((dkdy.*dy2).^2)), 1, 'significant');
                dk3 = round(sqrt(sum((dkdy.*dy3).^2)), 1, 'significant');
                dk4 = round(sqrt(sum((dkdy.*dy4).^2)), 1, 'significant');
                %uncertainties of the intercept
                dbdy = (sum(t.^2) - t*sum(t))/(N*sum(t.^2) - (sum(t))^2);
                db1 = round(sqrt(sum((dbdy.*dy1).^2)), 1, 'significant');
                db2 = round(sqrt(sum((dbdy.*dy2).^2)), 1, 'significant');
                db3 = round(sqrt(sum((dbdy.*dy3).^2)), 1, 'significant');
                db4 = round(sqrt(sum((dbdy.*dy4).^2)), 1, 'significant');
                %report numbers
            %     k1 = round(k1/10^floor(log10(dk1)),0)*10^floor(log10(dk1));
            %     k2 = round(k2/10^floor(log10(dk2)),0)*10^floor(log10(dk2));
            %     k3 = round(k3/10^floor(log10(dk3)),0)*10^floor(log10(dk3));
            %     k4 = round(k4/10^floor(log10(dk4)),0)*10^floor(log10(dk4));
            %     b1 = round(b1/10^floor(log10(db1)),0)*10^floor(log10(db1));
            %     b2 = round(b2/10^floor(log10(db2)),0)*10^floor(log10(db2));
            %     b3 = round(b3/10^floor(log10(db3)),0)*10^floor(log10(db3));
            %     b4 = round(b4/10^floor(log10(db4)),0)*10^floor(log10(db4));
                %compute change of scatter during O2
            %     dinc1 = abs(round((((k1+dk1)*268*24*3600/((k1-dk1)*O2ts+b1-db1)) - ((k1-dk1)*268*24*3600/((k1+dk1)*O2ts+b1+db1)))*100/2, 1, 'significant'));
            %     dinc2 = abs(round((((k2+dk2)*268*24*3600/((k2-dk2)*O2ts+b2-db2)) - ((k2-dk2)*268*24*3600/((k2+dk2)*O2ts+b2+db2)))*100/2, 1, 'significant'));
            %     dinc3 = abs(round((((k3+dk3)*268*24*3600/((k3-dk3)*O2ts+b3-db3)) - ((k3-dk3)*268*24*3600/((k3+dk3)*O2ts+b3+db3)))*100/2, 1, 'significant'));
            %     dinc4 = abs(round((((k4+dk4)*268*24*3600/((k4-dk4)*O2ts+b4-db4)) - ((k4-dk4)*268*24*3600/((k4+dk4)*O2ts+b4+db4)))*100/2, 1, 'significant'));
                dinc1 = abs(round((dk1*268*24*3600/(k1*O2ts+b1))*100, 1, 'significant'));
                dinc2 = abs(round((dk2*268*24*3600/(k2*O2ts+b2))*100, 1, 'significant'));
                dinc3 = abs(round((dk3*268*24*3600/(k3*O2ts+b3))*100, 1, 'significant'));
                dinc4 = abs(round((dk4*268*24*3600/(k4*O2ts+b4))*100, 1, 'significant'));
            %     dt = 268*24*3600;
            %     dinc1 = sqrt(( (b1*dt/(k1*O2ts+b1)^2) *dk1)^2+( (k1*dt/(k1*O2ts+b1)^2) *db1)^2);
            %     dinc2 = sqrt(( (b2*dt/(k2*O2ts+b2)^2) *dk2)^2+( (k2*dt/(k2*O2ts+b2)^2) *db2)^2);
            %     dinc3 = sqrt(( (b3*dt/(k3*O2ts+b3)^2) *dk3)^2+( (k3*dt/(k3*O2ts+b3)^2) *db3)^2);
            %     dinc4 = sqrt(( (b4*dt/(k4*O2ts+b4)^2) *dk4)^2+( (k4*dt/(k4*O2ts+b4)^2) *db4)^2);
            %     dinc1 = round(dinc1, 1, 'significant')*100;
            %     dinc2 = round(dinc2, 1, 'significant')*100;
            %     dinc3 = round(dinc3, 1, 'significant')*100;
            %     dinc4 = round(dinc4, 1, 'significant')*100;

                inc1 = round(100*k1*268*24*3600/(k1*O2ts+b1)/10^floor(log10(dinc1)),0)*10^floor(log10(dinc1));
                inc2 = round(100*k2*268*24*3600/(k2*O2ts+b2)/10^floor(log10(dinc2)),0)*10^floor(log10(dinc2));
                inc3 = round(100*k3*268*24*3600/(k3*O2ts+b3)/10^floor(log10(dinc3)),0)*10^floor(log10(dinc3));
                inc4 = round(100*k4*268*24*3600/(k4*O2ts+b4)/10^floor(log10(dinc4)),0)*10^floor(log10(dinc4));


                ticks = xticks;
                hold off
            %     legend(sprintf('PD1: P = (%g±%g)*t + (%g±%g)', k1, dk1, b1, db1),...
            %         sprintf('PD2: P = (%g±%g)*t + (%g±%g)', k2, dk2, b2, db2),...
            %         sprintf('PD3: P = (%g±%g)*t + (%g±%g)', k3, dk3, b3, db3),...
            %         sprintf('PD4: P = (%g±%g)*t + (%g±%g)', k4, dk4, b4, db4),...
            %         'Location', 'northwest');
                if(onlyShowPD14)
                    lgnd = legend(sprintf('PD1: $(%g \\pm %g)\\%%$', inc1, dinc1),...
                    sprintf('PD4: $(%g \\pm %g)\\%%$', inc4, dinc4),...
                    'Location', 'best'); %#ok<UNRCH>
                    temp = [lgnd; lgnd.ItemText];
                    set(temp, 'FontSize', 14)
                    %title([baffle ' PD1, 4 power measurements for stable time $>$ ' durationName ' between ' m.gps2utc(ticks(1)) ' and ' m.gps2utc(ticks(end))]);
                    ylim([min(min(PD1), min(PD4)) max(max(PD1), max(PD4))])

                else
                    lgnd = legend(sprintf('PD1: $(%g \\pm %g)\\%%$', inc1, dinc1),...
                    sprintf('PD2: $(%g \\pm %g)\\%%$', inc2, dinc2),...
                    sprintf('PD3: $(%g \\pm %g)\\%%$', inc3, dinc3),...
                    sprintf('PD4: $(%g \\pm %g)\\%%$', inc4, dinc4),...
                    'Location', 'best');
                    temp = [lgnd; lgnd.ItemText];
                    set(temp, 'FontSize', 14)

                    %title([baffle ' PD power measurements for stable time $>$ ' durationName ' between ' m.gps2utc(ticks(1)) ' and ' m.gps2utc(ticks(end))]);
                end

                set(gca, 'FontSize',16)
                title([bf ' Scatter in 2/25/17-6/6/17'])
                grid on
                ylabel(['BRDF [sr$^{-1}$]']);
                xticklabels(m.gps2utc(xticks,'day'));
                set(gca,'Yscale', 'log');
%                 if(onlyShowPD14)
%                     saveas(gcf, [baffle ' PD1, 4 power measurements for ' durationName ' stable time_' int2str(i) '.png']); %#ok<UNRCH>
%                 else
%                     saveas(gcf, [baffle ' PD power measurements for ' durationName ' stable time_' int2str(i) '.png']);
%                 end
            
            end
            set(0,'defaultfigureposition',[400 200 600 500])
            
            
        end
        % analyze O2 LSD steady-state scatter
        
        
        
        %% Transient scatter

        function prepForADSData(m, filename)
        %PREPFORADSDATA Generate 'startTime' and 'durations' variable to load
        %data from nds server (get_data2 function by Keith Thorne)
        %PREREQUISITE: struct data loaded (like O2_minTrend.mat)
        %
        %   .prepForADSData(filename)
        %   Get the .mat file (with specified name from filename) to
        %   extract data from server
        %
        %   See also GETO2ADSINDEX GETTIMEMORETHANDURATIONS
        
            m.getO2ADSIndex;
            
            [durations,startTime] = m.getTimeMoreThanDurations(m.ADSIndex);
            
            save(filename, 'startTime', 'durations');
        end
        % save startTime and duration for data pulling from NDS
        % load struct O2 all data

        function extractADS25WDataFromSection(m, chanName, dataName)
        %EXTRACTADS25WDATAFROMSECTION Extract the 25W alignment from cell
        %data loaded and save it to dataName file
        %PREREQUISITE: cell data extracted from .ADSIndex loaded 
        %(like ADS_O2_section.mat)
        %
        %   .extractADS25WDataFromSection(chanName, dataName)
        %   Extract the channels specified by chanName in the 25W alignment
        %   period. Save it to dataName file
        %
        %   See also WHICHCHAN GETSECTIONADSERRORINDEX
        
            
            chans = m.whichChan(chanName)';
            dat = m.dat;
            channelNames = m.channelNames;
            
            if(dataName(end-3:end) == '.mat')
                dataName = dataName(1:end-4);
            end
            
            if(contains(dataName, '_section'))
                sid = strfind(dataName, '_section');
                dataName(sid:sid+7) = [];
            end

            for n = 1:length(dat)
                [lowIndex, highIndex] = m.getSectionADSErrorIndex('n',n);
                t = 1:round(1/m.dat{n}(1).rate):dat{n}(1).duration;
                t = t+dat{n}(1).start;
                t = t(highIndex);
                
                ts = t(1);
                dur = length(t);
                
                for j = chans
                    dat{n}(j).data = dat{n}(j).data(highIndex);
                    dat{n}(j).start = ts;
                    dat{n}(j).duration = dur;
                end
                
                L = length(m.channelNames);
                for j = L:-1:1
                    if(~ismember(j, chans))
                        dat{n}(j) = [];
                    end
                end
                
            end
            
            for j = L:-1:1
                if(~ismember(j, chans))
                    channelNames(j) = [];
                end

            end

            eval(['save ./O2data/' dataName '_section.mat dat channelNames']);
            fprintf('\n Channels extracted to ''%s'' succeeded:\n', [dataName '_section.mat']);
            m.printChannels(channelNames);
            flag = input('Concatenate m.dat to struct? (Y/N): ','s');
            if ~(~isempty(flag) && (flag == 'y' || flag == 'Y'))
                return;
            end
            
            d = dat;
            
            dat = d{1};
            for i = 2:length(d)
                for j = 1:length(dat)
                    dat(j).data = [dat(j).data; d{i}(j).data];
                end
            end
            dat = rmfield(dat,'start');
            dat = rmfield(dat,'duration');
            
            eval(['save ./O2data/' dataName '.mat dat channelNames']);
            
            fprintf('\n Channels extracted to ''%s'' succeeded:\n\n', [dataName '.mat']);
            
        end
        % extract 25W ADS from m.dat to mat 
        % load section raw data
        
        function demoBothBeamPositionsOnSIS(m)
        %DEMOBOTHBEAMPOSITIONSONSIS Compare simulation with various beam
        %positions on both ITMX and ETMX
        %PREREQUISITE: SISPositionOnBothSide.mat is in directory
        %
        %   .demoBothBeamPositionsOnSIS
        %   plot ETMX PD1 and 4 measurements given beam positions (x,y) on
        %   ITMX and ETMX, where x, y = -10:2:10
            
            load SISPositionOnBothSide.mat
            
            for baffle = {'ITMX', 'ETMX'}
                bf = baffle{1};
                for ax = 'xy'
                    eval(['M = M_' bf '_' ax ';']);
                    set(0,'defaultfigureposition',[400 300 280 240]);
                    figure
                    for i = 1:length(M)
                        eval(['plot(M{i}.ETM' bf(end) '.SIS.r, db(M{i}.ETM' bf(end) '.SIS.BRDF));']);
                        hold on
                    end
                    
                    grid on
                    %xlabel('Radial distance (mm)');
                    ylabel('ETMX BRDF (dB)');
                    axis tight
                    %title([bf ' Patterns (ITMX Pos: (x,0); ETM Pos: (0,0))'])
    %                 legend('x = 0','x = 1 mm','x = 2 mm','x = 3 mm','x = 4 mm','x = 5 mm','x = 6 mm','x = 7 mm','x = 8 mm','x = 9 mm','x = 10 mm'...
    %                     , 'PD1', 'PD2', 'PD3', 'PD4');
%                     legend('x = -10 mm','x = -8 mm','x = -6 mm','x = -4 mm','x = -2 mm','x = 0','x = 2 mm','x = 4 mm','x = 6 mm','x = 8 mm','x = 10 mm'...
%                         , 'PD1', 'PD2', 'PD3', 'PD4');
%                     legend('y = -10 mm','y = -8 mm','y = -6 mm','y = -4 mm','y = -2 mm','y = 0','y = 2 mm','y = 4 mm','y = 6 mm','y = 8 mm','y = 10 mm'...
%                         , 'PD1', 'PD2', 'PD3', 'PD4');
                    xlim([min(m.ITMX.PD1.r,m.ITMX.PD4.r)-10 max(m.ITMX.PD1.r,m.ITMX.PD4.r)+10])
                    temp = ylim;
                    
                    plot([m.ITMX.PD1.r, m.ITMX.PD1.r], [temp(1), temp(2)], 'r--')
                    plot([m.ITMX.PD2.r, m.ITMX.PD2.r], [temp(1), temp(2)], 'g--')
                    plot([m.ITMX.PD3.r, m.ITMX.PD3.r], [temp(1), temp(2)], 'b--')
                    plot([m.ITMX.PD4.r, m.ITMX.PD4.r], [temp(1), temp(2)], 'k--')

                    
%                     figure
%                     for i = 1:length(M)
%                         eval(['plot(M{i}.ETM' bf(end) '.SIS.r, db(M{i}.ETM' bf(end) '.SIS.BRDF));']);
%                         hold on
%                     end
%                     
%                     grid on
%                     %xlabel('Radial distance (mm)');
%                     %ylabel('BRDF (dB)');
%                     axis tight
%                     %title([bf ' Patterns (ITMX Pos: (x,0); ETM Pos: (0,0))'])
%     %                 legend('x = 0','x = 1 mm','x = 2 mm','x = 3 mm','x = 4 mm','x = 5 mm','x = 6 mm','x = 7 mm','x = 8 mm','x = 9 mm','x = 10 mm'...
%     %                     , 'PD1', 'PD2', 'PD3', 'PD4');
% %                     legend('x = -10 mm','x = -8 mm','x = -6 mm','x = -4 mm','x = -2 mm','x = 0','x = 2 mm','x = 4 mm','x = 6 mm','x = 8 mm','x = 10 mm'...
% %                         , 'PD1', 'PD2', 'PD3', 'PD4');
% %                     legend('y = -10 mm','y = -8 mm','y = -6 mm','y = -4 mm','y = -2 mm','y = 0','y = 2 mm','y = 4 mm','y = 6 mm','y = 8 mm','y = 10 mm'...
% %                         , 'PD1', 'PD2', 'PD3', 'PD4');
%                     xlim([min(m.ITMX.PD2.r,m.ITMX.PD3.r)-10 max(m.ITMX.PD2.r,m.ITMX.PD3.r)+10])
%                     temp = ylim;
%                     
%                     plot([m.ITMX.PD1.r, m.ITMX.PD1.r], [temp(1), temp(2)], 'r--')
%                     plot([m.ITMX.PD2.r, m.ITMX.PD2.r], [temp(1), temp(2)], 'g--')
%                     plot([m.ITMX.PD3.r, m.ITMX.PD3.r], [temp(1), temp(2)], 'b--')
%                     plot([m.ITMX.PD4.r, m.ITMX.PD4.r], [temp(1), temp(2)], 'k--')

                end
            end
            
            set(0,'defaultfigureposition',[400 300 600 400]);
        end
        % plot ETMX PD1 and 4 measurements given beam positions (x,y) on
        % ITMX and ETMX, where x, y = -10:2:10
        
        function analyzeADSInO2LSD(m, bf, pd)
        %ANALYZEADSINO2LSD Analyze transient scatter response in the O2 LSD
        %(2/25/17 - 6/6/17) by animating the alingment process. A video is
        %created.
        %PREREQUISITE: O2 LSD 25W section data loaded (like ADS25W_O2_MA120_section.mat)
        %
        %   .analyzeADSInO2LSD('ITMX', 1)
        %   animate ITMX PD1 data with all beam alignments
        
            if(isempty(m.dat) || isempty(m.channelNames))
                error('\n\n No data loaded!!! \n\n');
            end

            if(iscell(bf))
                bf = bf{1};
            end
            
            %colorbar stuff
            colorRes = 1000;
            colTable = jet;
            cr = interp1(1:(colorRes-1)/(length(colTable(:,1))-1):colorRes, colTable(:,1), 1:colorRes);
            cg = interp1(1:(colorRes-1)/(length(colTable(:,2))-1):colorRes, colTable(:,2), 1:colorRes);
            cb = interp1(1:(colorRes-1)/(length(colTable(:,3))-1):colorRes, colTable(:,3), 1:colorRes);
                    
            %set up image viewer
            set(0,'defaultfigureposition',[400 30 832 750]); %set window size and location
            figure
            
            %background image
            imageAxe = axes('Position',[0 0 1 1]); %x, y, width, height
            if(all(bf == 'ITMX') || all(bf == 'ETMY'))
                filename = 'Skin left hole.png'; %D1003371. D1200677
            else
                filename = 'Skin right hole.png'; %D1100476, D1003374
            end

            [img, map, alphachannel] = imread(filename);
            
            image(imageAxe, img);
            %axis off
            %hold on
            xlimit = xlim;
            ylimit = ylim;
            text(xlimit(1)+10, ylimit(1)+27, [bf ' PD' int2str(pd) ' (Normalized \& MA Filtered)'], 'FontSize', 32);
            set(gca,'xtick',[])
            set(gca,'ytick',[])
            
            %colorbar plot
            cbarAxe = axes('Position',[0.1 0.1065 0.45 0.35]);
            colormap('jet')
            axis off
            %c = colorbar;
            
            % beam position plot
            vertR = 13.56*25.4/2;%mm LIGO-D1200322-v4
            horiR = 13.54*25.4/2;%mm LIGO-D1200322-v4
            beamAxe = axes('Position',[0 0 1 1]);
            %calibration plot
            plot(beamAxe, [-vertR/2,vertR/2], [0 0], 'k--');
            hold(beamAxe, 'on');
            plot(beamAxe, [0 0], [-vertR/2,vertR/2], 'k--');
%             theta = 0:0.1:2*pi;
%             plot(beamAxe, vertR*cos(theta), vertR*sin(theta)); 
%             hold on
            %text(-vertR*0.78, -vertR*0.5, [sprintf('xoffset = %.1f mm\n', x) sprintf('yoffset = %.1f mm\n', y)],'Color','k');
            if(all(bf == 'ITMX') || all(bf == 'ETMY'))
                xlim([-170*1.2, 502*1.2]);%set the scale correctly
            else
                xlim([-502*1.2, 170*1.2]);%set the scale correctly
            end
            ylim([-170*1.2,436*1.2]);
            axis off
            
            %time axe
            timeAxe = axes('Position',[0.015 0.87 0.3 0.05]); 
            axis off
            
            
            %PD axe
            PDAxe = axes('Position',[0.08 0.57 0.35 0.3]); 
            box on
            
            %ADS Error
            YAWAxe = axes('Position',[0.62 0.74 0.35 0.15]);
            box on
            
            PITAxe = axes('Position',[0.62 0.52 0.35 0.15]);
            box on
            
%             PIT5Axe = axes('Position',[0.62 0.30 0.35 0.15]);
%             box on
%             
%             YAW5Axe = axes('Position',[0.62 0.08 0.35 0.15]);
%             box on
            
            v = VideoWriter([bf '-00' int2str(pd) '.avi']);

            aITMPD = cell(1,4);
            aETMPD = cell(1,4);
            for n = 1:length(m.dat)
                
                
                PDdata = cell(1,4);
                for i = 1:4
                    PDdata{i} = m.dat{n}(m.whichChan([bf '_PD_' int2str(i) '*BRDF'])).data;
                end
                
                xdata = m.dat{n}(m.whichChan(['ETM' bf(end) '_x'])).data;
                ydata = m.dat{n}(m.whichChan(['ETM' bf(end) '_y'])).data;
                
%                 for i = 1:4
%                     aITMPD{i} = [aITMPD{i}, mean(ITMPD{i}(1:30))];
%                     aETMPD{i} = [aETMPD{i}, mean(ETMPD{i}(1:30))];
%                 end
                
                % animate plot
                %L = length(pErr);
                L = 2000;
                
                pd_h = plot(PDAxe, PDdata{pd}(1),'r-');
                xlim(PDAxe,[0 L]);
                ylim(PDAxe,[min(PDdata{pd}), max(PDdata{pd})]);
                grid(PDAxe, 'on');
                title(PDAxe,['PD ' int2str(pd) ' Power'])
                
                pit_h = plot(PITAxe, ydata(1),'-');
                xlim(PITAxe,[0 L]);
                ylim(PITAxe,[min(ydata), max(ydata)]);
                grid(PITAxe, 'on');
                title(PITAxe,'y [mm]')
                
                yaw_h = plot(YAWAxe, xdata(1),'-');
                xlim(YAWAxe,[0 L]);
                ylim(YAWAxe,[min(xdata), max(xdata)]);
                grid(YAWAxe, 'on');
                title(YAWAxe,'x [mm]')
                
%                 pit5_h = plot(PIT5Axe, p5Err(1),'-');
%                 xlim(PIT5Axe,[0 L]);
%                 ylim(PIT5Axe,[min(p5Err), max(p5Err)]);
%                 grid(PIT5Axe, 'on');
%                 title(PIT5Axe,'PR2 Pitch Error')
%                 
%                 yaw5_h = plot(YAW5Axe, y5Err(1),'-');
%                 xlim(YAW5Axe,[0 L]);
%                 ylim(YAW5Axe,[min(y5Err), max(y5Err)]);
%                 grid(YAW5Axe, 'on');
%                 title(YAW5Axe,'PR2 Yaw Error')
%                 xlabel(YAW5Axe,'Time [s]')
                
                da = max(xdata);
                xiao = min(xdata);
                if(xiao > 0)
                    c = colorbar(cbarAxe,'Ticks',[0,0.25,0.5,0.75,1],'TickLabels',...
                        {sprintf('%.1s',xiao), sprintf('%.1s',10^(log10(xiao)+(log10(da)-log10(xiao))/4)),...
                        sprintf('%.1s',10^(log10(xiao)+(log10(da)-log10(xiao))/2)),...
                        sprintf('%.1s',10^(log10(xiao)+(log10(da)-log10(xiao))*3/4)),...
                        sprintf('%.1s',da)});
                    %c.Label.String = 'Normalized PD Power (log)';
                else
                    c = colorbar(cbarAxe,'Ticks',[0,0.25,0.5,0.75,1],'TickLabels',...
                        {sprintf('%.1s',xiao), sprintf('%.1s',xiao+(da-xiao)/4),...
                        sprintf('%.1s',xiao+(da-xiao)/2), sprintf('%.1s',xiao+(da-xiao)*3/4), sprintf('%.1s',da)});
                    %c.Label.String = 'Normalized PD Power';
                end
                c.TickLabelInterpreter = 'latex';
                c.Label.Interpreter = 'latex';
                
                open(v);
                M(1) = getframe(gcf);
                j = 1;
                startTime = m.dat{n}(1).start;
                for i = 2:5:min(L, length(PDdata{1}))   
                    j = j+1;
                    
                    pd_h.YData = PDdata{1}(1:i);
                    pit_h.YData = ydata(1:i);
                    yaw_h.YData = xdata(1:i);
%                     pit5_h.YData = p5Err(1:i);
%                     yaw5_h.YData = y5Err(1:i);
                    
                    if(i > 10)
                        if(xiao > 0)
%                             id = floor(1+(colorRes-1)*(log(currPD{i}(j))-log(xiao))/(log(da)-log(xiao)));
                            id = floor(1+(colorRes-1)*(log10(PDdata{1}(i))-log10(xiao))/(log10(da)-log10(xiao)));
                        else
                            id = floor(1+(colorRes-1)*(PDdata{1}(i)-xiao)/(da-xiao));
                        end
                        id = max(min(id, colorRes), 1);
                        plot(beamAxe, xdata(1:i)*10, ydata(1:i)*10, 'o', 'MarkerSize',2, 'MarkerEdgeColor','none','MarkerFaceColor',[cr(id) cg(id) cb(id)]);
                        
                    end
                    temp = text(timeAxe, 0,1,['GPS Time = ' int2str(startTime+i)], 'FontSize', 12);
                    drawnow limitrate nocallbacks
                    M(j) = getframe(gcf);
                    
                    delete(temp);
                end
                writeVideo(v,M);
%                 pd_h.YData = [];
%                 pit_h.YData = [];
%                 yaw_h.YData = [];
%                 pit5_h.YData = [];
%                 yaw5_h.YData = [];
%                 ITMPD = [];
%                 ETMPD = [];
%                 pErr = [];
%                 yErr = [];
%                 p5Err = [];
%                 y5Err = [];
  
            end
            close(v);
            
            set(0,'defaultfigureposition',[400 200 600 500]); %set window size and location
        end
        % analyze ADS error in longest stable durations (LSD) of O2
        % (2/25/17 - 6/6/17)
        

         
        %% Regression
        function numberOfTerms(m)
        %NUMBEROFTERMS See the growth of terms with respect to highest
        %order k
        %
        %   .numberOfTerms(m)
        %   Plot 2 graphs of no interaction and with interaction terms
        %
        %   See also COUNTINTERACTIONTERMS
            k = 5;
            p = [4, 8];
            N = length(p);
            figure
            for i = 1:2
                subplot(1,2,i)
                if(i == 1)
                    
                    plot(0:k, p(1)*(0:k)+1)
                    hold on
                    plot(0:k, p(2)*(0:k)+1)
                    title('No Interaction Terms')
                else
                    
                    plot(0:k, m.countInteractionTerms(0:k,p(1)))
                    hold on
                    plot(0:k, m.countInteractionTerms(0:k,p(2)))
                    title('With Interaction Terms') 
                end
                
                grid on
                set(gca, 'fontsize',14)
                xlabel('Highest order $k$')
                ylabel('Number of terms')
                
                axis tight
                temp = ylim;
                ylim([0, temp(2)])
            
            end
            legend('4 Predictors','8 Predictors', 'location','northwest')
        end
        % demonstrate growth of terms in linear regression model
        
        function [order, model] = stepwiseRegression(m, highestOrder, varargin)
        %STEPWISEREGRESSION Run stepwise regression on predictors and
        %response (modify channels for changes)
        %PREREQUISITE: struct data loaded (like ADS25W_O2LSD_MA120.mat)
        %
        %   .stepwiseRegression(highestOrder)
        %   Do stepwise regression with highest order specified (no
        %   interaction terms)
        %
        %   .stepwiseRegression(highestOrder, 'interaction')
        %   Do stepwise regression with highest order specified including
        %   interaction terms
        %
        %   See also STEPWISELM
        
            if(m.argHas('interaction',varargin))
                interaction = true;
            else
                interaction = false;
            end
            ITMXPD = cell(1,4);
            ITMYPD = cell(1,4);
            ETMXPD = cell(1,4);
            ETMYPD = cell(1,4);
            for i = 1:4
                ITMXPD{i} = m.dat(m.whichChan(['ITMX*PD_' int2str(i)])).data;
                ITMYPD{i} = m.dat(m.whichChan(['ITMY*PD_' int2str(i)])).data;
                ETMXPD{i} = m.dat(m.whichChan(['ETMX*PD_' int2str(i)])).data;
                ETMYPD{i} = m.dat(m.whichChan(['ETMY*PD_' int2str(i)])).data;
            end
            
            ETMX_x = m.dat(m.whichChan('ETMX_x')).data;
            ETMX_y = m.dat(m.whichChan('ETMX_y')).data;
            ETMY_x = m.dat(m.whichChan('ETMY_x')).data;
            ETMY_y = m.dat(m.whichChan('ETMY_y')).data;

%             p3 = m.dat(m.whichChan('PIT3')).data;
%             y3 = m.dat(m.whichChan('YAW3')).data;
%             p4 = m.dat(m.whichChan('PIT4')).data;
%             y4 = m.dat(m.whichChan('YAW4')).data;
%             p5 = m.dat(m.whichChan('PIT5')).data;
%             y5 = m.dat(m.whichChan('YAW5')).data;
%             p3_n = p3./(max(p3) - min(p3));
%             p5_n = p5./(max(p5) - min(p5));
%             y5_n = y5./(max(y5) - min(y5));
%             y3_n = y3./(max(y3) - min(y3));
%             invpwr_n = invpwr./(max(invpwr) - min(invpwr));
            
        
%             for j = 1:5
%                 fprintf(['Order of' int2str(j) ':\n']);
%                 order = int2str(j);
%                 for i = 1:4
%                     currPD = ITMXPD{i};
%                     t = table(p3, y3, p5, y5, invpwr, currPD);
%                     evalc(['mdl = stepwiselm(t,''Upper'', ''currPD ~ y3^' order ...
%                         '+ p3^' order '+ y5^' order '+ p5^' order '+invpwr^' order ''');']);
%                     fprintf(['PD' int2str(i) ': R^2 = %g;   '], mdl.Rsquared.Ordinary);
%                 end
%                 
%                 for i = 1:4
%                     currPD = ITMYPD{i};
%                     t = table(p4, y4, p5, y5, invpwr, currPD);
%                     evalc(['mdl = stepwiselm(t,''Upper'', ''currPD ~ y4^' order ...
%                         '+ p4^' order '+ y5^' order '+ p5^' order '+invpwr^' order ''');']);
%                     fprintf(['PD' int2str(i) ': R^2 = %g;   '], mdl.Rsquared.Ordinary);
%                 end
%                 fprintf('\n')
%             end
            R2 = [];
            
            order = 1:highestOrder;
            model = cell(1,length(order));
            for i = order
                fprintf(['Order of ' int2str(i) ':\n']);
                odr = int2str(i);
                pd1 = ETMXPD{1};
                pd2 = ETMXPD{2};
                pd3 = ETMXPD{3};
                pd4 = ETMXPD{4};
                t = table(pd1, pd2, pd3, pd4, ETMX_x);
                if(interaction)
                    eval(['mdl = stepwiselm(t,''poly' odr odr odr odr...
                       ''', ''Upper'',''poly' odr odr odr odr ''');']);
                else
                    eval(['mdl = stepwiselm(t, ''ETMX_x ~ pd1^' odr ...
                             '+ pd2^' odr '+ pd3^' odr '+ pd4^' odr ''',''Upper'', ''ETMX_x ~ pd1^' odr ...
                             '+ pd2^' odr '+ pd3^' odr '+ pd4^' odr ''');']);
                end
                fprintf('R^2 = %g;   ', mdl.Rsquared.Ordinary);
                R2 = [R2 mdl.Rsquared.Ordinary];
                model{i} = mdl;
                fprintf('\n')
            end
        end
        % stepwise regressions
        % load struct MA filtered data
        
        function [trainedModel, validationRMSE] = trainEnsembleBag(m, trainingData)
        %TRAINENSEMBLEBAG Train ensemble of bagged trees model with input
        %table
        %   [trainedModel, validationRMSE] = .trainEnsembleBag(trainingData)
        %   return the trained model and validation RMSE given the table
        %   trainingData (response is always the last column)
        %      trainedModel.predictFcn: a function to make predictions on new data.
        %
        %      validationRMSE: a double containing the RMSE. In the app, the
        %       History list displays the RMSE for each model.
        %   For example, to retrain a regression model trained with the original data
        %   set T, enter:
        %       [trainedModel, validationRMSE] = trainRegressionModel(T)
        %
        %   To make predictions with the returned 'trainedModel' on new data T2, use
        %       yfit = trainedModel.predictFcn(T2)
        %
        %   T2 must be a table containing at least the same predictor columns as used
        %       during training. For details, enter:
        %       trainedModel.HowToPredict
        %
        %   See also FITRENSEMBLE REGRESSIONBAGGEDENSEMBLE


            % Extract predictors and response
            % This code processes the data into the right shape for training the
            % model.
            inputTable = trainingData;
            predictorNames = {'pd1', 'pd2', 'pd3', 'pd4'};
            predictors = inputTable(:, predictorNames);
            response = inputTable.ETMX_x;
            isCategoricalPredictor = [false, false, false, false];

            % Train a regression model
            % This code specifies all the model options and trains the model.
            template = templateTree(...
                'MinLeafSize', 8);
            regressionEnsemble = fitrensemble(...
                predictors, ...
                response, ...
                'Method', 'Bag', ...
                'NumLearningCycles', 30, ...
                'Learners', template);

            % Create the result struct with predict function
            predictorExtractionFcn = @(t) t(:, predictorNames);
            ensemblePredictFcn = @(x) predict(regressionEnsemble, x);
            trainedModel.predictFcn = @(x) ensemblePredictFcn(predictorExtractionFcn(x));

            % Add additional fields to the result struct
            trainedModel.RequiredVariables = {'pd1', 'pd2', 'pd3', 'pd4'};
            trainedModel.RegressionEnsemble = regressionEnsemble;
            trainedModel.About = 'This struct is a trained model exported from Regression Learner R2017a.';
            trainedModel.HowToPredict = sprintf('To make predictions on a new table, T, use: \n  yfit = c.predictFcn(T) \nreplacing ''c'' with the name of the variable that is this struct, e.g. ''trainedModel''. \n \nThe table, T, must contain the variables returned by: \n  c.RequiredVariables \nVariable formats (e.g. matrix/vector, datatype) must match the original training data. \nAdditional variables are ignored. \n \nFor more information, see <a href="matlab:helpview(fullfile(docroot, ''stats'', ''stats.map''), ''appregression_exportmodeltoworkspace'')">How to predict using an exported model</a>.');

            % Extract predictors and response
            % This code processes the data into the right shape for training the
            % model.
            inputTable = trainingData;
            predictorNames = {'pd1', 'pd2', 'pd3', 'pd4'};
            predictors = inputTable(:, predictorNames);
            response = inputTable.ETMX_x;
            isCategoricalPredictor = [false, false, false, false];

            % Perform cross-validation
            partitionedModel = crossval(trainedModel.RegressionEnsemble, 'KFold', 5);

            % Compute validation predictions
            validationPredictions = kfoldPredict(partitionedModel);

            % Compute validation RMSE
            validationRMSE = sqrt(kfoldLoss(partitionedModel, 'LossFun', 'mse'));
        end
        % train ensemble bagged trees model
        
        function residualPlots(m, model, t, name)
        %RESIDUALPLOTS Plot residuals with true response and its
        %distribution for ANOVA analysis
        %   .residualPlots(model, t)
        %   Plot residuals based on linearmodel 'model' and table 't',
        %   which was used to train the 'model'
        %
        %   .residualPlots(model, t, name)
        %   Plot residuals based on linearmodel 'model' and table 't',
        %   which was used to train the 'model'. The title will contain
        %   'name' information
        %
        %   See also LINEARMODEL
        
            %set(0,'defaultfigureposition',[400 300 600 400]);
            set(0,'defaultfigureposition',[400 300 525 400]);
            response = t(:,end);
            response = response.(1);
            yfit = model.predictFcn(t(:, 1:end-1));
            residual = response - yfit;
            sd = std(residual);
            
            fields = fieldnames(model);
            if(~exist('name')) 
                name = fields{3};
            end
            
            %residual v. true response
            figure
            plot(response, residual,'.')
            hold on
            plot(response, zeros(1,length(response)),'k','LineWidth',2)
            grid on
            axis tight
            xlabel('x on ETMY [mm]')
            ylabel('Residuals [mm]')
            title(['Residuals of ' name])
            set(gca,'FontSize',14)
            
            %histogram
            figure
            histogram(residual)
            axis tight
            xlim([-3*sd, 3*sd])
            hold on
            temp = ylim;
            plot([sd,sd],[temp(1),temp(2)],'k--')
            plot([-sd,-sd],[temp(1),temp(2)],'k--')
            xticks((-3:3)*sd)
            grid on
            xlabel('Residuals [mm]')
            ylabel('Counts')
            title(['Histogram of ' name])
            set(gca,'FontSize',14)
            
            
        end
        % residual plots and histogram
        % model is exported model from regression learner
        % t is the table used to train model (last one is response)
        
        function testModelSigmaWithNumOfTrainedData(m)
        %TESTMODELSIGMAWITHNUMOFTRAINEDDATA Use a number of data for model
        %training and validate with other data
        %PREREQUISITE: cell data loaded (like ADS25W_O2LSD_MA120_section.mat)
        %
        %   .testModelSigmaWithNumOfTrainedData
        %   Train half of ETMX PD data and use it to predict the other half
        %   (modify channel names to specify other predictors/responses)
        %
        %   See also TRAINENSEMBLEBAG RESIDUALPLOTS
            etmxch = m.whichChan('ETMX_x');
            pd1ch = m.whichChan('ETMX*PD_1');
            pd2ch = m.whichChan('ETMX*PD_2');
            pd3ch = m.whichChan('ETMX*PD_3');
            pd4ch = m.whichChan('ETMX*PD_4');
            
            ETMX_x = [];
            pd1 = [];
            pd2 = [];
            pd3 = [];
            pd4 = [];
            
            % 'new' data
            for i = 1:floor(length(m.dat)/2)
            %for i = ceil(length(m.dat)/2):1:length(m.dat)
                ETMX_x = [ETMX_x; m.dat{i}(etmxch).data];
                pd1 = [pd1; m.dat{i}(pd1ch).data];
                pd2 = [pd2; m.dat{i}(pd2ch).data];
                pd3 = [pd3; m.dat{i}(pd3ch).data];
                pd4 = [pd4; m.dat{i}(pd4ch).data];
            end
            test = table(pd1,pd2,pd3,pd4,ETMX_x);
            
            ETMX_x = [];
            pd1 = [];
            pd2 = [];
            pd3 = [];
            pd4 = [];
            
            % use i cells to train model
            for i = ceil(length(m.dat)/2)
                
                ETMX_x = [];
                pd1 = [];
                pd2 = [];
                pd3 = [];
                pd4 = [];
                for j = i:length(m.dat)
                    ETMX_x = [ETMX_x; m.dat{j}(etmxch).data];
                    pd1 = [pd1; m.dat{j}(pd1ch).data];
                    pd2 = [pd2; m.dat{j}(pd2ch).data];
                    pd3 = [pd3; m.dat{j}(pd3ch).data];
                    pd4 = [pd4; m.dat{j}(pd4ch).data];
                end
                t = table(pd1,pd2,pd3,pd4,ETMX_x);
                [model,validation] = m.trainEnsembleBag(t);
                m.residualPlots(model,test,['Ensemble - ' int2str(i) ' transiences']);
                
                
            end
            
            
        end 
        % load sectioned MA filtered data
       
       
        
        %% temporary testing (not in use)
        
        function temp(m)
            powerch = m.whichChan('POP_A_LF_OUTPUT');
            for arm = 'XY'
                if(eval(['isempty(m.ITM' arm '.SIS.E)']))
                    ITM_x = mean(m.dat{1}(m.whichChan(['ITM' arm '_x'])).data)/1000;
                    ITM_y = mean(m.dat{1}(m.whichChan(['ITM' arm '_y'])).data)/1000;
                    ETM_x = mean(m.dat{1}(m.whichChan(['ETM' arm '_x'])).data)/1000;
                    ETM_y = mean(m.dat{1}(m.whichChan(['ETM' arm '_y'])).data)/1000;
                    %m.runSIS('arm', arm, 'ITMx',ITM_x,'ITMy',ITM_y,'ETMx',ETM_x,'ETMy',ETM_y);
                    m.runSIS('arm', arm);% assume same pattern
                end
                for baffle = {'ITM', 'ETM'}
                    bf = [baffle{1} arm];
                    set(0,'defaultfigureposition',[400 300 600 400]);
                    figure
                    eval(['R = m.' bf '.SIS.r;']);
                    eval(['r2NP = m.' bf '.SIS.r2NP;']);
                    
                    semilogy(R, r2NP);
                    hold on
                    grid on
                    xlabel('Radial distance (mm)');
                    ylabel('PD power/FP cavity power (-)');
                    ylim([min(r2NP) max(r2NP)]);
                    style = {'r.', 'g.', 'b.', 'k.'};
                    pHandle = [];
                    rcell = {};
                    Pcell = {};
                    dPcell = {};
                    for pd = 1:4
                        eval(['xbch = m.whichChan(''BEAM_POSITION_' bf '_x'');'])
                        eval(['ybch = m.whichChan(''BEAM_POSITION_' bf '_y'');'])
                        eval(['pdpwrch = m.whichChan(''PDPOWER_' bf '_PD' int2str(pd) ''');']);
                        r = [];
                        nmlzdP = [];
                        dnmlzdP = [];
                        for i = 1:length(m.dat)
                            xb = mean(m.dat{i}(xbch).data);
                            yb = mean(m.dat{i}(ybch).data);
                            eval(['r = [r sqrt((m.' bf '.PD' int2str(pd) '.x - xb)^2 + (m.' bf '.PD' int2str(pd) '.y - yb)^2)];']);
                            temp = (m.dat{i}(pdpwrch).data./(m.dat{i}(powerch).data/2*m.G_c));
                            nmlzdP = [nmlzdP mean(temp)];
                            dnmlzdP = [dnmlzdP std(temp)];
                            
                        end
                        rcell = [rcell r];
                        Pcell = [Pcell nmlzdP];
                        dPcell = [dPcell dnmlzdP];
                        pHandle(pd) = errorbar(r,nmlzdP,dnmlzdP, style{pd});
                    end
                    hold off
                    legend(pHandle, 'PD1','PD2','PD3','PD4')
                    %title([bf ' steady-state PD data in ' m.fileName(14:24)])
                    title([bf ' steady-state PD data in entire O2'])
                    set(0,'defaultfigureposition',[400 300 280 240]);
                    figure
                    semilogy(R, r2NP);
                    hold on
                    grid on
                    errorbar(rcell{1}, Pcell{1}, dPcell{1}, style{1});
                    errorbar(rcell{4}, Pcell{4}, dPcell{4}, style{4});
                    xlim([floor(min(min(rcell{1}), min(rcell{4}))) ceil(max(max(rcell{1}), max(rcell{4})))])
                    ylim auto
                    
                    figure
                    semilogy(R, r2NP);
                    hold on
                    grid on
                    errorbar(rcell{2}, Pcell{2}, dPcell{2}, style{2});
                    errorbar(rcell{3}, Pcell{3}, dPcell{3}, style{3});
                    xlim([floor(min(min(rcell{2}), min(rcell{3}))) ceil(max(max(rcell{2}), max(rcell{3})))])
                    ylim auto
                end
            end
            
            
        end
        
        function stitch(m)% load O2SSperiod*_section_section.mat
            set(0,'defaultfigureposition',[400 300 600 400]);
            markersize = 3;
            pwrch = m.whichChan('POP_A_LF_OUTPUT');
            t = [];
            
            for i = 1:length(m.dat)
                for j = 1:length(m.dat{i})
                    thist = 0 : round(1/m.dat{i}{j}(1).rate) : m.dat{i}{j}(1).duration - round(1/m.dat{i}{j}(1).rate);
                    t = [t thist + m.dat{i}{j}(1).start];
                    
                end
                
                
            end
            
            
            
            for arm = 'XY'

                for baffle = {'ITM', 'ETM'}
                    bf = [baffle{1} arm];
                    
                    PDdata = cell(1,4);
                    ch1 = m.whichChan(['PDPOWER_' bf '_PD1']);
                    ch2 = m.whichChan(['PDPOWER_' bf '_PD2']);
                    ch3 = m.whichChan(['PDPOWER_' bf '_PD3']);
                    ch4 = m.whichChan(['PDPOWER_' bf '_PD4']);
                    ch = [ch1 ch2 ch3 ch4];
                    if(length(ch) ~= 4)
                        error('Wrong channel names!!!')
                    end
                    
                    figure
                    
                    style = {'r','g','b','k'};
                    for pd = 1:4
                        
                        PDdata{pd} = [];
                        prevPD = 1;
                        for i = 1:length(m.dat)% period cell
                            
                            thisPD = mean(m.dat{i}{1}(ch(pd)).data./m.dat{i}{1}(pwrch).data);
                            ratio = thisPD/prevPD;
                            %ratio = 1;
                            
                            for j = 1:length(m.dat{i})% section in each period

                                PDdata{pd} = [PDdata{pd}; m.dat{i}{j}(ch(pd)).data./m.dat{i}{j}(pwrch).data/ratio];
                                
                            end
                            
                            prevPD = mean(m.dat{i}{end}(ch(pd)).data./m.dat{i}{end}(pwrch).data/ratio);
                        end
                        
                        subplot(2,2,pd)
                        plot(t, PDdata{pd}, [style{pd} '.'], 'MarkerSize',markersize)
                        hold on
                        plot(t, ones(1, length(t)), [style{pd} '--'])
                        grid on
                        %xlabel('Time (UTC)');
                        xticklabels(m.gps2utc(xticks, 'day'));
                        ylabel([bf ' PD' int2str(pd) ' normalized']);
                        xlim([min(t) max(t)])
                        ylim([min(PDdata{pd}) max(PDdata{pd})])
                        
                    end
                    
                    %m.PDDataViewer(PDdata, t, bf, 'Stitched Power in entire O2');
                    
                    
                end
            end
            
            
        end
         
        function out = getAvgRadialIntegration(m, X, Y, Z, R, r, dr, dtheta) %all in mm

            if(nargin > 6)
                if(dr <= 0)
                   error('\n\n dr must > 0 !!!\n\n');
                end
                if(nargin > 7)
                    if(dtheta <=0 || dtheta >= pi)
                        error('\n\n dtheta must be (0, pi) !!!\n\n');
                    end
                else
                    dtheta = 0.01;
                end
            else
                dr = r/50;
                dtheta = 2*pi/50;
            end

            if(R <= 0 || r <= 0 || R+r > max(X))
                error('\n\n R and r must be > 0 and (R+r) < max(x) !!!\n\n');
            end

            rmin = R;
            rmax = R+r;

            val = [];
            for r = rmin:dr:rmax
                for theta = 0:dtheta:2*pi
                    val = [val m.biliInterp(X,Y,Z, (r+dr/2)*cos(theta+dtheta/2), (r+dr/2)*sin(theta+dtheta/2))];
                end
            end

            out = mean(val);


        end
        % all in mm
        % find averaged value of Z(X, Y) with radial integration between (R, R+r)
        %specify dr and dtheta for better resolution, otherwise dr and 
        %dtheta is predefined in the program
        
        function duration = searchStableDuration(m, name)
            if(isempty(m.channelNames) || isempty(m.dat))
                error('\n\n No data or channel names loaded!!!\n\n');
            end
            chan = m.whichChan(name);
            time = 1:m.dat(1).duration;
            duration = [];
            if(isempty(chan))
                error('\n\n No such channel! \n');
            else
                duration = cell(1, length(chan));
                for i = 1:length(chan)
                    data = m.dat(chan(i)).data;
                    temp = max(data)+1; %filler value
                    stableIndex = (data - [temp, data(1:end-1)])==(data - [data(2:end), temp])&(~(logical(diff([data, temp]))));
                    duration{i} = time(stableIndex);
                end
            end


        end
        
        %----Normalizations----%
        
        function normalize(m)
            
            flag = input('Normalize PD data (Y/N): ','s');
            if(flag == 'Y' || flag == 'y')
                m.normalizePDData;
            end
            
            flag = input('Normalize ADS error data (Y/N): ','s');
            if(flag == 'Y' || flag == 'y')
                m.normalizeADSData;
            end
            
            
            fprintf('\n Channels after normalization:\n\n');
            m.printChannels;
        end
        %normalize these things
        
        function normalizePDData(m)
            if(isempty(m.dat) || isempty(m.channelNames))
                error('\n\n No data loaded!!\n')
            end
            
            PDchan = m.whichChan('BAFFLE*POWER');
            powerch = m.whichChan('POP_A_LF_OUTPUT');
            
            if(length(powerch) ~= 1)
                error('\n\n Specify correct power channel!!!\n');
            end
            
            for i = 1:length(PDchan)
               ch = PDchan(i);
               chName = m.channelNames{ch};
               
               if(iscell(m.dat))
                   for j = 1:length(m.dat)
                       data = m.dat{j}(ch).data;
                       power = m.dat{j}(powerch).data;
%                        if(ch < length(m.channelNames))
%                            m.dat{j} = [m.dat{j}(1:ch) m.dat{j}(ch) m.dat{j}(ch+1:end)];
%                        else
%                            m.dat{j} = [m.dat{j}(1:ch) m.dat{j}(ch)];
%                        end
                       
                       m.dat{j} = [m.dat{j} m.dat{j}(end)];
                       %put data in new channel
                       m.dat{j}(end).data = data./(power/2);

                   end
               elseif(isstruct(m.dat))
                   data = m.dat(ch).data;
                   power = m.dat(powerch).data;
%                    if(ch < length(m.channelNames))
%                        m.dat = [m.dat(1:ch) m.dat(ch) m.dat(ch+1:end)];
%                    else
%                        m.dat = [m.dat(1:ch) m.dat(ch)];
%                    end

                   m.dat = [m.dat m.dat(end)];
                   %put data in new channel
                   m.dat(end).data = data./(power/2);

               end
             
%                if(ch < length(m.channelNames))
%                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch);m.channelNames(ch+1:end)];
%                else
%                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch)];
%                end

               m.channelNames = [m.channelNames;m.channelNames(end)];
               m.channelNames{end} = [chName '_NORMALIZED'];

            end
            
            
            
        end
        %normalize PDdata with power in cavity
        
        function normalizeADSData(m)
            if(isempty(m.dat) || isempty(m.channelNames))
                error('\n\n No data loaded!!\n')
            end
            
            errchan = m.whichChan('INMON');
            adschan = m.whichChan('ADS_GAIN');
            
            if(length(adschan) ~= 1)
                error('\n\n Specify correct channel!!!\n');
                
            end
            
            clkchan = zeros(1,length(errchan));
            for i = 1:length(errchan)
                name = m.channelNames{errchan(i)};
                if(contains(name, 'PIT'))
                    loc = strfind(name, 'PIT');
                    clkchan(i) = m.whichChan([name(loc:loc+3) '*CLKGAIN']);
                elseif(contains(name, 'YAW'))
                    loc = strfind(name, 'YAW');
                    clkchan(i) = m.whichChan([name(loc:loc+3) '*CLKGAIN']);
                end
            end
            
            
            for i = 1:length(errchan)
               ch = errchan(i);
               chName = m.channelNames{ch};
               
               if(iscell(m.dat))
                   for j = 1:length(m.dat)
                       data = m.dat{j}(ch).data;
                       adsGain = m.dat{j}(adschan).data;
                       clkGain = m.dat{j}(clkchan(i)).data;
%                        if(ch < length(m.channelNames))
%                            m.dat{j} = [m.dat{j}(1:ch) m.dat{j}(ch) m.dat{j}(ch+1:end)];
%                        else
%                            m.dat{j} = [m.dat{j}(1:ch) m.dat{j}(ch)];
%                        end
                       
                       m.dat{j} = [m.dat{j} m.dat{j}(end)];
                       %put data in new channel
                       m.dat{j}(end).data = data./(adsGain.*clkGain);

                   end
               elseif(isstruct(m.dat))
                   data = m.dat(ch).data;
                   adsGain = m.dat(adschan).data;
                   clkGain = m.dat(clkchan(i)).data;
%                    if(ch < length(m.channelNames))
%                        m.dat = [m.dat(1:ch) m.dat(ch) m.dat(ch+1:end)];
%                    else
%                        m.dat = [m.dat(1:ch) m.dat(ch)];
%                    end
                   
                   m.dat = [m.dat m.dat(end)];
                   %put data in new channel
                   m.dat(end).data = data./(adsGain.*clkGain);

               end
             
%                if(ch < length(m.channelNames))
%                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch);m.channelNames(ch+1:end)];
%                else
%                    m.channelNames = [m.channelNames(1:ch);m.channelNames(ch)];
%                end
               
               m.channelNames = [m.channelNames;m.channelNames(end)];

               m.channelNames{end} = [chName '_NORMALIZED'];

            end
            
            
            
        end
        %normalize ADS error with ADS gain 
        
        function beamPositionViewer(m, baffle, mode, titleName, index)
            
            
%     mode = 'time series': plot time series of the PD data
%     mode = 'relative power': plot relative power of PD data in log scale 
            if(isempty(m.channelNames) || isempty(m.dat))
                error('\n\n No data or channel names loaded!!!\n\n');
            end

            t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;

            set(0,'defaultfigureposition',[400 30 672 606]); %set window size and location

            figure

            %% background baffle image picture
            imageAxe = axes('Position',[0 0 1 1]); %x, y, width, height

        %     PD2Axe = axes('Position',[0.4 0.65 PDAxeWidth PDAxeWidth]);
        %     PD3Axe = axes('Position',[0.5 0.65 PDAxeWidth PDAxeWidth]);
        %     PD4Axe = axes('Position',[0.6 0.65 PDAxeWidth PDAxeWidth]);
            img = imread('PDLocation.png');
            image(imageAxe, img);
            %axis off
            %hold on
            xlimit = xlim;
            ylimit = ylim;
            text(xlimit(1)+10, ylimit(1)+25, titleName, 'FontSize', 32);
            set(gca,'xtick',[])
            set(gca,'ytick',[])
            %% beam picture
            vertR = 13.56*25.4/2;%mm LIGO-D1200322-v4
            horiR = 13.54*25.4/2;%mm LIGO-D1200322-v4

            beamAxe = axes('Position',[0 0 1 1]);

            %calibration plot
        %     plot(beamAxe, [-vertR/2,vertR/2], [0 0]);
        %     hold on
        %     plot(beamAxe, [0 0], [-vertR/2,vertR/2]);
        %     theta = 0:0.1:2*pi;
        %     plot(beamAxe, vertR*cos(theta), vertR*sin(theta)); 

            r = 30; %mm, Gaussian radius

            %get beam positions
            if(baffle(1) == 'I')
                opposite = ['E' baffle(2:4)];
            elseif(baffle(1) == 'E')
                opposite = ['I' baffle(2:4)];
            else        
                error('\n\n Wrong name for baffle\n');
            end
            pitch = m.dat(m.whichChan([opposite '*P2L_GAIN'])).data(1);
            yaw = m.dat(m.whichChan([opposite '*Y2L_GAIN'])).data(1);
            x = yaw*3.5; % x offset, 3.5 is only for ETM, but let's use it for now
            y = pitch*(-4.5); % y offset, -4.5 is only for ETM, but let's use it for now

            theta = 0:0.001:2*pi;
            %plot(beamAxe, r*cos(theta)+x, r*sin(theta)+y, 'r', 'MarkerSize', 10); 
            hold on
            %text(-vertR*0.78, -vertR*0.5, [sprintf('xoffset = %.1f mm\n', x) sprintf('yoffset = %.1f mm\n', y)],'Color','k');
            xlim([-170*1.2,502*1.2]);%set the scale correctly
            ylim([-170*1.2,436*1.2]);
            hold off
            %set(gca, 'Position', get(gca, 'Position') + [0 0 0 0])
            axis off
            %% index specified?
            switch nargin
                case 4
                    for i = 1:4
                        PDdata{i} = m.dat(m.whichChan([baffle '_BAFFLEPD_' int2str(i) '_POWER'])).data;
                    end
                case 5
                    for i = 1:4
                        PDdata{i} = m.dat(m.whichChan([baffle '_BAFFLEPD_' int2str(i) '_POWER'])).data;
                        PDdata{i} = PDdata{i}(index);
                    end
                    t = t(index);
                otherwise
                    error('\n\n Not enough inputs!!!\n');
            end
            %% select mode
            PDAxeWidth = 0.2; %width of the PD data
            switch mode
                case 'time series'

                    %PD1 data
                    PD1Axe = axes('Position',[0.08 0.53 PDAxeWidth PDAxeWidth]);
                    plot(PD1Axe, t, PDdata{1});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{1}),1,'significant');
                    avg = round(mean(PDdata{1})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD1: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);

                    %PD2 data
                    PD2Axe = axes('Position',[0.43 0.65 PDAxeWidth PDAxeWidth]);
                    plot(PD2Axe, t, PDdata{2});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{2}),1,'significant');
                    avg = round(mean(PDdata{2})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD2: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);

                    %PD3 data
                    PD3Axe = axes('Position',[0.78 0.27 PDAxeWidth PDAxeWidth]);
                    plot(PD3Axe, t, PDdata{3});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{3}),1,'significant');
                    avg = round(mean(PDdata{3})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD3: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);


                    %PD4 data
                    PD4Axe = axes('Position',[0.5 0.02 PDAxeWidth PDAxeWidth]);
                    plot(PD4Axe, t, PDdata{4});
                    xlim([min(t), max(t)]);
                    sd = round(std(PDdata{4}),1,'significant');
                    avg = round(mean(PDdata{4})/10^floor(log10(sd)),0)*10^floor(log10(sd));
                    title(sprintf('PD4: mean = %g;\n sd = %g', avg, sd));
                    box on
                    grid on
                    set(gca,'xtick',[]);

                case 'relative power'
        %             %color setting
        %             red = [1 0 0];
        %             blue = [0 0 1];
        %             green = [0 1 0];
        %             black = [0 0 0];
        %             fading = 0.1; % [0, 1] smaller the fader

                    barWidth = 0.9;
                    fontSize = 9;

                    avg = zeros(1,4);
                    sd = zeros(1,4);

                    for i = 1:4
                        sd(i) = round(std(PDdata{i}),1,'significant');
                        avg(i) = round(mean(PDdata{i})/10^floor(log10(sd(i))),0)*10^floor(log10(sd(i)));
                    end

                    %PD1 bar graph
                    PD1Axe = axes('Position',[0.05 0.53 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'r');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'w', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD1');
                    s = sprintf('\\begin{tabular}{c} %g \\\\ $\\pm$ %g \\end{tabular}', avg(1), sd(1));
                    text(1:length(avg),avg,[s; blanks(length(s)); blanks(length(s)); blanks(length(s))],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);

                    %PD2 bar graph
                    PD2Axe = axes('Position',[0.4 0.65 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'w');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'g', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'w', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD2');
                    s = sprintf('\\begin{tabular}{c} %g \\\\ $\\pm$ %g \\end{tabular}', avg(2), sd(2));
                    text(1:length(avg),avg,[blanks(length(s)); s; blanks(length(s)); blanks(length(s))],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);

                    %PD3 bar graph
                    PD3Axe = axes('Position',[0.78 0.27 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'w');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'b', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'w', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD3');
                    s = sprintf('\\begin{tabular}{c} %g \\\\ $\\pm$ %g \\end{tabular}', avg(3), sd(3));
                    text(1:length(avg),avg,[blanks(length(s)); blanks(length(s)); s; blanks(length(s))],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);


                    %PD4 bar graph
                    PD4Axe = axes('Position',[0.48 0.02 PDAxeWidth PDAxeWidth]);
                    bar(1, avg(1), 'FaceColor', 'w');
                    hold on

                    bar(2, avg(2), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(3, avg(3), 'FaceColor', 'w', 'BarWidth', barWidth);
                    bar(4, avg(4), 'FaceColor', 'k', 'BarWidth', barWidth);
                    errorbar(1, avg(1), sd(1), 'Color', 'k');
                    errorbar(2, avg(2), sd(2), 'Color', 'k');
                    errorbar(3, avg(3), sd(3), 'Color', 'k');
                    errorbar(4, avg(4), sd(4), 'Color', 'k');
                    hold off
                    set(gca, 'YScale', 'log')

                    xlim([1-barWidth/2 4+barWidth/2]);
                    ylim([min(avg)/2 max(avg+sd)*2]);
                    title('PD4');
                    s = sprintf('\\begin{tabular}{c} %g \\\\ $\\pm$ %g \\end{tabular}', avg(4), sd(4));
                    text(1:length(avg),avg,[blanks(length(s)); blanks(length(s)); blanks(length(s)); s],'vert','bottom','horiz','center', 'FontSize', fontSize); 
                    box on
                    grid on
                    set(gca,'xtick',[]);
                    %set(gca,'ytick',[]);

                otherwise
                    error('No such mode\n');
            end
            %print([baffle '_SIS.png'],'-dpng','-r600');
            %%
            set(0,'defaultfigureposition',[400 200 600 500]); %set window size and location
        end
        % ‘baffle’ = ‘*TM*’
        % gives a good view of PD data together with beam positions.
        % 2 modes: ‘time series’, ‘relative power’
        
        function checkVariationOfPD(m, baffle)
            
            
            if(isempty(m.channelNames) || isempty(m.dat))
                error('\n\n No data or channel names loaded!!!\n\n');
            end


            t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;

            alignIndices = m.getLockIndex(9); % 9 means that commissioners are putting main beam directly on PD 1 or 4
            leastDurationTime = 60*30;
            [durations, alignIndices] = m.getTimeMoreThanDurations(alignIndices, leastDurationTime);
            figure
            yyaxis left
            plot(durations/60)
            ylabel('minutes')
            yyaxis right
            plot(alignIndices)
            ylabel('seconds')
            xlabel('Alignment counts')
            title(['LOCK_STATE = 9 in O2 with duration > ', int2str(leastDurationTime/60), ' minutes'], 'interpreter', 'none');

            ITMXPDdata = cell(1,4);
            %compute PD power by Hunter's formula P =
            %volts/(responsivity*gain*transimpedance)
            for i = 1:4
                ITMXPDdata{i} = m.dat(m.whichChan(['ITMX_BAFFLEPD_' int2str(i) '_VOLTS'])).data;
            %     responsivity = dat(whichChan(['ITMX_BAFFLEPD_' int2str(i) '_RESPONSIVITY'])).data;
            %     gain = dat(whichChan(['ITMX_BAFFLEPD_' int2str(i) '_GAIN'])).data;
            %     transimpedance = dat(whichChan(['ITMX_BAFFLEPD_' int2str(i) '_TRANSIMPEDANCE'])).data;
            %     
            %     ITMXPDdata{i} = volts./(responsivity.*gain.*transimpedance);
            %     
            %     % normalize PD data by (input power)(recycling gain)/2
            %     power = dat(whichChan('PWR_IN')).data;
            %     recycle = dat(whichChan('PRC_GAIN')).data;
            %     ITMXPDdata{i} = ITMXPDdata{i}./(power.*recycle);


            end

            N = length(m.dat(1).data);
            for i = 1:0
                alignIndex = [false(1, alignIndices(i)-1), true(1, durations(i)), false(1, N-(alignIndices(i)+durations(i))+1)];
                m.chanViewer('LOCK', 'l', alignIndex);
                m.PDViewer(ITMXPDdata, t, sprintf('ITMX-LOCK=9 for %g minutes', durations(i)),alignIndex);

            end



            threshold = 0.005;
            tMargin = 10; % in the unit of index
            
            datadir = './O2data/';
            files = dir([datadir, 'check*.mat']);
            for i = 1:length(files)
                eval(sprintf('load %s', files(i).name));
                t = t0 + (1:length(m.dat(1).data))./m.dat(1).rate;
                PD1 = m.dat(m.whichChan([baffle '*1'])).data;
                PD2 = m.dat(m.whichChan([baffle '*2'])).data;
                PD3 = m.dat(m.whichChan([baffle '*3'])).data;
                PD4 = m.dat(m.whichChan([baffle '*4'])).data;

                noPeak1Index = m.removePeaksFromIndex(PD1, threshold, 10);
                noPeak4Index = m.removePeaksFromIndex(PD4, threshold, 10);
                noPeakIndex = noPeak1Index&noPeak4Index;

                PD1 = PD1(noPeakIndex);
            %     PD2 = PD2(noPeakIndex);
            %     PD3 = PD3(noPeakIndex);
                PD4 = PD4(noPeakIndex);
                t1and4 = t(noPeakIndex);

                for j = 1:length(PD1)
                    if(PD1(j) > threshold)
                        if(j > tMargin)
                            t1low = j - tMargin;
                        else
                            t1low = 1;
                        end
                        break;
                    end
                end
                for j = length(PD1):-1:1
                    if(PD1(j) > threshold)
                        if(j + tMargin <= length(PD1))
                            t1high = j + tMargin;
                        else
                            t1high = length(PD1);
                        end
                        break;
                    end
                end
                for j = 1:length(PD4)
                    if(PD4(j) > threshold)
                        if(j > tMargin)
                            t4low = j - tMargin;
                        else
                            t4low = 1;
                        end
                        break;
                    end
                end
                for j = length(PD4):-1:1
                    if(PD4(j) > threshold)
                        if(j + tMargin <= length(PD4))
                            t4high = j + tMargin;
                        else
                            t4high = length(PD4);
                        end
                        break;
                    end
                end
                tlow = min(t1low, t4low);
                thigh = max(t1high, t4high); %these are indices

                set(0,'defaultfigureposition',[360 100 800 600])

                figure
                plot(t1and4, PD1, 'r');
                hold on
                plot(t, PD2, 'g');
                plot(t, PD3, 'b');
                plot(t1and4, PD4, 'k');
                grid on

                %get offset
                PD1offset = round(mean(PD1(1:10)), 1, 'significant');
                PD2offset = round(mean(PD2(1:10)), 1, 'significant');
                PD3offset = round(mean(PD3(1:10)), 1, 'significant');
                PD4offset = round(mean(PD4(1:10)), 1, 'significant');
                legend(sprintf('PD1 (offset = %g)', PD1offset), sprintf('PD2 (offset = %g)', PD2offset), sprintf('PD3 (offset = %g)', PD3offset), sprintf('PD4 (offset = %g)', PD4offset), 'Location', 'southeast');
                xlim([t1and4(tlow), t1and4(thigh)]);
                ylim([-0.05, max(PD1)+0.05]);

                variation = round(abs((max(PD1)-PD1offset)-(max(PD4)-PD4offset))/min(max(PD1)-PD1offset, max(PD4)-PD4offset), 2, 'significant');
                title([baffle ' PD1/4 power variation $\sim$' num2str(variation*100) '\% when (LOCK\_STATE = 9)'])
                xlabel('Time (UTC)')
                xticklabels(m.gps2utc(xticks))
                ylabel(['L1:AOS-' baffle '\_BAFFLEPD\_POWER'])

            %     curtick = get(gca, 'XTick');
            %     set(gca, 'XTickLabel', cellstr(num2str(curtick(:))));

                %label maximum
                [PD1max, i1max] = max(PD1);
                text(t1and4(i1max), PD1(i1max)+0.01,0,sprintf('max = %.3f', PD1max), 'Color', 'red')
                [PD4max, i4max] = max(PD4);
                text(t1and4(i4max), PD4(i4max)+0.01,0,sprintf('max = %.3f', PD4max))
                %saveas(gcf, [baffle ' PD during alignment' int2str(i) '.png']);
                set(gca, 'FontSize', 14);
            end
            set(0,'defaultfigureposition',[400 200 600 500]); %set window size and location



            % %compute calibration across arm cavity
            % omega_ETM = 6; %cm
            % omega_ITM = 5.3; %cm
            % R = 0.99;
            % %r_PD = 0.3; %cm
            % r_PD = sqrt(1/pi); %cm
            % ItoERatio = ((1-exp(-2*r_PD^2/omega_ITM^2)))/(R*(1-exp(-2*r_PD^2/omega_ETM^2)))
            % 
            % 
            % 
            % 
            % files = dir([datadir, ['check*.mat']]);
            % for i = 1:length(files)
            %     eval(sprintf('load %s', files(i).name));
            %     chanViewer('ITMX+LOCK');
            % end
        end
        % calibration of the PD1 and 4 on each baffle box
        
        function inferBeamPositionFromSIS(m, baffle)
            if(eval(['isempty(m.' baffle '.SIS.E) || isempty(m.' baffle '.SIS.x)']))
                m.runSIS(baffle(end));
            end
            
            %normalize power
            eval(['PTM = abs(m.' baffle '.SIS.E).^2;']);
            PTM = PTM/max(max(PTM)); %#ok<NODEF>
            
            eval(['currx = m.' baffle '.SIS.x*1000;']);
            eval(['curry = m.' baffle '.SIS.x*1000;']);
            
            PDx = -m.boxSize:m.res:m.boxSize;
            PDy = -m.boxSize:m.res:m.boxSize;
            if(eval(['isempty(m.' baffle '.PDPowerMap)']))
                m.getPDPowerMapWithBeamPos(baffle, currx, curry, PTM);
            end
            eval(['PDPowerMap = m.' baffle '.PDPowerMap;']);
            
            if(isempty(m.dat) || isempty(m.channelNames))
                m.loadData('O2_all_1164499217.mat');
            end
            
            if(isempty(m.finalIndex))
                m.getO2FinalIndex();
            end
            
            t = m.dat(1).start + (1:length(m.dat(1).data))./m.dat(1).rate;
            t = t(m.finalIndex);
            PDdata = cell(1,4);
            for i = 1:4
                temp = m.dat(m.whichChan([baffle '_BAFFLEPD_' int2str(i) '_POWER'])).data;
                PDdata{i} = temp(m.finalIndex);
            end
            
            tic
            beamx = [];
            beamy = [];
            errors = [];
            for k = 1:length(PDdata{1})
                err = realmax;
                ti = 0;
                tj = 0;
                p1 = PDdata{1}(k);
                p2 = PDdata{2}(k);
                p3 = PDdata{3}(k);
                p4 = PDdata{4}(k);
                for i = 1:length(PDx)
                    for j = 1:length(PDy)
                        if(((p1/p2 - PDPowerMap{1}(i,j)/PDPowerMap{2}(i,j))^2+(p1/p3 - PDPowerMap{1}(i,j)/PDPowerMap{3}(i,j))^2 ...
                                +(p1/p4 - PDPowerMap{1}(i,j)/PDPowerMap{4}(i,j))^2) < err) %#ok<USENS>
                            ti = i;
                            tj = j;
                            err = (p1/p2 - PDPowerMap{1}(i,j)/PDPowerMap{2}(i,j))^2+(p1/p3 - PDPowerMap{1}(i,j)/PDPowerMap{3}(i,j))^2 ...
                                +(p1/p4 - PDPowerMap{1}(i,j)/PDPowerMap{4}(i,j))^2;
                        end
                    end
                end
                if(ti == 0 || tj == 0)
                    t(k) = [];
                    
                else
                    beamx = [beamx, PDx(ti)];
                    beamy = [beamy, PDy(tj)];
                    errors = [errors, err];
                end
            end
            toc
            
            figure
            subplot(2,2,1)
            plot(t, beamx, '-');
            xlim([min(t), max(t)]);
%             if(min(data) < max(data))
%                 ylim([min(data), max(data)]);
%             end
            ylabel('X (mm)');
            grid on
            xlabel('Time (UTC)');
            xticklabels(m.gps2utc(xticks, 'month'));
            set(gca, 'FontSize', 14)
            
            subplot(2,2,2)
            plot(t, beamy, '-');
            xlim([min(t), max(t)]);

            ylabel('Y (mm)');
            grid on
            xlabel('Time (UTC)');
            xticklabels(m.gps2utc(xticks, 'month'));
            set(gca, 'FontSize', 14)
            
            subplot(2,2,3)
            plot(t, errors, '-');
            xlim([min(t), max(t)]);

            ylabel('Relative error');
            grid on
            xlabel('Time (UTC)');
            xticklabels(m.gps2utc(xticks, 'month'));
            set(gca, 'FontSize', 14)
            
            
        end
        % infer beam position by solely SIS (not correct)
        


    end%end methods     


end%end class