classdef Pulse_Generator < matlab.apps.AppBase

    % Properties that correspond to app components
    properties (Access = public)
        AppWindow       matlab.ui.Figure                   % Pulse Generator
        axPulsePlot     matlab.ui.control.UIAxes          
        btnPlot         matlab.ui.control.Button           % Plot
        swPlotType      matlab.ui.control.Switch           % Pulse, Pulse S...
        lmpAutoUpdate   matlab.ui.control.Lamp            
        swAutoUpdate    matlab.ui.control.Switch           % off, on
        lblAutoUpdate   matlab.ui.control.Label            % Auto Update
        dknDispersion   matlab.ui.control.DiscreteKnob     % -1.0, -0.5, 0,...
        lblDispersion   matlab.ui.control.Label            % Dispersion
        dknModulation   matlab.ui.control.DiscreteKnob     % 0, 50, 100, 15...
        lblModulation   matlab.ui.control.Label            % Modulation
        cknHighPass     matlab.ui.control.Knob             % [0 1]
        lblHighPass     matlab.ui.control.Label            % High Pass
        cknWindow       matlab.ui.control.Knob             % [0 1]
        lblWindow       matlab.ui.control.Label            % Window
        cknLowPass      matlab.ui.control.Knob             % [0 1]
        lblLowPass      matlab.ui.control.Label            % Low Pass
        cknEdge         matlab.ui.control.Knob             % [0 4]
        lblEdge         matlab.ui.control.Label            % Edge
        ddType          matlab.ui.control.DropDown         % gaussian, sinc...
        lblType         matlab.ui.control.Label            % Type
        numSignalLength matlab.ui.control.NumericEditField % [1 Inf]
        lblSignalLength matlab.ui.control.Label            % Signal Length (s)
        numFrequency    matlab.ui.control.NumericEditField % [-Inf Inf]
        lblFrequency    matlab.ui.control.Label            % Frequency
    end


    properties (Access = private)
        autoUpdate
    end

    methods (Access = private)
        
        function updatePlot(app)
            
            signalLength = app.numSignalLength.Value ;
            frequency = app.numFrequency.Value ;
            plotType = app.swPlotType.Value ;
             
            p = generatePulse(app) ;
            t = -signalLength/2:1/frequency:signalLength/2;

            if strcmp(plotType,'Pulse')
                plot(app.axPulsePlot, t, p);
                xlabel(app.axPulsePlot,'Time (s)');
            else
                lp=length(p);
                Y=fft(p);
                sig=abs(Y(1:ceil(lp/2)));
                f=linspace(0, frequency/2, ceil(lp/2));
                plot(app.axPulsePlot, f(sig>1e-4), sig(sig>1e-4));
