使用 python 中的拟合数据有效求解超定非线性方程组

Effectively solve an overdetermined nonlinear equation system using fitted data in python

我认为用一个小例子来描述我的问题是最简单的方法。 我有这个数据,这是我的输入数据。我有 3 个 LED,每个 LED 由 4 个颜色部分表示(每个数组中的值 1 到 4)。如果我增加 LED 的强度(在这个例子中从 10% 到 30%),颜色部分会以不同的方式变化。

LED1_10 = np.array([1.5, 1, 0.5, 0.5])
LED1_20 = np.array([2.5, 1.75, 1.2, 1.2])
LED1_30 = np.array([3, 2.3, 1.7, 1.7])

LED2_10 = np.array([0.2, 0.8, 0.4, 0.4])
LED2_20 = np.array([0.6, 1.6, 0.5, 0.5])
LED2_30 = np.array([1.0, 2.0, 0.55, 0.55])

LED3_10 = np.array([1, 0.1, 0.4, 0.4])
LED3_20 = np.array([2.5, 0.8, 0.9, 0.9])
LED3_30 = np.array([3.25, 1, 1.3, 1.3])

数组的列元素属于一起。因此,如果我将 LED1 从 10% 提高到 30%,则第 1 列中的值会从 1.5 上升到 2.5,然后上升到 3。我想为每个 LED 颜色部分的上升找到一个多项式,所以我重新排列数据并使用多项式拟合得到描述每个 LED 值上升方式的方程式。

### Rearrange the values
LED1 = np.stack((LED1_10, LED1_20, LED1_30)).T
LED2 = np.stack((LED2_10, LED2_20, LED2_30)).T
LED3 = np.stack((LED3_10, LED3_20, LED3_30)).T

### Create x-vectro
x = np.array([10,20,30])

### Polynomal fits
Fit_LED1 = []
for i in range(len(LED1)):
    z = np.polyfit(x, LED1[i], 2)
    Fit_LED1.append(z)

Fit_LED2 = []
for i in range(len(LED2)):
    z = np.polyfit(x, LED2[i], 2)
    Fit_LED2.append(z)
    
Fit_LED3 = []
for i in range(len(LED3)):
    z = np.polyfit(x, LED3[i], 2)
    Fit_LED3.append(z)

现在我想生成特定颜色的光,将 3 个不同 LED 的光混合在一起。因此,我需要找出每个 LED 需要使用哪种强度才能获得最佳结果。颜色部分 1-4 由解向量表示:b = [7, 8, 2, 5] 我这样求解超定非线性方程组:

def f(x):
    x1, x2, x3 = x
    return np.asarray(((-2.50000000e-03*x1**2 + 1.75000000e-01*x1 + -5.91091254e-15) + (-2.03207837e-18*x2**2 + 4.00000000e-02*x2 + -2.00000000e-01) + (-0.00375*x3**2 + 0.2625*x3 + -1.25),
                       (-0.001*x1**2 + 0.105*x1 +  0.05) + (-0.002*x2**2 +  0.14*x2 + -0.4) + (-0.0025*x3**2 +  0.145*x3 + -1.1),
                       (-0.001*x1**2 + 0.1*x1 + -0.4 ) + (-0.00025*x2**2 +  0.0175*x2 +  0.25) + (-0.0005*x3**2 +  0.065*x3 + -0.2), 
                       (-0.001*x1**2 + 0.1*x1 + -0.4 ) + (-0.00025*x2**2 +  0.0175*x2 +  0.25) + (-0.0005*x3**2 +  0.065*x3 + -0.2)))

def system(x,b):
    return (f(x)-b)

b = [7, 8, 2, 5]
x = scipy.optimize.leastsq(system, np.asarray((1,1,1)), args=b)[0]

我使用从拟合每个 LED 得到的多项式并将它们相加以获得四个颜色部分中的每一个的方程式。这会给出相同的结果,并且可能更容易阅读:

def g(x):
    x1, x2, x3 = x
    return np.asarray(((Fit_LED1[0][0]*x1**2 + Fit_LED1[0][1]*x1 + Fit_LED1[0][2]) + (Fit_LED2[0][0]*x1**2 + Fit_LED2[0][1]*x1 + Fit_LED2[0][2]) + (Fit_LED3[0][0]*x1**2 + Fit_LED3[0][1]*x1 + Fit_LED3[0][2]),
                       (Fit_LED1[1][0]*x1**2 + Fit_LED1[1][1]*x1 + Fit_LED1[1][2]) + (Fit_LED2[1][0]*x1**2 + Fit_LED2[1][1]*x1 + Fit_LED2[1][2]) + (Fit_LED3[1][0]*x1**2 + Fit_LED3[1][1]*x1 + Fit_LED3[1][2]),
                       (Fit_LED1[2][0]*x1**2 + Fit_LED1[2][1]*x1 + Fit_LED1[2][2]) + (Fit_LED2[2][0]*x1**2 + Fit_LED2[2][1]*x1 + Fit_LED2[2][2]) + (Fit_LED3[2][0]*x1**2 + Fit_LED3[2][1]*x1 + Fit_LED3[2][2]),
                       (Fit_LED1[3][0]*x1**2 + Fit_LED1[3][1]*x1 + Fit_LED1[3][2]) + (Fit_LED2[3][0]*x1**2 + Fit_LED2[3][1]*x1 + Fit_LED2[3][2]) + (Fit_LED3[3][0]*x1**2 + Fit_LED3[3][1]*x1 + Fit_LED3[3][2])))
def system(x,b):
    return (f(x)-b)

b = [5, 8, 4, 12]
x = scipy.optimize.leastsq(system, np.asarray((1,1,1)), args=b)[0]

现在我的问题是我需要分别键入每个函数,这是一项繁重的工作,特别是因为我的实际应用程序包含 40 个 LED 和每个 LED 的 1000 多个颜色部分。有没有一种更简单、更有效的方法来定义方程系统的方程,而不是像我在这里做的那样分别输入每个方程?

def g(x):
    x1, x2, x3 = x
    return np.asarray(((Fit_LED1[0][0]*x1**2 + Fit_LED1[0][1]*x1 + Fit_LED1[0][2]) + (Fit_LED2[0][0]*x1**2 + Fit_LED2[0][1]*x1 + Fit_LED2[0][2]) + (Fit_LED3[0][0]*x1**2 + Fit_LED3[0][1]*x1 + Fit_LED3[0][2]),
                       (Fit_LED1[1][0]*x1**2 + Fit_LED1[1][1]*x1 + Fit_LED1[1][2]) + (Fit_LED2[1][0]*x1**2 + Fit_LED2[1][1]*x1 + Fit_LED2[1][2]) + (Fit_LED3[1][0]*x1**2 + Fit_LED3[1][1]*x1 + Fit_LED3[1][2]),
                       (Fit_LED1[2][0]*x1**2 + Fit_LED1[2][1]*x1 + Fit_LED1[2][2]) + (Fit_LED2[2][0]*x1**2 + Fit_LED2[2][1]*x1 + Fit_LED2[2][2]) + (Fit_LED3[2][0]*x1**2 + Fit_LED3[2][1]*x1 + Fit_LED3[2][2]),
                       (Fit_LED1[3][0]*x1**2 + Fit_LED1[3][1]*x1 + Fit_LED1[3][2]) + (Fit_LED2[3][0]*x1**2 + Fit_LED2[3][1]*x1 + Fit_LED2[3][2]) + (Fit_LED3[3][0]*x1**2 + Fit_LED3[3][1]*x1 + Fit_LED3[3][2])))

我希望我能够弄清楚我的问题,如果有人能帮助我解决这个问题,我将不胜感激。

非常感谢您:)

您的方程式中有一个可以向量化的模式。首先,将所有适合的 LED 聚集在一个 3D 阵列中。

fits = np.array([Fit_LED1, Fit_LED2, Fit_LED3])

然后定义g(x)

def g(x):
    X = np.array([x**2, x, np.ones_like(x)]).T
    return np.sum(fits * X[:,None], axis=(0, 2))

您也可以通过np.isclose(f(x), g(x))确认结果是否正确。

当然你应该对 LED1LED2 等做同样的事情,这样你就不必硬编码 Fit_LED1 等。只需将所有内容放在 3d 数组中,然后循环每个 LED 索引。

LEDs = np.array([LED1, LED2, LED3])
fits = [
    [np.polyfit(np.array([10, 20, 30]), LEDs[i,j], 2) for j in range(LEDs.shape[1])]
    for i in range(LEDs.shape[0])
]
fits = np.array(fits)