Related to this question on using the Windowing method for FIR filter design versus the optimized algorithms such as least squares (firls
in MATLAB, Octave and Python scipy.signal, my usual "go-to" for filter design), I ran into another interesting case where, as far as I could tell, could not be resolved with the least squares or Parks-McClellan algorithms. Specifically, I am in need of a set of high dynamic range filters, with stopband rejection (and passband distortion) less than -212 dB (and in general as a personal challenge, I would like to know how to approach the noise floor of any available numerical precision if ever needed).
Note since I am being asked: This is not for an application of processing analog signals captured with an ADC or for signals that will be converted to analog with a DAC. This is for an dsp algorithm where a very small quantization noise is needed or equivalently very high SNR.
My question is as follows: The least squares algorithm "converged" and provided results, but clearly in comparison to what I achieved with a Kaiser window with the same number of taps, the least squares solution is not "optimum in the least squares sense" as advertised. This was a surprise to me since there wasn't any indication otherwise of a convergence issue (as did occur with Parks-McClellan, here with least squares I got a result with no complaint), so then even in lower SNR cases, under which conditions can we no longer "trust" that the solution provided by the algorithm is actually optimum in the least squares sense?
Is what I am finding a theoretical limit/ constraint as part of the least squares algorithm and if so what is that constraint; or am I approaching it incorrectly somehow? Can the least squares algorithm achieve rejections below 212 dB for my specific example case given below? Are there other implementations of the least squares algorithm that can do this, and the specific ones in Python and Octave are somehow inferior?
Example
With the following in either Octave or Python:
coeff = firls(287, [0, .4, .6, 1], [1, 1, 0, 0])
I get the following results for this half-band filter shown below, which is directly compared to Kaiser windowing a Sinc impulse response (window method of FIR design) with the same number of coefficients. Note that increasing the number of coefficients further with the least squares algorithm was not productive in reducing the stopband further. I was also unsuccessful with using the weighting functions, but in this case I do want equal performance in passband and stopband: the plots show the passband magnitude error as well in orange as $20\log_{10}(1-|H(\omega)|)$
I do notice the wasted "chatter" in the wider transition band for the least squares case, which I can eliminate by tightening that transition band (such as [0, .49, .51, 1]), but doing that also reduces the stopband rejection (as expected). Increasing the number of taps from there eventually just adds the "chatter" back in to that "don't care region" rather than providing more rejection.
The least squares algorithm is detailed here, but I do not see any mention as to constraints on the ultimate dynamic range that can be achieved, nor what would be limiting it. It does concern me that the coefficients were returned without any issue, yet they are not actually optimum in the least squares sense, a point which up to now I assumed was assured by the algorithm, as long as it successfully converged- so at which point does that assurance no longer hold?
[0 .49 .51 1]
you'll get a much better behaved response. Kaiser is better behaved because it's a simple multiplication (e.g. both the sinc() and the window are static computations, not the result of some algorithm). $\endgroup$