classdef UI < handle
    properties
        FIGURE
        PANEL
        c = 331.57 + (0.607*20);
        f_vz = 20e3;
        noise_data
        N = 20e3*1.9
        noise_max
        loaded_data
        signal
        t_span
        filtr_t_span
        inp_peak
        angle_hor
        angle_ver
        filtr_signal
    end
    
    methods
        function Ob = UI
            Ob.create_Figure
            Ob.create_UI
        end
        function create_Figure(Ob)
            Ob.FIGURE = uifigure;
            Ob.FIGURE.MenuBar = 'none';
            Ob.FIGURE.Position = [100 50 1400 800];
        end
        function create_UI(Ob)
            
            %% dropdown
            Ob.PANEL.dropdown.rozmisteni = uidropdown('Position',[100 700 200 30],'Parent',Ob.FIGURE,'FontSize',15,'Items',...
                {'Lineární','Rovinné čtvercové'});
            Ob.PANEL.dropdown.metoda = uidropdown('Position',[400 700 200 30],'Parent',Ob.FIGURE,'FontSize',15,'Items',...
                {'DAS Beamformer','TDOA'});
            
            Ob.PANEL.dropdown.pocet = uidropdown('Position',[690 700 75 30],'Parent',Ob.FIGURE,'FontSize',15,'Items',...
                {'2','3','4'});
            Ob.PANEL.dropdown.vzdalenost = uidropdown('Position',[860 700 75 30],'Parent',Ob.FIGURE,'FontSize',15,'Items',...
                {'0.1','0.2'});
            Ob.PANEL.dropdown.uhel = uidropdown('Position',[1020 700 75 30],'Parent',Ob.FIGURE,'FontSize',15,'Items',...
                {'-90','-70','-50','-30','-10','0','10','30','50','70','90'});
            
            %% label
            Ob.PANEL.Label{1} = uilabel('Parent',Ob.FIGURE,...
                'Text','Rozmístění mikrofonů','Position',[108 740 200 30],'FontSize',18);
            Ob.PANEL.Label{2} = uilabel('Parent',Ob.FIGURE,...
                'Text','Metoda','Position',[465 740 200 30],'FontSize',18);
            
            Ob.PANEL.Label{3} = uilabel('Parent',Ob.FIGURE,...
                'Text','Počet mikrofonů','Position',[670 740 200 30],'FontSize',18);
            Ob.PANEL.Label{4} = uilabel('Parent',Ob.FIGURE,...
                'Text','Vzdálenost [m]','Position',[840 740 200 30],'FontSize',18);
            Ob.PANEL.Label{5} = uilabel('Parent',Ob.FIGURE,...
                'Text','Úhel [°]','Position',[1030 740 75 30],'FontSize',18);
            
            %% axes - grafy
            Ob.PANEL.axes.signal = uiaxes('Parent',Ob.FIGURE,'Position',[50 350 700 300],'FontSize',18);
            Ob.PANEL.axes.signal.Title.String = 'Nahraný signál';
            Ob.PANEL.axes.filtr = uiaxes('Parent',Ob.FIGURE,'Position',[50 50 700 300],'FontSize',18);
            Ob.PANEL.axes.filtr.Title.String = 'Signál po detekci';
            Ob.PANEL.axes.mik = uiaxes('Parent',Ob.FIGURE,'Position',[800 350 500 300],'FontSize',18,'XGrid','on','YGrid','on');
            Ob.PANEL.axes.mik.Title.String = 'Mikrofonní pole';
            %% button 
            Ob.PANEL.button = uibutton('Position',[1180 700 200 60],'Parent',Ob.FIGURE,'FontSize',18,'Text','START','ButtonPushedFcn',@Ob.Graf);
            
            %% TEXT AREA
            Ob.PANEL.disp{1} = uitextarea('Position',[800 80 200 60],'Parent',Ob.FIGURE,'FontSize',18,'Editable','off','FontWeight','bold','HorizontalAlignment','center');
            
            Ob.PANEL.disp{2} = uitextarea('Position',[1100 80 200 60],'Parent',Ob.FIGURE,'FontSize',18,'Editable','off','FontWeight','bold','HorizontalAlignment','center');
        end
        function Graf(Ob,handle,eventData)
            %% vynulovat data z minuleho vypoctu
            Ob.loaded_data = [];
            Ob.signal = [];
            Ob.inp_peak = [];
            Ob.angle_hor = [];
            Ob.angle_ver = [];
            Ob.t_span = [];
            Ob.filtr_t_span = [];
            Ob.noise_data = [];
            Ob.noise_max = [];
            Ob.filtr_signal = [];
            
            switch Ob.PANEL.dropdown.rozmisteni.Value
                case 'Lineární'
                    Ob.disp_LinPole;
                    Ob.load_linear;
                    Ob.create_Matice;
                    Ob.detekt_filtr;
                    Ob.pocitej_lin;
                case 'Rovinné čtvercové'
                    Ob.disp_ObdenikPole
                    Ob.load_ctverec;
                    Ob.create_Matice;
                    Ob.detekt_filtr;
                    Ob.pocitej_ctverec;
                case 'Rovinné obdélníkové'
                    Ob.disp_ObdenikPole
                    Ob.load_obdelnik;
                    Ob.create_MaticeObdelnik;                 
                    Ob.detekt_filtr;
                    Ob.pocitej_obdelnik;
            end
            
            %% vypolotuje signal
            plot(Ob.PANEL.axes.signal,Ob.t_span,Ob.signal);
            hold(Ob.PANEL.axes.signal,'on');
            plot(Ob.PANEL.axes.signal,Ob.filtr_t_span,Ob.filtr_signal,'r');
            hold(Ob.PANEL.axes.signal,'off');
            
            plot(Ob.PANEL.axes.filtr,Ob.filtr_t_span,Ob.inp_peak);
            
            %% vypise uhel
            Ob.PANEL.disp{1}.Value = sprintf('Horizontální úhel je: \n %0.5g [°]',Ob.angle_hor);
            Ob.PANEL.disp{2}.Value = sprintf('Vertikalni úhel je: \n %0.5g [°]',Ob.angle_ver);
            
        end
        
        function load_linear(Ob)
            switch Ob.PANEL.dropdown.vzdalenost.Value
                case '0.1'
                    load('DATA\Mik4_NOISE.mat');
                    Ob.noise_data = noise_signal;
                    Ob.hladina_Detekce;
                    
                switch Ob.PANEL.dropdown.uhel.Value
                     case '-90'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG-90.mat');
                    Ob.loaded_data = data;
                    case '-70'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG-70.mat');
                    Ob.loaded_data = data;
                     case '-50'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG-50.mat');
                    Ob.loaded_data = data;
                    case '-30'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG-30.mat');
                    Ob.loaded_data = data;
                    case '-10'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG-10.mat');
                    Ob.loaded_data = data;
                    case '0'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG0.mat');
                    Ob.loaded_data = data;
                    case '10'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG10.mat');
                    Ob.loaded_data = data;
                    case '30'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG30.mat');
                    Ob.loaded_data = data;
                    case '50'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG50.mat');
                    Ob.loaded_data = data;
                    case '70'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG70.mat');
                    Ob.loaded_data = data;
                    case '90'
                    load('DATA\4MIK_01_MERENI2\Mik4_01_DG90.mat');
                    Ob.loaded_data = data;
                end
                case '0.2'
                    load('DATA\NOISE.mat');
                    Ob.noise_data = noise_signal;
                    Ob.hladina_Detekce;
                    
                    switch Ob.PANEL.dropdown.uhel.Value
                    case '-90'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG-90_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '-70'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG-70_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '-50'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG-50_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '-30'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG-30_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '-10'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG-10_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '0'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG0_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '10'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG10_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '30'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG30_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '50'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG50_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '70'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG70_fvz20khz.mat');
                    Ob.loaded_data = data;
                    case '90'
                    load('DATA\4MIK_02\Mikr4_D02_modr_DG90_fvz20khz.mat');
                    Ob.loaded_data = data;
                    end
            end
        end
        function load_ctverec(Ob)
            load('DATA\Mik4_NOISE.mat');
            Ob.noise_data = noise_signal;
            Ob.hladina_Detekce;
            
            switch Ob.PANEL.dropdown.vzdalenost.Value
                case '0.2'
                    switch Ob.PANEL.dropdown.uhel.Value
                    case '-90'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ-90.mat');
                    Ob.loaded_data = data;
                    case '-70'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ-70.mat');
                    Ob.loaded_data = data;
                    case '-50'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ-50.mat');
                    Ob.loaded_data = data;
                    case '-30'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ-30.mat');
                    Ob.loaded_data = data;
                    case '-10'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ-10.mat');
                    Ob.loaded_data = data;
                    case '0'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ0.mat');
                    Ob.loaded_data = data;
                    case '10'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ10.mat');
                    Ob.loaded_data = data;
                    case '30'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ30.mat');
                    Ob.loaded_data = data;
                    case '50'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ50.mat');
                    Ob.loaded_data = data;
                    case '70'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ70.mat');
                    Ob.loaded_data = data;
                    case '90'
                    load('DATA\4MIK_CTVEREC_02\Mik4_CTVEREC_02_EL0_AZ90.mat');
                    Ob.loaded_data = data;
                    end
            end
        end
        
        function pocitej_lin(Ob)
            switch Ob.PANEL.dropdown.metoda.Value
                case 'DAS Beamformer'
                     Ob.angle_hor = Ob.Beamforming(Ob.inp_peak);
                     
                case 'TDOA'
                     Ob.angle_hor = Ob.TDOA(Ob.inp_peak);
            end
        end
        function pocitej_ctverec(Ob)
                signal_ver = Ob.inp_peak;
                signal_ver(:,2) = Ob.inp_peak(:,3);
                signal_ver(:,3) = Ob.inp_peak(:,2);
                signal_ver(:,4) = Ob.inp_peak(:,4);
                
            switch Ob.PANEL.dropdown.metoda.Value
                case 'DAS Beamformer'
                    %% horizontalni rovina
                    
                    B_hor1 = Ob.Beamforming(Ob.inp_peak(:,1:2));
                    B_hor2 = Ob.Beamforming(Ob.inp_peak(:,3:4));
                    Ob.angle_hor = (B_hor1+B_hor2)/2;
                    
                    %% vertikalni rovina
                    
                    B_ver1 = Ob.Beamforming(signal_ver(:,1:2));
                    B_ver2 = Ob.Beamforming(signal_ver(:,3:4));
                    Ob.angle_ver = (B_ver1+B_ver2)/2;
                    
                case 'TDOA'
                    %% horizontalni rovina
                    
                    B_hor1 = Ob.TDOA(Ob.inp_peak(:,1:2));
                    B_hor2 = Ob.TDOA(Ob.inp_peak(:,3:4));
                    Ob.angle_hor = (B_hor1+B_hor2)/2;
                    
                    %% vertikalni rovina
                    
                    B_ver1 = Ob.TDOA(signal_ver(:,1:2));
                    B_ver2 = Ob.TDOA(signal_ver(:,3:4));
                    Ob.angle_ver = (B_ver1+B_ver2)/2;
                    
            end
        end
        
        function hladina_Detekce(Ob)
            M = str2double(Ob.PANEL.dropdown.pocet.Value);
            noise = (zeros(Ob.N,M)); %% inicializacni matice
            for i = 1:M
                noise(:,i) = Ob.noise_data{i}.Values.Data(1:Ob.N,1); % kazdy sloupec jeden signal NxM
            end
            
           
            Mmax = zeros(M,1); % inicializace matice noise
        
            % urci hranici pro detekci pro kazdy signal
            for i = 1:M
                Mmax(i,1) = max(noise(:,i));
            end
            
            Ob.noise_max  = Mmax + (0.1*Mmax); % <---------------------- VYSTUP
            
        end
        function detekt_filtr(Ob)
            % rozsah oblasti detekce peaku
            if Ob.f_vz > 25e3
                D = 5; % dolni posunuti rozsahu v indexu
                H = 7; % horni posunuti rozsahu v indexu
            else
                D = 2;
                H = 2;
            end
            %% overeni spravneho zadani signalu
            
            Ob.inp_peak = zeros(141,(str2double(Ob.PANEL.dropdown.pocet.Value)));
            P = zeros ((str2double(Ob.PANEL.dropdown.pocet.Value)),141);
            oblast_s = zeros(141,(str2double(Ob.PANEL.dropdown.pocet.Value)));
            %% vybrat oblast peaku
            X = find(Ob.signal(:,1) > 1.3*Ob.noise_max(1)); % v prvnim signalu vybere oblast nad hranici signalu odpovidajici tomuto signalu
            
            if ~isempty(X) % overi, jestli se do X neco zapsalo (X neni prazdne)
                for i = 1:str2double(Ob.PANEL.dropdown.pocet.Value)
                    oblast_s(1:141,i) = Ob.signal(X(1)-40:X(1)+100,i);
                end
                Ob.filtr_t_span = Ob.t_span(X(1)-40:X(1)+100,1); % <---------------------- VYSTUP
                Ob.filtr_signal = oblast_s;
                for i = 1:(str2double(Ob.PANEL.dropdown.pocet.Value))
                    %% vybrany konkretni peak
                    Q = find(oblast_s(:,i) >= Ob.noise_max(i));
                    if isempty(Q)
                        continue
                    else
                        P(i,1:length(Q)) = Q;
                        Ob.inp_peak(P(i,1)-D:P(i,1)+H,i) = oblast_s(P(i,1)-D:P(i,1)+H,i); % <---------------------- VYSTUP
                    end
                end
            end
          
        end
        function create_Matice(Ob)
            Ob.t_span = Ob.loaded_data{1}.Values.Time(1:Ob.N,1); % <---------------------- VYSTUP
            for i = 1:(str2double(Ob.PANEL.dropdown.pocet.Value))
                Ob.signal(:,i) = Ob.loaded_data{i}.Values.Data(1:Ob.N,1); % kazdy sloupec jeden signal NxM <---------------------- VYSTUP
                %                 plot(Ob.t_span,Ob.signal(:,i));
            end
        end
        function create_MaticeObdelnik(Ob)
            Ob.t_span = Ob.loaded_data{1}.Values.Time(1:Ob.N,1);
            for i = 1:(str2double(Ob.PANEL.dropdown.pocet.Value)/2)
                Ob.signal(:,2*i) = Ob.loaded_data{i+4}.Values.Data(1:Ob.N,1);
                Ob.signal(:,2*i-1) = Ob.loaded_data{i}.Values.Data(1:Ob.N,1);
            end
        end
        
        function alfa_b = Beamforming(Ob,vybrany_signal)
