classdef  mpdrRadar < handle
    % mpdrRadar -- class to interface to the radar or radar data recordings
    %
              
    properties (SetAccess=protected,GetAccess=public)
        %% Define constants to support processing data
        cipMetaData; % default values loaded from configuration file
        configFile;
        configVals;
        discardPris = 0;
        discardSamples = 0; %number of samples to get to Range 0 LR pulse
        pcTaylorSll = 0; % taylor weighting side lobe level
        pcTaylorNbar = 0; % number of sidelobes for taylor weights
        iQ = 2; % two words per complex sample
        playback=false;
        readSize=0;
        Stc=0;
        StcStartDelay=0;
        stcScale=0;
        seekLoc;
        numClutterCells=0;
        clutterCells; % cells containting clutter
        dopplerCells; % cells which do not contain clutter
        UseMexFileRead = 0;
        RawFileRead = 0; 
    end

    %% 
    methods (Static)
        function cipMetaData = calcWaveformParams(obj)
            srChans=radChan.getSrChans();
            lrChans=radChan.getLrChans();
            srSum=uint32(radChan.sumSr());
            lrSum=uint32(radChan.sumLr());
            numChans=obj.cipMetaData.numChannels;
            cipMetaData = obj.cipMetaData;

            % that the transmitted energy (leakage) ends up when pulse
            % compressed.
            cipMetaData.cells.rangeZero=zeros(1,numChans); %range zero cell
            cipMetaData.cells.rangeZero(lrChans)=ceil(cipMetaData.pulseLength_s(lrChans) ...
                                                         .*cipMetaData.sampleRate_sps(uint32(radChan.sumLr()))+...
                                                         cipMetaData.cells.rxTxBiasCorr);
            cipMetaData.cells.rangeZero(srChans)=...
                ceil((cipMetaData.pulseLength_s(lrChans)+cipMetaData.pulseLength_s(srChans)) ...
                                                         .*cipMetaData.sampleRate_sps(uint32(radChan.sumSr()))+...
                                                         cipMetaData.cells.rxTxBiasCorr);
                                                     
            % calculate the location of the first cell to be processed.
            % This is the first cell after all transmit has completed.
            cipMetaData.cells.procStart=zeros(1,numChans);
            cipMetaData.cells.procStart(1:numChans)=ceil((cipMetaData.pulseLength_s(lrSum)+...
                cipMetaData.pulseLength_s(srSum)) *cipMetaData.sampleRate_sps(uint32(radChan.sumSr()))+1+...
                cipMetaData.cells.rxTxBiasCorr); %first cell after transmit done                                       
            
            % calculate the last cell to be processed. (last cell before
            % the next pulse marker)
            cipMetaData.cells.procEnd=zeros(1,numChans);
            cipMetaData.cells.procEnd(1:numChans)=cipMetaData.priSize;   %last cell processed
%             if cipMetaData.wxMode
%                 cipMetaData.cells.procEnd(lrChans)=floor(cipMetaData.priSize/4);
%             end
%             
            % calculate the length of the pulses in samples
            cipMetaData.cells.PulseLength_samp=zeros(1,numChans);
            cipMetaData.cells.PulseLength_samp=ceil(cipMetaData.pulseLength_s.*cipMetaData.sampleRate_sps);
            
            % determine the first cell to perform detection processing
            % on... this is the first non-eclipsed sample.  
            cipMetaData.cells.detStart=zeros(1,numChans);
            cipMetaData.cells.detStart=floor(cipMetaData.cells.procStart+cipMetaData.cells.PulseLength_samp);
            
            % determine the last cell to perform detections... this is the last cell processed less the background estimate distance. TODO: reduce
            % the range for Sr pulses to not overlap with LR pulses.
            cipMetaData.cells.detEnd=zeros(1,numChans);
            cipMetaData.cells.detEnd=cipMetaData.cells.procEnd -...
                obj.configVals.cfarWindowSize - obj.configVals.cfarGuardCells -1;
            
            % calculate the size in meters for each range cell
            cipMetaData.rangeCellSize_m=zeros(1,numChans);
            cipMetaData.rangeCellSize_m=radConst.c_mps./cipMetaData.sampleRate_sps/2; % meters per sample
            
            % determine the length of the CIP/PRI in seconds.
            cipMetaData.cip_s= cipMetaData.priSize*cipMetaData.numPris./cipMetaData.sampleRate_sps(radChan.sumLr());
            cipMetaData.priTime_s = cipMetaData.priSize / cipMetaData.sampleRate_sps(uint32(radChan.sumLr()));
            
            % create mask to access the clutter cells (zero dopper)
            obj.clutterCells = obj.configVals.clutterCellPeak-floor(obj.numClutterCells/2):...
                obj.configVals.clutterCellPeak+floor(obj.numClutterCells/2);

            %create a mask to access the processed doppler cells 
            obj.dopplerCells = [1:obj.configVals.clutterCellPeak-ceil(obj.numClutterCells/2) ...
                obj.configVals.clutterCellPeak+ceil(obj.numClutterCells/2):cipMetaData.numPris];
                           
            % calculate the wavelength
            cipMetaData.lambda=radConst.c_mps/cipMetaData.cipCenterFrequency_hz;
            
            % determine the doppler speed for each doppler bin...
            vwin=cipMetaData.lambda/(2*cipMetaData.priTime_s);
            Np=cipMetaData.numPris;
            cipMetaData.dopplerBins_mps= (0:1:Np-1)*vwin/Np-vwin/2; %meters per second

            % calculate video frame time for sync with recorded video
            cipMetaData.videoFrameTime=1/cipMetaData.videoFPS;
            cipMetaData.priPerVideoFrame= cipMetaData.videoFrameTime/cipMetaData.priTime_s;
        end
    end

    methods
        function obj = mpdrRadar(configFile,varargin)
