我需要确定Illumintaion变化的参数,这是由这个连续的分段多项式C(t)定义的,其中f(t)是由两个边界点(t1,c)定义的三次曲线和( t2,0),f'(t1)= 0且f'(t2)= 0。 Model Binding To A List
强度曲线从阴影边界的法线上采样,它看起来像这样:
每行都是样本,显示照度变化。所以X是列数,Y是像素强度。
我有这样的真实数据(从所有样本中抽取一个样本):
根本我有N个样本,我需要确定参数(c,t1,t2)
我该怎么做?
我尝试通过在Matlab中求解线性方程来做到这一点:
avr_curve是平均曲线,通过对所有样本求平均得到。
f(x)= x ^ 3 + a2 * x ^ 2 + a1 * x1 + a0是立方函数
%t1,t2 selected by hand
t1= 10;
t2= 15;
offset=10;
avr_curve= [41, 40, 40, 41, 41, 42, 42, 43, 43, 43, 51, 76, 98, 104, 104, 103, 104, 105, 105, 107, 105];
%gradx= convn(avr_curve,[-1 1],'same');
A= zeros(2*offset+1,3);
%b= zeros(2*offset+1,1);
b= avr_curve';
%for i= 1:2*offset+1
for i=t1:t2
i
x= i-offset-1
A(i,1)= x^2; %a2
A(i,2)= x; %a1
A(i,3)= 1; %a0
b(i,1)= b(i,1)-x^3;
end
u= A\b;
figure,plot(avr_curve(t1:t2))
%estimated cubic curve
for i= 1:2*offset+1
x= i-offset-1;
fx(i)=x^3+u(1)*x^2+u(2)*x+u(3);
end
figure,plot(fx(t1:t2))
[t1 t2]上avr_curve的一部分
我得到的立方曲线(看起来不像avr_curve)
所以我做错了什么?
更新 似乎我的错误是因为我使用3个变量模拟三次多项式:
f(x)= x^3+a2*x^2+a1*x1+a0 - 3 variables
然后我使用4个变量似乎一切正常:
f(x)= a3*x^3+a2*x^2+a1*x1+a0 - 4 variables
以下是Matlab中的代码:
%defined by hand
t1= 10;
t2= 14;
avr_curve= [41, 40, 40, 41, 41, 42, 42, 43, 43, 43, 51, 76, 98, 104, 104, 103, 104, 105, 105, 107, 105];
x= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
%x= [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; %real x axis
%%%model 1
%%f(x)= x^3+a2*x^2+a1*x1+a0 - 3 variables
%A= zeros(4,3);
%b= [43 104]';
%%cubic equation at t1
%A(1,1)= t1^2; %a2
%A(1,2)= t1; %a1
%A(1,3)= 1; %a0
%b(1,1)= b(1,1)-t1^3;
%%cubic equation at t2
%A(2,1)= t2^2; %a2
%A(2,2)= t2; %a1
%A(2,3)= 1; %a0
%b(2,1)= b(2,1)-t1^3;
%%1st derivative at t1
%A(3,1)= 2*t1; %a2
%A(3,2)= 1; %a1
%A(3,3)= 0; %a0
%b(3,1)= -3*t1^2;
%%1st derivative at t2
%A(4,1)= 2*t2; %a2
%A(4,2)= 1; %a1
%A(4,3)= 0; %a0
%b(4,1)= -3*t2^2;
%model 2
%f(x)= a3*x^3+a2*x^2+a1*x1+a0 - 4 variables
A= zeros(4,4);
b= [43 104]';
%cubic equation at t1
A(1,1)= t1^3; %a3
A(1,2)= t1^2; %a2
A(1,3)= t1; %a1
A(1,4)= 1; %a0
b(1,1)= b(1,1);
%cubic equation at t2
A(2,1)= t2^3; %a3
A(2,2)= t2^2; %a2
A(2,3)= t2; %a1
A(2,4)= 1; %a0
b(2,1)= b(2,1);
%1st derivative at t1
A(3,1)= 3*t1^2; %a3
A(3,2)= 2*t1; %a2
A(3,3)= 1; %a1
A(3,4)= 0; %a0
b(3,1)= 0;
%1st derivative at t2
A(4,1)= 3*t2^2; %a3
A(4,2)= 2*t2; %a2
A(4,3)= 1; %a1
A(4,4)= 0; %a0
b(4,1)= 0;
size(A)
size(b)
u= A\b;
u
%estimated cubic curve
%dx=[1:21]; % global view
dx=t1-1:t2+1; % local view in [t1 t2]
for x= dx
%fx(x)=x^3+u(1)*x^2+u(2)*x+u(3); % model 1
fx(x)= u(1)*x^3+u(2)*x^2+u(3)*x+u(4); % model 2
end
err= 0;
for x= dx
err= err+(fx(x)-avr_curve(x))^2;
end
err
figure,plot(dx,avr_curve(dx),dx,fx(dx))
间隔[t1-1 t2 + 1]的样条
并且在完整的时间间隔
答案 0 :(得分:2)
我无法保证下面给出的代码或方法的正确性,在使用任何代码或方法之前始终使用您的批评意义。
你有这个分段定义的功能
其中 f(t)是一个三次函数,为了唯一识别它,给出了以下附加条件
您希望恢复参数 t1 , t2 和 sigma 的最佳值,以便使用给定的点集最小化错误。
这基本上是符合least squares意义的曲线。
为了计算候选 Cl(t)函数与我们需要计算 f(t)的点集之间的误差,它的一般形式(正在一个立方体是
所以我们似乎还有四个额外的参数需要考虑。实际上,这些参数完全由 free 三个参数 t1 , t2 和 sigma 定义。
重要的是不要将 free 参数与依赖参数混淆。
考虑到 f(t)的附加条件,我们可以设置这个线性系统
由
给出一个解决方案(按预期)
这告诉我们如何在给定三个自由参数的情况下计算三次参数 这样 Cl(t)就完全确定了,现在是找到最佳候选人的时候了。
我现在通常会选择最小的方格
由于这不是线性函数,因此没有用于计算 sigma , t1 和 t2 的封闭形式。
然而,有一些数值方法,如Gauss-Newton。
然而,无论如何,都需要根据三个参数计算偏导数 我不知道如何根据 t1 之类的分离参数来计算导数。
我搜索过MathSE并找到了解决同一问题的this问题,但没有人回答。
没有偏导数,最小二乘法就结束了。
所以我采取了更实际的方法并在C中实现了一个强力函数,它可以尝试每个可能的参数三元组并返回最佳匹配。
鉴于问题的性质,样本数量的结果为 O (n ^ 2)。
算法如下:将样本集分为三部分,第一部分是 t1 之前的一部分, t1 之间的第二部分和 t2 以及 t2 之后的最后一个点。
第一部分仅用于计算 sigma , sigma 只是第1部分中各点的算术平均值。
t1 和 t2 通过一个循环计算, t1 设置为原始点集中的每个可能点,从第二个开始继续前进 对于 t1 的每个选项, t2 设置为 t1 之后的每个可能点。
在每次迭代时计算错误,如果它是有史以来的最小值,则保存使用的参数。
错误是计算机作为残差的绝对值,因为绝对值应该快(肯定比平方快)并且它符合度量的目的。
#include <stdio.h>
#include <math.h>
float point_on_curve(float sigma, float t1, float t2, float t)
{
float a,b,c,d, K;
if (t <= t1)
return sigma;
if (t >= t2)
return 0;
K = (t1-t2)*(t1-t2)*(t1-t2);
a = -2*sigma/K;
b = 3*sigma*(t1+t2)/K;
c = -6*sigma*t1*t2/K;
d = sigma*t2*t2*(3*t1-t2)/K;
return a*t*t*t + b*t*t + c*t + d;
}
float compute_error(float sigma, float t1, float t2, int s, int dx, int* data, int len)
{
float error=0;
unsigned int i;
for (i = 0; i < len; i++)
error += fabs(point_on_curve(sigma, t1, t2, s+i*dx)- data[i]);
return error;
}
/*
* s is the starting time of the samples set
* dx is the separation in time between two sample (a.k.a. sampling period)
* data is the array of samples
* len is the number of samples
* sigma, t1, t2 are pointers to output parameters computed
*
* return 1 if not enough (3) samples, 0 if everything went ok.
*/
int curve_fit(int s, int dx, int* data, unsigned int len, float* sigma, float* t1, float* t2)
{
float l_sigma = 0;
float l_t1, l_t2;
float sum = 0;
float min_error, cur_error;
char error_valid = 0;
unsigned int i, j;
if (len < 3)
return 1;
for (i = 0; i < len; i++)
{
/* Compute sigma as the average of points <= i */
sum += data[i];
l_sigma = sum/(i+1);
/* Set t1 as the point i+1 */
l_t1 = s+(i+1)*dx;
for (j = i+2; j < len; j++)
{
/* Set t2 as the points i+2, i+3, i+4, ... */
l_t2 = s+j*dx;
/* Compute the error */
cur_error = compute_error(l_sigma, l_t1, l_t2, s, dx, data, len);
if (cur_error < min_error || !error_valid)
{
error_valid = 1;
min_error = cur_error;
*sigma = l_sigma;
*t1 = l_t1;
*t2 = l_t2;
}
}
}
return 0;
}
int main()
{
float sigma, t1, t2;
int data[]={41, 40, 40, 41, 41, 42, 42, 43, 43, 43, 51, 76, 98, 104, 104, 103, 104, 105, 105, 107, 105};
unsigned int len = sizeof(data)/sizeof(int);
unsigned int i;
for (i = 0; i < len; i++)
data[i] -= 107; /* Subtract the max */
if (curve_fit(1,1,data, len, &sigma, &t1, &t2))
printf("Not enough data!\n");
else
printf("Parameters: sigma = %.3f, t1 = %.3f, t2 = %.3f\n", sigma, t1, t2);
return 0;
}
请注意 Cl(t)被定义为0作为其右限制,因此代码假设是这种情况。
这就是为什么从每个样本中减去最大值(107),我使用了开头给出的 Cl(t)的定义注意到样本有偏见。
到目前为止,我不打算调整代码,您可以轻松地在问题中添加另一个参数,并在需要时从1重做步骤,或者只是使用最大值翻译样本。
代码的输出是
Parameters: sigma = -65.556, t1 = 10.000, t2 = 14.000
与给定的点数相匹配,考虑到它被-107垂直平移。