Оптимизация функции расчета расстояния

После того, как вы смоделировали схему, вы можете ссылаться на нее, используя «ref»

var subConfigsSchema = new Schema({
    alias: String,
    value: String,
    position: Number
}, {_id: false});

var subConfigs = mongoose.model('SubConfig', subConfigsSchema);

var configsSchema = new Schema({
    bfq: [subConfigsSchema],
    qpa: [subConfigsSchema],
    fmb: [subConfigsSchema],
    cz: [subConfigsSchema]
}, {_id: false});

var config = mongoose.model('Config', ConfigsSchema);

var instrumentSchema = new Schema({
    _id: {
        type: Schema.Types.ObjectId, 
        ref: 'SubConfig',
        required: true,
        auto: true
    },
    configs: {
        type: Schema.Types.ObjectId, 
        ref: 'Config',
        required: true
    }
},
{
    strict: false,
    versionKey: false
});

module.exports = mongoose.model('Instrument', instrumentSchema)

. Теперь при запросе вам нужно заполнить ссылочную модель ... Так что для этого вам нужно заполнить ссылочную модель. [113 ]

Instrument.find({}).populate('subconfig').populate('config').exec((err, data)=> {
    if (err) throw err;

    instrument = data[0];

    console.log(instrument);
    console.log(instrument._id);
    console.log(instrument.inpname);
    console.log(Instrument['inpname']);
});
8
задан Community 23 May 2017 в 12:26
поделиться

12 ответов

Если Ваша цель состоит в том, чтобы занять место (сравнивают) расстояния, то приближения (sin и cos поиск по таблице), мог решительно уменьшить Ваше количество требуемых вычислений (реализуйте быстрое отклонение.)

Ваша цель состоит в том, чтобы только возобновить фактическое тригонометрическое вычисление, если различие между приближенными расстояниями (чтобы быть оцененным или сравненным) падает ниже определенного порога.

Например, использование справочных таблиц с 1 000 образцов (т.е. sin и cos выбранный каждый 2*pi/1000), неуверенность поиска самое большее 0.006284. Используя вычисление неуверенности для параметра к ACos, накопленная неуверенность, также быть пороговой неуверенностью, будет самое большее 0.018731.

Так, при оценке Math.Sin(lat2rad) * Math.Sin(lat1rad) + Math.Cos(lat2rad) * Math.Cos(lat1rad) * Math.Cos(lon2rad - lon1rad) использование sin и cos справочные таблицы для двух установленных на координату пар (расстояния) приводят к определенному рейтингу (одно расстояние кажется больше, чем другой на основе приближения), и модуль различия больше, чем порог выше, затем приближение допустимо. Иначе возобновите фактическое тригонометрическое вычисление.

5
ответ дан 5 December 2019 в 10:44
поделиться

Используя вдохновение от @Brann я думаю, что можно уменьшить вычисление немного (Предупреждение, что это - долгое время, так как я сделал любое из этого, и это должно будет быть проверено). Своего рода поиск предрасчетных значений, вероятно, самое быстрое, хотя

Вы имеете:

1: ACOS (ГРЕШАТ ГРЕХ B + COS COS B COS (A-B)),

но 2: COS (A-B) = ГРЕШИТ ГРЕХ B + COS COS B

который переписывается как 3: ГРЕШИТЕ ГРЕХ B = COS (A-B) - COS COS B

замените ГРЕХ ГРЕХ B в 1. Вы имеете:

4: ACOS (COS (A-B) - COS COS B + COS COS B COS (A-B))

Вы предварительно вычисляете X = COS (A-B) и Y = COS COS B, и Вы помещаете значения в 4

дать:

ACOS (X - Y + XY)

4 аккуратных вычисления вместо 6!

3
ответ дан 5 December 2019 в 10:44
поделиться

Алгоритм CORDIC работал бы на Вас (в отношении скорости/точности)?

4
ответ дан 5 December 2019 в 10:44
поделиться

Переключение на справочные таблицы для sin/cos/acos. Будет быстрее, существует много c/c ++ библиотеки фиксированной точки, которые также включают их.

Вот код от кого-то еще на Memoization. Который мог бы работать, если используемые фактические значения более кластеризируются.

Вот ТАК вопрос на Фиксированной точке.

1
ответ дан 5 December 2019 в 10:44
поделиться

Измените способ, которым Вы храните long/lat:

struct LongLat
{
  float
    long,
    lat,
    x,y,z;
}

При создании long/lat также вычислите (x, y, z) 3D точка, которая представляет эквивалентную позицию по сфере единицы, центрируемой в источнике.

