I tried the same benchmark and got very different results. On my machine and using Matlab R2106b (pre release), I got the following:
xin = rand(1, 1e6);
b = rand(1, 20e3);
% FILTER
tic; y1 = filter(b, 1, xin); t = toc;
fprintf('FILTER: Elapsed Time = %6.3f s\n',t);
% CONV
tic; y2 = conv(b, xin); t = toc;
fprintf('CONV: Elapsed Time = %6.3f s\n',t);
% FFTFILT
tic; y3 = fftfilt(b,xin); t = toc;
fprintf('FFTFILT: Elapsed Time = %6.3f s\n',t);
FILTER: Elapsed Time = 5.631 s
CONV: Elapsed Time = 4.921 s
FFTFILT: Elapsed Time = 0.105 s
There are a few things going on here:
- FILTER is a generic all purpose IIR filter. Even if you don't give it any poles, the code needs to be specifically written to take advantage of this. It probably isn't since there are different functions for handling FIR filters
- CONV is brute force and hence it's fairly slow, although it doesn't have any IIR code in it. Also note that with conv() the result is longer as it includes the "ringing" after the input has stopped (and is assumed to be zero). The excess samples can be viewed as the "state" or you filter.
- FFTFILT is by far the fastest since it basically implements the overlap add algorithm in the frequency domain.
- You could still speed this up by a factor of two or so by taking advantage of the fact that your input is real valued. That's beyond the scope of this question.
All of the methods allow you to "keep state" across calls, you just have to write the code for it. Below is an example that would work with FFTFILT.
%% state keeping example
xin = rand(1, 1e6)';
b = rand(1, 20e3)';
y3 = fftfilt(b,xin);
% break it up in 10 blocks
y4 = zeros(size(y3));
nBlocks = 10;
blockSize = length(xin)/nBlocks;
nTaps = length(b);
state = zeros(nTaps,1);
x2 = reshape(xin,blockSize,nBlocks);
counter = 0;
% implement overlap save
for i= 1:nBlocks
% grab an input block, prepend it with the state and filter
tmp = fftfilt(b,[state; x2(:,i)]);
% save the good samples
y4(counter + (1:blockSize)) = tmp((nTaps+1):end);
% update the state: save the last nTaps input samples
state = x2((end-nTaps+1):end,i);
% advance output counter
counter = counter + blockSize;
end
fprintf('Error = %6.2f dB\n', 10*log10(sum((y4-y3).^2)/sum(y3.^2)));