pocet_vzorku = length(vybrany_signal(1,:)); % pocet vzorku v periode
pocet_mikrofonu = (length(vybrany_signal(:,1))); % pocet mikrofonu

%% kontrola signalu, jestli je spravne zadany

if pocet_vzorku < pocet_mikrofonu
    vybrany_signal = vybrany_signal';
    pocet_vzorku = length(vybrany_signal(1,:)); % pocet vzorku v periode
    pocet_mikrofonu = (length(vybrany_signal(:,1))); % pocet mikrofonu
end

N_Scan = 181; % pocet scanovanych uhlu 
alfa_v = linspace(-90,90,N_Scan);  %mozne uhly odkud jde signal


%% INPUT - sig1,sig2,sig3,sig4

delta_t = zeros(pocet_mikrofonu,N_Scan);
y = zeros(pocet_mikrofonu,pocet_vzorku);

%% zpozdeni => delay
for i = 1:N_Scan % pro kazdy mozny uhel
    alfa = alfa_v(i);
    sig_all = zeros(pocet_mikrofonu,pocet_vzorku); %vytvorim novy vektor s 0 pro zpozdovani signalu
    
    for h = 1:pocet_mikrofonu % pro kazdy mikrofon  
        delta_t(h,i)= (sin(deg2rad(alfa))*str2double(Ob.PANEL.dropdown.vzdalenost.Value)*(h-1))/Ob.c;
        
        posunuti = round(delta_t(h,i)*Ob.f_vz); % posunuti ve vzorcich +/-
        
        if posunuti < 0  %zpozdeni zaporne, posouvam signal doprava
             posunuti = - posunuti;
             sig_all(h,posunuti:pocet_vzorku) = vybrany_signal(h,1:(pocet_vzorku-posunuti)+1);
        
        elseif posunuti > 0 % zpozdeni kladne, posun signalu doleva
             sig_all(h,1:(pocet_vzorku-posunuti)+1) = vybrany_signal(h,posunuti:pocet_vzorku);
        else
             sig_all(h,:) = vybrany_signal(h,1:pocet_vzorku);
        end
    end
    
    %% SUM - soucet
    
    y(i,:) = sum(sig_all,1); % soucet, pro kazdy radek jeden vystupni signal pro urceny uhel alfa
   
