UPDATE: I am looking for a robust approach to decompose linear phase FIR filters with 100s of coefficients into its minimum phase and all pass components.
I originally thought determining all the zeros from the coefficients would be a mathematical challenge, so this question was initially focused on approaches to find the zeros. Through comments from @MattL I've learned that determining the zeros from 100s of coefficients may not necessarily be the numerical challenge (roots
in Python and Octave appear to have no problem doing this) but the task of going from the roots back to a polynomial is significantly challenging.
I posted a related question on SE. Mathematics for this challenge of roots to polynomial.
A best answer will provide a feasible path for linear phase decomposition when dealing with a very large number of coefficients. We are given the coefficients for a large filter with 100s of coefficients, and from that I would like to be able to decompose it into minimum phase and maximum phase (all-pass) components.
Subsequent Update: As a response on the Mathematics site it was demonstrated that the issue may be in the precision of the roots
function itself in MATLAB, Octave and Python. This then elevates my original thoughts of precision root finding for the high level question of decomposition for large linear phase FIR filters into min phase/max phase components to be best approaches to find the roots for such a large polynomial).
Original Question:
I thought that it may be relatively trivial and efficient to do a gradient descent search for the zeros within the unit circle, since we know exactly how many zeros we are searching for, we only need to search within and up to the unit circle (bounded), and that the surface of the z-transform is analytic, so we are guaranteed to have a smooth descent as we slide down the magnitude of the surface toward each zero. I can envision starting at the origin and moving outward until all zeros are located (counting number of zeros for each radius, which we could get from the DTFT after scaling the coefficients to the radius under test). Further binary search algorithms on the space could make this task very efficient and fast, even for thousands of zeros.
Before I detail this algorithm and put it to practice, I wanted to find out if (a) this already exists and is available, or (b) there are alternate efficient algorithms that would not have any trouble with finding hundreds of zeros within the unit circle (factoring a polynomial of hundredth order and higher), or (c) practical examples where this task is no as trivial as I envision with my approach and no such algorithm exists.
Below is a graphic to picture what I am envisioning, here with a simple case of four zeros inside the unit circle, as depicted on the typical pole-zero diagram on the z-plane, and its associated analytic surface. Realizable (causal) linear phase FIR filters with $N$ zeros inside the unit circle would also have $N$ poles at the origin, but for this purpose of finding the zeros they needn't be included and are not shown in the graphic below.
Determining the Minimum Phase Component Using the Hilbert Transform
@ZRHann makes the good suggestion to use the Hilbert Transform to extract the minimum phase system. This suggestion has merit since the minimum phase system frequency response $G_{min}(\omega)$ for any magnitude response $|G(\omega)|$ is given as:
$$G_{min}(\omega) = |G(\omega)|e^{j \phi (\omega)}$$
$$\phi(\omega) = H\{\ln(|G(\omega)|\}$$
I made an attempt of this approach using a test case provided by @MattL in response to another question, and used in his response to this one, which is the coefficients of an equiripple filter provided by:
coeff = sig.remez(668, [0, .3, .31, 1], [1, 0],[1, 2800], fs = 2)
And results in the following frequency response (FIR order 667):
As a quick test of @ZRHann's suggestion I did the following:
w, g = sig.freqz(coeff,1,668*N, whole=True) # DTFT to establish mag response g
phase = np.imag(sig.hilbert(np.log(np.abs(g)))) # min phase
mincoeff = fft.ifft(np.conj(np.abs(g)*np.exp(1j*phase))) # ifft to get coeff
(Note a potential drawback as done, that the results is an FIR only system- we can't follow this procedure to extract a minimum phase IIR)
I extended the multiplier N to reduce aliasing effects in the inverse FFT. This approach has reasonable results for comparison to other solutions. Below shows the results from simply truncating the resulting impulse response back to the original filter length, while further improvements by using windowing of this response could likely be achieved:
Zooming in on the passband also shows a ripple that was consistent with the original filter which had passband ripple +/-0.25 dB. Windowing should reduce the additional variation from the equiripple response both in passband and stopband.