Plate Motions

Plate Motions

The motion of a plate is specified through two data types:

Motion

By default, RigidBodyMotion assumes a constant translational and angular velocity. For example,

julia> motion = Plates.RigidBodyMotion(1.0im, π/2)
Rigid Body Motion:
  ċ = 0.0 + 1.0im
  c̈ = 0.0 + 0.0im
  α̇ = 1.57
  α̈ = 0.0
  Constant (ċ = 0.0 + 1.0im, α̇ = 1.5707963267948966)

Here, Constant is a subtype of Kinematics that returns the same (ċ, c̈, α̇) triple at all times

julia> motion.kin.([0.0, 1.0, 2.0])
3-element Array{Tuple{Complex{Float64},Complex{Float64},Float64,Complex{Float64}},1}:
 (0.0 + 1.0im, 0.0 + 0.0im, 1.5707963267948966, 0.0 + 0.0im)
 (0.0 + 1.0im, 0.0 + 0.0im, 1.5707963267948966, 0.0 + 0.0im)
 (0.0 + 1.0im, 0.0 + 0.0im, 1.5707963267948966, 0.0 + 0.0im)

Calling Plates.RigidBodyMotion(1.0im, π/2) is equivalent doing

kin = Plates.RigidBodyMotions.Constant(1.0im, π/2)
motion = Plates.RigidBodyMotion(1.0im, 0.0im, π/2, 0.0, kin)

# output

Rigid Body Motion:
  ċ = 0.0 + 1.0im
  c̈ = 0.0 + 0.0im
  α̇ = 1.57
  α̈ = 0.0
  Constant (ċ = 0.0 + 1.0im, α̇ = 1.5707963267948966)

The next section describes how to construct more interesting kinematics.

Kinematics

The Kinematics type is just an abstract type for functions that take in time and return the (ċ, c̈, α̇) triple. Let's create a MyMotion type that describes a horizontally translating plate that also sinusoidally pitches about its centroid.

import PotentialFlow.Plates.RigidBodyMotions: Kinematics

struct MyMotion <: Kinematics
    U₀::ComplexF64
    ω::Float64
end

(m::MyMotion)(t) = (m.U₀, 0.0im, sin(m.ω*t))

sinusoid = MyMotion(1.0, π/4)

# output

MyMotion(1.0 + 0.0im, 0.7853981633974483)

We can then evaluate sinusoid at different times

julia> sinusoid.([0.0, 1.0, 2.0])
3-element Array{Tuple{Complex{Float64},Complex{Float64},Float64},1}:
 (1.0 + 0.0im, 0.0 + 0.0im, 0.0)
 (1.0 + 0.0im, 0.0 + 0.0im, 0.7071067811865475)
 (1.0 + 0.0im, 0.0 + 0.0im, 1.0)

Profiles

To make defining complex kinematics a little eaiser, the library also provides a Profile type, an abstract type for real-valued functions of time. Before going into how to define new profiles, we'll first show an example of why we might want to represent functions as a type. We start off with a predefined profile, a smooth ramp:

using Plots
using PotentialFlow.Plates.RigidBodyMotions

ramp = RigidBodyMotions.EldredgeRamp(6)

T = range(-1, 4, length=200)
plot(T, ramp.(T), xlabel = "t", ylabel="Smoothed Ramp",
     legend = :none, linewidth = 2)

Now suppose we want to scale the ramp and shift it

shifted_ramp = -(ramp >> 2)

plot(T, shifted_ramp.(T), xlabel = "t", ylabel="Smoothed Ramp",
     legend = :none, linewidth = 2, size=(600,300))

then take its derivative

ddt_ramp = d_dt(shifted_ramp)

plot(T, ddt_ramp.(T), xlabel = "t", ylabel="Smoothed Ramp",
     legend = :none, linewidth = 2, size = (600, 200))

We see that wrapping these functions in a type allows us to operate on them as if they values, making it easier to compose multiple motions together:

ps_ramp = RigidBodyMotions.ColoniusRamp(5)
composed_ramp = ramp - (ps_ramp >> 2)

plot(T, composed_ramp.(T), xlabel = "t", ylabel="Smoothed Ramp",
     legend = :none, linewidth = 2, size = (600, 300))

Defining a profile

Defining a profile is done in two steps:

  1. Create a subtype of RigidBodyMotions.Profile that contains the relavant parameters, e.g.
  2. Add a method on the type (see Function like objects)

For example,

using PotentialFlow.Plates.RigidBodyMotions

struct Sinusoid <: RigidBodyMotions.Profile
    ω::Float64
end

(s::Sinusoid)(t) = sin(s.ω*t)

which can then be used as follows:

T = range(-6, 6, length = 200)

s = Sinusoid(2.0)
c = d_dt(2s >> 0.5)

using Plots
plot(T, [s.(T) c.(T)], xlabel = "t", color = ["#00BFFF" "#D4CA3A"],
     legend = :none, linewidth = 2)

Function Documentation

An abstract type for types that takes in time and returns (ċ, c̈, α̇).

source
RigidBodyMotion

A type to store the plate's current kinematics

Fields

  • : current centroid velocity
  • : current centroid acceleration
  • α̇: current angular velocity
  • α̈: current angular acceleration
  • kin: a Kinematics structure

The first three fields are meant as a cache of the current kinematics while the kin field can be used to find the plate kinematics at any time.

source
d_dt(p::Profile)

Take the time derivative of p and return it as a new profile.

Example

julia> s = RigidBodyMotions.Sinusoid(π)
Sinusoid (ω = 3.14)

julia> s.([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
 0.0
 1.0
 0.7071067811865476

julia> c = RigidBodyMotions.d_dt(s)
d/dt (Sinusoid (ω = 3.14))

julia> c.([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
  3.141592653589793
  1.9236706937217898e-16
 -2.221441469079183
source
ConstantProfile(c::Number)

Create a profile consisting of a constant c.

Example

julia> p = RigidBodyMotions.ConstantProfile(1.0)
Constant (1.0)
source
PitchHeave <: Kinematics

Kinematics describing an oscillatory pitching and heaving (i.e. plunging) motion

Constructors

Fields

  • U₀

    Freestream velocity

  • a

    Axis of pitch rotation, relative to the plate centroid

  • K

    Reduced frequency $K = \frac{\Omega c}{2U_0}$

  • ϕ

    Phase lag of pitch to heave (in radians)

  • α₀

    Mean angle of attack

  • Δα

    Amplitude of pitching

  • A

    Amplitude of translational heaving

  • Y

  • Ÿ

  • α

  • α̇

  • α̈

source
Pitchup <: Kinematics

Kinematics describing a pitchup motion (horizontal translation with rotation)

Constructors

Fields

  • U₀

    Freestream velocity

  • a

    Axis of rotation, relative to the plate centroid

  • K

    Non-dimensional pitch rate $K = \dot{\alpha}_0\frac{c}{2U_0}$

  • α₀

    Initial angle of attack

  • t₀

    Nominal start of pitch up

  • Δα

    Total pitching angle

  • α

  • α̇

  • α̈

source

An abstract type for real-valued functions of time.

source
Base.:*Method.
s::Number * p::Profile

Returns a scaled profile with (s*p)(t) = s*p(t)

Example

julia> s = RigidBodyMotions.Sinusoid(π)
Sinusoid (ω = 3.14)

julia> 2s
2 × (Sinusoid (ω = 3.14))

julia> (2s).([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
 0.0
 2.0
 1.4142135623730951
source
Base.:+Method.
p₁::Profile + p₂::Profile

Add the profiles so that (p₁ + p₂)(t) = p₁(t) + p₂(t).

Examples

julia> ramp₁ = RigidBodyMotions.EldredgeRamp(5)
logcosh ramp (aₛ = 5.0)

julia> ramp₂ = RigidBodyMotions.ColoniusRamp(5)
power series ramp (n = 5.0)

julia> ramp₁ + ramp₂
AddedProfiles:
  logcosh ramp (aₛ = 5.0)
  power series ramp (n = 5.0)


julia> ramp₁ + (ramp₂ + ramp₁) == ramp₁ + ramp₂ + ramp₁
true
source
Base.:-Method.
-(p₁::Profile, p₂::Profile)
julia> s = RigidBodyMotions.Sinusoid(π)
Sinusoid (ω = 3.14)

julia> 2s
2 × (Sinusoid (ω = 3.14))

julia> (2s).([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
 0.0
 2.0
 1.4142135623730951

julia> s = RigidBodyMotions.Sinusoid(π);

julia> s.([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
 0.0
 1.0
 0.7071067811865476

julia> (-s).([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
 -0.0
 -1.0
 -0.7071067811865476

julia> (s - s).([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
 0.0
 0.0
 0.0
source
Base.:>>Method.
p::Profile >> Δt::Number

Shift the profile in time so that (p >> Δt)(t) = p(t - Δt)

Example

julia> s = RigidBodyMotions.Sinusoid(π);

julia> s >> 0.5
Sinusoid (ω = 3.14) >> 0.5

julia> (s >> 0.5).([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
 -1.0
  0.0
  0.7071067811865475

julia> (s << 0.5).([0.0, 0.5, 0.75])
3-element Array{Float64,1}:
  1.0
  1.2246467991473532e-16
 -0.7071067811865475
source

Index