Close

Free Falling with PL/SQL

I needed to calculate some free fall timings recently and while I could have used a calculator I decided I’d write a package to encapsulate the math for more convenient reuse if I ever needed to do so again. Once I had a couple calculations I expanded it to add more. Using the package I can determine distance fallen after a given number of seconds. The final velocity after falling for some amount of time, or if given a distance fallen instead, the velocity after falling that far. I can also reverse the calculation determine the time it takes to fall a given distance.

All of the calculations can be made with or without air resistance. In the process of coding those I added functions terminal_velocity and a function to calculate air resistance coefficient from the air density, cross section area and drag coefficient.

I also found that among all of the mathematical functions available in Oracle SQL, there is no ACOSH (inverse hyperbolic cosine) so I had to create one one of those too for calculating falling time over a known distance with air resistance.

I’ll concede it’s not likely to be a package I use often but it was an interesting exercise to dig into as some of the formulas were not ones I had previously known.

CREATE OR REPLACE PACKAGE free_fall
IS
    --                    .///.
    --                   (0 o)
    ---------------0000--(_)--0000---------------
    --
    --  Sean D. Stuber
    --  sean.stuber@gmail.com
    --
    --             oooO      Oooo
    --------------(   )-----(   )---------------
    --             \ (       ) /
    --              \_)     (_/

    -- Default coefficient of air resistance 0.24kg/m
    -- corrresponds to typical skydiver
    c_default_air_resistance   CONSTANT NUMBER := 0.24;

    -- Default acceleration due to gravity on Earth in m/(s^2)
    c_gravity_acceleration              NUMBER := 9.80665;

    -- The functions below accept an air resistance coefficient
    -- If it is not known, it can be calculated from:
    --   air density  (kg per cubic meter)
    --   cross-section area of the object (square meters)
    --   drag coefficient of the object's shape (dimensionless)
    FUNCTION air_resistance(p_density   IN NUMBER,
                            p_area      IN NUMBER,
                            p_drag      IN NUMBER)
        RETURN NUMBER;

    -- Given time (and optionally air resistance coefficient and mass)
    -- calculate the distance an object will fall
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION distance(p_seconds   IN NUMBER,
                      p_coeff     IN NUMBER DEFAULT NULL,
                      p_mass      IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC;

    -- Given time (and optionally air resistance coefficient and mass)
    -- calculate the final velocity of an object
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION velocity_t(p_seconds   IN NUMBER,
                      p_coeff     IN NUMBER DEFAULT NULL,
                      p_mass      IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC;

    -- Given distance (and optionally air resistance coefficient and mass)
    -- calculate the final velocity of an object
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION velocity_d(p_distance   IN NUMBER,
                       p_coeff      IN NUMBER DEFAULT NULL,
                       p_mass       IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC;

    -- Given air resistance coefficient and mass
    -- calculate the terminal velocity of an object
    -- air resistance coefficient should be in kg/m
    -- mass should be in kg
    -- The return result will be in m/s
    FUNCTION terminal_velocity(p_coeff   IN NUMBER DEFAULT NULL,
                               p_mass    IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC;

    -- Given distance (and optionally air resistance coefficient and mass)
    -- calculate the time required for an object to fall that distance
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION time(p_distance   IN NUMBER,
                  p_coeff      IN NUMBER DEFAULT NULL,
                  p_mass       IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC;
END;
CREATE OR REPLACE PACKAGE BODY free_fall
IS
    --                    .///.
    --                   (0 o)
    ---------------0000--(_)--0000---------------
    --
    --  Sean D. Stuber
    --  sean.stuber@gmail.com
    --
    --             oooO      Oooo
    --------------(   )-----(   )---------------
    --             \ (       ) /
    --              \_)     (_/


    -- The functions below accept an air resistance coefficient
    -- If it is not known, it can be calculated from:
    --   air density  (kg per cubic meter)
    --   cross-section area of the object (square meters)
    --   drag coefficient of the object's shape (dimensionless)
    FUNCTION air_resistance(p_density   IN NUMBER,
                            p_area      IN NUMBER,
                            p_drag      IN NUMBER)
        RETURN NUMBER
    IS
    BEGIN
        RETURN p_density * p_area * p_drag / 2;
    END air_resistance;

    -- Given time (and optionally air resistance coefficient and mass)
    -- calculate the distance an object will fall
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION distance(p_seconds   IN NUMBER,
                      p_coeff     IN NUMBER DEFAULT NULL,
                      p_mass      IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC
    IS
    BEGIN
        RETURN CASE
                   WHEN p_coeff IS NOT NULL
                   THEN
                         p_mass
                       / p_coeff
                       * LN(
                             COSH(
                                   p_seconds
                                 / SQRT(
                                         p_mass
                                       / (c_gravity_acceleration * p_coeff))))
                   WHEN p_coeff IS NULL
                   THEN
                       c_gravity_acceleration * p_seconds * p_seconds / 2
               END;
    END distance;

    -- Given time (and optionally air resistance coefficient and mass)
    -- calculate the final velocity of an object
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION velocity_t(p_seconds   IN NUMBER,
                      p_coeff     IN NUMBER DEFAULT NULL,
                      p_mass      IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC
    IS
    BEGIN
        RETURN CASE
                   WHEN p_coeff IS NOT NULL
                   THEN
                         SQRT(p_mass * c_gravity_acceleration / p_coeff)
                       * TANH(
                               p_seconds
                             / SQRT(
                                   p_mass / (c_gravity_acceleration * p_coeff)))
                   WHEN p_coeff IS NULL
                   THEN
                       c_gravity_acceleration * p_seconds
               END;
    END velocity_t;
    
    -- Given distance (and optionally air resistance coefficient and mass)
    -- calculate the final velocity of an object
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION velocity_d(p_distance   IN NUMBER,
                      p_coeff     IN NUMBER DEFAULT NULL,
                      p_mass      IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC
    IS
        v_seconds number := free_fall.time(p_distance,p_coeff,p_mass);
    BEGIN
        RETURN CASE
                   WHEN p_coeff IS NOT NULL
                   THEN
                         SQRT(p_mass * c_gravity_acceleration / p_coeff)
                       * TANH(
                               v_seconds
                             / SQRT(
                                   p_mass / (c_gravity_acceleration * p_coeff)))
                   WHEN p_coeff IS NULL
                   THEN
                       sqrt(2 * c_gravity_acceleration * p_distance)
               END;
    END velocity_d;

    -- Given air resistance coefficient and mass
    -- calculate the terminal velocity of an object
    -- air resistance coefficient should be in kg/m
    -- mass should be in kg
    -- The return result will be in m/s
    FUNCTION terminal_velocity(p_coeff   IN NUMBER DEFAULT NULL,
                               p_mass    IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC
    IS
    BEGIN
        RETURN SQRT(p_mass * c_gravity_acceleration / p_coeff);
    END terminal_velocity;

    FUNCTION acosh(x IN NUMBER)
        RETURN NUMBER
    IS
    BEGIN
        RETURN LN(x + SQRT(x * x - 1));
    END acosh;

    -- Given distance (and optionally air resistance coefficient and mass)
    -- calculate the number of seconds required for an object to fall that distance
    -- With a NULL coefficient then calculation assumes no air resistance
    -- air resistance coefficient, if used, should be in kg/m
    -- mass, if used, should be in kg
    FUNCTION time(p_distance   IN NUMBER,
                  p_coeff      IN NUMBER DEFAULT NULL,
                  p_mass       IN NUMBER DEFAULT NULL)
        RETURN NUMBER
        DETERMINISTIC
    IS
    BEGIN
        RETURN CASE
                   WHEN p_coeff IS NOT NULL
                   THEN
                         SQRT(p_mass / (c_gravity_acceleration * p_coeff))
                       * acosh(EXP(p_distance * p_coeff / p_mass))
                   WHEN p_coeff IS NULL
                   THEN
                       SQRT(2 * p_distance / c_gravity_acceleration)
               END;
    END time;
END;

If you ever find yourself needing to do some of this math, hopefully this package will be helpful. If not, hopefully you find it as interesting to read through as I did in writing it. Questions and comments, as always, are welcome.