# The Bridge to Nonlinearity ## Introduction: When Linear Theory Breaks Down In Module 1, we studied the harmonic oscillator where the restoring force is proportional to displacement: $F = -ky$. This linearity gave us exact sinusoidal solutions, constant frequency independent of amplitude, and the principle of superposition. But real physical systems rarely maintain perfect linearity, especially for larger displacements. In this module, we explore what happens when we include the next term in the Taylor series expansion of the restoring force—leading us from the familiar pendulum to the celebrated Duffing oscillator. ## From Pendulum to Duffing: A Natural Progression ### The Exact Pendulum Equation Consider a mass $m$ attached to a rigid, weightless rod of length $L$, free to rotate in a vertical plane about a frictionless pivot. The equation of motion is: $mL\ddot{\theta} + \gamma L\dot{\theta} + mg\sin(\theta) = f(t)$ where: - $\theta$ = angular displacement from vertical (positive counterclockwise) - $\gamma$ = Stokes' drag coefficient - $g$ = gravitational acceleration - $f(t)$ = external forcing ![[Teaching/MATH310/Lecture Notes/Nonlinear Oscillators/Oscillators - Bridge to Nonlinearity/pendulum_diagram.png]] *Figure: Forces acting on a pendulum showing the gravitational components and angular displacement* The nonlinearity enters through $\sin(\theta)$—a transcendental function that makes exact analytical solutions impossible for large amplitudes. ### The Hierarchy of Approximations To understand this nonlinearity, we expand $\sin(\theta)$ in a [Taylor series](https://en.wikipedia.org/wiki/Taylor_series): $\sin(\theta) = \theta - \frac{\theta^3}{3!} + \frac{\theta^5}{5!} - \cdots$ This leads to a hierarchy of approximations: #### 1. Linear (Small Angle) Approximation For $|\theta| \ll 1$, keeping only the first term: $\ddot{\theta} + \omega^2\theta = 0, \quad \text{where } \omega^2 = \frac{g}{L}$ This is our familiar harmonic oscillator with frequency $\omega$ independent of amplitude. #### 2. Cubic (Duffing) Approximation Keeping the first two terms: $\ddot{\theta} + \omega^2\left(\theta - \frac{\theta^3}{6}\right) = 0$ Rescaling by defining $y = \theta$ and rearranging: $m\ddot{y} + k_1 y + k_3 y^3 = 0$ where $k_1 = mg/L$ and $k_3 = -mg/(6L)$. This is the **Duffing equation**—the simplest nonlinear oscillator that captures essential features missing from linear theory. ## The Duffing Oscillator: A Universal Model ### General Form The Duffing oscillator represents any system with a cubic nonlinearity: $m\ddot{y} + \gamma\dot{y} + k_1 y + k_3 y^3 = f(t)$ The force law: $F_s(y) = -k_1 y - k_3 y^3$ represents the next odd term (preserving symmetry) in the Taylor expansion of a general [nonlinear spring](https://en.wikipedia.org/wiki/Nonlinear_system) force. ### Classification: Soft vs. Hard Springs The sign of $k_3$ fundamentally changes the system's behavior: #### Hard Spring ($k_3 > 0$) - Restoring force **increases** faster than linear for large displacements - Spring "hardens" or "supports" the linear term - Frequency **increases** with amplitude - Physical example: Stretched elastic materials approaching their limit #### Soft Spring ($k_3 < 0$) - Restoring force **increases** slower than linear for large displacements - Cubic term "retards" the linear term - Frequency **decreases** with amplitude - Physical example: Pendulum for moderate angles The pendulum naturally gives a soft spring with $k_3 = -mg/(6L) < 0$. ## Energy and Phase Space Structure ### The Nonlinear Hamiltonian For the conservative Duffing oscillator ($\gamma = 0$, $f(t) = 0$): $H(y, \dot{y}) = \frac{m\dot{y}^2}{2} + \frac{k_1 y^2}{2} + \frac{k_3 y^4}{4}$ This energy function consists of: - Kinetic energy: $T = \frac{m\dot{y}^2}{2}$ - Potential energy: $V(y) = \frac{k_1 y^2}{2} + \frac{k_3 y^4}{4}$ ### Numerical Demonstration: Energy Surfaces The Hamiltonian structure reveals how energy determines the allowed phase space trajectories. #### Implementation ## Python Step 1. Define the energy functions ```python import numpy as np import matplotlib.pyplot as plt class DuffingEnergy: def __init__(self, k1=1.0, k3=0.1, m=1.0): self.k1 = k1 self.k3 = k3 self.m = m def potential(self, y): """Potential energy V(y)""" return 0.5*self.k1*y**2 + 0.25*self.k3*y**4 def hamiltonian(self, y, v): """Total energy H(y,v) = T + V""" return 0.5*self.m*v**2 + self.potential(y) ``` Step 2. Visualize phase space contours ```python # Create mesh y = np.linspace(-2.5, 2.5, 100) v = np.linspace(-2, 2, 100) Y, V = np.meshgrid(y, v) # Calculate energy surface duff = DuffingEnergy(k1=-1.0, k3=0.5) # Double well H = duff.hamiltonian(Y, V) # Plot contours plt.contour(Y, V, H, levels=15) plt.xlabel('Position y') plt.ylabel('Velocity v') plt.title('Phase Space Energy Contours') plt.grid(True) plt.show() ``` ## R Step 1. Define the energy functions ```r # Create Duffing energy calculator create_duffing_energy <- function(k1 = 1.0, k3 = 0.1, m = 1.0) { list(k1 = k1, k3 = k3, m = m) } # Potential energy V(y) potential <- function(duff, y) { 0.5 * duff$k1 * y^2 + 0.25 * duff$k3 * y^4 } # Total energy H(y,v) = T + V hamiltonian <- function(duff, y, v) { 0.5 * duff$m * v^2 + potential(duff, y) } ``` Step 2. Visualize phase space contours ```r # Create mesh y <- seq(-2.5, 2.5, length.out = 100) v <- seq(-2, 2, length.out = 100) mesh <- expand.grid(y = y, v = v) # Calculate energy surface duff <- create_duffing_energy(k1 = -1.0, k3 = 0.5) # Double well H <- hamiltonian(duff, mesh$y, mesh$v) H_matrix <- matrix(H, nrow = length(y), ncol = length(v)) # Plot contours contour(y, v, H_matrix, nlevels = 15, xlab = "Position y", ylab = "Velocity v", main = "Phase Space Energy Contours") grid() ``` ## MATLAB Step 1. Define the energy functions ```matlab function duff = create_duffing_energy(k1, k3, m) if nargin < 1, k1 = 1.0; end if nargin < 2, k3 = 0.1; end if nargin < 3, m = 1.0; end duff.k1 = k1; duff.k3 = k3; duff.m = m; end function V = potential(duff, y) V = 0.5 * duff.k1 * y.^2 + 0.25 * duff.k3 * y.^4; end function H = hamiltonian(duff, y, v) H = 0.5 * duff.m * v.^2 + potential(duff, y); end ``` Step 2. Visualize phase space contours ```matlab % Create mesh y = linspace(-2.5, 2.5, 100); v = linspace(-2, 2, 100); [Y, V] = meshgrid(y, v); % Calculate energy surface duff = create_duffing_energy(-1.0, 0.5, 1.0); % Double well H = hamiltonian(duff, Y, V); % Plot contours contour(Y, V, H, 15); xlabel('Position y'); ylabel('Velocity v'); title('Phase Space Energy Contours'); grid on; ``` #### Results ![[Teaching/MATH310/Lecture Notes/Nonlinear Oscillators/Oscillators - Bridge to Nonlinearity/phase_space_verification.png]] *Figure: Phase space structures for different spring types, showing how nonlinearity affects the shape of trajectories.* The energy surfaces reveal distinct behaviors: - **Single well (k₁ > 0)**: Closed orbits at all energies - **Double well (k₁ < 0, k₃ > 0)**: Separatrix divides phase space - **Energy conservation**: Trajectories follow constant energy contours **Complete code**: `Module2_Bridge_to_Nonlinearity/codes/duffing_energy_surfaces_FAST.py` #### Exploration Exercises 1. **3D visualization**: Plot the Hamiltonian as a 3D surface. 2. **Poincaré sections**: Sample the phase space at regular intervals. 3. **Action-angle variables**: Transform to canonical coordinates. ### Potential Energy Landscapes The potential $V(y)$ determines the system's qualitative behavior: #### Case 1: $k_1 > 0$ (Single Well) - Potential has a single minimum at $y = 0$ - All trajectories are bounded oscillations - Phase portrait shows nested closed curves (centers) #### Case 2: $k_1 < 0, k_3 > 0$ (Double Well) - Potential has two minima at $y = \pm\sqrt{-k_1/k_3}$ - Local maximum at $y = 0$ (unstable equilibrium) - Phase portrait shows: - Small oscillations in each well - Large oscillations over both wells - Separatrix dividing these regions ### Phase Space Trajectories From energy conservation, trajectories satisfy: $H(y, \dot{y}) = E = \text{constant}$ Solving for velocity: $\dot{y} = \pm\sqrt{\frac{2(E - V(y))}{m}}$ This gives the phase space trajectory implicitly. The ± sign indicates clockwise motion in phase space. ### Critical Points and Stability Equilibrium points occur where $\dot{y} = 0$ and $\ddot{y} = 0$: $k_1 y + k_3 y^3 = 0$ Solutions: - $y = 0$ (always an equilibrium) - $y = \pm\sqrt{-k_1/k_3}$ (exist only if $k_1$ and $k_3$ have opposite signs) Stability determined by the linearized system: - **Center**: Stable equilibrium with purely imaginary eigenvalues (oscillatory) - **Saddle**: Unstable equilibrium with real eigenvalues of opposite sign - **Separatrix**: Special trajectory connecting saddle points, dividing phase space into regions with qualitatively different motion ![[Teaching/MATH310/Lecture Notes/Nonlinear Oscillators/Oscillators - Bridge to Nonlinearity/phase_portraits_comparison.png]] *Figure: Phase portrait showing centers, saddle points, and the separatrix in a nonlinear system* ## Amplitude-Dependent Phenomena ### Nonlinear Frequency Shift Unlike the harmonic oscillator, the Duffing oscillator's frequency depends on amplitude. We can derive this through perturbation analysis. #### Perturbation Expansion Method Starting with the normalized Duffing equation where the potential is: $V(q) = \frac{1}{2}m\omega_0^2 q^2 + \frac{1}{4}\varepsilon m q^4$ We expand the solution in powers of the perturbation parameter $\varepsilon$: $q(t) = q_0(t) + \varepsilon q_1(t) + \varepsilon^2 q_2(t) + \cdots$ This leads to a hierarchy of linear equations: - Order $\varepsilon^0$: $\ddot{q}_0 + \omega_0^2 q_0 = 0$ - Order $\varepsilon^1$: $\ddot{q}_1 + \omega_0^2 q_1 + q_0^3 = 0$ #### The Resonance Problem For initial conditions $q_0(0) = a$ and $\dot{q}_0(0) = 0$, we have $q_0(t) = a\cos(\omega_0 t)$. Substituting into the $\varepsilon^1$ equation: $\ddot{q}_1 + \omega_0^2 q_1 = -a^3\cos^3(\omega_0 t) = -\frac{a^3}{4}[3\cos(\omega_0 t) + \cos(3\omega_0 t)]$ The dangerous term $3\cos(\omega_0 t)$ resonates with the natural frequency, leading to a solution containing: $q_1(t) \sim -\frac{3a^3}{8\omega_0} t \sin(\omega_0 t)$ This **secular term** grows linearly with time, violating energy conservation! #### Frequency Renormalization To resolve this, we recognize that the frequency itself must be modified by the nonlinearity: $\omega(\varepsilon) = \omega_0 + \varepsilon\omega_1 + \varepsilon^2\omega_2 + \cdots$ By choosing: $\omega_1 = \frac{3a^2}{8\omega_0}$ we suppress the resonance, yielding the **amplitude-dependent frequency**: $\boxed{\omega(a) = \omega_0 + \varepsilon\frac{3a^2}{8\omega_0} + O(\varepsilon^2)}$ ### Numerical Demonstration: Amplitude-Frequency Relationship The frequency shift can be verified numerically by measuring oscillation periods at different amplitudes. #### Implementation Strategy ## Python Step 1. Define the Duffing oscillator class ```python import numpy as np import matplotlib.pyplot as plt from scipy.integrate import solve_ivp from scipy.signal import find_peaks class DuffingOscillator: def __init__(self, k1=1.0, k3=0.1, m=1.0): self.k1 = k1 self.k3 = k3 self.m = m self.omega0 = np.sqrt(k1/m) if k1 > 0 else 0 def dynamics(self, t, state): """ODE system for Duffing oscillator""" y, v = state return [v, -(self.k1*y + self.k3*y**3)/self.m] def perturbation_frequency(self, amplitude): """Theoretical frequency from perturbation theory""" if self.omega0 == 0: return 0 epsilon = self.k3/self.k1 return self.omega0 + epsilon * 3*amplitude**2/(8*self.omega0) ``` Step 2. Measure frequency numerically ```python def measure_frequency(self, amplitude, t_max=50): """Measure frequency using peak detection""" # Solve ODE sol = solve_ivp(self.dynamics, [0, t_max], [amplitude, 0], method='RK45', rtol=1e-8) # Find peaks and compute period peaks, _ = find_peaks(sol.y[0], height=amplitude*0.8) if len(peaks) > 1: period = np.mean(np.diff(sol.t[peaks])) return 2*np.pi/period return self.omega0 ``` Step 3. Compare hard and soft springs ```python # Test parameters oscillators = { 'Linear': DuffingOscillator(k1=1.0, k3=0.0), 'Hard Spring': DuffingOscillator(k1=1.0, k3=0.5), 'Soft Spring': DuffingOscillator(k1=1.0, k3=-0.3) } amplitudes = np.linspace(0.1, 2.0, 10) plt.figure(figsize=(10, 6)) for name, osc in oscillators.items(): frequencies = [osc.measure_frequency(a) for a in amplitudes] plt.plot(amplitudes, frequencies, 'o-', label=name, linewidth=2) plt.xlabel('Amplitude') plt.ylabel('Frequency (rad/s)') plt.title('Amplitude-Frequency Relationship') plt.legend() plt.grid(True) plt.show() ``` ## R Step 1. Define the Duffing oscillator functions ```r library(deSolve) library(pracma) # Create Duffing oscillator create_duffing <- function(k1 = 1.0, k3 = 0.1, m = 1.0) { list( k1 = k1, k3 = k3, m = m, omega0 = if (k1 > 0) sqrt(k1/m) else 0 ) } # ODE dynamics duffing_dynamics <- function(t, state, parameters) { with(as.list(c(state, parameters)), { dy <- v dv <- -(k1*y + k3*y^3)/m list(c(dy, dv)) }) } # Theoretical frequency from perturbation theory perturbation_frequency <- function(osc, amplitude) { if (osc$omega0 == 0) return(0) epsilon <- osc$k3/osc$k1 osc$omega0 + epsilon * 3*amplitude^2/(8*osc$omega0) } ``` Step 2. Measure frequency numerically ```r measure_frequency <- function(osc, amplitude, t_max = 50) { # Initial conditions y0 <- c(y = amplitude, v = 0) times <- seq(0, t_max, length.out = 5000) # Parameters for ODE parms <- list(k1 = osc$k1, k3 = osc$k3, m = osc$m) # Solve ODE sol <- ode(y = y0, times = times, func = duffing_dynamics, parms = parms, method = "ode45", rtol = 1e-8) # Find peaks to determine period peaks <- findpeaks(sol[, "y"], minpeakheight = amplitude * 0.8) if (!is.null(peaks) && nrow(peaks) > 1) { peak_indices <- peaks[, 2] periods <- diff(times[peak_indices]) avg_period <- mean(periods) frequency <- 2*pi/avg_period return(frequency) } return(osc$omega0) } ``` Step 3. Compare hard and soft springs ```r # Create oscillators oscillators <- list( Linear = create_duffing(k1 = 1.0, k3 = 0.0), HardSpring = create_duffing(k1 = 1.0, k3 = 0.5), SoftSpring = create_duffing(k1 = 1.0, k3 = -0.3) ) amplitudes <- seq(0.1, 2.0, length.out = 10) # Plot setup plot(NULL, xlim = range(amplitudes), ylim = c(0.5, 1.5), xlab = "Amplitude", ylab = "Frequency (rad/s)", main = "Amplitude-Frequency Relationship") colors <- c("black", "red", "blue") for (i in seq_along(oscillators)) { osc <- oscillators[[i]] frequencies <- sapply(amplitudes, function(a) measure_frequency(osc, a)) lines(amplitudes, frequencies, col = colors[i], lwd = 2) points(amplitudes, frequencies, col = colors[i], pch = 19) } legend("topright", names(oscillators), col = colors, lwd = 2, pch = 19) grid() ``` ## MATLAB Step 1. Define the Duffing oscillator functions ```matlab function osc = create_duffing(k1, k3, m) if nargin < 1, k1 = 1.0; end if nargin < 2, k3 = 0.1; end if nargin < 3, m = 1.0; end osc.k1 = k1; osc.k3 = k3; osc.m = m; if k1 > 0 osc.omega0 = sqrt(k1/m); else osc.omega0 = 0; end end function dydt = duffing_dynamics(t, state, osc) y = state(1); v = state(2); dydt = zeros(2,1); dydt(1) = v; dydt(2) = -(osc.k1*y + osc.k3*y^3)/osc.m; end function freq = perturbation_frequency(osc, amplitude) if osc.omega0 == 0 freq = 0; return; end epsilon = osc.k3/osc.k1; freq = osc.omega0 + epsilon * 3*amplitude^2/(8*osc.omega0); end ``` Step 2. Measure frequency numerically ```matlab function frequency = measure_frequency(osc, amplitude, t_max) if nargin < 3, t_max = 50; end % Initial conditions y0 = [amplitude; 0]; % Solve ODE options = odeset('RelTol', 1e-8, 'AbsTol', 1e-8); [t, y] = ode45(@(t, state) duffing_dynamics(t, state, osc), ... [0 t_max], y0, options); % Find peaks to determine period [pks, locs] = findpeaks(y(:,1), 'MinPeakHeight', amplitude*0.8); if length(locs) > 1 periods = diff(t(locs)); avg_period = mean(periods); frequency = 2*pi/avg_period; else frequency = osc.omega0; end end ``` Step 3. Compare hard and soft springs ```matlab % Create oscillators oscillators = struct(); oscillators.Linear = create_duffing(1.0, 0.0, 1.0); oscillators.HardSpring = create_duffing(1.0, 0.5, 1.0); oscillators.SoftSpring = create_duffing(1.0, -0.3, 1.0); amplitudes = linspace(0.1, 2.0, 10); figure; hold on; names = fieldnames(oscillators); colors = {'k', 'r', 'b'}; for i = 1:length(names) osc = oscillators.(names{i}); frequencies = zeros(size(amplitudes)); for j = 1:length(amplitudes) frequencies(j) = measure_frequency(osc, amplitudes(j)); end plot(amplitudes, frequencies, 'o-', 'Color', colors{i}, ... 'LineWidth', 2, 'DisplayName', names{i}); end xlabel('Amplitude'); ylabel('Frequency (rad/s)'); title('Amplitude-Frequency Relationship'); legend('Location', 'best'); grid on; hold off; ``` #### Results ![[Teaching/MATH310/Lecture Notes/Nonlinear Oscillators/Oscillators - Bridge to Nonlinearity/frequency_amplitude_FAST.png]] *Figure: Amplitude-dependent frequency for different spring types. Hard springs (k₃>0) show increasing frequency with amplitude, while soft springs (k₃<0) show decreasing frequency.* The numerical results confirm the theoretical prediction: - **Hard spring (k₃ > 0)**: Frequency increases up to 35% at large amplitudes - **Soft spring (k₃ < 0)**: Frequency decreases up to 32% at large amplitudes - **Linear spring (k₃ = 0)**: Frequency remains constant **Complete code**: `Module2_Bridge_to_Nonlinearity/codes/duffing_frequency_amplitude_FAST.py` #### Exploration Exercises 1. **Parameter study**: Modify k₃ in the code to see how the nonlinearity strength affects the frequency shift. 2. **Phase portraits**: Add phase space plots to visualize how orbits change shape with amplitude. 3. **Energy check**: Verify that energy remains constant during oscillations. #### Physical Consequences This result has profound implications: 1. **Frequency increases with amplitude** for hard springs ($\varepsilon > 0$) 2. **Frequency decreases with amplitude** for soft springs ($\varepsilon < 0$) 3. **Sound analogy**: If this oscillator produced sound, its pitch would depend on volume—louder means higher (or lower) pitch! ![](https://www.youtube.com/watch?v=YNbEJS2b05k) ![](https://youtu.be/Rw2aghxJD1o) 4. **Harmonic generation**: The solution contains a $3\omega$ component: $q_1(t) = -\frac{a^3}{32\omega_0^2}[\cos(\omega t) - \cos(3\omega t)]$ This third harmonic is a signature of cubic nonlinearity. ### Numerical Demonstration: Harmonic Generation The cubic nonlinearity generates odd harmonics (3ω, 5ω, ...) with amplitudes that scale as powers of the fundamental amplitude. #### Implementation Step 1. Compute the frequency spectrum ```python def fast_spectrum(y, dt): """Compute FFT spectrum""" N = len(y) window = 0.5 - 0.5 * np.cos(2*np.pi*np.arange(N)/N) y_windowed = y * window Y = fft(y_windowed) freqs = fftfreq(N, dt) # Positive frequencies only pos_mask = freqs > 0 return freqs[pos_mask], np.abs(Y[pos_mask]) ``` Step 2. Analyze harmonic content vs amplitude ```python osc = DuffingHarmonics(k1=1.0, k3=0.5) amplitudes = [0.5, 1.0, 1.5] for amp in amplitudes: # Solve ODE sol = solve_ivp(osc.dynamics, [0, 20], [amp, 0], method='DOP853', rtol=1e-6) # Compute spectrum freqs, spectrum = osc.fast_spectrum(sol.y[0], dt) # Plot normalized to fundamental plt.semilogy(freqs/osc.omega0, spectrum/max(spectrum), label=f'a={amp}') ``` #### Results ![[Teaching/MATH310/Lecture Notes/Nonlinear Oscillators/Oscillators - Bridge to Nonlinearity/harmonics_FAST.png]] *Figure: Harmonic spectrum for different amplitudes. Cubic nonlinearity generates odd harmonics with amplitudes that scale as a³, a⁵, etc.* Key observations: - **Odd harmonics only**: Cubic nonlinearity preserves symmetry - **Scaling laws**: 3rd harmonic ∝ a³, 5th harmonic ∝ a⁵ - **Waveform distortion**: Larger amplitudes show more harmonics **Complete code**: `Module2_Bridge_to_Nonlinearity/codes/duffing_harmonics_FAST.py` #### Exploration Exercises 1. **Even nonlinearity**: Add a quadratic term (k₂y²) and observe even harmonics. 2. **Forced response**: Drive the oscillator and see harmonic mixing. 3. **Spectral cascade**: Track how energy flows to higher frequencies. ### Exact Solutions via Elliptic Functions While perturbation theory works for weak nonlinearity, the exact solution of the Duffing equation reveals a profound connection to one of mathematics' most beautiful subjects: elliptic functions. #### From Duffing to Elliptic Integrals Starting from energy conservation: $H = \frac{m\dot{y}^2}{2} + \frac{k_1 y^2}{2} + \frac{k_3 y^4}{4} = E$ Solving for velocity: $\dot{y} = \pm\sqrt{\frac{2(E - V(y))}{m}} = \pm\sqrt{\frac{2E - k_1 y^2 - \frac{k_3 y^4}{2}}{m}}$ Separating variables and integrating: $\int \frac{dy}{\sqrt{2E - k_1 y^2 - \frac{k_3 y^4}{2}}} = \pm\sqrt{\frac{1}{m}}\int dt$ With appropriate scaling (choosing $m = 1$, $E = 1/2$, $k_3 = -\kappa^2$, and $k_1 = 1 + \kappa^2$), this becomes: $\boxed{\int \frac{dy}{\sqrt{(1-y^2)(1-\kappa^2 y^2)}} = \pm \int dt}$ This is the **standard form of an elliptic integral of the first kind**. #### The Jacobi Elliptic Functions The solution to this integral involves the Jacobi elliptic functions. For our Duffing oscillator: $y(t) = \text{cn}(u, \kappa)$ where $u = \omega t$ and $\kappa$ is the **elliptic modulus** (determined by initial conditions). The Jacobi elliptic functions—$\text{sn}(u, \kappa)$, $\text{cn}(u, \kappa)$, and $\text{dn}(u, \kappa)$—are generalizations of trigonometric functions: - **When $\kappa = 0$** (linear limit): - $\text{sn}(u, 0) = \sin(u)$ - $\text{cn}(u, 0) = \cos(u)$ - $\text{dn}(u, 0) = 1$ - **When $\kappa = 1$** (separatrix): - $\text{sn}(u, 1) = \tanh(u)$ - $\text{cn}(u, 1) = \text{sech}(u)$ - $\text{dn}(u, 1) = \text{sech}(u)$ - **When $0 < \kappa < 1$**: True elliptic behavior—periodic but not sinusoidal #### The Period Formula The period of oscillation is given by: $T = 4K(\kappa)\sqrt{\frac{m}{|k_1 + k_3 a^2|}}$ where $K(\kappa)$ is the **complete elliptic integral of the first kind**: $K(\kappa) = \int_0^{\pi/2} \frac{d\theta}{\sqrt{1 - \kappa^2\sin^2\theta}}$ This shows explicitly how the period depends on amplitude through the modulus $\kappa$. #### Historical Context and Mathematical Significance ##### Origins in Geometry Elliptic integrals were first studied in the mid-18th century by mathematicians trying to find the arc length of an ellipse—hence the name "elliptic." Notable contributions came from: - **Fagnano** (1718): Doubling and bisection of elliptic arcs - **Euler** (1760s): Systematic study of elliptic integrals - **Legendre** (1811-1817): Comprehensive treatise and standard forms ##### The Revolution of Inversion The breakthrough came when **Abel** (1827) and **Jacobi** (1829) independently realized that instead of trying to evaluate the integrals, they should study their inverse functions—the elliptic functions. This was analogous to defining $\sin(x)$ as the inverse of $\int \frac{dy}{\sqrt{1-y^2}}$. ##### Profound Connections **Jacobi's Remarkable Observation** (noted by Arnold in 1997): > "Jacobi noted, as mathematics' most fascinating property, that in it one and the same function controls both the representations of a whole number as a sum of four squares and the real movement of a pendulum." This refers to the appearance of theta functions (related to elliptic functions) in: 1. **Number theory**: Lagrange's four-square theorem 2. **Physics**: Exact pendulum solutions ##### Modern Applications Elliptic functions and their associated curves have found applications far beyond oscillators: 1. **Cryptography**: Elliptic curve cryptography (ECC) provides security for internet communications 2. **Number Theory**: - Proof of Fermat's Last Theorem (Wiles, 1995) - Birch and Swinnerton-Dyer conjecture (Millennium Prize Problem) 3. **String Theory**: Modular forms and elliptic functions appear in partition functions 4. **Engineering**: Optimal filter design, signal processing 5. **General Relativity**: Geodesics in Schwarzschild and Kerr spacetimes #### The Elliptic Functions as a Bridge The appearance of elliptic functions in the Duffing oscillator reveals a fundamental truth: **nonlinearity connects elementary physics to advanced mathematics**. While linear oscillators require only high school trigonometry, the cubic term in the Duffing equation opens a door to: - 19th-century special function theory - Modern algebraic geometry - Contemporary cryptography - Unsolved problems in mathematics This exemplifies how even simple nonlinearities lead to mathematical structures of extraordinary richness and continuing relevance. ## Connecting to Physical Systems ### The Pendulum Revisited For the pendulum with moderate amplitudes, the Duffing approximation: $\ddot{\theta} + \omega^2\theta - \frac{\omega^2\theta^3}{6} = 0$ captures the essential nonlinearity while remaining analytically tractable. The soft spring character ($k_3 < 0$) correctly predicts that larger swings have longer periods. ### Numerical Demonstration: Pendulum Approximations We can compare the exact pendulum equation with its linear and Duffing approximations to see the range of validity. #### Implementation Step 1. Define the three pendulum models ```python class ExactPendulum(PendulumModel): def dynamics(self, t, state): theta, theta_dot = state theta_ddot = -(self.g/self.L * np.sin(theta)) return [theta_dot, theta_ddot] class LinearPendulum(PendulumModel): def dynamics(self, t, state): theta, theta_dot = state theta_ddot = -(self.omega0**2 * theta) return [theta_dot, theta_ddot] class DuffingPendulum(PendulumModel): def dynamics(self, t, state): theta, theta_dot = state theta_ddot = -(self.omega0**2 * (theta - theta**3/6)) return [theta_dot, theta_ddot] ``` Step 2. Compare period vs amplitude ```python theta0_range = np.array([0.1, 0.3, 0.5, 0.8, 1.0, 1.5, 2.0, 2.5]) models = {'Exact': ExactPendulum(), 'Linear': LinearPendulum(), 'Duffing': DuffingPendulum()} for name, model in models.items(): periods = [model.fast_measure_period(theta0) for theta0 in theta0_range] plt.plot(np.degrees(theta0_range), periods/T0, 'o-', label=name) ``` #### Results ![[Teaching/MATH310/Lecture Notes/Nonlinear Oscillators/Oscillators - Bridge to Nonlinearity/pendulum_approximations_FAST.png]] *Figure: Comparison of pendulum approximations. The Duffing (cubic) approximation extends the valid range significantly beyond the linear approximation.* ![[Teaching/MATH310/Lecture Notes/Nonlinear Oscillators/Oscillators - Bridge to Nonlinearity/taylor_series_FAST.png]] *Figure: Taylor series approximations of sin(θ). The cubic term in the Duffing approximation captures the nonlinearity up to about 60°.* Key findings: - **Linear approximation**: Valid for θ < 15° (error < 1%) - **Duffing approximation**: Valid for θ < 60° (error < 1%) - **Period increase**: At 90°, period is 18% longer than small-angle prediction **Complete code**: `Module2_Bridge_to_Nonlinearity/codes/pendulum_approximations_FAST.py` #### Exploration Exercises 1. **Higher-order terms**: Add the fifth-order term (θ⁵/120) and see the improvement. 2. **Phase portraits**: Compare the phase space trajectories for the three models. 3. **Energy surfaces**: Plot the potential energy for each approximation. ### Beyond Pendulums The Duffing equation models numerous physical systems: - **Mechanical**: Beams and plates under large deflections - **Electrical**: Nonlinear inductors in circuits - **Optical**: Nonlinear refractive index in intense laser fields - **Biological**: Nonlinear elasticity in tissues - **Architectural**: Building sway under wind loads ## Mathematical Structure and Symmetry ### Symmetry Properties The cubic nonlinearity preserves the system's symmetry: - If $y(t)$ is a solution, so is $-y(t)$ - The phase portrait is symmetric about both axes - Only odd powers of $y$ appear in the force law ### Loss of Superposition A fundamental consequence of nonlinearity: the principle of superposition fails. - If $y_1(t)$ and $y_2(t)$ are solutions, $y_1(t) + y_2(t)$ is generally **not** a solution - Linear combinations of normal modes do not yield new normal modes - Energy does not partition cleanly between modes ### Qualitative Changes with Parameters As parameters vary, the system undergoes qualitative changes: - **Bifurcations**: Critical parameter values where the number or stability of equilibria changes - **Hysteresis**: System response depends on history (increasing vs. decreasing parameter) - **Jump phenomena**: Sudden transitions between oscillation states ## Summary: The Nonlinear Difference The transition from linear to [nonlinear oscillators](https://en.wikipedia.org/wiki/Nonlinear_system) reveals fundamentally new phenomena: 1. **Amplitude-dependent frequency**: Period depends on energy 2. **Multiple [equilibria](https://en.wikipedia.org/wiki/Equilibrium_point)**: Possibility of coexisting stable states 3. **[Separatrices](https://en.wikipedia.org/wiki/Separatrix_(dynamical_systems))**: Boundaries between qualitatively different motions 4. **Special functions**: [Elliptic functions](https://en.wikipedia.org/wiki/Elliptic_function) replace trigonometric ones 5. **Rich [phase space](https://en.wikipedia.org/wiki/Phase_space)**: Centers, [saddles](https://en.wikipedia.org/wiki/Saddle_point), and complex trajectory structures These features, absent in linear systems, make nonlinear oscillators both challenging and fascinating. The Duffing oscillator, as the simplest model exhibiting these behaviors, serves as our gateway to understanding more complex nonlinear dynamics, including chaos—topics we'll explore in subsequent modules. ## Numerical Codes Summary All demonstration codes are optimized for educational use, running in seconds rather than minutes while maintaining physical accuracy. ### Available Python Codes 1. **`duffing_frequency_amplitude_FAST.py`** - Amplitude-frequency relationships - Demonstrates frequency shifts for hard/soft springs - Compares numerical results with perturbation theory - Runtime: ~5 seconds 2. **`duffing_phase_portraits.py`** - Phase space structures - Shows single well, double well, and separatrices - Visualizes different parameter regimes - Runtime: ~8 seconds 3. **`pendulum_approximations_FAST.py`** - Pendulum approximation comparison - Exact vs linear vs Duffing approximations - Period-amplitude relationships - Runtime: ~6 seconds 4. **`duffing_harmonics_FAST.py`** - Harmonic generation analysis - FFT spectrum analysis - Demonstrates odd harmonic generation - Runtime: ~7 seconds 5. **`duffing_energy_surfaces_FAST.py`** - Energy and Hamiltonian visualization - 3D energy surfaces - Phase space contours - Runtime: ~5 seconds 6. **`elliptic_functions_demo_FAST.py`** - Connection to elliptic functions - Jacobi elliptic functions - Transition from periodic to soliton - Runtime: ~4 seconds ### Running the Codes ```bash cd Module2_Bridge_to_Nonlinearity/codes python3 duffing_frequency_amplitude_FAST.py ``` ### Suggested Explorations 1. **Parameter Study**: Vary k₃ from -1 to +1 to see the transition from soft to hard spring 2. **Initial Conditions**: Try different initial velocities to explore different energy levels 3. **Damping Effects**: Add small damping (γ = 0.1) to see energy decay 4. **Forcing**: Add periodic forcing to observe resonance and chaos (preview of Module 3) ## Key Takeaways - The Duffing oscillator naturally emerges from the pendulum equation through systematic approximation - The sign of the cubic coefficient ($k_3$) determines whether the spring is "soft" or "hard" - Nonlinearity introduces amplitude-dependent frequencies and complex phase space structures - Exact solutions require elliptic functions, reflecting the fundamental difference from linear systems - The loss of superposition makes nonlinear systems qualitatively different, not just quantitatively more complex ### Verified Relationships Our numerical demonstrations confirm: - **Hard spring (k₃ > 0)**: Frequency increases with amplitude (up to 35% at a = 1.5) - **Soft spring (k₃ < 0)**: Frequency decreases with amplitude (down to 32% at a = 1.5) - **Harmonic generation**: 3rd harmonic amplitude ∝ a³, 5th harmonic ∝ a⁵ - **Theory agreement**: Perturbation theory is accurate to within 2% for moderate amplitudes The mathematical tools developed here—phase portraits, potential energy landscapes, and perturbation methods—will be essential as we explore driven systems and the route to chaos in Module 3.