- Class folder 'Timing Recovery' with different methods - Minimal example for the timing recovery in the FSO folder - New evaluation scripts for FSO data
238 lines
7.6 KiB
Matlab
238 lines
7.6 KiB
Matlab
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
|