Extracting harmonic equations
Once a DifferentialEquation is defined and its harmonics specified, one can extract the harmonic equations using get_harmonic_equations, which itself is composed of the subroutines harmonic_ansatz, slow_flow, fourier_transform! and drop_powers.
The harmonic equations use an additional time variable specified as slow_time in get_harmonic_equations. This is essentially a label distinguishing the time dependence of the harmonic variables (expected to be slow) from that of the oscillating terms (expeted to be fast). When the equations are Fourier-transformed to remove oscillating terms, slow_time is treated as a constant. Such an approach is exact when looking for steady states.
HarmonicBalance.get_harmonic_equations — Functionget_harmonic_equations(diff_eom::DifferentialEquation; fast_time=nothing, slow_time=nothing)Apply the harmonic ansatz, followed by the slow-flow, Fourier transform and dropping higher-order derivatives to obtain a set of ODEs (the harmonic equations) governing the harmonics of diff_eom.
The harmonics evolve in slow_time, the oscillating terms themselves in fast_time. If no input is used, a variable T is defined for slow_time and fast_time is taken as the independent variable of diff_eom.
By default, all products of order > 1 of slow_time-derivatives are dropped, which means the equations are linear in the time-derivatives.
Example
julia> @variables t, x(t), ω0, ω, F;
# enter the simple harmonic oscillator
julia> diff_eom = DifferentialEquation( d(x,t,2) + ω0^2 * x ~ F *cos(ω*t), x);
# expand x in the harmonic ω
julia> add_harmonic!(diff_eom, x, ω);
# get equations for the harmonics evolving in the slow time T
julia> harmonic_eom = get_harmonic_equations(diff_eom)
A set of 2 harmonic equations
Variables: u1(T), v1(T)
Parameters: ω0, ω, F
Harmonic ansatz:
x(t) = u1*cos(ωt) + v1*sin(ωt)
Harmonic equations:
(ω0^2)*u1(T) + (2//1)*ω*Differential(T)(v1(T)) - (ω^2)*u1(T) ~ F
(ω0^2)*v1(T) - (ω^2)*v1(T) - (2//1)*ω*Differential(T)(u1(T)) ~ 0HarmonicBalance.harmonic_ansatz — Functionharmonic_ansatz(eom::DifferentialEquation, time::Num; coordinates="Cartesian")Expand each variable of diff_eom using the harmonics assigned to it with time as the time variable. For each harmonic of each variable, an instance of HarmonicVariable (describing a pair of variables (u,v)) is automatically created and named.
coordinates allows for using different coordinate systems (e.g. 'polars') - CURRENTLY INACTIVE
HarmonicBalance.slow_flow — Functionslow_flow(eom::HarmonicEquation; fast_time::Num, slow_time::Num, degree=2)Removes all derivatives w.r.t fast_time (and their products) in eom of power degree. In the remaining derivatives, fast_time is replaced by slow_time.
HarmonicBalance.fourier_transform — Functionfourier_transform(eom::HarmonicEquation, time::Symbolics.Num) -> HarmonicEquation
Extract the Fourier components of eom corresponding to the harmonics specified in eom.variables. For each harmonic of each variable, 2 equations are generated (cos and sin Fourier coefficients). time does not appear in the resulting equations anymore.
Underlying assumption: all time-dependences are harmonic.
HarmonicBalance.drop_powers — Functiondrop_powers(expr, vars, deg)
Remove parts of expr where the combined power of vars is => deg.
Example
julia> @variables x,y;
julia>drop_powers((x+y)^2, x, 2)
y^2 + 2*x*y
julia>drop_powers((x+y)^2, [x,y], 2)
0
julia>drop_powers((x+y)^2 + (x+y)^3, [x,y], 3)
x^2 + y^2 + 2*x*yHarmonicVariable and HarmonicEquation types
The equations governing the harmonics are stored using the two following structs. When going from the original to the harmonic equations, the harmonic ansatz $x_i(t) = \sum_{j=1}^M u_{i,j} (T) \cos(\omega_{i,j} t)+ v_{i,j}(T) \sin(\omega_{i,j} t)$ is used. Internally, each pair $(u_{i,j}, v_{i,j})$ is stored as a HarmonicVariable. This includes the identification of $\omega_{i,j}$ and $x_i(t)$, which is needed to later reconstruct $x_i(t)$.
HarmonicBalance.HarmonicVariable — Typemutable struct HarmonicVariableHolds a pair of variables stored under symbols describing the harmonic ω of natural_variable.
Fields
symbols::Vector{Symbolics.Num}Symbols of the two variables in the HarmonicBalance namespace.
names::Dict{Symbolics.Num, String}Human-readable labels of the two variables, used for plotting.
types::Vector{String}Types of the two variables ((u,v) for quadratures, (a,ϕ) for polars etc.)
ω::Symbolics.NumThe harmonic being described.
natural_variable::Symbolics.NumThe natural variable whose harmonic is being described.
When the full set of equations of motion is expanded using the harmonic ansatz, the result is stored as a HarmonicEquation. For an initial equation of motion consisting of $M$ variables, each expanded in $N$ harmonics, the resulting HarmonicEquation holds $2NM$ equations of $2NM$ variables. Each symbol not corresponding to a variable is identified as a parameter.
A HarmonicEquation can be either parsed into a steady-state Problem or solved using a dynamical ODE solver.
HarmonicBalance.HarmonicEquation — Typemutable struct HarmonicEquationHolds a set of algebraic equations governing the harmonics of a DifferentialEquation.
Fields
equations::Vector{Symbolics.Equation}A set of equations governing the harmonics.
variables::Vector{HarmonicVariable}A set of variables describing the harmonics.
parameters::Vector{Symbolics.Num}The parameters of the equation set.
natural_equation::DifferentialEquationThe natural equation (before the harmonic ansatz was used).