René's URL Explorer Experiment


Title: Disk margin calculations by josiahdelange · Pull Request #1146 · python-control/python-control · GitHub

Open Graph Title: Disk margin calculations by josiahdelange · Pull Request #1146 · python-control/python-control

X Title: Disk margin calculations by josiahdelange · Pull Request #1146 · python-control/python-control

Description: Am relatively new to this toolbox, have been using it here and there and found #726. This is an initial prototype Python implementation of disk margins, built on top of python-control and slycot. The code should work both for SISO and MIMO systems, the latter of which requires slycot (for SLICOT's AB13MD) to compute the upper bound of $\mu$ at each discrete frequency. The function disk_margins computes disk margins (and corresponding disk-based gain/phase margins), optionally returning the whole frequency-dependent vectors for further plotting. It's been verified against the example SISO loop transfer functions in the published paper and the "spinning satellite" MIMO example from the MathWorks documentation. I also confirmed SISO disk margins match the relevant output of existing function stability_margins corresponding to the Nyquist plot's distance to -1. All seem to match within a few significant digits, so the general behavior seems correct. Might be good to get another set of eyes to double check/test further. I tried to base as much as possible (e.g. style conventions) on existing code in control/margins.py. Example usage (see examples/disk_margin.py): import os, sys, math import numpy as np import control import math import matplotlib import matplotlib.pyplot as plt from warnings import warn import numpy as np import scipy as sp # Frequencies of interest omega = np.logspace(-1, 3, 1001) # Laplace variable s = control.tf('s') # MIMO loop transfer gain for the spinning satellite example # https://www.mathworks.com/help/robust/ug/mimo-stability-margins-for-spinning-satellite.html P = control.ss([[0, 10],[-10, 0]], np.eye(2), [[1, 10], [-10, 1]], [[0, 0],[0, 0]]) # plant C = control.ss([],[],[], [[1, -2], [0, 1]]) # controller L = P*C # output loop gain print(f"------------- Sensitivity function (S) -------------") DM, GM, PM = control.disk_margins(L, omega, skew = 1.0, returnall = True) # S-based (S) print(f"min(DM) = {min(DM)} (omega = {omega[np.argmin(DM)]})") print(f"GM = {GM[np.argmin(DM)]} dB") print(f"PM = {PM[np.argmin(DM)]} deg") print(f"min(GM) = {min(GM)} dB") print(f"min(PM) = {min(PM)} deg\n") plt.figure(3) plt.subplot(3,3,1) plt.semilogx(omega, DM, label='$\\alpha$') plt.legend() plt.title('Disk Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 2]) plt.figure(3) plt.subplot(3,3,4) plt.semilogx(omega, GM, label='$\\gamma_{m}$') plt.ylabel('Gain Margin (dB)') plt.legend() plt.title('Gain-Only Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 40]) plt.figure(3) plt.subplot(3,3,7) plt.semilogx(omega, PM, label='$\\phi_{m}$') plt.ylabel('Phase Margin (deg)') plt.legend() plt.title('Phase-Only Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 90]) print(f"------------- Complementary sensitivity function (T) -------------") DM, GM, PM = control.disk_margins(L, omega, skew = -1.0, returnall = True) # T-based (T) print(f"min(DM) = {min(DM)} (omega = {omega[np.argmin(DM)]})") print(f"GM = {GM[np.argmin(DM)]} dB") print(f"PM = {PM[np.argmin(DM)]} deg") print(f"min(GM) = {min(GM)} dB") print(f"min(PM) = {min(PM)} deg\n") plt.figure(3) plt.subplot(3,3,2) plt.semilogx(omega, DM, label='$\\alpha$') plt.legend() plt.title('Disk Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 2]) plt.figure(3) plt.subplot(3,3,5) plt.semilogx(omega, GM, label='$\\gamma_{m}$') plt.ylabel('Gain Margin (dB)') plt.legend() plt.title('Gain-Only Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 40]) plt.figure(3) plt.subplot(3,3,8) plt.semilogx(omega, PM, label='$\\phi_{m}$') plt.ylabel('Phase Margin (deg)') plt.legend() plt.title('Phase-Only Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 90]) print(f"------------- Balanced sensitivity function (S - T) -------------") DM, GM, PM = control.disk_margins(L, omega, skew = 0.0, returnall = True) # balanced (S - T) print(f"min(DM) = {min(DM)} (omega = {omega[np.argmin(DM)]})") print(f"GM = {GM[np.argmin(DM)]} dB") print(f"PM = {PM[np.argmin(DM)]} deg") print(f"min(GM) = {min(GM)} dB") print(f"min(PM) = {min(PM)} deg\n") plt.figure(3) plt.subplot(3,3,3) plt.semilogx(omega, DM, label='$\\alpha$') plt.legend() plt.title('Disk Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 2]) plt.figure(3) plt.subplot(3,3,6) plt.semilogx(omega, GM, label='$\\gamma_{m}$') plt.ylabel('Gain Margin (dB)') plt.legend() plt.title('Gain-Only Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 40]) plt.figure(3) plt.subplot(3,3,9) plt.semilogx(omega, PM, label='$\\phi_{m}$') plt.ylabel('Phase Margin (deg)') plt.legend() plt.title('Phase-Only Margin') plt.grid() plt.xlim([omega[0], omega[-1]]) plt.ylim([0, 90]) Output: ------------- Sensitivity function (S) ------------- min(DM) = 0.3697398698410271 (omega = 0.1) GM = 2.732761944304522 dB PM = 21.30709883385843 deg min(GM) = 2.732761944304522 dB min(PM) = 21.30709883385843 deg ------------- Complementary sensitivity function (T) ------------- min(DM) = 0.3683035923739884 (omega = 0.1) GM = 2.7236493433653735 dB PM = 21.223368586091564 deg min(GM) = 2.7236493433653735 dB min(PM) = 21.223368586091564 deg ------------- Balanced sensitivity function (S - T) ------------- min(DM) = 0.3769872636944355 (omega = 0.1) GM = 3.3140985364257256 dB PM = 21.349285542574695 deg min(GM) = 3.3140985364257256 dB min(PM) = 21.349285542574695 deg The example script also shows how to plot the allowable/stable region of gain and phase variations which will not destabilize the loop, in a local function plot_allowable_region, e.g. . . . DM_plot = [] DM_plot.append(control.disk_margins(L, omega, skew = -1.0)[0]) # T-based (T) DM_plot.append(control.disk_margins(L, omega, skew = 0.0)[0]) # balanced (S - T) DM_plot.append(control.disk_margins(L, omega, skew = 1.0)[0]) # S-based (S) plt.figure(30) plot_allowable_region(DM_plot, skew = [-1.0, 0.0, 1.0])

