Эффективное решение переопределенной системы нелинейных уравнений с использованием подогнанных данных в python

#python #arrays #numpy #least-squares #nonlinear-optimization

Вопрос:

Я думаю, что это самый простой способ описать мою проблему на небольшом примере. У меня есть эти данные, которые являются моими входными данными. У меня есть 3 светодиода, и каждый светодиод представлен 4 цветовыми частями (значение от 1 до 4 в каждом массиве). Если я увеличу интенсивность светодиодов (в этом примере с 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. Я хочу найти полином для увеличения каждой из цветовых частей светодиода, поэтому я переставляю данные и использую полиномиальную подгонку, чтобы получить уравнения, описывающие, как растут значения для каждого светодиода.

 ### 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 разных светодиодов. Для этого мне нужно выяснить, какую интенсивность мне нужно использовать от каждого из светодиодов, чтобы получить наилучший возможный результат. Цвет-части 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]
 

Я использовал многочлены, полученные из подгонки для каждого светодиода, и добавил их друг к другу, чтобы получить уравнение для каждой из четырех цветовых частей. Это дало бы тот же результат и, возможно, было бы немного легче читать:

 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 светодиодов и более 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])))
 

Я надеюсь, что смог прояснить свою проблему и был бы очень благодарен, если бы кто-нибудь мог помочь мне решить эту задачу.

Заранее большое вам спасибо 🙂

Ответ №1:

В ваших уравнениях есть закономерность, которую вы можете векторизировать. Прежде всего, соберите все светодиоды в 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)) помощью .

Конечно, вы должны сделать то же самое с LED1 , LED2 и т. Д. , Чтобы вам не нужно было жестко Fit_LED1 кодировать и т. Д. Просто поместите все в 3d-массив и выполните цикл для каждого светодиодного индекса.

 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)
 

Комментарии:

1. Отлично, большое вам спасибо, это именно то, что я искал.