%% Reduce Latency Through Partitioned Numerator
% Partition the impulse response length of a frequency domain FIR filter. Compare 
% the outputs of the partitioned filter and the original filter.
% 
% Design the FIR lowpass filter coefficients using the |fir1| function. The 
% sampling frequency is 8 kHz and the cutoff frequency of the filter is 2 kHz. 
% The impulse response is of length 4000.

impL    = 4000;
Fs      = 8000;
Fcutoff = 2000;
imp     = fir1(impL,2 * Fcutoff / Fs);
%% 
% Create a |dsp.FrequencyDomainFIRFilter| with coefficients set to the |imp| 
% vector. The latency of this filter is given by $FFT Length - Length(Numerator) 
% + 1$, which is equal to 4002. By default, FFT length is equal to twice the numerator 
% length. This makes the latency proportional to the impulse response length.
%%
fdfOS  = dsp.FrequencyDomainFIRFilter(imp,'Method','overlap-save');
fprintf('Frequency domain filter latency is %d samples\n',fdfOS.Latency);
%% 
% Partition the impulse response to blocks of length 256. The latency after 
% partitioning is proportional to the block length.
%%
fdfRL  = dsp.FrequencyDomainFIRFilter(imp,'Method','overlap-save',...
    'PartitionForReducedLatency',true,...
    'PartitionLength',256);
fprintf('Frequency domain filter latency is %d samples\n',fdfRL.Latency);
%% 
% Compare the outputs of the two frequency domain filters. The latency of 
% |fdfOS| is 4002, and the latency of |fdfRL| is 256. To compare the two outputs, 
% delay the input to |fdfRL| by 4002 - 256 samples.
%%
dly = dsp.Delay('Length',(fdfOS.Latency-fdfRL.Latency));
%% 
% Create two |dsp.SineWave| objects. The sine waves have a sample rate of 
% 8000 Hz, frame size of 256, and frequencies of 100 Hz and 3 kHz, respectively. 
% Create a |timescope| object to view the filtered outputs.
%%
frameLen  = 256;
sin_100Hz = dsp.SineWave('Frequency',100,'SampleRate',Fs,...
    'SamplesPerFrame',frameLen);
sin_3KHz  = dsp.SineWave('Frequency',3e3,'SampleRate',Fs,...
    'SamplesPerFrame',frameLen);
ts = timescope('TimeSpanOverrunAction','Scroll','ShowGrid',true,...
    'TimeSpanSource','Property','TimeSpan',5 * frameLen/Fs,...
    'YLimits',[-1.1 1.1],...
    'ShowLegend',true,...
    'SampleRate',Fs,...
    'ChannelNames',{'Overlap-save With Partition','Overlap-save Without Partition'});
%% 
% Stream 1e4 frames of noisy input data. Pass this data through the two 
% frequency domain filters. View the filtered outputs in the time scope.
%%
numFrames = 1e4;
for idx = 1:numFrames
    x = sin_100Hz() + sin_3KHz() + .1 * randn(frameLen,1);
    yRL = fdfRL(dly(x));
    yOS = fdfOS(x);
    ts([yRL,yOS]);
end
%% 
% The outputs match exactly.

%% 
% Copyright 2012 The MathWorks, Inc.