简体   繁体   中英

How to fit a rotated and translated hyperbola to a set of x,y points in Python

I want to fit a set of data points in the xy plane to the general case of a rotated and translated hyperbola to back out the coefficients of the general equation of a conic. I've tried the methodology proposed in here but so far I cannot make it work. When fitting to a set of points known to be a hyperbola I get quite different outputs. What I'm doing wrong in the code below? Or is there any other way to solve this problem?

import numpy as np
from sympy import plot_implicit, Eq
from sympy.abc import x, y

def fit_hyperbola(x, y):   
    D1 = np.vstack([x**2, x*y, y**2]).T
    D2 = np.vstack([x, y, np.ones(len(x))]).T
    S1 = D1.T @ D1
    S2 = D1.T @ D2
    S3 = D2.T @ D2

    # define the constraint matrix and its inverse
    C = np.array(((0, 0, -2), (0, 1, 0), (-2, 0, 0)), dtype=float)
    Ci = np.linalg.inv(C)

    # Setup and solve the generalized eigenvector problem
    T = np.linalg.inv(S3) @ S2.T

    S = Ci@(S1 - S2@T)

    eigval, eigvec = np.linalg.eig(S)

    # evaluate and sort resulting constraint values
    cond = eigvec[1]**2 - 4*eigvec[0]*eigvec[2]

    # [condVals index] = sort(cond)
    idx = np.argsort(cond)
    condVals = cond[idx]

    possibleHs = condVals[1:] + condVals[0]
    minDiffAt = np.argmin(abs(possibleHs))
    # minDiffVal = possibleHs[minDiffAt]
    alpha1 = eigvec[:, idx[minDiffAt + 1]]
    alpha2 = T@alpha1
    return np.concatenate((alpha1, alpha2)).ravel()

if __name__ == '__main__':

    # known hyperbola coefficients
    coeffs = [1., 6., -2., 3., 0., 0.]

    # hyperbola points
    x_ = [1.56011303e+00, 1.38439984e+00, 1.22595618e+00, 1.08313085e+00,
           9.54435408e-01, 8.38528681e-01, 7.34202759e-01, 6.40370424e-01,
           5.56053814e-01, 4.80374235e-01, 4.12543002e-01, 3.51853222e-01,
           2.97672424e-01, 2.49435970e-01, 2.06641170e-01, 1.68842044e-01,
           1.35644673e-01, 1.06703097e-01, 8.17157025e-02, 6.04220884e-02,
           4.26003457e-02, 2.80647476e-02, 1.66638132e-02, 8.27872926e-03,
           2.82211172e-03, 2.37095181e-04, 4.96740239e-04, 3.60375275e-03,
           9.59051203e-03, 1.85194083e-02, 3.04834928e-02, 4.56074477e-02,
           6.40488853e-02, 8.59999904e-02, 1.11689524e-01, 1.41385205e-01,
           1.75396504e-01, 2.14077865e-01, 2.57832401e-01, 3.07116093e-01,
           3.62442545e-01, 4.24388335e-01, 4.93599021e-01, 5.70795874e-01,
           6.56783391e-01, 7.52457678e-01, 8.58815793e-01, 9.76966133e-01,
           1.10813998e+00, 1.25370436e+00]

    y_ =  [-0.66541515, -0.6339625 , -0.60485332, -0.57778425, -0.5524732 ,
           -0.52865638, -0.50608561, -0.48452564, -0.46375182, -0.44354763,
           -0.42370253, -0.4040097 , -0.38426392, -0.3642594 , -0.34378769,
           -0.32263542, -0.30058217, -0.27739811, -0.25284163, -0.22665682,
           -0.19857079, -0.16829086, -0.13550147, -0.0998609 , -0.06099773,
           -0.01850695,  0.02805425,  0.07917109,  0.13537629,  0.19725559,
            0.26545384,  0.34068177,  0.42372336,  0.51544401,  0.61679957,
            0.72884632,  0.85275192,  0.98980766,  1.14144182,  1.30923466,
            1.49493479,  1.70047747,  1.92800474,  2.17988774,  2.45875143,
            2.76750196,  3.10935692,  3.48787892,  3.90701266,  4.3711261 ]


    plot_implicit (Eq(coeffs[0]*x**2 + coeffs[1]*x*y + coeffs[2]*y**2 + coeffs[3]*x + coeffs[4]*y, -coeffs[5]))

    coeffs_fit = fit_hyperbola(x_, y_)

    plot_implicit (Eq(coeffs_fit[0]*x**2 + coeffs_fit[1]*x*y + coeffs_fit[2]*y**2 + coeffs_fit[3]*x + coeffs_fit[4]*y, -coeffs_fit[5]))

The general equation of hyperbola is defined with 5 independent coefficients (not 6). If the model equation includes dependant coefficients (which is the case with 6 coefficients) trouble might occur in the numerical regression calculus.

That is why the equation A * x * x + B * x * y + C * y * y + D * x + F * y = 1 is considered in the calculus below. The fitting is very good.

Then one can goback to the standard equation a * x * x + 2 * b * x * y + c * y * y + 2 * d * x + 2 * f * y + g = 0 in setting a value for g (for example g=-1).

The formulas to find the coordinates of the center, the equations of asymptotes, the equations of axis, are given in addition.

在此处输入图像描述

https://mathworld.wolfram.com/ConicSection.html

https://en.wikipedia.org/wiki/Conic_section

https://en.wikipedia.org/wiki/Hyperbola

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM