summaryrefslogtreecommitdiff
path: root/TapTogglingAlgos/LeveragedLMS.m
blob: ed20f67b854e01fd23f41bc1aa8960656cf5bace (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
classdef LeveragedLMS < handle
    % Version: 0.2 (min-COM-based)
    % Description:
    %   If the smallest registered COM is above 3dB for some period,
    %   then assume it is safe to turn off the most "insignificant"
    %   tap (which now is, kind of, the smallest one)
    %
    %   However, if smallest COM drops below 3dB for some period,
    %   then activate the fallback mechanism and turn on the recently
    %   disabled tap and terminate the algorithm
    
    properties
        lastDisabledTap
        internalFFETapsMask
        lastUpdateTime
        reachedHighErr

        lastMeanErr
        maxErr
        reachedHighCOM
        reducedErrSeqCounter
        increasedErrSeqCounter

        targetCounters
        targetCounterIndex
    end

    methods
        function obj = LeveragedLMS(LMSUpdateObj)
            obj.lastDisabledTap = -1;
            obj.internalFFETapsMask = LMSUpdateObj.FFE_TapsMask;
            obj.lastUpdateTime = LMSUpdateObj.StartFFEAdaptTime * LMSUpdateObj.WindowSize;
            obj.reachedHighErr = 0;

            obj.lastMeanErr = inf;
            obj.maxErr = 0;
            obj.reachedHighCOM = 0;
            obj.reducedErrSeqCounter = 0;
            obj.increasedErrSeqCounter = 0;

            obj.targetCounters = [2 1];
            obj.targetCounterIndex = 1;
        end

        function FFETapsMask = GetFFETapsMask(obj, LMSUpdateObj)
            initialTogglingStart = LMSUpdateObj.StartFFEAdaptTime + 5;

            if ismember(LMSUpdateObj.IterCount, LMSUpdateObj.LearningRatesAdjustTimes * LMSUpdateObj.WindowSize)
                obj.targetCounterIndex = obj.targetCounterIndex + 1;
            end

            obj.maxErr = max(obj.maxErr, max(abs(LMSUpdateObj.ErrorVec)));

            if mod(LMSUpdateObj.IterCount, LMSUpdateObj.WindowSize) == 0 && ...
                    LMSUpdateObj.IterCount > initialTogglingStart * LMSUpdateObj.WindowSize && ~obj.reachedHighErr
                %avgErr = mean(abs(LMSUpdateObj.ErrorVec));

                dlevDiff1 = LMSUpdateObj.Dlev_0p5 - LMSUpdateObj.Dlev_0p16;
                dlevDiff2 = LMSUpdateObj.Dlev_0p16 - LMSUpdateObj.Dlev_m0p16;
                dlevDiff3 = LMSUpdateObj.Dlev_m0p16 - LMSUpdateObj.Dlev_m0p5;
                minDlevDiff = min([dlevDiff1 dlevDiff2 dlevDiff3]);
                t = minDlevDiff / 2;

                minCOM = 20*log10(t / obj.maxErr);

                if minCOM >= 3
                    obj.reducedErrSeqCounter = obj.reducedErrSeqCounter + 1;
                    obj.increasedErrSeqCounter = 0;
                    obj.reachedHighCOM = 1;
                else
                    obj.reducedErrSeqCounter = 0;
                    if obj.reachedHighCOM
                        obj.increasedErrSeqCounter = obj.increasedErrSeqCounter + 1;
                    end
                end
                %obj.lastMeanErr = avgErr * 1.125;

                obj.maxErr = 0;
            end

            weights = abs(LMSUpdateObj.TapWeights);

            % Take into account the neighboring taps as well
            weights_padded = [0 weights 0];
            weights_avg = (weights_padded(1:end-2) + 2*weights_padded(2:end-1) + weights_padded(3:end)) / 3;
            weights_avg(~obj.internalFFETapsMask) = inf;

            [~, minTapIndex] = min(weights_avg);

            if obj.reducedErrSeqCounter == obj.targetCounters(obj.targetCounterIndex) && ...
                    LMSUpdateObj.IterCount > initialTogglingStart * LMSUpdateObj.WindowSize && ~obj.reachedHighErr
                obj.internalFFETapsMask(minTapIndex) = 0;
                obj.lastDisabledTap = minTapIndex;
                obj.lastUpdateTime = LMSUpdateObj.IterCount;
                obj.reducedErrSeqCounter = 0;
                obj.increasedErrSeqCounter = 0;
            end
        
            if obj.increasedErrSeqCounter == obj.targetCounters(obj.targetCounterIndex)*2 && ~obj.reachedHighErr
                obj.reachedHighErr = 1;
                if obj.lastDisabledTap ~= -1
                    obj.internalFFETapsMask(obj.lastDisabledTap) = 1;
                end

                % to make sure it throws an error in case tried being accessed
                obj.lastDisabledTap = -1;
                obj.reducedErrSeqCounter = 0;
                obj.increasedErrSeqCounter = 0;
            end
        
            FFETapsMask = obj.internalFFETapsMask;
        end
    end
end