#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. Отлично, большое вам спасибо, это именно то, что я искал.