GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — describing_function_response reports sin(w*dt), not w, for discrete-time systems, and refines at z = jw · Issue #1269 · python-control/python-control

describing_function_response reports sin(w*dt), not w, for discrete-time systems, and refines at z = jw #1269

New issue
Copy link
New issue
Copy link
Open
Open
describing_function_response reports sin(w*dt), not w, for discrete-time systems, and refines at z = jw#1269
Copy link

Description

@gimballock
gimballock
opened on Nov 5, 2026
Issue body actions

For a discrete-time system, describing_function_response finds the right amplitude but reports the wrong frequency. It returns about sin(ω·dt), the same number whatever dt is. Its refinement step, and the returned positions, evaluate H at z = jω rather than on the unit circle.

import warnings
import numpy as np
import control as ct

warnings.simplefilter("ignore")
for dt in (1, 0.5):
    H = ct.tf([0.5], [1, -0.5, 0], dt=dt)
    # where the Nyquist curve, H(exp(j w dt)), crosses the negative real axis
    w = np.linspace(1e-4, np.pi / dt, 200_001)
    Hw = H(np.exp(1j * w * dt))
    k = np.flatnonzero((np.diff(np.sign(Hw.imag)) != 0) & (Hw.real[:-1] < 0))[0]
    r = ct.describing_function_response(H, np.sign, np.linspace(0.01, 5, 400), omega=np.linspace(1e-3, np.pi / dt, 2000))
    a, om = r.intersections[0]
    print(f"dt={dt}: crossing at w={w[k]:.4f}, H={Hw[k].real:.3f} -> a={4 / np.pi * abs(Hw[k].real):.4f}; "
          f"describing_function_response: a={a:.4f}, omega={om:.4f}")

Output, with control 0.10.2 and the same on main (bfe9380):

dt=1: crossing at w=1.3181, H=-0.500 -> a=0.6366; describing_function_response: a=0.6339, omega=0.9703
dt=0.5: crossing at w=2.6362, H=-0.500 -> a=0.6366; describing_function_response: a=0.6339, omega=0.9703

With the default refine=True it also warns not able to refine result; returning estimate.

Cause (control/descfcn.py on main):

  • The frequency. Line 349 is H_omega, H_vals = response.contour.imag, H(response.contour). For a discrete system, nyquist_response's contour is in z, exp(jω·dt), so its imaginary part is about sin(ω·dt), not ω (sin(1.318) = 0.968). The intersection itself is found on H(response.contour), which is why the amplitude is right.
  • The refinement and the positions. _cost (line 378) and pos (line 389) use H(1j * omega), which for a discrete system evaluates at z = jω.

Suggested fix: when H.isdtime(), take the frequencies as np.angle(response.contour) / H.dt, and evaluate H(np.exp(1j * omega * H.dt)) in _cost and for pos. A test on a discrete loop with a known crossing, such as the one above, would cover it.

Workaround: compute the crossing on the unit circle directly, as in the first lines of the example, and use describing_function for N(a).

Activity

  1. slivingston commented on Nov 5, 2026

    @slivingston
    slivingston
    on Nov 5, 2026
    Member
    More actions

    @gimballock Please add a disclosure about tool use if appropriate: https://numpy.org/doc/stable/dev/ai_policy.html

  2. gimballock commented on Nov 5, 2026

    @gimballock
    gimballock
    on Nov 5, 2026
    Author
    More actions

    Disclosure: yes, this was written with an AI agent, Claude Code (Anthropic's Claude Opus 5.5 model).

    • How it was used: the agent hit the problem while testing a describing-function analysis of a sampled loop for a research project of mine. It wrote the reproduction, ran it against control 0.10.2 and against main, wrote the issue text, and posted it through the GitHub CLI at my request.
    • What's AI-generated: all of the text and code in the issue. The numbers are program output from those runs, and the code block runs as posted.
    • My part: I asked for it to be filed, but didn't review the text before it was posted.

    I'm responsible for what's posted under my account, and questions are welcome.

  3. slivingston commented on Nov 5, 2026

    @slivingston
    slivingston
    on Nov 5, 2026
    Member
    More actions

    @gimballock You didn't even review the text before posting it? So you just posted generated text without review and expect us to review it for you?

  4. slivingston commented on Nov 5, 2026

    @slivingston
    slivingston
    on Nov 5, 2026
    Member
    More actions

    Anyway, you are welcome to use AI tools, but you absolutely must review stuff before you post it. (That said, I appreciate your honesty.)

    Reacted by Eric Price
  5. gimballock commented on Nov 5, 2026

    @gimballock
    gimballock
    on Nov 5, 2026
    Author
    More actions

    Anyway, you are welcome to use AI tools, but you absolutely must review stuff before you post it. (That said, I appreciate your honesty.)

    Hi, sorry for the frustration. You're point is fair, it was a relatively low effort issue filing on my part. I'm prototyping analysis tools a bit ahead of my complete understanding with regard to control theory analysis and the algorithms underlying all that.

    Having said that I was involved in checking that the analysis of the bug, I did an adversarial review with ponytail to simplify/minimize the issue content (which i find works pretty well) but i trusted the agent to largely copy/paste what i read from the adversarial review to github. So the 'without review' phrasing is referring to the final copy not the whole interaction. But to your point i'm adding in a rule to have the agent quiz me on key points as an automated guard rail to check comprehension before posting publicly.

  6. slivingston commented on Nov 5, 2026

    @slivingston
    slivingston
    on Nov 5, 2026
    Member
    More actions

    @gimballock Thanks, that is a good plan. I appreciate that you are making your contributions sincerely and carefully.

    As you know, the cost of submitting plausible issues and PRs is now almost zero, but the effort of review has not meaningfully become less. AI tools can help with review, but humans must sign-off, and maintainers of open source bear responsibility of the consequences of new/edited code. (Fire-and-forget AI users like RoboX2020 are thus very frustrating to work with.)

  7. slivingston commented on Nov 6, 2026

    @slivingston
    slivingston
    on Nov 6, 2026
    Member
    More actions

    @gimballock I read over this again, and I think this generation process is unreliable but maybe is the best you can do. Ideally, to me, you would write the description yourself, assuming you understand the issue/PR. At the very least, you need to commit to review 100% of the generated issue, PR, comment, etc. text before posting it. Only having the chat bot "quiz" you is unacceptable. (If you expect me to read the post, then you should read it first, from beginning to end.)

  8. slivingston commented on Nov 6, 2026

    @slivingston
    slivingston
    on Nov 6, 2026
    Member
    More actions

    By the way, read links under https://numpy.org/doc/stable/dev/ai_policy.html#other-resources if you do not understand why "low effort issue filing" is a problem for the projects you want to contribute to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.