summaryrefslogtreecommitdiff
path: root/adaptFFE.m
blob: b76bae3c120cbb1c316a88eb8fef5b3c7ecb7650 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
function TapWeights = adaptFFE(waveIn,SamplesPerSymbol,SampleInterval,cmx,cpx,bmax)
%ADAPTFFE Adapt FFE taps based on an input impulse response
% Adapt FFE taps such that the convolution of FFE taps and pulse response 
% results in minimum ISI in the root-mean squared sense.
% Determines the required FFE tap weights needed to cancel out ISI at the
% the UI sample points.  Function is DFE aware, where it will NOT zero force
% 1st post-cursor ISI if a DFE is present. The resulting FFE will have
% cmx + 1 + cpx taps.
%   Inputs:
%       waveIn - Input impulse response to be equalized by the Rx FFE
%       SamplesPerSymbol - the number of samples per each symbol UI used for waveIn
%       SampleInterval - the simulation time step size
%       cmx - number of pre-cursor FFE taps
%       cpx - number of post-cursor FFE taps
%       bmax - the maximum value of 1-tap DFE that follows FFE, if DFE isn't present
%              then this should be set to zero
%   Output:
%       TapWeights       - Adapted tap weights
%
% The required FFE taps are calculated as follows
% 1. To make the adaptation somewhat CDR implementation independent, the peak
%    input pulse amplitude is assumed to be the UI center sampling point.
% 2. The input pulse response is sampled, once per UI, relative to the
%    determined sampling point.
% 3. A circularly shifted matrix (VV) is constructed based on the sampled input
%    pulse response.  It is then trimmed such that the top first row starts at
%    the cursor.  This implmentation follows COM script implementation.
% 4. The target pulse response vector (FV) is constructed.  This vector is an
%    all zero matrix, other than at the cursor position (cmx+1), where the
%    current cursor value is used.
% 5. If bmax is non-zero, then the target for the 1st post-cursor is set to the
%    minimum of the current post-cursor value or bmax scaled by the cursor
%    amplitude.
% 6. The tap weights are calcuated as the pseudo inverse of the VV matrix
%    multiplied by the desired pulse target (FV).

%   Copyright 2020 The MathWorks, Inc.

%Validate inputs
validateattributes(waveIn,{'numeric'},{'vector','finite'},'adaptFFE','waveIn',1);
validateattributes(SamplesPerSymbol,{'numeric'},...
    {'scalar','finite','integer','positive'},...
    'adaptFFE','SamplesPerSymbol',2);
validateattributes(SampleInterval,{'numeric'},...
    {'scalar','finite','positive','real'},...
    'adaptFFE','SampleInterval',3);
validateattributes(cmx,{'numeric'},...
    {'scalar','finite','integer','nonnegative'},...
    'adaptFFE','cmx',4);
validateattributes(cpx,{'numeric'},...
    {'scalar','finite','integer','nonnegative'},...
    'adaptFFE','cpx',5);


% Calculate pulse response
pulseIn = impulse2pulse(waveIn(:), SamplesPerSymbol, SampleInterval);

% Peak amplitude phase detection
[~, pulseMaxPt] = max(pulseIn);

% Sampling phase
samplePhase = mod(pulseMaxPt - 1, SamplesPerSymbol) + 1;

% Re-sample the pulse at UI centers
sampledPulseIn = pulseIn(samplePhase:SamplesPerSymbol:end);

% Construct the adaptation matrix: shifted versions of the sampled waveform
VV = convmtx(sampledPulseIn, cmx+cpx+1)';

% Find cursor in the sampled waveform
[sampledPulseMax, sampledPulseMaxPt] = max(sampledPulseIn);

% Trim the adaptation matrix to include pre- to post-cursor range
VV = VV(:, sampledPulseMaxPt : sampledPulseMaxPt + cmx + cpx);

% Construct adaptation target pulse, FV
FV = zeros(1, cmx + 1 + cpx);
FV(cmx + 1) = sampledPulseMax;

% Adjust adaptation target pulse: DFE takes precedence for 1st post-cursor
if (bmax > 0) && (cpx > 0) 
    FV(cmx+2) = min(bmax * sampledPulseMax, sampledPulseIn(sampledPulseMaxPt + 1));
end

% Calculate FFE tap weights: pseudo inverse of the adaptation matrix
[i_m, i_n] = size(VV);
I_VV = eye(i_m, i_n);
lambda = 0;
C = ((VV' * VV + lambda*I_VV)^-1 * VV')' * FV';

% Assign output
TapWeights = C';
  
end