end
    
%% vyhodnoceni odkud prichazi signal
% root mean square RMS - stredni hodnota 
RMS = zeros(1,N_Scan);

for p = 1:N_Scan
    
    RMS(1,p) = sqrt((sum(y(p,:).^2))/pocet_vzorku);

end

[~,index] = max(RMS);
alfa_b = alfa_v(index);

        end
        
        function alfa_tdoa = TDOA(Ob,sig_c)
            M = length(sig_c(1,:)); % pocet vstupnich signalu
            Angle_c = zeros(M-1,1);
            tau_est = zeros(M,1);
            
            for i = 1:M
                [Cor,Posunuti] = xcorr(sig_c(:,i),sig_c(:,1));
                [~,I] = max(abs(Cor)); % najdeme index maximalni hodnoty v korelaci
                tau_est(i,1) = Posunuti(I)/Ob.f_vz; % hodnota posunuti se prepocita na casovy rozdil
            end
            
            for n = 2:M
                %% vyhodnoceni uhlu
                Angle_c(n-1,1) = rad2deg(asin((tau_est(n)*Ob.c)/(str2double(Ob.PANEL.dropdown.vzdalenost.Value)*(n-1))));
                
                % overeni, ze hodnota neni NaN
                if isnan(Angle_c(n-1,1))
                    Angle_c(n-1,1) = [];
                end
            end
            
            
            Angle_vector = real(Angle_c); 
            alfa_tdoa = mean(Angle_vector); % prumerna hodnota z vektoru uhlu
        end
        
        function disp_LinPole(Ob)
            M = str2double(Ob.PANEL.dropdown.pocet.Value);
            L = str2double(Ob.PANEL.dropdown.vzdalenost.Value)*(M-1);
            M_x = linspace(-L/2,L/2,M);
            M_y = zeros(1,length(M_x));
            scatter(Ob.PANEL.axes.mik,M_x,M_y,60,'filled');
            Ob.PANEL.axes.mik.XAxis.Limits = [-(L+0.2)/2 (L+0.2)/2];
        end
        function disp_ObdenikPole(Ob)
            d = str2double(Ob.PANEL.dropdown.vzdalenost.Value);
            M = str2double(Ob.PANEL.dropdown.pocet.Value);
            L = d*((M/2)-1);
            M_x = linspace(-L/2,L/2,M/2);
            M_y = zeros(2,M/2);
            
            M_y(1,:) = M_y(1,:)+(d/2);
            M_y(2,:) = M_y(2,:)-(d/2);
            
   
            scatter(Ob.PANEL.axes.mik, M_x, M_y(1,:), 60, 'filled','b')
            hold(Ob.PANEL.axes.mik, 'on')
            scatter(Ob.PANEL.axes.mik, M_x, M_y(2,:), 60, 'filled','b')
            hold(Ob.PANEL.axes.mik, 'off')
            
            Ob.PANEL.axes.mik.XAxis.Limits = [-0.4 0.4];
            Ob.PANEL.axes.mik.YAxis.Limits = [-0.2 0.2];
           
        end
    end
end