Files
imdd_silas/Classes/01_transmit/Pulseformer.m
magf a8daf12b20 Added:
- Class folder 'Timing Recovery' with different methods
- Minimal example for the timing recovery in the FSO folder
- New evaluation scripts for FSO data
2026-02-02 10:15:07 +01:00

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