Теперь, чтобы определить, ближе ли точка B для указания, чем точка C, сделайте следующее:

// is B nearer to A than C?
bool IsNearer (LongLat A, LongLat B, LongLat C)
{
  return (A.x * B.x + A.y * B.y + A.z * B.z) < (A.x * C.x + A.y * C.y + A.z * C.z);
}

и получить расстояние между двумя точками:

float Distance (LongLat A, LongLat B)
{
  // radius is the size of sphere your mapping long/lats onto
  return radius * acos (A.x * B.x + A.y * B.y + A.z * B.z);
}

Вы могли удалить термин 'радиуса', эффективно нормализовав расстояния.

2
ответ дан 5 December 2019 в 10:44
поделиться

Как точный Вам нужны значения, чтобы быть?

Если Вы вокруг Ваших значений немного затем Вы могли бы сохранить результат всех поисков и проверить, использовались ли thay перед каждым вычислением?

0
ответ дан 5 December 2019 в 10:44
поделиться

Каково горлышко бутылки? Вызовы синуса/косинусной функции или вызов arcsine?

Если Ваши вызовы синуса/косинуса являются медленными, Вы могли бы использовать следующую теорему для предотвращения такого количества вызовов:

1 = sin(x)^2 + cos(x)^2
cos(x) = sqrt(1 - sin(x)^2)

Но мне нравится отображающаяся идея так, чтобы Вы не повторно вычисляли значения, которые Вы уже вычислили. Хотя быть осторожным, поскольку карта могла стать очень большой очень быстро.

1
ответ дан 5 December 2019 в 10:44
поделиться

Я утверждал бы, что можно хотеть вновь исследовать, как Вы нашли что функция быть узким местом. (IE Вы представляли приложение?)

Уравнение мне кажется очень легким весом и не должно доставлять неприятности. Предоставленный, я не знаю Ваше приложение, и Вы говорите, что делаете много этих вычислений.

Тем не менее, это - что-то для рассмотрения.

0
ответ дан 5 December 2019 в 10:44
поделиться

Ну, так как lat и lon, как гарантируют, будут в определенном диапазоне, Вы могли попытаться использовать некоторую форму справочной таблицы для Вас Математика.* вызовы метода. Скажите, a Dictionary<double,double>

0
ответ дан 5 December 2019 в 10:44
поделиться

Как кто-то еще указал, действительно ли Вы уверены, что это - Ваше узкое место?

Я сделал некоторое тестирование производительности подобного приложения, которое я создаю, где я называю простой метод возвратить расстояние между двумя точками с помощью аккуратного стандарта. 20 000 вызовов к нему пихают его прямо во главе вывода профилирования, все же нет никакого способа, которым я могу сделать его быстрее... Это - просто сдвиг # вызовов.

В этом случае я должен уменьшить вызовы # до него... Не то, чтобы это - узкое место.

0
ответ дан 5 December 2019 в 10:44
поделиться

кто-то уже упомянул memoisation, и это немного подобно. если Вы сравнивающий ту же точку со многими другими точками затем лучше предварительно вычислить части того уравнения.

вместо

double result = Math.Acos(Math.Sin(lat2rad) * Math.Sin(lat1rad) 
+ Math.Cos(lat2rad) * Math.Cos(lat1rad) * Math.Cos(lon2rad - lon1rad));

имейте:

double result = Math.Acos(lat2rad.sin * lat1rad.sin 
+ lat2rad.cos * lat1rad.cos * (lon2rad.cos * lon1rad.cos + lon1rad.sin * lon2rad.sin));

и я думаю, что это - та же формула, как кто-то еще отправил, потому что часть уравнения исчезнет при расширении скобок:)

0
ответ дан 5 December 2019 в 10:44
поделиться

Я использую другой алгоритм для вычисления расстояния между 2 lati/longi положениями, это могло быть легче, чем Ваш, так как это только делает 1 вызов Cos и 1 вызов Sqrt.

public static double GetDistanceBetweenTwoPos(double lat1, double long1, double lat2, double long2)
{
  double distance = 0;
  double x = 0;
  double y = 0;

  x = 69.1 * (lat1 - lat2);
  y = 69.1 * (long1 - long2) * System.Math.Cos(lat2 / 57.3);

  //calculation base : Miles
  distance = System.Math.Sqrt(x * x + y * y);

  //Distance calculated in Kilometres
  return distance * 1.609;
}
0
ответ дан 5 December 2019 в 10:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: