(*
Transfer Function Analysis by Manipulation of Poles and Zeros
by Nasser M. Abbasi
version April 12 2009*)
Manipulate[
Module[{graphicsOptions, frameThickness = 0.001},
If[plotType == "root Locus", useClosedLoop = False];
graphicsOptions = {ImageSize -> {240, 240}, ImagePadding -> 0,
Axes -> True,
PlotRange -> {{-ext - 3 del, ext + 3 del}, {-ext - 3 del,
ext + 3 del}},
GridLines -> {Range[-ext - 3 del, ext + 3 del, del],
Range[-ext - 3 del, ext + 3 del, del]},
GridLinesStyle ->
Directive[{LightGray, Thickness[frameThickness]}],
AspectRatio -> 1,
Background -> White,
TicksStyle -> Small,
Ticks -> {{-1, -0.5, 0, 0.5, 1}, {-1, -0.5, 0, 0.5, 1}},
AxesStyle -> Directive[{Blue, Thickness[frameThickness]}]};
If[showGrid,
baseGraphics = {{LightGray,
Rectangle[{-ext - 3 del, -ext - 3 del}, {ext + 3 del,
ext + 3 del}]},
{White, Rectangle[{-ext, -ext}, {ext, ext}]},
{Gray, PointSize[0.001],
Point[#] & /@
Flatten[Outer[List, Range[-ext , ext , del],
Range[-ext , ext , del]], 1]},
{Black, Circle[{0, 0}, 1]}}
,
baseGraphics = {{LightGray,
Rectangle[{-ext - 3 del, -ext - 3 del}, {ext + 3 del,
ext + 3 del}]},
{White, Rectangle[{-ext, -ext}, {ext, ext}]},
{Black, Circle[{0, 0}, 1]}}
];
mousePos = If[showToolTip, MousePosition["Graphics"], 0];
Row[{
Grid[{
{Dynamic[formatedTransferFunctions], SpanFromLeft},
{
Switch[pointType,
POLE,
LocatorPane[Dynamic[poles], Graphics[
{
Sequence@baseGraphics,
Dynamic@
If[showToolTip,
formatRadialLine[MousePosition["Graphics"], ts],
Text["", {0, 0}], Enabled -> showToolTip == True],
Dynamic[
Refresh[format[Chop@poles, Chop@zeros, ext],
TrackedSymbols -> {poles}],
Enabled -> showToolTip == False]
}, graphicsOptions],
{{-ext - 2 del, 0}, {ext + 2 del, ext + 2 del}, {gridSpacing,
gridSpacing}},
Appearance -> None, LocatorAutoCreate -> {All},
AutoAction -> False, Enabled -> showToolTip == False
],
_,
LocatorPane[Dynamic[zeros], Graphics[
{
Sequence@baseGraphics,
Dynamic@
If[showToolTip,
formatRadialLine[MousePosition["Graphics"], ts],
Text["", {0, 0}], Enabled -> showToolTip == True],
Dynamic[
Refresh[format[Chop@poles, Chop@zeros, ext],
TrackedSymbols -> {zeros}],
Enabled -> showToolTip == False]
}, graphicsOptions],
{{-ext - 2 del, 0}, {ext + 2 del, ext + 2 del}, {gridSpacing,
gridSpacing}},
Appearance -> None, LocatorAutoCreate -> {All},
AutoAction -> False, Enabled -> showToolTip == False
]
],
Dynamic[processResult]
}
}, Spacings -> {0, 0}, Frame -> All, Alignment -> Center,
FrameStyle -> Directive[Thickness[frameThickness], Gray]],
(*format returned is {order,{x,y}} *)
Dynamic[
Refresh[internalPoles = findInternalPoints[Chop@poles, ext]; "",
TrackedSymbols -> {poles}]],
Dynamic[
Refresh[internalZeros = findInternalPoints[Chop@zeros, ext]; "",
TrackedSymbols -> {zeros}]],
Dynamic[
Refresh[hz =
makeHz[internalPoles, internalZeros, z, useClosedLoop]; "",
TrackedSymbols -> {poles, zeros, useClosedLoop}]],
Dynamic[
Refresh[{formatedTransferFunctions, tf, sys, statusOfConversion,
statusMessage, polesInSPlane , zerosInSPlane} =
formatTransferFunctions[{z, s, y, t}, internalPoles,
internalZeros, hz, conversionType, ts]; "",
TrackedSymbols -> {poles, zeros, conversionType, ts,
useClosedLoop}]],
Dynamic[
Refresh[processResult =
First@process[z, ts, plotType, simulationTime, rootLocusK,
bodeMagScales, bodePhaseScales, mousePos, showToolTip,
responseJoined, showPlotsGrid, showStabilityMargins, tf, sys,
internalPoles, internalZeros, hz, addContResponse,
statusOfConversion, statusMessage, polesInSPlane ,
zerosInSPlane, conversionType, forcingFrequency]; "",
TrackedSymbols -> {mousePos, poles, zeros, ts, plotType,
simulationTime, rootLocusK, bodeMagScales, bodePhaseScales,
responseJoined, showPlotsGrid, showStabilityMargins,
addContResponse, conversionType, forcingFrequency,
useClosedLoop}
], ContinuousAction -> True
]
}](*Row*)
],(*Manipulate expression completed*)
(*control variables layout. Top panel*)
Item[
Grid[{{
Grid[{{
Grid[{
{Control[{{pointType, POLE, ""}, {POLE -> Style["pole", 11],
ZERO -> Style["zero", 11]},
ControlType -> RadioButtonBar, ImageSize -> Tiny,
ImageMargins -> 0, Appearance -> "Vertical",
Background -> LightGray}]}
}, Spacings -> {0, .2}],
Grid[{
{Text@Style["plot type", 12]},
{Control[{ {plotType, "step",
""}, (# -> Text@Style[#, 12]) & /@ {"Bode",
"root Locus", "Nyquist", "Nichols", "H(z) margins",
"H(s) margins", "S-plane map", "impulse", "step",
"ramp", "cos(2\[Pi]fn)",
"\!\(\*SuperscriptBox[\(\[ExponentialE]\), \
\(-n\)]\)cos(2\[Pi]fn)"},
ControlType -> PopupMenu, ImageSize -> All}]
}
}, Spacings -> {0, .2}]
}}, Frame -> True,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {-.5, .4}]
,
Grid[{
{Text@Row[{Style[" k", Italic, 12]}],
Control[{{rootLocusK, 3, ""}, 1, 20, 1, ImageSize -> Tiny,
Enabled -> plotType == "root Locus"}],
Text@Row[{" ", Style[Dynamic[rootLocusK], 10]}]
},
{
Text@Row[{Style[" f", Italic, 12]}],
Control[{{forcingFrequency, 1, ""}, 0, 2, 0.05,
ImageSize -> Tiny,
Enabled ->
plotType == "cos(2\[Pi]fn)" ||
plotType ==
"\!\(\*SuperscriptBox[\(\[ExponentialE]\), \
\(-n\)]\)cos(2\[Pi]fn)"}],
Text@Row[{" ",
Style[Dynamic[padIt1[forcingFrequency, {2, 2}]], 10]}]
}
}, Frame -> True, Alignment -> Left,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {0, 0.3}
],
Grid[{
{Text@Style["Bode units (mag)", 12],
Text@Style["Bode units (phase)", 12]
},
{Control[{ {bodeMagScales, {"Linear", "Absolute"},
""}, (# -> Style[#, 10]) & /@ {{"Log10", "dB"}, {"Log10",
"Absolute"}, {"Linear", "dB"}, {"Linear", "Absolute"}},
ControlType -> PopupMenu, ImageSize -> All,
Enabled -> plotType == "Bode"}],
Control[{ {bodePhaseScales, {"Linear", "Degree"},
""}, (# -> Style[#, 10]) & /@ {{"Log10",
"Degree"}, {"Log10", "Radian"}, {"Linear",
"Degree"}, {"Linear", "Radian"}},
ControlType -> PopupMenu, ImageSize -> All,
Enabled -> plotType == "Bode"}]
}
}, Frame -> True,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {0, 0.3}],
Grid[{
{Text@Style["grid lines", 10],
Control[{{showPlotsGrid, True, ""}, {True, False},
ImageSize -> Tiny, ImagePadding -> 0,
Enabled ->
plotType == "Bode" || plotType == "Nyquist" ||
plotType == "Nichols" || plotType == "impulse" ||
plotType == "step" || plotType == "ramp" ||
plotType == "cos(2\[Pi]fn)" ||
plotType ==
"\!\(\*SuperscriptBox[\(\[ExponentialE]\), \
\(-n\)]\)cos(2\[Pi]fn)"}]
},
{Text@Style["margins", 10],
Control[{{showStabilityMargins, False, ""}, {True, False},
ImageSize -> Tiny, ImagePadding -> 0,
Enabled ->
plotType == "Bode" || plotType == "Nyquist" ||
plotType == "Nichols" || plotType == "root Locus"}]
},
{Text@Style["closed loop", 10],
Control[{{useClosedLoop, False, ""}, {True, False},
ImageSize -> Tiny, ImagePadding -> 0,
Enabled -> plotType != "root Locus"}]
}
}, Frame -> True,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {.5, 0}, Alignment -> Left]
}}, Frame -> None,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {.1, 0}, Alignment -> Center
], ControlPlacement -> Top, ItemSize -> All, Alignment -> Left],
(*Bottom panel*)
Item[
Grid[{
{
Grid[{
{Text@Style["background", 11],
Control[{{showGrid, True, ""}, {True, False},
ControlType -> Checkbox, ImageSize -> Tiny}]},
{Text@Style["tooltip", 11],
Control[{{showToolTip, False, ""}, {True, False},
ControlType -> Checkbox, ImageSize -> Tiny}]}
}, Alignment -> Left, Frame -> True,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {0.3, 0.6}],
Grid[{
{Text@Style[" grid spacing", 10]},
{Control[{ {gridSpacing, 0.1, ""}, {0.1 -> Style["0.1", 10],
0 -> Style["0", 10]},
ControlType -> PopupMenu, ImageSize -> All}]
}
}, Frame -> True,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {0.2, 0.3}],
Grid[{
{Text@Style["time", 11],
Control[{{simulationTime, 25, ""}, 2, 50, 1,
ImageSize -> Tiny}],
Text@Style[Dynamic[simulationTime], 10]
},
{Text@Style["\!\(\*SubscriptBox[\(T\), \(s\)]\)", 11],
Control[{{ts, 1, ""}, 1, 4, 0.1, ImageSize -> Tiny,
ImagePadding -> 0}],
Text@Style[Dynamic[padIt1[ts, {2, 2}]], 10]
}
}
, Frame -> True, FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {.2, .3}],
Grid[{
{Text[Style["response shape", 11]]},
{Control[{{responseJoined, True,
Text@Style["joined plot ", 10]}, {True, False},
ImageSize -> Tiny, ImagePadding -> 0,
Enabled ->
plotType == "impulse" || plotType == "step" ||
plotType == "ramp" || plotType == "cos(2\[Pi]fn)" ||
plotType ==
"\!\(\*SuperscriptBox[\(\[ExponentialE]\), \
\(-n\)]\)cos(2\[Pi]fn)"}]
},
{Control[{{addContResponse, True,
Text@Style["superimpose", 10]}, {True, False},
ImageSize -> Tiny, ImagePadding -> 0,
Enabled ->
plotType == "impulse" || plotType == "step" ||
plotType == "ramp" || plotType == "cos(2\[Pi]fn)" ||
plotType ==
"\!\(\*SuperscriptBox[\(\[ExponentialE]\), \
\(-n\)]\)cos(2\[Pi]fn)"}]
}
}, Frame -> True,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {.5, .1}, Alignment -> Left],
Grid[{
{Text@Style["conversion method", 12]},
{Control[{ {conversionType, "BilinearTransform",
""}, (#[[2]] ->
Text@Style[#[[2]], 11]) & /@ {"FirstOrderHold" ->
"FirstOrderHold", "ZeroOrderHold" -> "ZeroOrderHold",
"ZeroPoleMapping" -> "ZeroPoleMapping",
"BilinearTransform" -> "BilinearTransform",
"BackwardRectangularRule" -> "BackwardRectangularRule",
"ForwardRectangularRule" -> "ForwardRectangularRule"},
ControlType -> PopupMenu, ImageSize -> All}]
}
}, Frame -> True,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {0, 0.3}],
Button[
Text@Style["init", 10], {showGrid = True; showToolTip = False;
gridSpacing = 0.1; ts = 1; showPlotsGrid = True;
simulationTime = 25; rootLocusK = 2;
bodePhaseScales = {"Linear", "Degree"};
bodeMagScales = {"Linear", "Absolute"}; plotType = "impulse";
poles = {{0.7, .1}, {1.3, .1}, {1.3, .3}, {1.3, .5}};
zeros = {{0, 0}, {-1.3, .1}, {-1.3, .3}, {-1.3, .5}}},
ImageSize -> {30, 50}]
}}, Frame -> None,
FrameStyle -> Directive[Thickness[.001], Gray],
Spacings -> {.1, 0}, Alignment -> Center
], ControlPlacement -> Bottom],
{{POLE, 2}, ControlType -> None},
{{ZERO, 3}, ControlType -> None},
{{poles, {{0.2, 0.8}, {1.3, .1}, {1.3, .3}, {1.3, .5}}},
ControlType -> None},
{{zeros, {{0.0, 0.0}, {-1.3, .1}, {-1.3, .3}, {-1.3, .5}}},
ControlType -> None},
{{ext, 1.2}, ControlType -> None},
{{del, 0.1}, ControlType -> None},(*grid size*)
{{statusOfConversion, True}, ControlType -> None},
{{statusMessage, ""}, ControlType -> None},
{{polesInSPlane, {}}, ControlType -> None},
{{zerosInSPlane , {}}, ControlType -> None},
{{internalPoles, {{1, {0.2, 0.8}}}}, ControlType -> None},
{{internalZeros, {{1, {0.0, 0.0}}}}, ControlType -> None},
{{hz, z/(z^2 - 0.4 z + 0.68)}, ControlType -> None},
{{mousePos, 0}, ControlType -> None},
{{processResult, {}}, ControlType -> None},
(*This below is initialized here for proper use with AutoRunSequence*)
\
{{formatedTransferFunctions, Grid[{
{Graphics[
Text@
Row[{ Style["H(z)", Italic, 12], Style[" = "],
Style["\!\(\*FractionBox[\(z\), \(\*SuperscriptBox[\(z\), \
\(2\)] - 0.4 z + 0.68\)]\)", 14], Style[" ROC |", 9],
Style["z", Italic, 12], Style["| > ", 12], 0.825,
Style[" " <> "stable", 12]}], ImageSize -> {527, 28}
]
},
{
Graphics[
Text@Row[{Style["H(s)", Italic, 12], Style[" = "],
Style["\!\(\*FractionBox[\(1 - 0.25 \*SuperscriptBox[\(s\), \
\(2\)]\), \(0.52 \*SuperscriptBox[\(s\), \(2\)] + 0.32 s + \
1.28\)]\)", 14]}], ImageSize -> {527, 30}]
},
{
Graphics[
Text@Row[{Style["0.52 y''(t)+0.32 y(t)+1.28 y(t)", 10]}],
ImageSize -> {527, 15}]
}
}, Spacings -> 0, Frame -> None]}, ControlType -> None},
TrackedSymbols :> {pointType, showGrid, showToolTip, gridSpacing,
responseJoined, responseGrid, showPlotsGrid, showStabilityMargins,
addContResponse, plotType, mousePos, useClosedLoop,
forcingFrequency},
ImageMargins -> 0,
Alignment -> Center,
FrameMargins -> 0,
ContinuousAction -> True,
AutoAction -> False,
SynchronousUpdating -> True,
ContentSize -> Automatic,
AutorunSequencing -> {{13, 1}},
Initialization :>
(
$MinPrecision = $MachinePrecision;
$MaxPrecision = $MachinePrecision;
(*---------------------------------------------------------*)
makeHz[internalPoles_List,
internalZeros_List,
z_,
useClosedLoop_ /; Element[useClosedLoop, Booleans]] :=
Module[{num, den, numCoeffList, denCoeffList, plant},
den =
Replace[internalPoles, {o_, {x_, y_}} :> (z - (x + I y))^o, {1}];
num =
Replace[internalZeros, {o_, {x_, y_}} :> (z - (x + I y))^o, {1}];
numCoeffList = Chop@CoefficientList[Expand@Apply[Times, num], z];
denCoeffList = Chop@CoefficientList[Expand@Apply[Times, den], z];
plant =
Expand@FromDigits[Reverse[numCoeffList], z]/
Expand@FromDigits[Reverse[denCoeffList], z];
If[useClosedLoop, Simplify[plant/Expand[1 + plant]], plant]
];
(*---------------------------------------------------------*)
(*input format {order,{x,y}}*)
polesAndZerosAsList[p_List, z_List] := {
Flatten[Replace[p, {n_, {x_, y_}} :> Table[{x, y}, {n}], {1}],
1], Flatten[
Replace[z, {n_, {x_, y_}} :> Table[{x, y}, {n}], {1}], 1]
};
(*---------------------------------------------------------*)
getContinuouseTimeTFfromHz[{z_, s_, t_, y_},
hz_,
conversionType_String,
ts_?(NumberQ[#] && Positive[#] &),
poles_List,
zeros_List] :=
Module[{tf, sys, statusOfConversion = True, statusMessage = "",
polesInSPlane = {}, zerosInSPlane = {}, poly, num, den, lap,
out, odeOutput, numberOfPoles, numberOfZeros},
tf = TransferFunctionModel[1.*hz, z, SamplingPeriod -> ts];
numberOfPoles = Length[poles[[All, 2]]];
numberOfZeros = Length[zeros[[All, 2]]];
If[ Length[
Cases[poles, {xx_, yy_} /; (
Abs[yy] < $MachineEpsilon && xx <= 0)]] > 0 ||
numberOfZeros > numberOfPoles,
(
If[conversionType == "ZeroOrderHold",
(
statusOfConversion = False;
statusMessage =
"Warning: Negative pure real pole using ZeroOrderHold \
detected"
)
]
),
(
If[
Length[Cases[
poles, {xx_, yy_} /; (
Abs[yy] < $MachineEpsilon && (Abs[
xx - 1] < $MachineEpsilon))]] > 0,
If[
conversionType == "ZeroOrderHold" ||
conversionType == "FirstOrderHold",
(
statusOfConversion = False;
statusMessage =
"Warning: Pole at 1 using ZeroOrderHold or FirstOrderHold \
detected"
)
]
]
)
];
If[statusOfConversion == False,
(
odeOutput = "";
out = Style[statusMessage, Red, 10]
),
(
sys = ToContinuousTimeModel[tf, s, Method -> conversionType];
lap = Chop@Expand@Denominator@First@sys[s][[1]];
If[lap === 1,
(
polesInSPlane = {0, 0};
zerosInSPlane = {0, 0}
),
(
polesInSPlane = s /. NSolve[lap == 0, s];
If[polesInSPlane === s, polesInSPlane = {0, 0}];
zerosInSPlane =
s /. NSolve[Chop@Expand@Numerator@First@sys[s][[1]] == 0, s];
If[zerosInSPlane === s, zerosInSPlane = {0, 0}]
)
];
odeOutput = InverseLaplaceTransform[lap, s, t];
odeOutput =
ReplaceAll[
odeOutput, {a_. DiracDelta[t] :> round[Chop@a, 2] y[t],
b_. Derivative[n_][DiracDelta][t] :>
round[Chop@b, 2] Derivative[n][y][t]}];
poly = First@sys;
num = First@CoefficientRules[First@poly[[1]], s];
num =
Table[num[[i, 1]] -> round[Chop@num[[i, 2]], 2], {i, 1,
Length[num]}];
den = poly[[2]];
den = CoefficientRules[First@Flatten[{den}], s];
den =
Table[den[[i, 1]] -> round[Chop@den[[i, 2]], 2], {i, 1,
Length[den]}];
out = FromCoefficientRules[num, s]/FromCoefficientRules[den, s]
)
];
{tf, sys, statusOfConversion, statusMessage, polesInSPlane ,
zerosInSPlane, out, odeOutput}
];
(*---------------------------------------------------------*)
formatTransferFunctions[{z_, s_, y_, t_},
internalPoles_List,
internalZeros_List,
hz_,
conversionType_String,
ts_?(NumberQ[#] && Positive[#] &)
] :=
Module[{largestPole, stable, poles, zeros, tf, sys, out,
odeOutput, fontSize = 12, statusOfConversion, statusMessage,
zerosInSPlane, polesInSPlane},
{poles, zeros} =
polesAndZerosAsList[internalPoles, internalZeros];
{tf, sys, statusOfConversion, statusMessage, polesInSPlane ,
zerosInSPlane, out, odeOutput} =
getContinuouseTimeTFfromHz[{z, s, t, y}, hz, conversionType, ts,
poles, zeros];
largestPole = Max[Norm[#] & /@ poles];
Which[largestPole < 1, stable = "stable",
Abs[largestPole - 1] <= $MachineEpsilon, stable = "marginal",
True, stable = "unstable"
];
{
Grid[{
{Graphics[
Text@Row[{ Style["H(z)", Italic, fontSize], Style[" = "],
Style[NumberForm[hz, 3], 16], Style[" ROC |", fontSize],
Style["z", Italic, fontSize], Style["| > ", fontSize],
NumberForm[largestPole, 3],
Style[" " <> stable, fontSize]}], ImageSize -> {527, 28}
]
},
{
Graphics[
Text@Row[{Style["H(s)", Italic, fontSize], Style[" = "],
Style[out, 16]}], ImageSize -> {527, 30}]
},
{
Graphics[Text@Row[{Style[odeOutput, 10]}],
ImageSize -> {527, 15}]
}
}, Spacings -> 0, Frame -> None]
, tf, sys, statusOfConversion, statusMessage, polesInSPlane ,
zerosInSPlane
}
];
(*---------------------------------------------------------*)
formatRadialLine[pt_, ts_?(NumberQ[#] && Positive[#] &)] :=
Module[{norm, line, text, point, angle, displayedAngle, offset,
at},
norm = Norm[pt];
If[pt === None ,
(
line = Line[{{0, 0}, {0, 0}}];
text = Text["", {0, 0}];
point = {PointSize[0], Point[{0, 0}]}
)
,
(
angle = ArcTan[pt[[1]], pt[[2]]];
displayedAngle = angle;
If[angle <= 0.0, displayedAngle = 2 Pi + angle];
Which[displayedAngle >= 3/2 Pi || displayedAngle <= Pi/2,
offset = {1.3, 0},
displayedAngle > Pi/2 || displayedAngle < 3/2 Pi,
offset = {-1.3, 0}
];
If[norm > 0.8 && norm < 1.2,
(
at = {Cos[angle], Sin[angle]};
line = {Thick, Dashed, Red, Arrow[{{0, 0}, at}]};
point = {PointSize[0.03], Blue, Point[at]};
text = Text[Grid[{
{Row[{Style[NumberForm[(1/(2 Pi ts))*displayedAngle, 3],
12, Red], Style[" hz", 10]}]}
}, Spacings -> {0.1, 0.1}, Alignment -> Left,
Frame -> None], at, offset]
),
(
line = Line[{{0, 0}, {0, 0}}];
text = Text["", {0, 0}];
point = {PointSize[0], Point[{0, 0}]}
)
]
)
];
{line, text, point}
];
(*---------------------------------------------------------*)
round2[digit_, delta_?(IntegerQ[#] && Positive[#] &)] :=
Module[{f, d, dd, r, res},
If[Abs[digit] <= $MachineEpsilon,
(
res = digit
),
(
f = FractionalPart[digit];
d = RealDigits[f, 10, 10];
r = Flatten[Prepend[d[[1]], Table[0, {Abs[d[[2]] ]}]]];
dd = If[Length[r] <= delta, FromDigits[r]/10^Length[r],
Round[ FromDigits[r[[1 ;; delta + 1]]]/10^(delta + 1),
1/10^delta]
];
res = N[IntegerPart[digit] + Sign[digit]*dd]
)
];
If[res == 1.0, res = 1];
If[res == -1.0, res = -1];
res
];
(*---------------------------------------------------------*)
round[digit_, delta_?(IntegerQ[#] && Positive[#] &)] := Module[{},
Chop@round2[N@Re[digit], delta] +
Chop@round2[N@Im[digit], delta] I
];
(*---------------------------------------------------------*)
padIt1[v_?(NumberQ[#] &), f_List] :=
AccountingForm[Chop[v] , f, NumberSigns -> {"", ""},
NumberPadding -> {"0", "0"}, SignPadding -> True
];
(*---------------------------------------------------------*)
padIt2[v_?(NumberQ[#] &), f_List] :=
AccountingForm[Chop[v] , f, NumberSigns -> {"-", "+"},
NumberPadding -> {"0", "0"}, SignPadding -> True
];
(*---------------------------------------------------------*)
findInternalPoints[points_List,
ext_?(NumberQ[#] && Positive[#] &)] := Module[{pointsFound},
(*find points inside region*)
pointsFound =
Cases[points, {x_, y_} /; (Abs[x] - ext) <= $MachineEpsilon];
(*generate order, convert {x,y} to {order,{x,y}} *)
pointsFound =
Union[
Replace[pointsFound, {x_,
y_} :> {Length[Cases[pointsFound, {x, y}]], {x, y}}, {1}]];
(*add complex conjugate points*)
Replace[
pointsFound, {o_, {x_, y_}} /; y > 0.0 :>
Sequence[{o, {x, y}}, {o, {x, -y}}], {1}]
];
(*-----------------------------------*)
findExternalPoints[points_List,
ext_?(NumberQ[#] && Positive[#] &)] := Module[{pointsFound},
pointsFound = Cases[points, {x_, y_} /; Abs[x] > ext];
(*add complex conjugate points*)
Union[
Replace[pointsFound, {x_,
y_} :> {Length[Cases[pointsFound, {x, y}]], {x, y}}, {1}]
]
];
(*---------------------------------------------------------*)
format[poles_List, zeros_List,
ext_?(NumberQ[#] && Positive[#] &)] := Module[{p, z},
padIt1[x_] := NumberForm[N[x], 3];
p = Join[findInternalPoints[poles, ext],
findExternalPoints[poles, ext]];
z = Join[findInternalPoints[zeros, ext],
findExternalPoints[zeros, ext]];
(* each entry in the p and z is now in the form {order,{x,
y}} *)
{
Replace[p, {
{o_, {x_, y_}} /; o > 1 :>
Sequence[{Tooltip[
Text[Style["\[Times]", Red, 16], {x, y}], {padIt1[x],
padIt1[y]}]}, {Text[
Style[o, Blue, 10], {x, y}, {-2, 0}]}],
{o_, {x_, y_}} :>
Tooltip[Text[Style["\[Times]", Red, 16], {x, y}], {padIt1[x],
padIt1[y]}]}, {1}]
,
Replace[z, {
{o_, {x_, y_}} /; o > 1 :>
Sequence[{Tooltip[
Text[Style["\[EmptyCircle]", Black, 16], {x, y}], {padIt1[
x], padIt1[y]}]}, {Text[
Style[o, Blue, 10], {x, y}, {-2, 0}]}],
{o_, {x_, y_}} :>
Tooltip[Text[
Style["\[EmptyCircle]", Black, 16], {x, y}], {padIt1[x],
padIt1[y]}]}, {1}]
}
];
(*---------------------------------------------------------*)
phaseBodePlot[phasePlot_, {xScale_, yScale_}, bodePlotOptions_,
bodePhaseTicks_, opt___] :=
Module[{x, y, yToUse, xToUse, yPlotRange, data, p},
data = Cases[Normal@phasePlot, Line[pts_] -> pts, Infinity];
x = data[[1, All, 1]];
y = data[[1, All, 2]];
xToUse = x;
If[yScale == "Degree",
(
yToUse = Mod[y, 360, -180];
yPlotRange = {-180, 180};
If[xScale == "Linear",
(
p =
ListPlot[Transpose[{xToUse, yToUse}],
Evaluate@bodePlotOptions, Ticks -> Evaluate@bodePhaseTicks,
Evaluate@opt, PlotRange -> {Automatic, {-200, 200}}]
),
(
p = ListPlot[Transpose[{xToUse, yToUse}],
GridLinesStyle -> Black,
(*Evaluate@First@AbsoluteOptions[phasePlot,GridLines],*)
PlotRange -> {Automatic, yPlotRange},
Evaluate@bodePlotOptions,
Evaluate@opt,
Ticks -> {{{-3, 0.001}, {-2, 0.01}, {-1, 0.1}, {0, 1}, {10,
1}}, Automatic},
AxesOrigin -> {Min[xToUse], 0},
PlotRange -> {Automatic, {-185, 185}}
]
)]
),
(
yToUse = Mod[y, 2 Pi, -Pi];
yPlotRange = {-Pi, Pi};
If[xScale == "Linear",
(
p =
ListPlot[Transpose[{xToUse, yToUse}],
Evaluate@bodePlotOptions, Ticks -> Evaluate@bodePhaseTicks,
Evaluate@opt, PlotRange -> {Automatic, {-1.2 Pi, 1.2 Pi}}]
),
(
p = ListPlot[Transpose[{xToUse, yToUse}],
GridLinesStyle -> Black(*,
Evaluate@First@AbsoluteOptions[phasePlot,GridLines]*),
PlotRange -> {Automatic, yPlotRange},
Evaluate@bodePlotOptions, Evaluate@opt,
Ticks -> {{{-3, 0.001}, {-2, 0.01}, {-1, 0.1}, {0, 1}, {10,
1}}, Automatic}, AxesOrigin -> {Min[xToUse], 0},
PlotRange -> {Automatic, {- Pi, Pi}}]
)
]
)
];
p
];
(*---------------------------------------------------------*)
makeBodeDiagrams[mousePtIn_,
z_,
ts_?(NumberQ[#] && Positive[#] &),
bodeMagScales_List,
bodePhaseScales_List,
showToolTip_ /; (Element[showToolTip, Booleans]),
hzIn_,
tf_,
showPlotsGrid_ /; (Element[showPlotsGrid, Booleans]),
showStabilityMargins_ /; (Element[showStabilityMargins,
Booleans])] :=
Module[{bodePhase, bodePlotOptions, yLabelBodeMag, xLabelBodeMag,
yLabelBodePhase, xLabelBodePhase, xForBodeMag, yForBodeMag,
xForBodePhase, yForBodePhase, bodePlot, w, pt, norm, freq = 0,
bodeMagTicks, bodePhaseTicks, scaledFreq, ticks, hz = hzIn,
bodeMagTicksX, bodeMagTicksY, xLabel, mousePt = mousePtIn,
labelFontSize = 9},
If[Not[showToolTip], mousePt = None];
If[Not[mousePt === None],
(
freq = ArcTan[mousePt[[1]], mousePt[[2]]];
If[freq <= 0.0, freq = 2 Pi + freq];
norm = Norm[mousePt];
pt = mousePt
)
,
(
norm = Infinity
)
];
If[norm < 0.9 || norm > 1.1,
pt = None];(*do not tooltip if far from circle*)
hz =
ReplaceAll[hz,
z -> Exp[I*w]];(*needed just for the tracking point *)
scaledFreq = freq/ts;
xLabel =
Grid[{{Style["\[Omega]", labelFontSize]}, {Style["rad/sec",
labelFontSize]}}, Spacings -> {0, -0.2}];
xLabelBodeMag = xLabel;
(*find tracking point coordinates for Magnitude plot*)
If[Order[bodeMagScales[[1]], "Linear"] == 0,
(
xForBodeMag = scaledFreq;
bodeMagTicksX = {0, Pi/4, Pi/2, 3/4 Pi, Pi, (5 Pi)/4, (3 Pi)/2,
7/4 Pi, 2 Pi};
bodeMagTicksY = Automatic;
bodeMagTicks = {bodeMagTicksX, bodeMagTicksY}
),
(
xForBodeMag = Log[10, scaledFreq];
bodeMagTicksX = Automatic;
bodeMagTicksY = Automatic;
bodeMagTicks = {bodeMagTicksX, bodeMagTicksY}
)
];
If[Order[bodeMagScales[[2]], "Absolute"] == 0,
(
yLabelBodeMag = Text@Style["|H(\[Omega])|", labelFontSize];
yForBodeMag = Abs[hz /. w -> freq]
),
(
yLabelBodeMag =
Text@Row[{Style["|H(\[Omega])| dB", labelFontSize]}];
yForBodeMag = 20*Log[10, Abs[hz /. w -> freq]]
)
];
(*find tracking point coordinates for Phase plot*)
xLabelBodePhase = xLabel;
If[Order[bodePhaseScales[[1]], "Linear"] == 0,
(
xForBodePhase = scaledFreq;
bodePhaseTicks = {{0, Pi/4, Pi/2, 3/4 Pi, Pi, (5 Pi)/4, (3 Pi)/
2, 7/4 Pi, 2 Pi}, Automatic}
),
(
xForBodePhase = Log[10, scaledFreq];
bodePhaseTicks = {Automatic, Automatic}
)
];
If[Order[bodePhaseScales[[2]], "Degree"] == 0,
(
yLabelBodePhase = Text@Style["phase (deg)", labelFontSize];
yForBodePhase = Arg[hz /. w -> freq]*180/Pi
),
(
yLabelBodePhase = Style["phase (rad)", labelFontSize];
yForBodePhase = Arg[hz /. w -> freq]
)
];
ticks = Ticks -> {bodeMagTicks, bodePhaseTicks};
bodePlotOptions = {If[
showPlotsGrid, {GridLines -> Automatic,
GridLinesStyle -> Directive[{LightGray, Thickness[0.001]}]},
GridLines -> None], PlotStyle -> Red, AspectRatio -> 0.25,
PlotRangeClipping -> False};
bodePlot = BodePlot[tf, {0.001, 2*Pi - 0.0001},
Evaluate@
If[showStabilityMargins, {StabilityMargins -> True,
StabilityMarginsStyle -> {Blue, Blue}},
StabilityMargins -> False],
Frame -> False,
ScalingFunctions -> {bodeMagScales, bodePhaseScales},
Evaluate@bodePlotOptions,
ImageSize -> {{280, 121}, {280, 121}},
ImagePadding -> {{{25, 30}, {25, 25}}, {{25, 30}, {25, 25}}},
TicksStyle -> {Directive[8], Directive[8]},
PlotLayout -> "List",
PlotLabel ->
Evaluate@If[pt === None || Not[showToolTip ], {"", ""},
{Row[{Style["\[VerticalSeparator]H(", 10],
Style[padIt1[scaledFreq*180/Pi, {5, 2}], 10],
Style["\[Degree])\[VerticalSeparator] = ", 10],
Style[padIt1[yForBodeMag, {5, 2}], 10]}],
Row[{Style["Arg(H(", 10],
Style[padIt1[scaledFreq*180/Pi, {5, 2}], 10],
Style["\[Degree]) = ", 10],
Style[padIt2[yForBodePhase, {5, 2}], 10]}]
}
],
Evaluate@ticks,
PlotRange -> {{Full, Full}, {Full, Full}},
AxesLabel -> {{xLabelBodeMag, yLabelBodeMag}, {xLabelBodePhase,
yLabelBodePhase}}];
bodePhase = phaseBodePlot[bodePlot[[2]],
bodePhaseScales,
bodePlotOptions,
bodePhaseTicks,
{ImageSize -> {280, 121},
AspectRatio -> 0.33,
ImagePadding -> {{25, 30}, {5, 25}},
TicksStyle -> Directive[8],
Frame -> False,
Joined -> True,
Axes -> True,
AxesLabel -> {xLabelBodePhase, yLabelBodePhase},
PlotLabel -> Evaluate@If[pt === None || Not[showToolTip ], "",
Row[{Style["Arg(H(", 10],
Style[padIt1[scaledFreq*180/Pi, {5, 2}], 10],
Style["\[Degree]) = ", 10],
Style[padIt2[yForBodePhase, {5, 2}], 10]}]]
}];
If[pt === None || Not[showToolTip ],
Grid[{
{bodePlot[[1]]},
{bodePhase}
}, Spacings -> {0, 0}, Frame -> All,
FrameStyle -> Directive[Thickness[.001], LightGray],
Alignment -> Center],
Grid[{
{
Show[
bodePlot[[1]],
Graphics[{PointSize[0.03], Blue,
Point[{xForBodeMag, yForBodeMag}]}],
PlotRange -> All
]
},
{
Show[
bodePhase,
Graphics[{PointSize[0.03], Blue,
Point[{xForBodePhase, yForBodePhase}]}],
PlotRange -> All
]
}}, Spacings -> {0, 0}, Frame -> All,
FrameStyle -> Directive[Thickness[.001], LightGray],
Alignment -> Center]
]
];
(*---------------------------------------------------------*)
formatSPlane[p_, z_, ts_?(NumberQ[#] && Positive[#] &)] :=
Module[{},
{
Replace[
p, {x_, y_} :>
Tooltip[{PointSize[.2], White, Opacity -> 0, Point[{x, y}]},
Grid[{
{Row[{Style["(", 14], round[Chop@x, 2], Style[" , ", 10],
round[Chop@y, 2], Style[")", 14]}], SpanFromLeft},
{Style["\[Omega] = ", 10],
round[(Chop@Norm[{x, y}]*ts)/(2 Pi), 2],
Style["hz", Italic, 10]},
{Style["\[Zeta] = ",
10], -round[
Chop@Cos[If[Abs[x] < $MachineEpsilon, 0, ArcTan[x, y]]],
2]}
}, Spacings -> {0, 0}, Alignment -> Left]], {1}]
,
Replace[
z, {x_, y_} :>
Tooltip[{PointSize[.2], White, Opacity -> 0, Point[{x, y}]},
Grid[{
{Row[{Style["(", 14], round[Chop@x, 2], Style[" , ", 10],
round[Chop@y, 2], Style[")", 14]}]}
}, Spacings -> {0, 0}, Alignment -> Left]], {1}]
}
];
(*---------------------------------------------------------*)
gainPhaseMargins[tf_TransferFunctionModel, title_] :=
Module[{phasecross, gaincross, g, roundDelta = 3, len,
emptySpace = Text@Style[" ", 12]},
g = GainPhaseMargins[tf];
phasecross = g[[1]];
gaincross = g[[2]];
phasecross =
Replace[
phasecross, {{None, y_} :> {Text@Style["None", 12],
Text@Style[y, 12]}, {x_,
y_} :> {Text@Style[round2[x/(2*Pi), roundDelta], 12],
Text@Style[round2[y, roundDelta], 12]}}, {1}];
PrependTo[
phasecross, {Text@Style["phase crossover (hz)", 12],
Text@Style["gain margins", 12]}];
len = Length[phasecross];
If[len < 5,
Table[AppendTo[phasecross, {emptySpace, emptySpace}], {i, 1,
5 - len}]];
gaincross =
Replace[gaincross, {{None, y_} :> {Text@Style["None", 12],
Text@Style[y, 12]}, {x_,
y_} :> {Text@Style[round2[x/(2*Pi), roundDelta], 12],
Text@Style[round2[y*180/Pi, roundDelta], 12]}}, {1}];
PrependTo[
gaincross, {Text@Style["gain crossover (hz)", 12],
Text@Style["phase margins (deg)", 12]}];
len = Length[gaincross];
If[len < 5,
Table[AppendTo[gaincross, {emptySpace, emptySpace}], {i, 1,
5 - len}]];
Grid[{
{title},
{Grid[phasecross, Alignment -> Left, Spacings -> {.4, .2},
Frame -> All,
FrameStyle -> Directive[Thickness[.001], Gray]]},
{Grid[gaincross, Alignment -> Left, Spacings -> {.4, .2},
Frame -> All, FrameStyle -> Directive[Thickness[.001], Gray]]}
}, Frame -> None, Alignment -> Left, Spacings -> {0, 1}]
];
(*---------------------------------------------------------*)
process[z_,
ts_?(NumberQ[#] && Positive[#] &),
plotType_String,
simulationTime_?(NumberQ[#] && Positive[#] &),
rootLocusK_?(IntegerQ[#] &),
bodeMagScales_List,
bodePhaseScales_List,
mousePt_,
showToolTip_ /; (Element[showToolTip, Booleans]),
responseJoined_ /; (Element[responseJoined, Booleans]),
showPlotsGrid_ /; (Element[showPlotsGrid, Booleans]),
showStabilityMargins_ /; (Element[showStabilityMargins,
Booleans]),
tf_,
sys_,
ppoles_List,
zzeros_List,
hz_,
addContResponse_ /; (Element[addContResponse, Booleans]),
statusOfConversion_,
statusMessage_String,
polesInSPlane_List,
zerosInSPlane_List,
conversionType_String,
forcingFrequency_?(NumberQ[#] &)] :=
Module[{input, res, largestPole, numberOfZeros, numberOfPoles, n,
imageSize = {280, 240}, t, contResponse, poles, zeros, labels,
okToDisplayContPlot = True, discretePlotOptions,
analogPlotOptions},
{poles, zeros} = polesAndZerosAsList[ppoles, zzeros];
(*do not display analog repsonse for Bilinear when poles<-1*)
If[Length[Cases[poles, {x_, y_} /; x <= -1]] > 0,
If[conversionType == "BilinearTransform" ||
conversionType == "BackwardRectangularRule",
okToDisplayContPlot = False
]
];
If[Length[Cases[poles, {x_, y_} /; x <= 0]] > 0 &&
conversionType == "BackwardRectangularRule",
okToDisplayContPlot = False
];
largestPole = Max[Norm[#] & /@ poles];
numberOfPoles = Length[poles];
numberOfZeros = Length[zeros];
If[numberOfZeros > numberOfPoles,
Framed[
Text@Grid[{
{Style["Warning:", Red, 12]}
, {Row[{Style["number of zeros (", 12], numberOfZeros,
Style[")", 12]}]}
, {Row[{Style["is larger than number of poles (", 12],
numberOfPoles, ")."}]}
, {Style["Not a physical system.", 12]}
}, Spacings -> {0, 0}, Alignment -> Left]
],
{
discretePlotOptions = {Evaluate@
If[responseJoined,
Sequence[{Joined -> True,
InterpolationOrder -> 0}], {Filling -> Axis,
FillingStyle -> Red,
PlotMarkers ->
Graphics[{PointSize[0.05], Point[{0, 0}]}]}],
Evaluate@
If[showPlotsGrid, {GridLines -> Automatic,
GridLinesStyle ->
Directive[{LightGray, Thickness[0.001]}]},
GridLines -> None],
PlotRange -> All,
ImageSize -> imageSize,
ImagePadding -> {{40, 10}, {35, 10}},
AspectRatio -> 0.8,
AxesOrigin -> {0, 0},
FrameLabel -> {{None, None}, {Text[Style["time (sec)", 10]],
None}},
Frame -> True,
PlotStyle -> Red,
FrameTicksStyle -> Directive[Black, 8],
Axes -> None,
DataRange -> {0, simulationTime}};
analogPlotOptions = {Joined -> True, InterpolationOrder -> 0,
PlotRange -> All,
ImageSize -> imageSize,
ImagePadding -> {{40, 10}, {35, 10}},
AspectRatio -> 0.9,
AxesOrigin -> {0, 0},
PlotStyle -> {Dashed, Black},
FrameTicksStyle -> Directive[Black, 8],
DataRange -> {0, simulationTime},
Axes -> None};
Which[plotType == "Bode",
(
makeBodeDiagrams[mousePt, z, ts, bodeMagScales,
bodePhaseScales, showToolTip, hz, tf, showPlotsGrid,
showStabilityMargins]
),
plotType == "root Locus",
(
RootLocusPlot[
TransferFunctionModel[n hz, z, SamplingPeriod -> ts], {n, 0,
rootLocusK}, AspectRatio -> 0.7,
PlotRange -> {{-2, 2}, {-2, 2}},
PoleZeroMarkers -> {Text[Style["\[Times]", Red, 16]],
Automatic, Text[Style["\[EmptyCircle]", Black, 16]]},
ImageSize -> imageSize,
ImagePadding -> {{30, 10}, {25, 30}},
PerformanceGoal -> "Speed", MaxRecursion -> 1,
Method -> "NDSolve", PlotPoints -> 7]
),
plotType == "Nyquist",
(
Quiet[
NyquistPlot[tf, {-Pi, Pi},
ImagePadding -> {{30, 30}, {25, 30}}, Exclusions -> True,
PlotRange -> Automatic, ImageSize -> imageSize,
AxesLabel -> {"Re", "Im"},
Evaluate@
If[showPlotsGrid, NyquistGridLines -> Automatic,
NyquistGridLines -> None], PlotStyle -> Red,
PerformanceGoal -> "Speed", MaxRecursion -> 1,
Method -> "NDSolve", PlotPoints -> Automatic,
Evaluate@
If[showStabilityMargins, {StabilityMargins -> True,
StabilityMarginsStyle -> Blue},
StabilityMargins -> False], AspectRatio -> 1]]
),
plotType == "Nichols",
(
NicholsPlot[tf, {-Pi, Pi},
Evaluate@
If[showPlotsGrid, NicholsGridLines -> Automatic,
NicholsGridLines -> None],
ImagePadding -> {{30, 40}, {25, 30}},
ScalingFunctions -> {"Degree", "Absolute"},
AxesLabel -> {Text@
Column[{Style["phase", 10], Style["(deg)", 10]},
Alignment -> Center], Text[Style["magnitude", 10]]},
ImageSize -> imageSize,
PlotStyle -> Red,
AspectRatio -> 0.8,
PerformanceGoal -> "Speed", MaxRecursion -> 1,
Method -> "NDSolve",
Evaluate@
If[showStabilityMargins, {StabilityMargins -> True,
StabilityMarginsStyle -> Blue},
StabilityMargins -> False]]
),
plotType == "impulse",
(
res =
First@Simplify@
OutputResponse[tf,
DiscreteDelta[n], {n, 0, Ceiling[simulationTime/ts]}];
If[okToDisplayContPlot,
(
If[addContResponse && statusOfConversion,
(
contResponse =
Chop@First@
Simplify@
OutputResponse[sys,
DiracDelta[t], {t, 0, simulationTime}]
)
,
contResponse = {}
]
),
contResponse = {}
];
Show[
ListPlot[res, Sequence@discretePlotOptions],
Plot[ts*contResponse, {t, 0, simulationTime },
PlotRange -> All],
PlotRange -> All
]
),
plotType == "step",
(
input =
Table[{n, UnitStep[n]}, {n, 0, Ceiling[simulationTime/ts]}];
res =
First@Simplify@
OutputResponse[tf, UnitStep[n], {n, 0, simulationTime}];
If[okToDisplayContPlot,
(
If[addContResponse && statusOfConversion,
contResponse =
Chop@First@
OutputResponse[sys, UnitStep[t], {t, 0, simulationTime}]
,
contResponse = {}
]
),
contResponse = {}
];
Show[
ListPlot[res, Sequence@discretePlotOptions],
ListPlot[input[[All, 2]], Sequence@analogPlotOptions],
Plot[contResponse, {t, 0.001, simulationTime},
PlotRange -> All],
PlotRange -> All
]
),
plotType == "ramp",
(
input = Table[{n, n}, {n, 0, Ceiling[simulationTime/ts]}];
res = Simplify@OutputResponse[tf, input[[All, 2]]][[1]];
If[okToDisplayContPlot,
(
If[addContResponse && statusOfConversion,
(
contResponse =
First@Simplify@
OutputResponse[sys, t UnitStep[t], {t, simulationTime}]
),
(
contResponse = {}
)
]
),
contResponse = {}
];
Show[
ListPlot[res, Sequence@discretePlotOptions],
ListPlot[input[[All, 2]], Sequence@analogPlotOptions],
Plot[contResponse, {t, 0.001, simulationTime},
PlotRange -> All],
PlotRange -> All
]
),
plotType == "cos(2\[Pi]fn)",
(
input =
Table[{n, Cos[2 Pi forcingFrequency n]}, {n, 0,
Ceiling[simulationTime/ts]}];
res = Simplify@OutputResponse[tf, input[[All, 2]]][[1]];
If[okToDisplayContPlot,
(
If[addContResponse && statusOfConversion,
(
contResponse =
First@Simplify@
OutputResponse[sys,
Cos[2 Pi forcingFrequency t], {t, 0, simulationTime}]
),
(
contResponse = {}
)
]
),
contResponse = {}
];
Show[
ListPlot[res, Sequence@discretePlotOptions],
ListPlot[input[[All, 2]], Sequence@analogPlotOptions],
Plot[contResponse, {t, 0, simulationTime}, PlotRange -> All],
PlotRange -> All
]
),
plotType ==
"\!\(\*SuperscriptBox[\(\[ExponentialE]\), \(-n\)]\)cos(2\
\[Pi]fn)",
(
input =
Table[{n, Exp[-n] Cos[2 Pi forcingFrequency n]}, {n, 0,
Ceiling[simulationTime/ts]}];
res = Simplify@OutputResponse[tf, input[[All, 2]]][[1]];
If[okToDisplayContPlot,
(
If[addContResponse && statusOfConversion,
(
contResponse =
First@Simplify@
OutputResponse[sys,
Exp[-t] Cos[2 Pi forcingFrequency t], {t, 0,
simulationTime}]
),
(
contResponse = {}
)
]
),
contResponse = {}
];
Show[
ListPlot[res, Sequence@discretePlotOptions],
ListPlot[input[[All, 2]], Sequence@analogPlotOptions],
Plot[contResponse, {t, 0, simulationTime}, PlotRange -> All],
PlotRange -> All
]
),
plotType == "H(z) margins",
(
gainPhaseMargins[tf,
Text@Style["discrete system gain phase margins", 12]]
),
plotType == "H(s) margins",
(
gainPhaseMargins[sys,
Text@Style["continuous system gain phase margins", 12]]
),
plotType == "S-plane map",
(
If[statusOfConversion,
(
sPoles = Replace[polesInSPlane, x_ :> {Re[x], Im[x]}, {1}];
sZeros = Replace[zerosInSPlane, x_ :> {Re[x], Im[x]}, {1}];
labels = formatSPlane[sPoles, sZeros, ts];
Show[
ListPlot[{sPoles, sZeros},
AxesOrigin -> {0, 0},
PlotMarkers -> {Style["\[Cross]", 18, Bold, Red],
Style["\[EmptyCircle]", 16, Bold, Red]},
PlotRange -> {Automatic, Automatic},
ImageSize -> imageSize,
ImagePadding -> {{45, 45}, {25, 25}},
Frame -> False,
Axes -> True,
AxesStyle -> Thick,
Ticks -> None,
PlotRangeClipping -> False,
GridLines -> Automatic,
GridLinesStyle -> {{Thickness[0.005],
LightGray}, {Thickness[0.005], LightGray}},
AspectRatio -> 1,
AxesLabel -> {Text@
Row[{Style["Re(", 10], Style["s", Italic, 10],
Style[")", 10]}],
Text@Row[{Style["Im(", 10], Style["s", Italic, 10],
Style[")", 10]}]},
ImageMargins -> 0, Epilog -> {labels}],
PlotRange -> All
]
),
(
Graphics[Text[Style[statusMessage, Red, 10]],
ImageSize -> imageSize]
)
]
)
]
}
]
];
)
]