如何使用 numpy 创建一个 returns 来自数据数组的二维值的函数?

How can I use numpy to create a function that returns two-dimensional values from arrays of data?

这道题是关于推导一个数学函数,该函数 returns 基于数据数组的值对 - 来自二维值的二维值。

我创建了a Python library that drives a pen-plotter using cheap servo motors

从笔的 x/y 位置,我获得了所需的电机角度,以及需要馈送到它们的脉冲宽度。

这些廉价电机当然是非线性的,整个机械系统表现出滞后和扭曲行为。

库可以用不同的方式计算所需的脉冲宽度值。一种方法是为每个伺服确定一些实际的 pulse-width/angle 测量值,如下所示:

servo_angle_pws = [
    # angle, pulse-width
    [ 45, 1000],
    [ 60, 1200],
    [ 90, 1500],
    [120, 1800],
    [135, 2000],
]

然后 use numpy to create a function that fits the curve 由这些值描述:

servo_2_array = numpy.array(servo_2_angle_pws)
self.angles_to_pw = numpy.poly1d(numpy.polyfit(servo_2_array[:, 0], servo_2_array[:, 1], 3))

看起来像这样:

现在我想采取另一个步骤,以类似的方式找到一个函数,它给我 x/y 位置和脉冲宽度之间的关系,而不是角度(这将提供更高的准确性,因为它将考虑系统中更多现实世界的缺陷)。不过在这种情况下,我将有两对值,如下所示:

# x/y positions, servo pulse-widths
((-8.0,  8.0),  (1900, 1413)),
((-8.0,  4.0),  (2208, 1605)),
(( 8.0,  4.0),  ( 977, 1622)),
((-0.0,  4.0),  (1759, 1999)),
(( 6.0, 13.0),  (1065, 1121)),

我的问题是:我需要做什么才能得到一个函数(我当然需要其中两个),returns 所需的一对 x/y 脉冲宽度值职位?例如:

pw1 = xy_to_pulsewidths1(x=-4, y=6.3)
pw2 = xy_to_pulsewidths2(x=-4, y=6.3)

我相信我需要做一个“多元回归”——但我不是数学家所以我不知道这是否正确,即使是这样,我在 numpy 的研究中还没有发现任何东西scipy 表示我在代码中实际需要做什么。

如果我没理解错的话,你要进行多元回归,相当于求解一个多元least-squares问题。假设您的函数是二维多项式,您可以使用 polyval2d and scipy.optimize.least_squares:

的组合
import numpy as np
from numpy.polynomial.polynomial import polyval2d
from scipy.optimize import least_squares

x = np.array((-8.0,-8.0, 8.0, -0.0, 6.0))
y = np.array((8.0, 4.0, 4.0, 4.0, 13.0))
pulse_widths = np.array(((1900, 1413),(2208, 1605),(977, 1622),(1759, 1999),(1065, 1121)))

# we want to minimize the sum of the squares of the residuals
def residuals(coeffs, x, y, widths, poly_degree):
    return polyval2d(x, y, coeffs.reshape(-1, poly_degree+1)) - widths

# polynomial degree
degree = 3

# initial guess for the polynomial coefficients
x0 = np.ones((degree+1)**2)

# res1.x and res2.x contain your coefficients
res1 = least_squares(lambda coeffs: residuals(coeffs, x, y, pulse_widths[:, 0], degree), x0=x0)
res2 = least_squares(lambda coeffs: residuals(coeffs, x, y, pulse_widths[:, 1], degree), x0=x0)

# Evaluate the 2d Polynomial at (x,y)
def xy_to_pulswidth(x, y, coeffs):
    num_coeffs = int(np.sqrt(coeffs.size))
    return polyval2d(x, y, coeffs.reshape(-1, num_coeffs))

# Evaluate the function
pw1 = xy_to_pulswidth(-4, 6.3, res1.x)
pw2 = xy_to_pulswidth(-4, 6.3, res2.x)