%                 semilogy(app.axPulsePlot, f(sig>1e-4), sig(sig>1e-4));
                xlabel(app.axPulsePlot,'Frequency (Hz)');
            end            
            
        end

        function result = generatePulse(app)
            
            frequency = app.numFrequency.Value ;
            signalLength = app.numSignalLength.Value ;
            edge = app.cknEdge.Value ;
            window = app.cknWindow.Value ;
            modulation = str2num(app.dknModulation.Value) ;
            type = app.ddType.Value ;
            lowpass = app.cknLowPass.Value ;
            highpass = app.cknHighPass.Value ;
            dispersion = str2num(app.dknDispersion.Value) ;
            
            startFrequency = 10 ;
            stopFrequency = 20 ;
            
            t = -signalLength/2:1/frequency:signalLength/2 ;
            sig = (signalLength/(8*edge))^2 ;
            
            switch app.ddType.Value
                
                case 'gaussian'
                    y = exp(-(t).^2/sig) ;
                case 'sinc'
                    x = 2*pi*edge*50.*t/(5*signalLength) ;
                    y = sin(x)./x ;
                    y(x==0) = 1 ;
                case 'square'
                    y = (t > -signalLength/edge/2) & (t < signalLength/edge/2) ;
                case 'triangle'
                    y = (t + signalLength/edge/2).*(t < 0) - (t - signalLength/edge/2).*(t >= 0);
                    y(y < 0) = 0 ;
                case 'monocycle'
                    if (sig == 0)
                        y = t ;
                    else
                        y = 2*t./sig.*exp(-(t).^2/sig) ;
                    end
                case 'exponential'
                    y = exp(-t*8*edge/signalLength) ;
                    y(t<0) = 0 ;
                case 'biexponential'
                    y = exp(-abs(t)*8*edge/signalLength) ;
                case 'mexican hat'
                    z = t./sqrt(0.75*sig);
                    y = sqrt(1/2*pi).*(1-z.^2).*exp(-z.^2/2) ;
                case 'raised cosine'
                    rb = 2*edge*50/(5*signalLength);
                    x = pi.*t.*rb ;
                    y = sin(x)./x ;
                    y(x==0) = 1 ;
                    y = y.*(cos(2*pi*rb.*t)./(1 - (4*rb.*t).^2));
                case 'double sinc'
                    x1 = 2*stopFrequency*pi.*t ;
                    x2 = 2*startFrequency*pi.*t ;
                    y1 = sin(x1)./x1 ;
                    y1(x1==0) = 1 ;
                    y2 = sin(x2)./x2 ;
                    y2(x2==0) = 1 ;
                    y = stopFrequency*y1 - startFrequency*y2;
                case 'sinc squared'
                    x = 2*pi*edge*16.*t/(5*signalLength) ;
                    y = sin(x)./x ;
                    y(x==0) = 1 ;
                    y = y.^2 ;
                case 'sweep'
                    theta = startFrequency.*(t + signalLength/2) + ...
                        ((stopFrequency - startFrequency)/(signalLength)).*(t+signalLength/2).^2;
                    y = real(exp(1j*(2*pi.*theta - pi/2)));
            end
            
            if (lowpass < 1) || (highpass > 0) || (dispersion ~= 0)
                c = length(y) ;
            end
            
            s = fft(y);
            sA = abs(s);
            sP = angle(s);
            if (lowpass < 1)
                cP = ceil(lowpass*c/2);
                if (cP == 0)
                    sA(:) = 0;
                else
                    sA(cP:end-cP+2) = 0;
                end
            end
            
            if (highpass > 0)
                cP = floor(highpass*c/2);
                if (cP ~= 0)
                    sA(1:cP) = 0;
                    sA(end-cP+2:end) = 0;
                end
            end
            
            if (dispersion ~= 0)
                pp = dispersion.*linspace(0,2*pi,c);
                sP = sP + pp;
            end
            s2 = sA.*cos(sP) + 1j*sA.*sin(sP);
            y = real(ifft(s2));
            
            if (window > 0)
                c = length(y);
                w = ones(size(y));
                p1 = floor(c*window/2);
                % Window is defined in three sections: taper, constant, taper
                w(1:p1+1) = (-cos((0:p1)/p1*pi)+1)/2;
                w(end-p1:end) = (cos((0:p1)/p1*pi)+1)/2;
                y=w.*y;
            end
            
            if modulation ~= 0
                y = y.*cos(pi*t*modulation);
            end
            result = y./max(abs(y)) ;            
            
        end

    end


    methods (Access = private)

        % Code that executes after component creation
        function startupFcn(app)
            app.swAutoUpdate.Value = 'on';
            app.swPlotType.Value = 'Pulse' ;
            app.btnPlot.Visible = 'off' ;
            app.autoUpdate = 1 ;
            updatePlot(app)
        end

        % swAutoUpdate value changed function
        function swAutoUpdateValueChanged(app)
            if strcmp(app.swAutoUpdate.Value, 'on')
                app.autoUpdate = 1 ;
                app.btnPlot.Visible = 'off' ;
                app.lmpAutoUpdate.Color = [0 1 0] ;
            else
                app.autoUpdate = 0 ;
                app.btnPlot.Visible = 'on' ;
                app.lmpAutoUpdate.Color = [0.5 0.5 0.5] ;  
            end            
        end

        % btnPlot button pushed function
        function btnPlotButtonPushed(app)
            updatePlot(app)            
        end

        % numFrequency value changed function
        function numFrequencyValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % numSignalLength value changed function
        function numSignalLengthValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % ddType value changed function
        function ddTypeValueChanged(app, event)
            if app.autoUpdate
                updatePlot(app)
            end            
        end

        % dknDispersion value changed function
        function dknDispersionValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % swPlotType value changed function
        function swPlotTypeValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % cknLowPass value changed function
        function cknLowPassValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % dknModulation value changed function
        function dknModulationValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % cknEdge value changed function
        function cknEdgeValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % cknWindow value changed function
        function cknWindowValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end

        % cknHighPass value changed function
        function cknHighPassValueChanged(app)
            if app.autoUpdate
                updatePlot(app)
            end
        end
    end

    % App initialization and construction
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Create AppWindow
            app.AppWindow = uifigure;
            app.AppWindow.Position = [100 100 1057 471];
            app.AppWindow.Name = 'Pulse Generator';
            setAutoResize(app, app.AppWindow, true)

            % Create axPulsePlot
            app.axPulsePlot = uiaxes(app.AppWindow);
            xlabel(app.axPulsePlot, 'Time (s)');
            ylabel(app.axPulsePlot, 'Response');
            app.axPulsePlot.Position = [509 19 535 400];

            % Create btnPlot
            app.btnPlot = uibutton(app.AppWindow, 'push');
            app.btnPlot.ButtonPushedFcn = createCallbackFcn(app, @btnPlotButtonPushed);
            app.btnPlot.Position = [272 373 100 20];
            app.btnPlot.Text = 'Plot';

            % Create swPlotType
            app.swPlotType = uiswitch(app.AppWindow, 'slider');
            app.swPlotType.Items = {'Pulse', 'Pulse Spectrum'};
            app.swPlotType.ValueChangedFcn = createCallbackFcn(app, @swPlotTypeValueChanged);
            app.swPlotType.Position = [750 426 45 20];
            app.swPlotType.Value = 'Pulse Spectrum';

            % Create lmpAutoUpdate
            app.lmpAutoUpdate = uilamp(app.AppWindow);
            app.lmpAutoUpdate.Position = [461 426 20 20];

            % Create swAutoUpdate
            app.swAutoUpdate = uiswitch(app.AppWindow, 'slider');
            app.swAutoUpdate.Items = {'off', 'on'};
            app.swAutoUpdate.ValueChangedFcn = createCallbackFcn(app, @swAutoUpdateValueChanged);
            app.swAutoUpdate.Position = [383 426 45 20];
            app.swAutoUpdate.Value = 'on';

            % Create lblAutoUpdate
            app.lblAutoUpdate = uilabel(app.AppWindow);
            app.lblAutoUpdate.Position = [272 429 76 15];
            app.lblAutoUpdate.Text = 'Auto Update';

            % Create dknDispersion
            app.dknDispersion = uiknob(app.AppWindow, 'discrete');
            app.dknDispersion.Items = {'-1.0', '-0.5', '0', '0.5', '1.0'};
            app.dknDispersion.ValueChangedFcn = createCallbackFcn(app, @dknDispersionValueChanged);
            app.dknDispersion.Position = [384 57 60 60];
            app.dknDispersion.Value = '0';

            % Create lblDispersion
            app.lblDispersion = uilabel(app.AppWindow);
            app.lblDispersion.HorizontalAlignment = 'center';
            app.lblDispersion.Position = [378 19 72 15];
            app.lblDispersion.Text = 'Dispersion';

            % Create dknModulation
            app.dknModulation = uiknob(app.AppWindow, 'discrete');
            app.dknModulation.Items = {'0', '50', '100', '150', '200', '250'};
            app.dknModulation.ValueChangedFcn = createCallbackFcn(app, @dknModulationValueChanged);
            app.dknModulation.Position = [384 207 60 60];
            app.dknModulation.Value = '0';

            % Create lblModulation
            app.lblModulation = uilabel(app.AppWindow);
            app.lblModulation.HorizontalAlignment = 'center';
            app.lblModulation.Position = [378 166 73 15];
            app.lblModulation.Text = 'Modulation';

            % Create cknHighPass
            app.cknHighPass = uiknob(app.AppWindow, 'continuous');
            app.cknHighPass.Limits = [0 1];
            app.cknHighPass.MajorTicks = [0 0.2 0.4 0.6 0.8 1];
            app.cknHighPass.ValueChangedFcn = createCallbackFcn(app, @cknHighPassValueChanged);
            app.cknHighPass.Position = [229 57 60 60];

            % Create lblHighPass
            app.lblHighPass = uilabel(app.AppWindow);
            app.lblHighPass.HorizontalAlignment = 'center';
            app.lblHighPass.Position = [229.5 19 58 15];
            app.lblHighPass.Text = 'High Pass';

            % Create cknWindow
            app.cknWindow = uiknob(app.AppWindow, 'continuous');
            app.cknWindow.Limits = [0 1];
            app.cknWindow.MajorTicks = [0 0.2 0.4 0.6 0.8 1];
            app.cknWindow.ValueChangedFcn = createCallbackFcn(app, @cknWindowValueChanged);
            app.cknWindow.Position = [229 207 60 60];

            % Create lblWindow
            app.lblWindow = uilabel(app.AppWindow);
            app.lblWindow.HorizontalAlignment = 'center';
            app.lblWindow.Position = [232.5 166 52 15];
            app.lblWindow.Text = 'Window';

            % Create cknLowPass
            app.cknLowPass = uiknob(app.AppWindow, 'continuous');
            app.cknLowPass.Limits = [0 1];
            app.cknLowPass.MajorTicks = [0 0.2 0.4 0.6 0.8 1];
            app.cknLowPass.ValueChangedFcn = createCallbackFcn(app, @cknLowPassValueChanged);
            app.cknLowPass.Position = [62 57 60 60];
            app.cknLowPass.Value = 0.4;

            % Create lblLowPass
            app.lblLowPass = uilabel(app.AppWindow);
            app.lblLowPass.HorizontalAlignment = 'center';
            app.lblLowPass.Position = [63 19 57 15];
            app.lblLowPass.Text = 'Low Pass';

            % Create cknEdge
            app.cknEdge = uiknob(app.AppWindow, 'continuous');
            app.cknEdge.Limits = [0 4];
            app.cknEdge.ValueChangedFcn = createCallbackFcn(app, @cknEdgeValueChanged);
            app.cknEdge.Position = [62 207 60 60];
            app.cknEdge.Value = 1;

            % Create lblEdge
            app.lblEdge = uilabel(app.AppWindow);
            app.lblEdge.HorizontalAlignment = 'center';
            app.lblEdge.Position = [75 166 33 15];
            app.lblEdge.Text = 'Edge';

            % Create ddType
            app.ddType = uidropdown(app.AppWindow);
            app.ddType.Items = {'gaussian', 'sinc', 'square', 'triangle', 'monocycle', 'exponential', 'biexponential', 'mexican hat', 'raised cosine', 'double sinc', 'sinc squared', 'sweep'};
            app.ddType.ValueChangedFcn = createCallbackFcn(app, @ddTypeValueChanged, true);
            app.ddType.Position = [134 321 100 20];
            app.ddType.Value = 'gaussian';

            % Create lblType
            app.lblType = uilabel(app.AppWindow);
            app.lblType.HorizontalAlignment = 'right';
            app.lblType.Position = [87 324 32 15];
            app.lblType.Text = 'Type';

            % Create numSignalLength
            app.numSignalLength = uieditfield(app.AppWindow, 'numeric');
            app.numSignalLength.ValueChangedFcn = createCallbackFcn(app, @numSignalLengthValueChanged);
            app.numSignalLength.Limits = [1 Inf];
            app.numSignalLength.Position = [134 373 100 20];
            app.numSignalLength.Value = 2;

            % Create lblSignalLength
            app.lblSignalLength = uilabel(app.AppWindow);
            app.lblSignalLength.HorizontalAlignment = 'right';
            app.lblSignalLength.Position = [22 376 97 15];
            app.lblSignalLength.Text = 'Signal Length (s)';

            % Create numFrequency
            app.numFrequency = uieditfield(app.AppWindow, 'numeric');
            app.numFrequency.ValueChangedFcn = createCallbackFcn(app, @numFrequencyValueChanged);
            app.numFrequency.Position = [134 426 100 20];
            app.numFrequency.Value = 500;

            % Create lblFrequency
            app.lblFrequency = uilabel(app.AppWindow);
            app.lblFrequency.HorizontalAlignment = 'right';
            app.lblFrequency.Position = [55 429 64 15];
            app.lblFrequency.Text = 'Frequency';
        end
    end

    methods (Access = public)

        % Construct app
        function app = Pulse_Generator()

            % Create and configure components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.AppWindow)

            % Execute the startup function
            runStartupFcn(app, @startupFcn)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.AppWindow)
        end
    end
end