diff options
| author | Davit Grigoryan <[email protected]> | 2026-04-09 12:25:24 -0700 |
|---|---|---|
| committer | Davit Grigoryan <[email protected]> | 2026-04-22 02:37:26 -0700 |
| commit | 14ca50edb249d5f4ef621903259d955deb3a2fc3 (patch) | |
| tree | a1798764b97c2c351ea9c8ab1422886e9488d18b /RxClock.m | |
Diffstat (limited to 'RxClock.m')
| -rw-r--r-- | RxClock.m | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/RxClock.m b/RxClock.m new file mode 100644 index 0000000..f5f1e08 --- /dev/null +++ b/RxClock.m @@ -0,0 +1,183 @@ +classdef (StrictDefaults) RxClock < serdes.SerdesAbstractSystemObject + % RxClock Receiver clock generator + % obj = RxClock returns a System Object, obj, that generates a + % multiphase clock. + % + % RxClock methods: + % step - Generates a multiphase clock. Example usage: + % ClockOut = stepImpl(obj,PhaseControl) + % + % RxClock properties: + % MaxTimingMismatch - Maximum timing mismatch in UI between the 1st + % and 2nd clock phases. + % NumberOfClocks - Number of output clock phases + % SymbolTime - Symbol time of the system + % SampleInterval - Uniform time step of the system + + % Copyright 2021 The MathWorks, Inc. + + %#codegen + + properties (Nontunable) + + %Max Timing Mismatch (UI) + MaxTimingMismatch = 0.0 + + %Number of output clock phases + NumberOfClocks = 4 + + %Symbol Time Multiplier Factor + SymbolTimeMultiplier = 1; + end + properties (Hidden, SetAccess=private) + Frequency % Clock frequency, Hz + Period % Clock period, seconds + PhaseInitial % Initial core phase + PhaseIncrement % Phase increment per sampling interval + PhaseCore % Clock core phase + PolyPhaseOffset % Array of VCO phase offsets + PhaseOutput % Output phases + ClockRate % Clock rate w.r.t. baud rate + + InterPhaseOutput + 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 = RxClock(varargin) + % Support name-value pair arguments when constructing object + obj.BlockName = 'RxClock'; + 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) + + % Derived parameters + fb = 1/(obj.SymbolTime*obj.SymbolTimeMultiplier); + obj.ClockRate = 1/obj.NumberOfClocks; + obj.Frequency = fb * obj.ClockRate ; + obj.Period = 1 / obj.Frequency ; + obj.PhaseIncrement = obj.SampleInterval / obj.Period ; + + % Multi-phase clock setup, poly phase. Inject an offset + % between the 1st and 2nd clocks. + v = zeros(obj.NumberOfClocks,1); + v(1) = obj.MaxTimingMismatch; + obj.PolyPhaseOffset = (0:-1:-(obj.NumberOfClocks-1))' / obj.NumberOfClocks + ... + v(mod(0:obj.NumberOfClocks-1,3)+1); + + % Initialize clock core and output phases + obj.PhaseCore = -obj.PhaseIncrement; + obj.PhaseOutput = obj.PhaseCore + obj.PolyPhaseOffset; + + obj.InterPhaseOutput = 0; + end + + function validateInputsImpl(~,waveIn) + validateattributes(waveIn,{'numeric'},{'finite'},'','waveIn'); + end + + function [ck_out] = stepImpl(obj,ctrl_ph,initial_ph) + %ck_out = stepImpl(obj,ctrl_ph) + %ctrl_ph_const = -0.125; + + if isSample(obj) + % Update clock core and output phases + obj.PhaseCore = mod(obj.PhaseCore + obj.PhaseIncrement, 1); + obj.InterPhaseOutput = obj.PhaseCore - ctrl_ph - initial_ph / obj.Period; + obj.PhaseOutput = obj.InterPhaseOutput + obj.PolyPhaseOffset; + end + % Update output clock + ck_out = sin(2*pi*obj.PhaseOutput); + end + function releaseImpl(obj) + fprintf('[CDR] Phase Offset: %6.32f\n', obj.InterPhaseOutput); + end + function [out1] = getOutputSizeImpl(obj) + % Return size for each output port + out1 = [obj.NumberOfClocks 1]; + end + function [dt1] = getOutputDataTypeImpl(~) + dt1 = "double"; + end + + function [out1] = isOutputComplexImpl(obj) + % Return true for each output port with complex data + out1 = false; + + % Example: inherit complexity from first input port + % out = propagatedInputComplexity(obj,1); + end + + function [out1] = isOutputFixedSizeImpl(obj) + % Return true for each output port with fixed size + out1 = true; + + % Example: inherit fixed-size status from first input port + % out = propagatedInputFixedSize(obj,1); + end + function resetImpl(~) + % Initialize / reset discrete-state properties + end + + %% Simulink functions + function icon = getIconImpl(~) + % Define icon for System block + icon = sprintf("Rx\nClock"); + end + function [name1, name2] = getInputNamesImpl(~) + name1 = 'Ctrl Ph'; + name2 = 'Initial Ph'; + end + function [name1] = getOutputNamesImpl(~) + name1 = 'Clock'; + end + function num = getNumInputsImpl(~) + num = 2; + 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',{'MaxTimingMismatch','NumberOfClocks',... + 'SymbolTime','SymbolTimeMultiplier','SampleInterval'}); + end + end +end |
