summaryrefslogtreecommitdiff
path: root/LoopFilter.m
blob: ab9ea8e684335169ef33571faed2ee1ab196dcd1 (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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
classdef (StrictDefaults) LoopFilter < serdes.SerdesAbstractSystemObject & TriggeredComponent
    % LoopFilter    Loop Filter
    %   obj = LoopFilter returns a System Object, obj, that integrates the
    %   input Up/Down signal and increments or decrements the output phase
    %   control signal.
    %
    % LoopFilter methods:
    %   step - Integrates the input Up/Down phase detector signal and
    %   increments or decrements the output phase control signal when the
    %   sum exceeds some limit.  The useage is:
    %   PhaseControl = step(obj,ClockIn,UpDown)
    %
    % LoopFilter properties:
    %   ProportionalGain - Proportional gain.  Typically set to 1/timeInterleaveDepth
    %   PhaseStep        - Step size for phase increment or decrement
    %   UpDownMaxLimit   - Up/down counter limit

    %   Copyright 2021 The MathWorks, Inc.

    %#codegen

    properties (Nontunable)

        % Proportional gain
        %   Typically set to 1/timeInterleaveDepth
        ProportionalGain =  1.0;

        % Step size for phase increment/decrement
        PhaseStep = 1/128;

        % Up/down counter limit
        UpDownMaxLimit = 16;
    end
    properties (Hidden, SetAccess=private)
        PhaseControlInternal % Phase control output
        UpDownSum            % Accumulated up/down pulses (sum)
        UpDownLimit          % Current limit of up/down sum
        PhaseChange          % Phase increment/decrement
    end
    properties(Hidden,Nontunable)
        %Required by abstract class but not used
        NumberOfClocks = 1;
    end

    properties (SetAccess = immutable, Nontunable, Hidden)
        IsLinear = true;
        IsTimeInvariant = true;
    end
    properties (Nontunable,Hidden)
        %Input Waveform Type
        %   Set the input wave type as one of 'Sample' | 'Impulse' |
        %   'Waveform'.  The default is 'Sample'.
        WaveType = 'Sample';
    end
    properties(Hidden, Constant)
        WaveTypeSet = matlab.system.StringSet({'Sample','Impulse','Waveform'});
    end

    methods
        % Constructor
        function obj = LoopFilter(varargin)
            % Support name-value pair arguments when constructing object
            obj.BlockName = 'LoopFilter';
            setProperties(obj,nargin,varargin{:})
        end
    end
    methods (Hidden)
        % The below methods, getAMIParameters, getAMIInputNames and
        % getAMIOutputNames are for use only within the serdesDesigner App
        % and will not influence the AMI parameters in Simulink whatsoever.
        function amiParameters = getAMIParameters(~)
            amiParameters = {};
        end
        function names = getAMIInputNames(~)
            names = {};
        end
        function names = getAMIOutputNames(~)
            names = {};
        end
    end
    methods (Access = protected, Hidden)
        function val = isSample(obj)
            val = strcmpi(obj.WaveType,'Sample');
        end
    end
    methods(Access = protected)
        %% Common functions
        function setupImpl(obj)

            setupClock(obj);

            % Initialize phase error output
            obj.PhaseControlInternal = 0.0;

            % Initialize filter properties
            obj.UpDownSum   =  0.0;
            obj.UpDownLimit =  0.0;
            obj.PhaseChange =  0.0;
        end

        function validateInputsImpl(~,waveIn)
            validateattributes(waveIn,{'numeric'},{'finite'},'','waveIn');
        end

        function PhaseControl = stepImpl(obj,ClockIn,UpDown)
            %PhaseControl = stepImpl(obj,ClockIn,UpDown)

            if isSample(obj)
                %Triggered clock step
                ClockStep(obj,ClockIn)

                % On falling clock edge, filter the incoming phase error
                if obj.PhaseFallingIndex > 0

                    % Reset phase increment/decrement
                    obj.PhaseChange = 0.0;

                    % Update up/down accumulator
                    obj.UpDownSum = obj.UpDownSum + UpDown;

                    % Up/down sum exceed current limit (positive or negative side)
                    if abs(obj.UpDownSum) >= obj.UpDownLimit

                        % Set phase increment/decrement
                        obj.PhaseChange = sign(obj.UpDownSum) * obj.PhaseStep;

                        % Reset up/down accumulator
                        obj.UpDownSum = 0;

                        % Ramp up up/down limit at start up
                        if obj.UpDownLimit >= obj.UpDownMaxLimit
                            obj.UpDownLimit = obj.UpDownMaxLimit;
                        else
                            obj.UpDownLimit = obj.UpDownLimit + 1;
                        end

                    end

                    % Update phase control
                    obj.PhaseControlInternal = obj.PhaseControlInternal + obj.ProportionalGain * obj.PhaseChange;

                end % obj.PhaseFallingIndex > 0
            end

            % Assign output
            PhaseControl = obj.PhaseControlInternal;
        end

        function resetImpl(~)
            % Initialize / reset discrete-state properties
        end

        %% Simulink functions
        function icon = getIconImpl(~)
            % Define icon for System block
            icon = "Loop\nFilter";
        end
        function [name1,name2] = getInputNamesImpl(~)
            name1 = sprintf('Demux\nClock');
            name2 = 'UpDown';
        end
        function name1 = getOutputNamesImpl(~)
            name1 = sprintf('Phase\nControl');
        end
    end
    methods(Static, Access=protected)
        function group = getPropertyGroupsImpl(~)
            % Define property section(s) for System block dialog
            group = matlab.system.display.SectionGroup(...
                'Title','Main',...
                'PropertyList',{'ProportionalGain','PhaseStep',...
                'UpDownMaxLimit'});
        end
    end
end