classdef Pulseformer
    %Pulseformer Summary of this class goes here
    %   Detailed explanation goes here

    properties(Access=public)
        fdac
        fsym
        pulse
        pulselength
        rrcalpha
    end

    methods (Access=public)
        function obj = Pulseformer(options)
            %NAME Construct an instance of this class
            %   Detailed explanation goes here

            arguments
                options.fdac double 
                options.fsym double 
                options.pulse pulseform = pulseform.rrc
                options.pulselength double {mustBeInteger} = 32
                options.rrcalpha double = 0.05
            end

            %
            fn = fieldnames(options);
            for n = 1:numel(fn)
                try
                    obj.(fn{n}) = options.(fn{n});
                end
            end

            % do more stuff

        end

        function signalclass_out = process(obj,signalclass_in)

            % actual processing of the signal (steps 1. - 3.)
            signalclass_in.signal = obj.process_(signalclass_in.signal);

            % append to logbook
            lbdesc = 'Applied Pulseshaping';
            signalclass_in  = signalclass_in.logbookentry(lbdesc);

            % write fs to signal 
            signalclass_in.fs = obj.fdac;

            % write to output
            signalclass_out = signalclass_in;

        end



    end

    methods (Access=private)
        % Cant be seen from outside! So put all your functions here that can/
        % shall not be called from outside

        function data_out = process_(obj,data_in)
            %METHOD1 Summary of this method goes here
            %   Detailed explanation goes here
            arguments(Input)
                obj
                data_in 
            end

            arguments(Output)
                data_out 
            end

            if ~rem(obj.fdac,obj.fsym)
                %ist ein Vielfaches
                sps = obj.fdac / obj.fsym;
                up = sps;
                dn = 1;
            else
                %ist kein Vielfaches
                up = obj.fdac / gcd(obj.fdac, obj.fsym);
                dn = obj.fsym / gcd(obj.fdac, obj.fsym);
                sps= up;
            end

            if obj.pulse ==  pulseform.rrc
                %Bau das Filter (hier rrc)
                racos_len   = obj.pulselength*2;
                alpha       = obj.rrcalpha;
                h           = rcosdesign(alpha,racos_len,sps,"normal");
                h           = h./ max(h);
            end

            % Apply filter the long way (from move_it)
            % block length in samples 
        
            data_in = data_in';
            blen = length(data_in)*sps;
        
            % oversample symbol sequence
        
            symbolov=zeros(size(data_in,1),blen);
            symbolov(:,1:sps:blen-sps+1)=data_in;

            H=fft(h,blen);
        
            % Convolution of Bit sequence with impulse response

            % cyclic convolution         
            data_out=ifft( fft(symbolov.') .* repmat( H,size(data_in,1),1 ).' ).';

            data_out = circshift(data_out,[0 -(obj.pulselength*sps)]);

            if rem(obj.fdac,obj.fsym)
                data_out = data_out(1:dn:end); %!
            end


%             %Apply Filter using Matlab build in fctn.
%              h           = rcosdesign(alpha,racos_len,sps);
%              h           = h./ max(h);
             %data_out_ = upfirdn(data_in,h,up,dn);
% 
%             %cut signal, which is longer due to fir filter
             st = round(up/dn*racos_len/2); %we need to cut y_out
%             en = round(st + (length(data_in)*up/dn) -1);
%             data_out = data_out(st:en);

            %scaling?! see pulsef module line 696
%             scale = max(max([abs(real(data_out)) abs(imag(data_out))])); %find max value from real and imag part
%             data_out = data_out./scale;

            data_out = data_out';

            %Check output integrity
            if round(up/dn * length(data_in)) ~= length(data_out)
                %warning('Check signal length after pulse shaping');
                %disp('Check signal length after pulse shaping');
            end


        end


    end
end
