Skip to content

Update place to use scipy.signal.place_poles #176

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

Merged
merged 6 commits into from
Jan 5, 2018

Conversation

rabraker
Copy link
Contributor

@rabraker rabraker commented Jan 3, 2018

This PR addresses issue #117 by using the place_poles function in scipy.signals.

Aside from just being run in matlab_test.py, there wasn't, as far as I could tell, a unit test for place previously, so I added one.

The one limitation of the algorithm used in scipy.signals is that it can't place multiple poles at the same location for SISO systems, which made the "test" in matlab_tests.place fail, so I modified the requested pole location there.

Also worth pointing that the previous implementation would fail for discrete time systems because the slycot function needed to be called with a different flag and the alpha parameter needed to be computed differently.

@coveralls
Copy link

coveralls commented Jan 3, 2018

Coverage Status

Coverage increased (+0.09%) to 78.619% when pulling 186d6d8 on rabraker:update_place into df4ee82 on python-control:master.

@murrayrm
Copy link
Member

murrayrm commented Jan 3, 2018

I like this change, but it brings up an interesting issue: what should we do when there are multiple algorithms available to solve a certain problem, each with different limitations? The previous version of the place command use a method by Varga (IEEE TAC, 1981), implemented via slycot, that did not have the limitation on repeated poles, but may give solutions that are less well-conditioned (as pointed out in issue #117).

As an alternative, what if we implement an algorithm keyword that allows different algorithms to be used. This would give:

  • place(sys, poles, algorithm='scipy'): proposed implementation in this PR
  • place(sys, poles, algorithm='varga'): original solution

We could have place() be a wrapper that looks for the algorithm keyword and decides whether to call place_scipy or place_varga.

Would be interested in getting thoughts on this from anyone paying attention, especially @rabraker, @vmatos, and @robertobucher (who have been involved in the conversation and code up to now).

@cwrowley
Copy link
Contributor

cwrowley commented Jan 3, 2018

I like the suggestion to add a keyword argument to specify the algorithm. I also think it would be good to retain the repeated-pole test, somehow marking it as "expected to fail" if the YT algorithm is used. Also, note that scipy.signal.place_poles has a keyword argument method, which can take values YT or KNV0. So it might make sense to have at least the three options (varga, YT, KNV0). Might be cleanest to handle the keyword argument varga ourselves, and just pass along the other keyword arguments to scipy.signal.place_poles, in case other algorithms are implemented in scipy.signal in the future.

@rabraker
Copy link
Contributor Author

rabraker commented Jan 3, 2018

I think trying to cram too much functionality into a single function makes the code more difficult to test, maintain, use and document. Part of the problem is that varga and YT require different parameters. For example, to place discrete poles using varga, you need to pass D into the slycot function. This is not required with YT. Because we are passing in just matrices (A, B) and not the full LTI system, then this flag must necessarily be an argument in the wrapper function. Now, you have a parameter that only gets used sometimes and this must be explained in the documentation.

We already have acker as its own function. If it were up to me, I would keep the convention that different algorithms stay in their own functions. It can be up to us to decide which is the "canonical" implementation and gets put into place proper. The rest can reside in place_varga or place_yt or similar and will be discoverable via 'see also:' in the doc string.

My proposal would be the following:

  • keep the current code for place, but change the function name to place_varga(). Also, expose the alpha parameter and C or D flag to the user. There is a bug in how the alpha parameter is currently calculated that causes the placement to fail in some situations. This should probably be fixed in a separate pull request.
  • Keep the YT implementation in place proper. It is my understanding that this algorithm most closely resembles the matlab implementation and would be least likely to surprise users.

@ilayn
Copy link

ilayn commented Jan 3, 2018

Note that, the arbitrary eigenstructure assignment problem has gained a lot of attention lately and people like R. Schmid et al. seem to have the general solution to pole placement. I have asked Amit Pandey from UCSD and he kindly shared his matlab code with me. I will try to propose a PR to SciPy whenever I can find time. This means, if accepted, there will be at least one additional SciPy method.

@murrayrm
Copy link
Member

murrayrm commented Jan 3, 2018

Creating separate functions for now seems OK.

@rabraker Can you implement your proposal above by updating this PR to pull out the previous functionality as place_varga() and create an issue to capture the alpha parameter bug?

@ilayn If you (or someone) wants to convert the MATLAB code for the R. Schmid et al method into a separate place_XYZ method, we could include here while waiting for the official SciPy update.

@rabraker
Copy link
Contributor Author

rabraker commented Jan 3, 2018

will do

…y implementation of YT stays in place() proper
@coveralls
Copy link

coveralls commented Jan 3, 2018

Coverage Status

Coverage decreased (-0.2%) to 78.289% when pulling 311e9e2 on rabraker:update_place into df4ee82 on python-control:master.

@rabraker
Copy link
Contributor Author

rabraker commented Jan 3, 2018

As requested, I have submitted the bug report and have put the old place function into place_varga.

@coveralls
Copy link

coveralls commented Jan 3, 2018

Coverage Status

Coverage decreased (-0.2%) to 78.289% when pulling 100eb1f on rabraker:update_place into df4ee82 on python-control:master.

def testPlace(self):
place(self.siso_ss1.A, self.siso_ss1.B, [-2, -2])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should leave this test in place, but calling place_varga (assuming slycot is installed). Also, can we add a check for the right type of error if we call place with repeated poles?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made this change. I have also added two place-holder tests (or whatever they are called) into matlab_test.py for place and acker.

I added an assert_raises(ValueError....) test for place() to statefbk_test.py.

[0, 0,],
[-3.146, 0]])
P = np.array([-0.5+1j, -0.5-1j, -5.0566, -8.6659])
K = place(A, B, P)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add some tests for place_varga and acker here, as a way to increase coverage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think acker already has a test (line 125)...

I added a test for place_varga.

…or repeated poles in place. Added placeholder tests in matlab_test for place and acker and reverted the repeated pole test for place varga.
@coveralls
Copy link

coveralls commented Jan 4, 2018

Coverage Status

Coverage decreased (-0.5%) to 77.993% when pulling 45fdea9 on rabraker:update_place into df4ee82 on python-control:master.

@coveralls
Copy link

coveralls commented Jan 4, 2018

Coverage Status

Coverage increased (+0.09%) to 78.618% when pulling 70ecf75 on rabraker:update_place into df4ee82 on python-control:master.

@ilayn
Copy link

ilayn commented Jan 4, 2018

If you (or someone) wants to convert the MATLAB code for the R. Schmid et al method into a separate place_XYZ method, we could include here while waiting for the official SciPy update.

I will get back to this asap and let you know.

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

Successfully merging this pull request may close these issues.

5 participants