%% Implement CIC Decimation Filter for HDL
%
% This example shows how to use the CIC Decimation HDL Optimized block to 
% filter and downsample data. You can generate HDL code from the subsystem 
% in the Simulink(R)model.
%
% # Generate frames of random input samples.
% # Generate reference output data from the |dsp.CICDecimation| System object(TM).
% # Run the Simulink model that contains the CIC Decimation HDL Optimized block.
% # Compare the Simulink block output data with the reference data.
%
% Copyright 2019 The MathWorks, Inc.
%%
% Set up input data parameters. The model uses these workspace variables to 
% configure the CIC Decimation HDL Optimized block. The block supports 
% variable decimation factor specified at an input port. Choose a range for 
% the input decimFactor and set the Decimation factor parameter of the 
% block to the maximum expected decimation factor.

R = 8; % Decimation factor
M = 1; % Differential delay
N = 3; % Number of sections

varRValue = [4,R];

numFrames = length(varRValue);
dataSamples = cell(1,numFrames);
varRtemp = cell(1,numFrames);
cicFcnOutput = [];
WL = 0; % Word length
FL = 0; % Fraction length

%%
% Generate frames of random input samples. To generate reference output data for comparison,
% apply the samples to the |dsp.CICDecimation| System object. This object does not support variable 
% decimation rate, so you must create and release the object for each change 
% in the decimation factor.

for i = 1:numFrames
    framesize = varRValue(i)*randi([5 20],1,1);
    dataSamples{i} = fi(randn(framesize,1),1,16,8);
    varRtemp{i} = fi(varRValue(i)*ones(framesize,1),0,12,0);
    obj = dsp.CICDecimator('DifferentialDelay',M,'NumSections',N,'DecimationFactor',varRValue(i));
    cicOut = step(obj,dataSamples{i}).';
    WL = max([WL,cicOut.WordLength]);
    FL = max([FL,cicOut.FractionLength]);
    cicFcnOutput = [fi(cicFcnOutput,1,WL,FL),cicOut];
    release(obj);
end

%%
% Generate a stream of samples by converting frames to samples, and provide 
% those samples (|sampleIn|) as input to the Simulink model along with the 
% corresponding valid signal (|validIn|) and decimation rate (|varRIn|).

idlecyclesbetweensamples = 0;
idlecyclesbetweenframes = 4+N;

% The block has a latency of 3+N cycles for fixed decimation rate and 4+N 
% for variable decimation rates when Gain correction is Off. To flush 
% remaining data before changing the decimation rate, run the model by 
% inserting required number of idle cycles after each frame.

sampleIn = []; validIn = []; varRIn = [];

for ij = 1:numFrames

    dataInFrame =  dataSamples{ij};

    data = []; valid=[]; varR = [];
    for ii = 1:length(dataInFrame)
        data = [data dataInFrame(ii) ...
            zeros(1,idlecyclesbetweensamples)];
        valid = [valid true(1,1) ...
            false(1,idlecyclesbetweensamples)];
        varR = [varR varRtemp{ij}(ii) ...
            zeros(1,idlecyclesbetweensamples)];
    end

    sampleIn = cast([sampleIn,data,zeros(1,idlecyclesbetweenframes)],'like',dataInFrame);
    validIn = logical([validIn,valid,zeros(1,idlecyclesbetweenframes)]);
    varRIn = fi([varRIn,varR,zeros(1,idlecyclesbetweenframes)],0,12,0);

end

sampletime = 1;
simTime = length(validIn);

%%
% Run the Simulink model.
modelname = 'HDLCICDecimationModel';
open_system(modelname);
sim(modelname);

%%
% Capture the output data from the Simulink model, and compare it against
% the output from the |dsp.CICDecimation| System object.

sampleOut = squeeze(sampleOut_ts.Data).';
validOut  = squeeze(validOut_ts.Data);
cicOutput = sampleOut(validOut);

fprintf('\nHDL CIC Decimation\n');
difference = (abs(cicOutput-cicFcnOutput(1:length(cicOutput)))>0);
fprintf('\nTotal number of samples differed between Simulink block output and MATLAB function output is: %d \n',sum(difference));