Математическая ошибка снаряда

Итак, по сути, я пытаюсь создать два метода расчета, чтобы сделать следующее:

1) Получить место попадания ракетной установки на основе положения, скорости и угла выстрела.

2) Получите угол стрельбы на основе скорости и желаемого места попадания.

В настоящее время у меня есть следующий код.

'use strict';

import Mortar from '../mortar/Mortar.js';

const GRAVITY = 9.8;
const MAX_RANGE = 1250;
const MIN_RANGE = 50;

/**
 * A class for the mortar calculator.
 */
class Calc {
    /**
     * Get Hit Location Data from Dial Data.
     * @param {*} dialData The current dialed in data
     * @param {*} mortarData The current Mortar Data
     * @return {*} Hit Location Data
     */
    static getHitLocData(dialData, mortarData = Mortar.getDefaultData()) {
        const {mrads, bearing} = dialData;
        const {velocity, x, y, elevation} = mortarData;

        const rads = Calc.getRadFromMils(mrads);
        const b = Calc.getRadFromDegree(bearing);

        const vx = (velocity * Math.cos(rads));
        const vy = (velocity * Math.sin(rads));
        const time = (2 * (vy / GRAVITY));
        const range = ((2 * vx) * (vy / GRAVITY));
        const yMax = (Math.pow(vy, 2) / (2 * GRAVITY));

        let canHit = true;

        // We need a modification for the difference in elevation

        // If the range wont hit
        if ((range < MIN_RANGE) || (range > MAX_RANGE)) {
            canHit = false;
        }

        const hitX = (x + (range * Math.cos(b)));
        const hitY = (y + (range * Math.sin(b)));

        return {
            bearing,
            'mrads': `${Math.round(mrads)}mrads`,
            'map': {
                'x': Math.round(hitX),
                'y': Math.round(hitY),
                'heightDiff': '0m',
                'distance': `${range.toFixed(2)}m`,
                'flight': `${time.toFixed(2)}sec`
            },
            'grid': 'A1-1-1-000',
            'misc': {
                'velocityX': `${vx.toFixed(1)}m/s`,
                'velocityY': `${vy.toFixed(1)}m/s`,
                'maxHeight': `${yMax.toFixed(2)}m`
            },
            canHit
        };
    }

    /**
     * Get Dial Data Data from Hit Location Data.
     * @param {*} hitLocData The current requested hit location
     * @param {*} mortarData The current Mortar Data
     * @return {*} Dial Data
     */
    static getDialData(hitLocData, mortarData = Mortar.getDefaultData()) {
        const {hitX, hitY, hitHeight} = hitLocData;
        const {x, y, mortHeight, velocity} = mortarData;

        const range = Math.sqrt(Math.pow((hitX - x), 2) + Math.pow((hitY - y), 2));
        const bearing = (Math.atan2((hitY - y), (hitX - x)) * (180 / Math.PI));
        const heightDiff = (hitHeight - mortHeight);
        let rads = 0;

        if (heightDiff) {
            // Height difference has not been math proven as 0,0 doesnt even work

            const v4 = Math.pow(velocity, 4);
            const gx = (GRAVITY * range);
            const gx2 = (GRAVITY * Math.pow(range, 2));
            const yv2 = (heightDiff * (Math.pow(velocity, 2)));
            const m1 = (GRAVITY * (gx2 - (2 * yv2)));
            rads = Math.atan((v4 - m1) / gx);
        } else {
            const gx = (GRAVITY * range);
            rads = Math.atan(Math.pow(velocity, 2) / gx);
        }

        const mrads = (rads * 1000);

        const vy = (velocity * Math.sin(rads));
        const time = (2 * (vy / GRAVITY));

        let canHit = true;

        // If the range wont hit
        if ((range < MIN_RANGE) || (range > MAX_RANGE)) {
            canHit = false;
        }

        return {
            bearing,
            'mrads': (`${Math.round(mrads)}mrad`),
            'heightDiff': (`${heightDiff}m`),
            'flight': (`${time.toFixed(2)}sec`),
            'distance': (`${range.toFixed(2)}m`),
            'spread': 0,
            canHit
        };
    }

    /**
     * Get the number of radians from Milradians.
     *
     * @param {Number} mrads The number of mrads
     * @return {Number} The new number of rads
     */
    static getRadFromMils(mrads) {
        return (mrads / 1000);
    }

    /**
     * Get the number of radians from degrees.
     *
     * @param {Number} deg The current degree bearing
     * @return {Number} The new number of rads
     */
    static getRadFromDegree(deg) {
        return (deg * (Math.PI / 180));
    }
}

export default Calc;

Я знаю, что первое, получение места попадания, работает. Если я передам ему заданный пеленг и угол обстрела мрад, я могу найти, куда я попал по отношению к местоположению миномета.

Однако последний не соответствует, несмотря на то, что он передает тот же результат, что и первая функция. Ниже приведены примеры входных и выходных данных.

Ввод:

var dialData = getDialData({
  'hitX': 1250,
  'hitY': 0,
  'hitHeight': 0
}, {
  'x': 0,
  'y': 0,
  'mortHeight': 0,
  'velocity': 110.75
});
var hitData = getHitLocData({
  'mrads': 800,
  'bearing': 0,
}, {
  'x': 0,
  'y': 0,
  'elevation': 0,
  'velocity': 110.75
});

Вывод:

{"bearing":0,"mrads":"786mrad","heightDiff":"0m","flight":"15.99sec","distance":"1250.00m","spread":0,"canHit":true}
{"bearing":0,"mrads":"800mrads","map":{"x":1251,"y":0,"heightDiff":"0m","distance":"1251.05m","flight":"16.21sec"},"grid":"A1-1-1-000","misc":{"velocityX":"77.2m/s","velocityY":"79.4m/s","maxHeight":"322.03m"},"canHit":false}

Я не могу в жизни понять, почему это происходит. Оба должны рассчитать, чтобы иметь одинаковое расстояние, мрад и полет.


person Ben Lyon    schedule 21.03.2018    source источник


Ответы (1)


Я понял, в чем дело. Проблема заключалась в следующем уравнении: Equation image Моя реализация была совершенно неправильной. Вместо того, чтобы вычислять обе стороны ±, я просто вычислял одну или другую. Вы можете увидеть это в операторе if, который проверяет heightDiff.

Правильное решение состоит в следующем:

// Below are the two calculaitons we need to work out
        const dx = range;
        const v = velocity;
        const g = GRAVITY;
        const hd = heightDiff;

        const v4 = (Math.pow(velocity, 4));
        const gx2 = (GRAVITY * Math.pow(range, 2));
        const yv2 = (heightDiff * Math.pow(velocity, 2));
        const gx = (GRAVITY * range);

        const p1 = Math.sqrt(v4 - (GRAVITY * (gx2 + (2 * yv2))));
        const a1 = Math.atan((Math.pow(velocity, 2) + p1) / gx);

        rads = a1;
        const mrads = (rads * 1000);

person Ben Lyon    schedule 26.03.2018