Best-Fit без точечной интерполяции - PullRequest
1 голос
/ 04 июля 2019

У меня есть два набора данных.Одним из них является номинальная форма.Другая актуальная форма.Проблема в том, что когда я хочу вычислить ошибку формы в одиночку.Это большая проблема, когда два набора данных не находятся "друг над другом".Это дает ошибки, которые также включают в себя позиционную ошибку.

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

Я пробовал различные методы «Best-Fit», которые я нашел и здесь, и там, где когда-либо меня брал Google.Но проблема в том, что все они сглаживают мои «актуальные» данные.Таким образом, он изменяется и не сохраняет свою действительную форму.

Есть ли какая-либо функция в scipy или любой другой библиотеке python, которая "просто" может совмещать мои две кривые вместе, не изменяя фактическую форму?Мне бы хотелось, чтобы зеленая кривая с красными точками как можно больше лежала поверх черного.

enter image description here

Возможно ли рассчитать центртяжести обеих кривых, а затем переместить фактическую кривую в х и у в зависимости от разности значений от центральной точки?Это может быть не окончательное решение, но это будет ближе?

1 Ответ

1 голос
/ 05 июля 2019

Вот решение, предполагающее, что номинальная форма может быть описана как коническая , т.е. как решение уравнения a x ^ 2 + b y ^ 2 + c x y + d x + e y = 1. Затем для нахождения коэффициентов (a, b, c, d, e) можно применить метод наименьших квадратов.

import numpy as np
import matplotlib.pylab as plt

# Generate example data
t = np.linspace(-2, 2.5, 25)
e, theta = 0.5, 0.3  # ratio minor axis/major & orientation angle major axis
c, s = np.cos(theta), np.sin(theta)
x = c*np.cos(t) - s*e*np.sin(t)
y = s*np.cos(t) + c*e*np.sin(t)

# add noise:
xy = 4*np.vstack((x, y))
xy += .08 *np.random.randn(*xy.shape) + np.random.randn(2, 1)


# Least square fit by a generic conic equation
# a*x^2 + b*y^2 + c*x*y + d*x + e*y = 1
x, y = xy
x = x - x.mean()
y = y - y.mean()

M = np.vstack([x**2, y**2, x*y, x, y]).T
b = np.ones_like(x)
# solve M*w = b
w, res, rank, s = np.linalg.lstsq(M, b, rcond=None)
a, b, c, d, e = w

# Get x, y coordinates for the fitted ellipse:
# using polar coordinates
# x = r*cos(theta), y = r*sin(theta)
# for a given theta, the radius is obtained with the 2nd order eq.:
# (a*ct^2 + b*st^2 + c*cs*st)*r^2 + (d*ct + e*st)*r - 1 = 0
# with ct = cos(theta) and st = sin(theta)

theta = np.linspace(-np.pi, np.pi, 97)
ct, st = np.cos(theta), np.sin(theta)

A = a*ct**2 + b*st**2 + c*ct*st
B = d*ct + e*st
D = B**2 + 4*A
radius = (-B + np.sqrt(D))/2/A

# Graph
plt.plot(radius*ct, radius*st, '-k', label='fitted ellipse');
plt.plot(x, y, 'or', label='measured points');
plt.axis('equal'); plt.legend();
plt.xlabel('x'); plt.ylabel('y');

least square fit of an ellipse

...