MARGIN
Stability margins measure how much uncertainty a feedback system can tolerate before it becomes unstable.
The two standard quantities are gain margin and phase margin:
G_m = \text{allowable gain factor at the } -180^\circ \text{ phase crossing}
P_m = 180^\circ + \angle G(j\omega_{cp})
where \omega_{cp} is the gain crossover frequency at which |G(j\omega)| = 1. This wrapper returns a single spreadsheet row containing gain margin, phase margin, phase crossover frequency, and gain crossover frequency.
Excel Usage
=MARGIN(sysdata)
sysdata(list[list], required): The open-loop transfer function, provided as numerator and denominator coefficients in consecutive rows.
Returns (list[list]): A 1x4 horizontal array containing [Gain Margin, Phase Margin, Wcg, Wcp]. If a margin is infinite, it returns ‘inf’.
Example 1: Check margins of a stable system
Inputs:
| sysdata |
|---|
| 1 |
| 1 |
Excel formula:
=MARGIN({1;1,2,1,0})
Expected output:
| Result | |||
|---|---|---|---|
| 2 | 21.3864 | 1 | 0.682328 |
Example 2: System with infinite gain margin
Inputs:
| sysdata |
|---|
| 10 |
| 1 |
Excel formula:
=MARGIN({10;1,5,6})
Expected output:
| Result | |||
|---|---|---|---|
| inf | 102.663 | 1.95135 |
Python Code
Show Code
import control as ct
import numpy as np
def margin(sysdata):
"""
Calculate the gain and phase margins and crossover frequencies of a system.
See: https://python-control.readthedocs.io/en/latest/generated/control.margin.html
This example function is provided as-is without any representation of accuracy.
Args:
sysdata (list[list]): The open-loop transfer function, provided as numerator and denominator coefficients in consecutive rows.
Returns:
list[list]: A 1x4 horizontal array containing [Gain Margin, Phase Margin, Wcg, Wcp]. If a margin is infinite, it returns 'inf'.
"""
try:
def flatten_to_1d(x):
if not isinstance(x, list):
return [float(x)] if str(x) != "" else []
flat = []
for row in x:
if isinstance(row, list):
for val in row:
if str(val) != "":
flat.append(float(val))
elif str(row) != "":
flat.append(float(row))
return flat
if not sysdata or len(sysdata) < 2:
return "Error: sysdata must contain numerator and denominator rows"
num = flatten_to_1d(sysdata[0])
den = flatten_to_1d(sysdata[1])
if not num or not den:
return "Error: Invalid numerator or denominator arrays"
sys = ct.tf(num, den)
gm, pm, wcg, wcp = ct.margin(sys)
# Handle infs and NaNs for excel
def clean_val(v):
if v is None or np.isnan(v):
return ""
if np.isinf(v):
return "inf" if v > 0 else "-inf"
return float(v)
# Return as a 1x4 2D array
return [[clean_val(gm), clean_val(pm), clean_val(wcg), clean_val(wcp)]]
except Exception as e:
return f"Error: {str(e)}"