Skip to content

Entering equations of motion

The struct DifferentialEquation is the primary input method; it holds an ODE or a coupled system of ODEs composed of terms with harmonic time-dependence The dependent variables are specified during input, any other symbols are identified as parameters. Information on which variable is to be expanded in which harmonic is specified using add_harmonic!.

DifferentialEquation.equations stores a dictionary assigning variables to equations. This information is necessary because the harmonics belonging to a variable are later used to Fourier-transform its corresponding ODE.

QuestBase.d Function

The derivative of f w.r.t. x of degree deg

source
QuestBase.DifferentialEquation Type
julia
mutable struct DifferentialEquation

Holds differential equation(s) of motion and a set of harmonics to expand each variable. This is the primary input for HarmonicBalance.jl. After inputting the equations, the harmonics ansatz needs to be specified using add_harmonic!.

Fields

  • equations::OrderedCollections.OrderedDict{Num, Equation}: Assigns to each variable an equation of motion.

  • harmonics::OrderedCollections.OrderedDict{Num, OrderedCollections.OrderedSet{Num}}: Assigns to each variable a set of harmonics.

Example

julia
julia> @variables t, x(t), y(t), ω0, ω, F, k;

# equivalent ways to enter the simple harmonic oscillator
julia> DifferentialEquation(d(x,t,2) + ω0^2 * x - F * cos*t), x);
julia> DifferentialEquation(d(x,t,2) + ω0^2 * x ~ F * cos*t), x);

# two coupled oscillators, one of them driven
julia> DifferentialEquation(
    [d(x,t,2) + ω0^2 * x - k*y, d(y,t,2) + ω0^2 * y - k*x] .~ [F * cos*t), 0], [x,y]
);
source
QuestBase.add_harmonic! Function
julia
add_harmonic!(diff_eom::DifferentialEquation, var::Num, ω)

Add the harmonic ω to the harmonic ansatz used to expand the variable var in diff_eom.

Example

define the simple harmonic oscillator and specify that x(t) oscillates with frequency ω

julia
julia> @variables t, x(t), y(t), ω0, ω, F, k;
julia> diff_eq = DifferentialEquation(d(x,t,2) + ω0^2 * x ~ F * cos*t), x);
julia> add_harmonic!(diff_eq, x, ω) # expand x using ω

System of 1 differential equations
Variables:       x(t)
Harmonic ansatz: x(t) => ω;

(ω0^2)*x(t) + Differential(t)(Differential(t)(x(t))) ~ F*cos(t*ω)
source
Symbolics.get_variables Method
julia
get_variables(diff_eom::DifferentialEquation) -> Vector{Num}

Return the dependent variables of diff_eom.

source
QuestBase.get_independent_variables Method
julia
get_independent_variables(
    diff_eom::DifferentialEquation
) -> Vector{Num}

Return the independent dependent variables of diff_eom.

source

Which equations can be entered

The equations have to be polynomial in the variables and their derivatives. Harmonic balance replaces each variable by a truncated Fourier series, and only sums, products and non-negative integer powers turn a finite Fourier series into another finite Fourier series. A term such as sin(x), ex or 1/x does not, so get_harmonic_equations and get_krylov_equations reject it:

julia
julia> @variables α, ω0, ω, F, t, x(t);

julia> diff_eq = DifferentialEquation(d(x, t, 2) + ω0^2 * x + α * sin(x) ~ F * cos* t), x);

julia> add_harmonic!(diff_eq, x, ω);

julia> get_harmonic_equations(diff_eq)
ERROR: ArgumentError: The term(s) sin(x(t)) are not polynomial in x(t) and cannot be averaged. [...]

Expand such a term in the variable first. For the pendulum above, sin(x)xx3/6 turns the equation into a Duffing oscillator, which harmonic balance handles.

The time dependence of the parameters, on the other hand, must be harmonic: cos(2ωt) * x is fine, cos(ω t^2) * x and t * x are not.

Choosing the harmonics

Only the harmonics passed to add_harmonic! are kept, everything else the nonlinearity generates is projected out. A nonlinear term therefore only shows up in the harmonic equations if it feeds back into a harmonic of the ansatz. With the single-harmonic ansatz x=ucos(ωt)+vsin(ωt):

x3

generates ω and 3ω; the ω part is kept, so the term contributes.

  • x2, x4, x10 and every other even power generate only 0,2ω,4ω, and contribute nothing. The harmonic equations are then those of the linear oscillator, which is correct for this ansatz rather than a sign that the term was ignored by mistake.

To capture an even nonlinearity, add the harmonics it produces, e.g. add_harmonic!(diff_eq, x, 2ω) next to add_harmonic!(diff_eq, x, ω). Adding harmonics enlarges the system (two equations per harmonic per variable), so add them one at a time and stop once the quantity you care about no longer changes.