#set document(title: "4.1 Linear Phase Portraits", author: "XYZ Homework") #set page(width: 8.5in, height: auto, margin: 1in) #import "@preview/cetz:0.5.2" #set text(font: ("STIX Two Text", "Libertinus Serif", "New Computer Modern"), size: 10.5pt, lang: "en") #show math.equation: set text(font: ("STIX Two Math", "New Computer Modern Math")) #set par(justify: true, leading: 0.62em, spacing: 0.9em) #set enum(spacing: 1.1em) // room between list items so tall inline fractions don't collide #set list(spacing: 1.1em) #set table(stroke: 0.5pt + rgb("#c7ccd3")) #let BLUE = rgb("#183B6F") // brand navy — section bars + example/solution labels (white on navy 11.09:1) #let ORANGE = rgb("#A94509") // brand primary-700 — AA-safe deep orange for TEXT (5.93:1 on white; raw brand #F37021 is 2.94:1 and must never carry text) #let RED = rgb("#DC2626") // brand error-600 #let GREEN = rgb("#059669") // brand success-600 (decoration only; small green text uses green-text #007942) #show heading.where(level: 1): it => block(width: 100%, above: 0pt, below: 16pt, fill: gradient.linear(BLUE, rgb("#2C5AA0")), inset: (x: 14pt, y: 12pt), radius: 3pt, text(fill: white, weight: "bold", size: 19pt, it.body)) #show heading.where(level: 2): it => block(width: 100%, above: 18pt, below: 10pt, fill: BLUE, inset: (x: 10pt, y: 6pt), radius: 2pt, text(fill: white, weight: "bold", size: 12pt, it.body)) #show heading.where(level: 3): it => text(fill: ORANGE, weight: "bold", size: 12.5pt, it.body) #show heading.where(level: 4): it => text(fill: BLUE, weight: "bold", size: 10.5pt, it.body) #let examplebox(label, title, body) = block(width: 100%, breakable: true, fill: rgb("#EFF1F5"), stroke: 0.5pt + rgb("#CFDDF0"), radius: 4pt, inset: 10pt, above: 12pt, below: 12pt)[ #block(below: 6pt)[#box(fill: BLUE, inset: (x: 6pt, y: 2pt), radius: 2pt, text(fill: white, weight: "bold", size: 8.5pt, label)) #h(0.4em) #strong[#title]] #body] // rail = decorative left rule (raw brand token); labelcolor = AA-safe label text shade #let notebox(label, rail, labelcolor, tint, body) = block(width: 100%, breakable: true, fill: tint, stroke: (left: 3pt + rail), inset: (left: 10pt, rest: 8pt), radius: (right: 4pt), above: 11pt, below: 11pt)[ #text(fill: labelcolor, weight: "bold", size: 7.5pt, tracking: 0.5pt)[#upper(label)] #linebreak() #body] #let solutionbox(body) = block(above: 4pt, below: 8pt)[ #text(fill: BLUE, weight: "bold", size: 8.5pt)[Solution] #linebreak() #body] #let figph(msg) = block(width: 100%, height: 60pt, fill: rgb("#f6f7f9"), stroke: (paint: rgb("#c7ccd3"), dash: "dashed"), radius: 4pt, inset: 10pt)[ #align(center + horizon, text(fill: rgb("#889"), style: "italic", size: 9pt, msg))] // Standardize inlined figure sizes: measure the natural CeTZ canvas, then scale to a // consistent envelope (aspect-aware; see build_typst.py FIG_* constants). Unlike the // print preamble, dimensions are FLOORED: in an editor a user can trim a figure to a // degenerate 1-D shape (a bare line), and w/h or tw/w would then divide by zero. #let _STD_W = 3.5 #let _WIDE_W = 5.6 #let _MAX_H = 3.4 #let _ASPECT_WIDE = 2.2 #let _UPSCALE_MAX = 1.15 #let stdfig(body) = context { let m = measure(body) let w = calc.max(m.width / 1in, 0.01) let h = calc.max(m.height / 1in, 0.01) let tw = if w / h > _ASPECT_WIDE { _WIDE_W } else { _STD_W } let s = calc.min(tw / w, _MAX_H / h, _UPSCALE_MAX) align(center, box(scale(x: s * 100%, y: s * 100%, reflow: true, body))) } #show figure: set block(breakable: false) #set figure(gap: 8pt) #show figure.caption: set text(size: 8.5pt, fill: rgb("#555")) == 4.1#h(0.6em)Linear Phase Portraits #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Objectives] - Solve a linear system with real eigenvalues and eliminate time to find the equation of its orbits. - Read the invariant straight lines of a phase portrait as the system's eigendirections. - Explain how two different solutions can trace the same orbit, and why the portrait discards the clock. ] The simplest system of two equations is one whose equations ignore each other: #math.equation(block: true, alt: "x prime equals x , y prime equals minus y .")[$x^(′) = x , #h(2em) y^(′) = − y .$] Each unknown solves on its own: #math.equation(block: false, alt: "x open parenthesis t close parenthesis equals x sub 0 e to the power t")[$x ( t ) = x_(0) e^(t)$] grows, #math.equation(block: false, alt: "y open parenthesis t close parenthesis equals y sub 0 e to the power minus t")[$y ( t ) = y_(0) e^(− t)$] decays. The two rates, #math.equation(block: false, alt: "plus 1")[$+ 1$] and #math.equation(block: false, alt: "minus 1")[$− 1$], are the system's #emph[eigenvalues], and the directions along which the motion is pure exponential growth or pure exponential decay — here, the coordinate axes — are its #emph[eigendirections]. A state on the positive #math.equation(block: false, alt: "x")[$x$]-axis flees the origin along it forever; a state on the #math.equation(block: false, alt: "y")[$y$]-axis slides down it toward the origin forever. Every other state feels both influences at once. What does "both at once" look like? A solution is a moving point #math.equation(block: false, alt: "open parenthesis x open parenthesis t close parenthesis , y open parenthesis t close parenthesis close parenthesis")[$( x ( t ) , y ( t ) )$], and eliminating time exposes its path: the product #math.equation(block: false, alt: "x open parenthesis t close parenthesis y open parenthesis t close parenthesis equals x sub 0 y sub 0 e to the power t e to the power minus t equals x sub 0 y sub 0")[$x ( t ) y ( t ) = x_(0) y_(0) e^(t) e^(− t) = x_(0) y_(0)$] never changes. Every orbit lies on a hyperbola #math.equation(block: false, alt: "x y equals c")[$x y = c$] (or, when #math.equation(block: false, alt: "c equals 0")[$c = 0$], on an axis). The figure draws three of them. {"camera":{"fov":50,"position":\[3,5,24\],"projection":"perspective","target":\[3,5,0\]},"grid":{"axisColors":{"x":"\#ef4444","y":"\#22c55e","z":"\#3b82f6"},"divisions":20,"gridColor":"\#e5e7eb","showAxes":true,"showLabels":true,"size":20,"visible":true},"id":"b5c5dedb-b309-4f4b-8d8c-36c42e1e06a1","metadata":{"alt\_text":"Three hyperbola-shaped arcs in the plane, viewed face-on: a red and a green arc sweeping through the upper-right quadrant toward the horizontal axis, and a blue arc mirrored into the upper-left quadrant. Each arc rides in along the vertical axis direction and out along the horizontal axis direction, the signature flow of a saddle point at the origin.","created\_at":"2026-08-01T00:00:00.000Z","description":"Three representative solution curves (x, y) = (c e^t, d e^(-t)) of the saddle system x' = x, y' = -y, for t in \[-2, 2\]: through (1, 2), (-1, 1), and (2, 1). The axes are the invariant eigendirections; no sliders.","tags":\["diffeq","systems","phase-plane","saddle","eigenvalues"\],"updated\_at":"2026-08-01T00:00:00.000Z"},"objects":\[{"id":"5bc04d8d-d920-4c19-984a-7969ea1595e3","kind":"parametric-curve","label":{"text":"orbit through (1, 2)","visible":true},"samples":600,"style":{"color":"\#ef4444","dash":\[\],"lineWidth":4},"tDomain":\[-2,2\],"visible":true,"xExpr":"exp(t)","yExpr":"2\*exp(-t)","zExpr":"0"},{"id":"868a2353-dc5d-43c0-91fe-aec8974491d8","kind":"parametric-curve","label":{"text":"orbit through (-1, 1)","visible":true},"samples":600,"style":{"color":"\#3b82f6","dash":\[\],"lineWidth":4},"tDomain":\[-2,2\],"visible":true,"xExpr":"-exp(t)","yExpr":"exp(-t)","zExpr":"0"},{"id":"113bbfc4-f90d-495f-af67-28073fbfdbce","kind":"parametric-curve","label":{"text":"orbit through (2, 1)","visible":true},"samples":600,"style":{"color":"\#16a34a","dash":\[\],"lineWidth":4},"tDomain":\[-2,2\],"visible":true,"xExpr":"2\*exp(t)","yExpr":"exp(-t)","zExpr":"0"}\],"title":"Saddle orbits of x' = x, y' = -y","version":1} Three orbits of the saddle system #math.equation(block: false, alt: "x prime equals x")[$x^(′) = x$], #math.equation(block: false, alt: "y prime equals minus y")[$y^(′) = − y$], viewed face-on, each drawn for #math.equation(block: false, alt: "minus 2 less than or equal to t less than or equal to 2")[$− 2 ≤ t ≤ 2$]: red through #math.equation(block: false, alt: "open parenthesis 1 , 2 close parenthesis")[$( 1 , 2 )$], green through #math.equation(block: false, alt: "open parenthesis 2 , 1 close parenthesis")[$( 2 , 1 )$], and blue through #math.equation(block: false, alt: "open parenthesis minus 1 , 1 close parenthesis")[$( − 1 , 1 )$]. Each arc sweeps in along the vertical direction and out along the horizontal — the axes are the eigendirections, the only straight-line orbits. === Explore + #strong[Observe.] Follow the red arc in the direction of increasing time. At #math.equation(block: false, alt: "t equals minus 2")[$t = − 2$] it sits at #math.equation(block: false, alt: "open parenthesis 0.14 , 14.8 close parenthesis")[$( 0.14 , 14.8 )$], high against the vertical axis; by #math.equation(block: false, alt: "t equals 2")[$t = 2$] it has swept down and out to #math.equation(block: false, alt: "open parenthesis 7.4 , 0.27 close parenthesis")[$( 7.4 , 0.27 )$], flat along the horizontal. It falls in toward the origin, turns, and flees — and never actually arrives anywhere. + #strong[Predict.] The red orbit passes through #math.equation(block: false, alt: "open parenthesis 1 , 2 close parenthesis")[$( 1 , 2 )$] and the green through #math.equation(block: false, alt: "open parenthesis 2 , 1 close parenthesis")[$( 2 , 1 )$]. Compute #math.equation(block: false, alt: "x y")[$x y$] for each point before looking closely: are these two different hyperbolas, or two pieces of the same one? + #strong[Verify.] Both products equal #math.equation(block: false, alt: "2")[$2$] — one hyperbola, #math.equation(block: false, alt: "x y equals 2")[$x y = 2$]. Check the shared point #math.equation(block: false, alt: "open parenthesis 2 , 1 close parenthesis")[$( 2 , 1 )$]: the red solution reaches it at #math.equation(block: false, alt: "t equals ln 2 approximately equals 0.69")[$t = ln 2 ≈ 0.69$], while the green solution starts there at #math.equation(block: false, alt: "t equals 0")[$t = 0$]. Two different solutions, one orbit. + #strong[Observe.] The blue arc, through #math.equation(block: false, alt: "open parenthesis minus 1 , 1 close parenthesis")[$( − 1 , 1 )$], rides the branch #math.equation(block: false, alt: "x y equals minus 1")[$x y = − 1$] in the second quadrant — the same shape, mirrored. Notice that no arc ever touches an axis: on the vertical axis #math.equation(block: false, alt: "x equals 0")[$x = 0$] forces #math.equation(block: false, alt: "x prime equals 0")[$x^(′) = 0$], so a state born on an axis stays on it forever. The eigendirections are #emph[invariant lines], and other orbits can only approach them. + #strong[Predict, then reason.] Suppose both equations drained: #math.equation(block: false, alt: "x prime equals minus x")[$x^(′) = − x$], #math.equation(block: false, alt: "y prime equals minus y")[$y^(′) = − y$]. No figure needed — what quantity is now constant along orbits in place of #math.equation(block: false, alt: "x y")[$x y$], what shape are the orbits, and where does every state end up? === Connect The example generalizes further than it looks. A general linear system #math.equation(block: false, alt: "x prime equals a x plus b y")[$x^(′) = a x + b y$], #math.equation(block: false, alt: "y prime equals c x plus d y")[$y^(′) = c x + d y$] hides its rates, but they are still there: along each eigendirection the motion is a pure exponential #math.equation(block: false, alt: "e to the power λ t")[$e^(λ t)$], and the pair of eigenvalues classifies the portrait completely. Real eigenvalues of opposite sign give a #emph[saddle] — this figure: in along one direction, out along the other, hyperbolic arcs between. Real eigenvalues of the same sign give a #emph[node]: every orbit sweeps into the origin (both negative) or out of it (both positive), with no way around. Complex eigenvalues #math.equation(block: false, alt: "α ± i β")[$α ± i β$] give a #emph[spiral] — rotation at rate #math.equation(block: false, alt: "β")[$β$] with amplitude #math.equation(block: false, alt: "e to the power α t")[$e^(α t)$]; the phase loop of Chapter 2 was exactly this, eigenvalues #math.equation(block: false, alt: "minus a ± i b")[$− a ± i b$]. And purely imaginary eigenvalues give a #emph[center], the closed ellipses of the undamped spring. It is the damping-regime trichotomy again, wearing geometric clothes. The portrait forgets the clock, and does so deliberately. Because the system is #emph[autonomous] — time appears nowhere on the right-hand sides — delaying a solution produces another solution, and both trace the same curve. That is what the Explore steps uncovered: the green solution is the red one delayed by #math.equation(block: false, alt: "ln 2")[$ln 2$]. An orbit is a road; a solution is a journey along it with a schedule. The phase portrait is the road map — every road, no schedules — and that economy is why one still image can hold every possible history of the system at once. #examplebox("Example 1")[A saddle in disguise][ Classify the system #math.equation(block: false, alt: "x prime equals y")[$x^(′) = y$], #math.equation(block: false, alt: "y prime equals x")[$y^(′) = x$] and find its orbits. Nothing is decoupled here — but the combinations #math.equation(block: false, alt: "u equals x plus y")[$u = x + y$] and #math.equation(block: false, alt: "v equals x minus y")[$v = x − y$] are: #math.equation(block: false, alt: "u prime equals x prime plus y prime equals y plus x equals u")[$u^(′) = x^(′) + y^(′) = y + x = u$] and #math.equation(block: false, alt: "v prime equals x prime minus y prime equals y minus x equals minus v")[$v^(′) = x^(′) − y^(′) = y − x = − v$]. So #math.equation(block: false, alt: "u equals u sub 0 e to the power t")[$u = u_(0) e^(t)$] and #math.equation(block: false, alt: "v equals v sub 0 e to the power minus t")[$v = v_(0) e^(− t)$]: the same saddle as the figure, rotated onto new axes. The eigenvalues are again #math.equation(block: false, alt: "1")[$1$] and #math.equation(block: false, alt: "minus 1")[$− 1$]; the eigendirections are the diagonals #math.equation(block: false, alt: "y equals x")[$y = x$] (growing) and #math.equation(block: false, alt: "y equals minus x")[$y = − x$] (decaying); and the conserved product is #math.equation(block: false, alt: "u v equals open parenthesis x plus y close parenthesis open parenthesis x minus y close parenthesis equals x squared minus y squared")[$u v = ( x + y ) ( x − y ) = x^(2) − y^(2)$], so the orbits are the hyperbolas #math.equation(block: false, alt: "x squared minus y squared equals c")[$x^(2) − y^(2) = c$]. A state on the line #math.equation(block: false, alt: "y equals minus x")[$y = − x$] slides into the origin; a state anywhere else eventually escapes along the direction of #math.equation(block: false, alt: "y equals x")[$y = x$]. Keep this example in hand — it returns in the next section as the local picture beside a pendulum balanced upside down. ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ Eigenvalues classify, eigendirections carry the straight-line orbits, and everything else interpolates between them: saddle for opposite signs, node for equal signs, spiral for complex pairs. The phase portrait shows every solution at once by forgetting #emph[when] and keeping only #emph[where]. ]