Подбор эллипса по орбитальным данным

Я сгенерировал кучу данных для (x, y, z) координат планеты, когда она вращается вокруг Солнца. Теперь я хочу поместить эллипс в эти данные.

Что я пытался сделать:

Я создал фиктивный эллипс на основе пяти параметров: большой полуоси и эксцентриситета, который определяет размер и форму, и трех углов Эйлера, которые вращают эллипс вокруг. Поскольку мои данные не всегда сосредоточены в начале координат, мне также нужно перевести эллипс, требующий дополнительных трех переменных (dx, dy, dz). Как только я инициализирую эту функцию этими восемью переменными, я возвращаю N точек, лежащих на этом эллипсе. (N = количество точек данных, через которые я рисую эллипс) Я рассчитываю отклонение этих фиктивных точек от фактических данных, а затем минимизирую это отклонение, используя некоторый метод минимизации, чтобы найти наилучшие подходящие значения для эти восемь переменных.

Моя проблема связана с самой последней частью: минимизировать отклонение и найти значения переменных.

Чтобы свести к минимуму отклонение, я использую scipy.optimize.minimize, чтобы попытаться аппроксимировать наиболее подходящие переменные, но этого недостаточно:

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

Вот весь код. (Данные не требуются, это генерирует свои собственные фальшивые данные)

Короче говоря, я использую эту scipy-функцию:

initial_guess = [0.3,0.2,0.1,0.7,3,0.0,-0.1,0.0]
bnds = ((0.2, 0.5), (0.1, 0.3), (0, 2*np.pi), (0, 2*np.pi), (0, 2*np.pi), (-0.5,0.5), (-0.5,0.5), (-0.3,0.3)) #reasonable bounds for the variables
result = optimize.minimize(deviation, initial_guess, args=(data,), method='L-BFGS-B', bounds=bnds, tol=1e-8) #perform minimalisation
semi_major,eccentricity,inclination,periapsis,longitude,dx,dy,dz = result["x"]

Чтобы минимизировать эту функцию ошибки (или отклонения):

    def deviation(variables, data):
    """
    This function calculates the cumulative seperation between the ellipse fit points and data points and returns it
    """
    num_pts = len(data[:,0])
    semi_major,eccentricity,inclination,periapsis,longitude,dx,dy,dz = variables
    dummy_ellipse = generate_ellipse(num_pts,semi_major,eccentricity,inclination,periapsis,longitude,dz,dy,dz)
    deviations = np.zeros(len(data[:,0]))
    pair_deviations = np.zeros(len(data[:,0]))
    # Calculate separation between each pair of points
    for j in range(len(data[:,0])):
        for i in range(len(data[:,0])):
            pair_deviations[i] = np.sqrt((data[j,0]-dummy_ellipse[i,0])**2 + (data[j,1]-dummy_ellipse[i,1])**2 + (data[j,2]-dummy_ellipse[i,2])**2)
            deviations[j] = min(pair_deviations) # only pick the closest point to the data point j.
    total_deviation = sum(deviations)
    return total_deviation

(Мой код может быть немного грязным и неэффективным, я новичок в этом)

Возможно, я делаю какую-то логическую ошибку в своем коде, но я думаю, что все сводится к функции scipy.minimize.optimize. Я недостаточно знаю, как это работает и чего от этого ожидать. Мне также порекомендовали попробовать цепь Маркова Монте-Карло при работе с таким количеством переменных. Я взглянул на ведущего, но сейчас он немного выше моей головы.


person SubTachyon    schedule 10.03.2015    source источник
comment
Отказ от ответственности: я не прочитал весь ваш код. Насколько на самом деле это плохо? Просто потому, что он выглядит немного не так, не обязательно означает, что он действительно плохо подходит. Когда я запустил ваш код, все подогнанные параметры были правильными не более чем на +-0,05 (наклон), остальные были даже точнее примерно на +-0,02. Поможет ли создание своего рода конвейера, в котором вы будете подгонять только пару параметров за раз, повысить точность? (т.е. предположим, что все ваши углы равны нулю и соответствуют только e и a, затем возьмите этот эллипс и подгоните к нему углы на основе исходных данных, возможно, с помощью другого метода и т. д.)   -  person ljetibo    schedule 10.03.2015
comment
Просто наблюдение: поскольку ваши данные предположительно лежат в плоскости, может быть идеей определить ваш эллипс в этой плоскости, прежде чем вы его подгоните, а не пытаться соответствовать углам Эйлера.   -  person xnx    schedule 10.03.2015
comment
Ссылка в посте битая, поэтому кода в вопросах/ответах недостаточно для воссоздания примера...   -  person    schedule 15.12.2019


Ответы (1)


Во-первых, у вас есть опечатка в вашей целевой функции, которая препятствует оптимизации одной из переменных:

dummy_ellipse = generate_ellipse(...,dz,dy,dz)

должно быть

dummy_ellipse = generate_ellipse(...,dx,dy,dz)

Кроме того, удаление sqrt и минимизация суммы квадратов евклидовых расстояний несколько упрощает задачу оптимизатора.

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

Кроме того, может помочь подход к проблеме с точки зрения аналитической геометрии: эллипс в 3D определяется как решение двух уравнений

f1(x,y,z,p) = 0
f2(x,y,z,p) = 0

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

F(p) = sum_{j=1}^N [f1(x_j,y_j,z_j,p)**2 + f2(x_j,y_j,z_j,p)**2]

где сумма проходит по точкам данных.

Более того, в этой формулировке задачи вы можете использовать optimize.leastsq, что может быть более эффективным в задачах наименьших квадратов.

person pv.    schedule 10.03.2015
comment
Конечно, должна была быть опечатка. -.- Очень полезно! Благодарю вас! - person SubTachyon; 11.03.2015