byuflowlab / VortexLattice.jl

A Comprehensive Julia implementation of the Vortex Lattice Method

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Stability derivatives with non-zero [p,q,r]

jdebecdelievre opened this issue · comments

Hi all,

I think that there is a small chain rule term forgotten in the stability derivatives computation with respect to alpha. It in stability_derivatives.jl, in the stability_derivatives(system) function.

Line 113, CF_a = CFs_a should be CF_a = CFs_a + CFs_pb * pb_a + CFs_qb * qb_a + CFs_rb * rb_a. Similarly, line 119, we should have CM_a = CMs_a + CMs_pb * pb_a + CMs_qb * qb_a + CMs_rb * rb_a.

The reason would be that, when taking a partial derivative wrt alpha in the stability frame, we assume that the rotation rates in the stability frame do not change.

Below is a code snippet using the first example from the documentation to compare the analytic solution with finite differences. Note that I use fixed angular velocity in the stability frame when finite differencing.

I'm happy to do a pull request if you would like to incorporate the change.
Let me know if I'm missing something!

-Jean

using VortexLattice

function example1(alpha)
    # geometry (right half of the wing)
    xle = [0.0, 0.4]
    yle = [0.0, 7.5]
    zle = [0.0, 0.0]
    chord = [2.2, 1.8]
    theta = [2.0*pi/180, 2.0*pi/180]
    phi = [0.0, 0.0]
    fc = fill((xc) -> 0, 2) # camberline function for each section

    # discretization parameters
    ns = 12
    nc = 6
    spacing_s = Uniform()
    spacing_c = Uniform()

    # reference parameters
    Sref = 30.0
    cref = 2.0
    bref = 15.0
    rref = [0.50, 0.0, 0.0]
    Vinf = 1.0
    ref = Reference(Sref, cref, bref, rref, Vinf)

    # freestream parameters
    beta = 0.0
    Omega_stability = [0.1; 0.2; 0.3]
    Omega_body = VortexLattice.body_to_stability(sincos(alpha)...)' * Omega_stability
    fs = Freestream(Vinf, alpha, beta, Omega_body)

    # construct geometry with mirror image
    grid, surface = wing_to_surface_panels(xle, yle, zle, chord, theta, phi, ns, nc;
        fc=fc, spacing_s=spacing_s, spacing_c=spacing_c, mirror=true)

    # symmetry is not used in the analysis
    symmetric = false

    # create vector containing all surfaces
    surfaces = [surface]

    # perform steady state analysis
    system = steady_analysis(surfaces, ref, fs; symmetric=symmetric)
    CF, CM = body_forces(system; frame=Stability())
    dCF, dCM = stability_derivatives(system)

    CL = CF[3]; CLα = dCF[1][3];
    Cm = CM[2]; Cmα = dCM[1][2];

    return CL, CLα, Cm, Cmα
end

# Use derivative computation
alpha = 1. * pi/180
_, CLα, _, Cmα = example1(alpha)

# Use finite differences
CL1, _, Cm1, _ = example1(alpha-1e-6)
CL2, _, Cm2, _ = example1(alpha+1e-6)
CLα_fd = (CL2-CL1)/2e-6
Cmα_fd = (Cm2-Cm1)/2e-6

println(
    """
    CLα    = $(CLα)
    CLα_fd = $(CLα_fd)
    Cmα    = $(Cmα)
    Cmα_fd = $(Cmα_fd)
    """
)

Returns:

CLα    = 5.052638734014063
CLα_fd = 10.006357994279957
Cmα    = -0.38029095592363177
Cmα_fd = -0.944973063028709

The discrepancy is large partly because I've used very large rotation rates. It is fixed with the change that have suggested above.

Since CM_a = CMs_a + CMs_pb * pb_a + CMs_qb * qb_a + CMs_rb * rb_a now mixes derivatives around x, y, and z, the full fix requires to multiply every CM_... by [ref.b, ref.c, ref.b], do all the calculations, and then re-divide by [ref.b, ref.c, ref.b] at the end.

Thanks for the catch! I probably just forgot to keep the rotation rates in the stability frame constant when verifying the derivatives. It sounds like you have a good handle on the issue. If you're willing to put together a pull request for this I would greatly appreciate it.