%             if(nargin > 0)
%                 useWxMode = varargin{1};
%             end

            wxDefault=radChan.WxMode(false);
            obj.configFile = configFile;
            configValues = yaml.loadFile(obj.configFile,"ConvertToArray",true);

            %mpdrRadar Construct an instance of this class
            obj.cipMetaData = configValues.cipMetaData;

% RANGE offset ESTIMATE.  May not be accurate for all captures. MPS
            obj.cipMetaData.cells.rxTxBiasCorr=30; % initial value
            obj.cipMetaData.fileSizeCips=0;
            obj.cipMetaData.fileSizePris=0;
            obj.cipMetaData.fileVer=0;
            obj.discardPris = configValues.discardPris; % must be >= need to discard first PRI always...
            obj.pcTaylorSll = configValues.pcTaylorSll;
            obj.pcTaylorNbar = configValues.pcTaylorNbar;
            obj.numClutterCells = configValues.numClutterCells;
            obj.configVals=configValues;
            obj.readSize = (obj.cipMetaData.numPris * obj.cipMetaData.numChannels * obj.iQ * obj.cipMetaData.priSize);
            obj.cipMetaData = obj.calcWaveformParams(obj);
            Stc=configValues.Stc;
            StcVarNames = Stc.StcTableCols;
            [row,~] = size(Stc.StcTableRows);
            obj.Stc = table('Size',[row 5], 'VariableTypes', {'double', 'double', 'double', 'double', 'double'}, 'VariableNames',StcVarNames);
            for ii = 1:row
                %    stcCell = cell2mat(obj.Stc.StcTableRows(ii,1));
                stcCell = Stc.StcTableRows(ii,:);
                for jj = 1:5
                    cell =  mat2cell(stcCell(jj), 1);
                    obj.Stc(ii,jj) = cell;
                end
            end

            obj.StcStartDelay=configValues.StcStartDelay;
            startDelay = obj.StcStartDelay;

            StcScaleVec=ones(1,obj.cipMetaData.priSize);
            [StcVecLen,~]=size(obj.Stc.FirstSample);

            for ii = 1:StcVecLen-1
                StcScaleVec(obj.Stc.FirstSample(ii)+1+startDelay:obj.Stc.LastSample(ii)+1+startDelay)=obj.Stc.Multiplier(ii);
            end
            obj.stcScale=repmat(StcScaleVec,obj.cipMetaData.numChannels,1,obj.cipMetaData.numPris);
            
%             obj.cipCount = 0;               %debug
%             obj.iqdata=0;
        end
        
        
        
        %% class destructor ...
        function delete(obj)
            try
                obj.closeFile();
            catch
            end
        end

        %%
        function numChan=getNumChan(obj)
            numChan = uint32(obj.cipMetaData.numChannels);
        end

        %%
        function numPris = getNumPris(obj)
            numPris = uint32(obj.cipMetaData.numPris);
        end

        %% get the meta data for the last CIP read (or default from config file)
        function cipMetaData=getCipMetaData(obj)
            cipMetaData = obj.cipMetaData;
        end

        %% set the meta data for the last CIP read (or default from config file)
        function setCipMetaData(obj,aCipMetaData)
            obj.cipMetaData=aCipMetaData;
        end


        %%
        function numPriSize=getPriSize(obj)
            numPriSize = uint32(obj.cipMetaData.priSize);
        end
        %% is the radar in Wx mode?
        function aWxMode = isWxMode(obj)
            aWxMode = obj.cipMetaData.wxMode;
        end

        %% get taylor weighting settings...
        function [aPcTaylorSll,aPcTaylorNbar] = getPcWeightConfig(obj)
            aPcTaylorSll = obj.pcTaylorSll;
            aPcTaylorNbar = obj.pcTaylorNbar;
        end

        %% stcCorrect function
        function aStcCorr=getStcCorr(obj)
            aStcCorr=obj.stcScale;
        end

        %% getDopCells function
        function aReturn=getDopCells(obj)
            aReturn=obj.dopplerCells;
        end

        %% getClutterCells function
        function aReturn=getClutterCells(obj)
            aReturn=obj.clutterCells;
        end

        %% getConfigValues function
        function aReturn=getConfigValues(obj)
            aReturn=obj.configVals;
        end  

        function setPlayback(obj, aPlayback)
            obj.playback = aPlayback;
        end

        function setClutterCells(obj, aClutterCells)
            obj.clutterCells = aClutterCells;
        end

        function setDopplerCells(obj, aDopplerCells)
            obj.dopplerCells = aDopplerCells;
        end
    end

end