Open Graph Description: Am relatively new to this toolbox, have been using it here and there and found #726. This is an initial prototype Python implementation of disk margins, built on top of python-control and slycot. ...

X Description: Am relatively new to this toolbox, have been using it here and there and found #726. This is an initial prototype Python implementation of disk margins, built on top of python-control and slycot. ...

Opengraph URL: https://github.com/python-control/python-control/pull/1146

X: @github

direct link

Domain: github.com

route-pattern/:user_id/:repository/pull/:id/checks(.:format)
route-controllerpull_requests
route-actionchecks
fetch-noncev2:306aeebb-9c4a-ccc9-4481-30b7f280bbf0
current-catalog-service-hash87dc3bc62d9b466312751bfd5f889726f4f1337bdff4e8be7da7c93d6c00a25a
request-idBB34:1DF41E:7628BC:A3E6CE:697A6BFF
html-safe-nonce8e0a43caa0c88f2fb0144037778925e0c968623882047fd9501063897906cdc2
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCQjM0OjFERjQxRTo3NjI4QkM6QTNFNkNFOjY5N0E2QkZGIiwidmlzaXRvcl9pZCI6IjgyNzE5NTk1NTkwNDg0MjQ0NDciLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ==
visitor-hmac2cf55e151650467c20e53fd4da191e75aa7adad5132b460220e39f6651ea6275
hovercard-subject-tagpull_request:2478921952
github-keyboard-shortcutsrepository,pull-request-list,pull-request-conversation,pull-request-files-changed,checks,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///pull_requests/show/checks
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/python-control/python-control/pull/1146/checks
twitter:imagehttps://avatars.githubusercontent.com/u/7785578?s=400&v=4
twitter:cardsummary_large_image
og:imagehttps://avatars.githubusercontent.com/u/7785578?s=400&v=4
og:image:altAm relatively new to this toolbox, have been using it here and there and found #726. This is an initial prototype Python implementation of disk margins, built on top of python-control and slycot. ...
og:site_nameGitHub
og:typeobject
hostnamegithub.com
expected-hostnamegithub.com
None4f4c032790588250388c2e36a0e1ea776c0a3f887d37d994e1ac3d7ea79d34ef
turbo-cache-controlno-cache
go-importgithub.com/python-control/python-control git https://github.com/python-control/python-control.git
octolytics-dimension-user_id2285872
octolytics-dimension-user_loginpython-control
octolytics-dimension-repository_id22791752
octolytics-dimension-repository_nwopython-control/python-control
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id22791752
octolytics-dimension-repository_network_root_nwopython-control/python-control
turbo-body-classeslogged-out env-production page-responsive full-width full-width-p-0
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release06b3a5a9a6214e1e06e508d250d778cbaf17c577
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://github.com/python-control/python-control/pull/1146/checks#start-of-content
https://github.com/
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython-control%2Fpython-control%2Fpull%2F1146%2Fchecks
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub SparkBuild and deploy intelligent appshttps://github.com/features/spark
GitHub ModelsManage and compare promptshttps://github.com/features/models
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
GitHub SponsorsFund open source developershttps://github.com/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/accelerator
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython-control%2Fpython-control%2Fpull%2F1146%2Fchecks
Sign up https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fpull_requests%2Fshow%2Fchecks&source=header-repo&source_repo=python-control%2Fpython-control
Reloadhttps://github.com/python-control/python-control/pull/1146/checks
Reloadhttps://github.com/python-control/python-control/pull/1146/checks
Reloadhttps://github.com/python-control/python-control/pull/1146/checks
python-control https://github.com/python-control
python-controlhttps://github.com/python-control/python-control
Notifications https://github.com/login?return_to=%2Fpython-control%2Fpython-control
Fork 447 https://github.com/login?return_to=%2Fpython-control%2Fpython-control
Star 2k https://github.com/login?return_to=%2Fpython-control%2Fpython-control
Code https://github.com/python-control/python-control
Issues 87 https://github.com/python-control/python-control/issues
Pull requests 8 https://github.com/python-control/python-control/pulls
Discussions https://github.com/python-control/python-control/discussions
Actions https://github.com/python-control/python-control/actions
Projects 0 https://github.com/python-control/python-control/projects
Wiki https://github.com/python-control/python-control/wiki
Security 0 https://github.com/python-control/python-control/security
Insights https://github.com/python-control/python-control/pulse
Code https://github.com/python-control/python-control
Issues https://github.com/python-control/python-control/issues
Pull requests https://github.com/python-control/python-control/pulls
Discussions https://github.com/python-control/python-control/discussions
Actions https://github.com/python-control/python-control/actions
Projects https://github.com/python-control/python-control/projects
Wiki https://github.com/python-control/python-control/wiki
Security https://github.com/python-control/python-control/security
Insights https://github.com/python-control/python-control/pulse
Sign up for GitHub https://github.com/signup?return_to=%2Fpython-control%2Fpython-control%2Fissues%2Fnew%2Fchoose
terms of servicehttps://docs.github.com/terms
privacy statementhttps://docs.github.com/privacy
Sign inhttps://github.com/login?return_to=%2Fpython-control%2Fpython-control%2Fissues%2Fnew%2Fchoose
murrayrmhttps://github.com/murrayrm
python-control:mainhttps://github.com/python-control/python-control/tree/main
josiahdelange:jdelange/disk-marginshttps://github.com/josiahdelange/python-control/tree/jdelange/disk-margins
Conversation 39 https://github.com/python-control/python-control/pull/1146
Commits 40 https://github.com/python-control/python-control/pull/1146/commits
Checks 14 https://github.com/python-control/python-control/pull/1146/checks
Files changed https://github.com/python-control/python-control/pull/1146/files
Please reload this pagehttps://github.com/python-control/python-control/pull/1146/checks
Please reload this pagehttps://github.com/python-control/python-control/pull/1146/checks
Sign in for the full log viewhttps://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython-control%2Fpython-control%2Fpull%2F1146%2Fchecks
Disk margin calculations https://github.com/python-control/python-control/pull/1146/checks#top
Please reload this pagehttps://github.com/python-control/python-control/pull/1146/checks
Doctest on: pull_request https://github.com/python-control/python-control/actions/runs/15807352356
doctest-linux https://github.com/python-control/python-control/actions/runs/15807352356/job/44769159628?pr=1146
Conda-based pytest on: pull_request https://github.com/python-control/python-control/actions/runs/15807352364
Py3.10; no Slycot; no Pandas; no CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162340?pr=1146
Py3.10; no Slycot; no Pandas; conda CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162316?pr=1146
Py3.10; conda Slycot; no Pandas; no CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162338?pr=1146
Py3.10; conda Slycot; no Pandas; conda CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162367?pr=1146
Py3.12; no Slycot; no Pandas; no CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162320?pr=1146
Py3.12; no Slycot; no Pandas; conda CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162333?pr=1146
Py3.12; conda Slycot; no Pandas; no CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162324?pr=1146
Py3.12; conda Slycot; no Pandas; conda CVXOPT https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162366?pr=1146
Py3.12; conda Slycot; conda Pandas; conda CVXOPT ; QtAgg https://github.com/python-control/python-control/actions/runs/15807352364/job/44769162424?pr=1146
Finalize parallel coveralls https://github.com/python-control/python-control/actions/runs/15807352364/job/44770365190?pr=1146
ruff-check on: pull_request https://github.com/python-control/python-control/actions/runs/15807352365
ruff-check-linux https://github.com/python-control/python-control/actions/runs/15807352365/job/44769159895?pr=1146
Slycot from source on: pull_request https://github.com/python-control/python-control/actions/runs/15807352370
build-linux https://github.com/python-control/python-control/actions/runs/15807352370/job/44769160329?pr=1146
Setup, Examples, Notebooks on: pull_request https://github.com/python-control/python-control/actions/runs/15807352377
install-examples https://github.com/python-control/python-control/actions/runs/15807352377/job/44769160004?pr=1146
https://github.com/python-control/python-control/pull/1146/checks#annotation:3:730
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.