Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-write utils.polygcd, utils.polylcm and utils.multi_polylcm and create utils.multi_polygcd #295

Open
NicVDMey opened this issue Jun 8, 2017 · 1 comment

Comments

@NicVDMey
Copy link
Contributor

NicVDMey commented Jun 8, 2017

The method currently used to calculate polynomial greatest common divisor and lowest common multiple involves calculating the roots of the polynomials then using logic to determine the gcd and lcm. This method only works well for lower order polynomials (up to approximately 5th order), due to the inherent difficulty in accurately calculating polynomial roots for higher order polynomials. This causes erroneous results in many of the functions in utils when applied to large mimo systems (bigger than 2x2), including utils.poles, utils.zeros and utils.tf2ss, as many of the interim calculations involve large polynomials. A new method should be created that does not rely on calculating roots. Also, Euclid's algorithm (or any method closely related to this) should not be used as it is not applicable to polynomials in floating point arithmetic.

@ilayn has given the following recommendation:

For LCM, I'm using a similar result to Karcanias, Mitrouli, "System theoretic based characterisation and computation of the least common multiple of a set of polynomials", Lin Alg App, 381, 2004. The results is acceptable but never stress tested it to the extremes.

For GCD, Sylvester-matrix based methods are sufficiently good for medium difficulty/size problems.

The following code can be used to test if the new method is working correctly:

import utils
import numpy
s = utils.tf([1,0], 1)
G = utils.mimotf([[1/((s+1)*(s+2)), 1/((s+2)*(s+3)), 1/((s+3)*(s+4)), 1/((s+4)*(s+1))],
                 [1/((s+1)*(s+2)), 1/((s+2)*(s+3)), 1/((s+3)*(s+4)), 1/((s+4)*(s+1))],
                 [1/((s+1)*(s+2)), 1/((s+2)*(s+3)), 1/((s+3)*(s+4)), 1/((s+4)*(s+1))],
                 [1/((s+1)*(s+2)), 1/((s+2)*(s+3)), 1/((s+3)*(s+4)), 1/((s+4)*(s+1))]])
poles = utils.poles(G)
assert poles.shape == (4,)
#There should be exactly 4 poles
Gpoles = [G(i) for i in poles]
AbsoluteMaximums = numpy.array([abs(i).max() for i in Gpoles])
SmallestMaximum = Maximums.min()
assert SmallestMaximum > 10**6
#Evaluating G(poles) should give at least one very large (infinite) element for each pole
@ilayn
Copy link

ilayn commented Jun 8, 2017

In case you haven't written the code yet, you can just take the code in https://github.com/ilayn/harold/blob/master/harold/_polynomial_ops.py

That's the whole point about MIT license :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants