classdef Pulseformer %Pulseformer Summary of this class goes here % Detailed explanation goes here properties(Access=public) end properties(Access=public) fdac fsym pulse pulselength alpha matched 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.rc options.pulselength double {mustBeInteger} = 32 options.alpha double = 0.05 options.matched = 0; 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); % append to logbook lbdesc = 'Applied Pulseshaping'; signalclass_in = signalclass_in.logbookentry(lbdesc); % write fs to signal signalclass_in.fs = obj.fdac;%.* (obj.fdac./obj.fsym); % 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_signal) % Extract the incoming sampling rate % Safety check: If fs is missing (e.g. raw symbols), assume it is fsym if isprop(data_in_signal, 'fs') && ~isempty(data_in_signal.fs) f_in = data_in_signal.fs; else f_in = obj.fsym; end f_out = obj.fdac; % 1. Calculate Resampling Factors (P and Q) % We need rational approximation: f_out/f_in = p/q [p, q] = rat(f_out / f_in); % 2. Calculate SPS for the Filter Design % The filter operates at the INTERMEDIATE rate (f_in * p). % We need to know how many samples represent one symbol AT THAT RATE. fs_intermediate = f_in * p; sps_filter = fs_intermediate / obj.fsym; % 3. Filter Design if obj.pulse == pulseform.rc filtertype = 'normal'; elseif obj.pulse == pulseform.rrc % assuming enum logic holds filtertype = 'sqrt'; end % Standard RRC Design % Note: rcosdesign sps must be integer? Usually yes, but for polyphase it can handle it. % If sps_filter is not integer, rcosdesign might complain. % For your setup (powers of 2), it will likely be integer. racos_len = obj.pulselength; % span in symbols h = rcosdesign(obj.alpha, racos_len, sps_filter, filtertype); % h = gaussdesign(obj.alpha, racos_len, sps_filter); % Matched Filter Flip (Complex Conjugate Time Reversal) if obj.matched h = conj(fliplr(h)); end % 4. Processing % Apply upfirdn using the calculated P and Q data_out_ = upfirdn(data_in_signal.signal, h, p, q); % 5. Trim Tail (Group Delay Correction) % The delay of linear phase filter is (N-1)/2 samples @ intermediate rate delay_samples_intermediate = (length(h) - 1) / 2; % Convert delay to output samples delay_samples_out = delay_samples_intermediate / q; % We usually want to trim the "start" transient st = floor(delay_samples_out) + 1; % Calculate expected output length len_out = ceil(length(data_in_signal.signal) * p / q); % Cut data_out = data_out_(st : st + len_out - 1); end % % 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; % p = sps; % q = 1; % else % %ist kein Vielfaches % p = obj.fsym / gcd(obj.fdac, obj.fsym); %upsampling p->->-> % q = obj.fdac/ gcd(obj.fdac, obj.fsym); %downsampling <-q % sps= q; %sps während dem pulse shaping % end % % if obj.pulse == pulseform.rc % filtertype = 'normal'; % elseif pulseform.rrc % filtertype = 'sqrt'; % end % % %Bau das Filter (hier rc) % racos_len = obj.pulselength*2; % h = rcosdesign(obj.alpha,racos_len,sps,filtertype); % % h = h./ max(h); % % if obj.matched % h = conj(fliplr(h)); % end % % manual_cyclic_convolution = 0; % upfirdn_convolution = 1; % % if manual_cyclic_convolution % % % Apply filter the long way (from move_it) % 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 % 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:q:end); % end % % end % % if upfirdn_convolution % % %Apply Filter using Matlab build in fctn. % % data_out_ = upfirdn(data_in,h,p,q); % % %cut signal, which is longer due to fir filter % st = round(p/q*racos_len/2); %we need to cut y_out % en = round(st + (length(data_in)*p/q)); % data_out = data_out_(st:en); % % end % % if upfirdn_convolution && manual_cyclic_convolution % figure() % subplot(2,1,1) % title("Convolution vs. Upfirdn and Cut") % hold on % % plot(data_out_(1:200),'DisplayName','Matlab upfirdn'); % plot(data_out(1:200),'DisplayName','By Hand cyclic convolution') % subplot(2,1,2) % hold on % plot(data_out(1:2000),'DisplayName','OUT'); % plot(data_in(1:2000),'DisplayName','IN'); % end % % %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 abs(round(p/q * length(data_in)) - length(data_out)) > 4 % warning('Check signal length after pulse shaping'); % %disp('Check signal length after pulse shaping'); % end % % % end end end