我有一组与温度相关的曲线。 即曲线 Mat1 是针对 310C 的温度,而 Mat2 是针对 420C 的。
如您所见,数据采用对数刻度时看起来更好;
现在我需要通过插入 Mat1 和 Mat2 曲线来获得温度为 370C 的 Mat3 曲线。解决此问题的最佳方法是什么?我猜我可能需要做某种 3D 插值。还需要考虑数据的性质(对数行为)。
这是 Mat1 的数据
9.43E+06 6.00E+04
3.96E+06 6.20E+04
1.78E+06 6.40E+04
8.52E+05 6.60E+04
4.28E+05 6.80E+04
2.25E+05 7.00E+04
1.23E+05 7.20E+04
6.95E+04 7.40E+04
4.05E+04 7.60E+04
2.43E+04 7.80E+04
1.49E+04 8.00E+04
9.39E+03 8.20E+04
这是 Mat2 的数据
5.14E+08 4.80E+04
1.35E+08 5.00E+04
4.36E+07 5.20E+04
1.64E+07 5.40E+04
6.90E+06 5.60E+04
3.18E+06 5.80E+04
1.58E+06 6.00E+04
8.35E+05 6.20E+04
4.64E+05 6.40E+04
2.69E+05 6.60E+04
1.62E+05 6.80E+04
1.01E+05 7.00E+04
6.47E+04 7.20E+04
4.25E+04 7.40E+04
2.86E+04 7.60E+04
1.96E+04 7.80E+04
1.37E+04 8.00E+04
9735.23 8.20E+04
任何帮助将不胜感激。
编辑: 我正在为两条附加曲线添加数据;
温度 21C 时的曲线
3.98E+07 6.30E+04
1.58E+07 6.40E+04
4.03E+06 6.60E+04
1.47E+06 6.80E+04
6.57E+05 7.00E+04
3.37E+05 7.20E+04
1.91E+05 7.40E+04
1.16E+05 7.60E+04
7.49E+04 7.80E+04
5.04E+04 8.00E+04
3.52E+04 8.20E+04
2.53E+04 8.40E+04
1.87E+04 8.60E+04
1.41E+04 8.80E+04
1.08E+04 9.00E+04
8.47E+03 9.20E+04
537C 温度下的曲线
7.91E+06 3.80E+04
3.29E+06 4.00E+04
1.51E+06 4.20E+04
7.48E+05 4.40E+04
3.95E+05 4.60E+04
2.20E+05 4.80E+04
1.28E+05 5.00E+04
7.77E+04 5.20E+04
4.87E+04 5.40E+04
3.14E+04 5.60E+04
2.08E+04 5.80E+04
1.41E+04 6.00E+04
9.73E+03 6.20E+04
6.85E+03 6.40E+04
有关曲线的更多信息 - 这些是不同温度下材料的交变应力(y 轴)、失效循环数(x 轴)曲线。
谢谢。
答案 0 :(得分:1)
我设法让简单的示例工作。首先,您的数据必须排序,因此测量值必须按温度排序,并且每个测量值必须按 y
(应力)排序。我使用升序。第一种算法:
计算 BBOX
简单地计算所有测量值的最小和最大 x,y
坐标。这将用于对数刻度和线性刻度之间的转换以及对齐。
重新采样并对齐所有测量值
因此将所有测量值转换为样本具有相同的 y
值(跨所有测量值)。我使用了均匀采样的 y
轴。所以简单的步骤是 (ymax-ymin)/(n-1)
,其中 n
是重采样数据的点数。因此,所有测量将具有相同的大小,并且所有 y
值在同一索引的测量中将相同。缺失的 x
数据将用 0
填充。
重采样可以在线性范围内完成。我使用了 piecewise cubic interpolation。
为新温度创建新的测量值
因此只需再次创建包含 n
点的新测量。 y
值与之前相同(因此只需从任何对齐的测量中复制它),然后从与我们正在处理的同一点对应的 4 个测量中的每一个中取 1 个点,并对其位置进行三次插值.但是这必须以对数标度来完成!
温度的有效范围在第 2 次和第 3 次测量温度之间。
此处使用您的数据和 370 C 进行预览:
这里是 C++/VCL 示例(忽略 VCL 内容):
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
int xs,ys; // screen resolution
Graphics::TBitmap *bmp; // back buffer bitmap for rendering
//---------------------------------------------------------------------------
// here starts the important stuff
//---------------------------------------------------------------------------
float in[4][40]= // input measureements format is: { temperature,x0,y0,x1,y1...,-1 }
{{ 21.0,
3.98E+07,6.30E+04,
1.58E+07,6.40E+04,
4.03E+06,6.60E+04,
1.47E+06,6.80E+04,
6.57E+05,7.00E+04,
3.37E+05,7.20E+04,
1.91E+05,7.40E+04,
1.16E+05,7.60E+04,
7.49E+04,7.80E+04,
5.04E+04,8.00E+04,
3.52E+04,8.20E+04,
2.53E+04,8.40E+04,
1.87E+04,8.60E+04,
1.41E+04,8.80E+04,
1.08E+04,9.00E+04,
8.47E+03,9.20E+04,
-1.0 },
{ 310.0,
9.43E+06,6.00E+04,
3.96E+06,6.20E+04,
1.78E+06,6.40E+04,
8.52E+05,6.60E+04,
4.28E+05,6.80E+04,
2.25E+05,7.00E+04,
1.23E+05,7.20E+04,
6.95E+04,7.40E+04,
4.05E+04,7.60E+04,
2.43E+04,7.80E+04,
1.49E+04,8.00E+04,
9.39E+03,8.20E+04,
-1.0 },
{ 420.0,
5.14E+08,4.80E+04,
1.35E+08,5.00E+04,
4.36E+07,5.20E+04,
1.64E+07,5.40E+04,
6.90E+06,5.60E+04,
3.18E+06,5.80E+04,
1.58E+06,6.00E+04,
8.35E+05,6.20E+04,
4.64E+05,6.40E+04,
2.69E+05,6.60E+04,
1.62E+05,6.80E+04,
1.01E+05,7.00E+04,
6.47E+04,7.20E+04,
4.25E+04,7.40E+04,
2.86E+04,7.60E+04,
1.96E+04,7.80E+04,
1.37E+04,8.00E+04,
9735.23 ,8.20E+04,
-1.0 },
{ 537.0,
7.91E+06,3.80E+04,
3.29E+06,4.00E+04,
1.51E+06,4.20E+04,
7.48E+05,4.40E+04,
3.95E+05,4.60E+04,
2.20E+05,4.80E+04,
1.28E+05,5.00E+04,
7.77E+04,5.20E+04,
4.87E+04,5.40E+04,
3.14E+04,5.60E+04,
2.08E+04,5.80E+04,
1.41E+04,6.00E+04,
9.73E+03,6.20E+04,
6.85E+03,6.40E+04,
-1.0 }};
//---------------------------------------------------------------------------
// temp and output data
//---------------------------------------------------------------------------
const n=40; // points to resmaple curves with
float dat[4][2+n+n]; // resampled input curves
float out[2+n+n]; // interpolated curve
float xmin,xmax,ymin,ymax; // BBOX
void resample(float *out,float *in,float y0,float y1) // resample and align y to range and n points and store it to out
{
float t,d1,d2,a0,a1,a2,a3,x,y,x0,x1,x2,x3;
int i,ii,i0,i1,i2,i3,nn;
// scan how many points in[] has
for (nn=0,i=1;in[i]>=0.0;i+=2) nn++;
// resample input curves to n points
out[0]=in[0]; // copy T
out[n+n+1]=-1; // end of data
for (i=0;i<n;i++)
{
// y uniformly distributed and aligned in the dat array
y=y0+((y1-y0)*float(i)/float(n-1));
ii=1+i +i ;
// check if range present
if ((y<in[1+1])||(y>in[1+nn-1+nn-1+1]))
{
out[ii+0]=0.0;
out[ii+1]=y;
continue;
}
// find i1 so in[i1] <= y < in[i1+1]
// linear search, can be replaced with binary search
for (i1=0;i1<nn;i1++) if (in[1+i1+i1+1]>=y) break;
if (in[1+i1+i1+1]>y) i1--;
// neigboring indexes
i0=i1-1; if (i0< 0) i0= 0;
i2=i1+1; if (i2>=nn) i2=nn-1;
i3=i1+2; if (i3>=nn) i3=nn-1;
// convert to array index
i0=1+i0+i0;
i1=1+i1+i1;
i2=1+i2+i2;
i3=1+i3+i3;
// parameter is based on y value
d1=y-in[i1+1];
d2=in[i2+1]-in[i1+1];
if (fabs(d2)>1e-6) t=d1/d2; else t=0.0;
// points to interpolate
x0=in[i0];
x1=in[i1];
x2=in[i2];
x3=in[i3];
// cubic interpoaltion of x
d1=0.5*(x2-x0);
d2=0.5*(x3-x1);
a0=x1;
a1=d1;
a2=(3.0*(x2-x1))-(2.0*d1)-d2;
a3=d1+d2+(2.0*(-x2+x1));
x=a0+(a1*t)+(a2*t*t)+(a3*t*t*t);
if (x<0.0) x=0.0; // just to be sure data is not messed up
// copy point
out[ii+0]=x;
out[ii+1]=y;
}
}
//---------------------------------------------------------------------------
void interpolate(float *out,float T) // interpolate out[] as n point curve from dat[4][] matching temperature T
{ // dat[][] must be ordered ascending by T,x,y
int i,ii; // valid T range is <dat[1][0],dat[2][0]>
float t,d1,d2,a0,a1,a2,a3,x,x0,x1,x2,x3,t0,t1,t2,t3;
out[0]=T; // copy T
out[n+n+1]=-1; // end of data
// parameter from T
t=(T-dat[1][0])/(dat[2][0]-dat[1][0]);
t0=dat[0][0];
t1=dat[1][0];
t2=dat[2][0];
t3=dat[3][0];
// cubic interpolation between curves
for (i=0;i<n;i++)
{
// points to interpolate
ii=1+i+i;
x0=dat[0][ii];
x1=dat[1][ii];
x2=dat[2][ii];
x3=dat[3][ii];
// logarithm scale
(x0>=xmin)?x0=log(x0/xmin)/log(xmax/xmin):x0=0.0;
(x1>=xmin)?x1=log(x1/xmin)/log(xmax/xmin):x1=0.0;
(x2>=xmin)?x2=log(x2/xmin)/log(xmax/xmin):x2=0.0;
(x3>=xmin)?x3=log(x3/xmin)/log(xmax/xmin):x3=0.0;
out[ii+1]=dat[0][ii+1]; // copy y
// too much missing data
if ((x1<=0.0)||(x2<=0.0)){ out[ii+0]=0; continue; }
// mirror missing data
if (x0<=0.0) x0=x1-((x2-x1)*(t1-t0)/(t2-t1));
if (x3<=0.0) x3=x2+((x2-x1)*(t3-t2)/(t2-t1));
// interpolate x
d1=0.5*(x2-x0);
d2=0.5*(x3-x1);
a0=x1;
a1=d1;
a2=(3.0*(x2-x1))-(2.0*d1)-d2;
a3=d1+d2+(2.0*(-x2+x1));
x=a0+(a1*t)+(a2*t*t)+(a3*t*t*t);
if (x<0.0) x=0.0; // just to be sure data is not messed up
else x=exp(x*log(xmax/xmin))*xmin; // back to linear scale
out[ii+0]=x;
}
}
//---------------------------------------------------------------------------
void minmax(float *dat,bool _reset) // compute BBOX of the curves
{
int i;
float x,y;
for (i=1;dat[i]>=0.0;)
{
x=dat[i]; i++;
y=dat[i]; i++;
if (x<=0.0) continue;
if (_reset){ xmin=xmax=x; ymin=ymax=y; _reset=false; }
if (xmin>x) xmin=x;
if (xmax<x) xmax=x;
if (ymin>y) ymin=y;
if (ymax<y) ymax=y;
}
}
//---------------------------------------------------------------------------
void toscr(float &x,float &y) // convert x,y from plot data to screen coordinates (just for rendering)
{
float x0,dx,y1,dy;
// range <0,1>
// x=(x-xmin)/(xmax-xmin); // linear
// y=(y-ymin)/(ymax-ymin); // linear
(x>=xmin)?x=log(x/xmin)/log(xmax/xmin):x=0.0; // logarithmic
(y>=ymin)?y=log(y/ymin)/log(ymax/ymin):y=0.0; // logarithmic
// view
x0=0.1*xs; dx=0.8*xs;
y1=0.9*ys; dy=0.8*ys;
// [pixels]
x=x0+x*dx;
y=y1-y*dy;
}
//---------------------------------------------------------------------------
void plot(float *dat,TColor col)// renders measurement data (just for rendering)
{
int i,e;
float x,y,r=2;
// curve
bmp->Canvas->Pen->Color=col;
bmp->Canvas->Font->Color=col;
for (e=1,i=1;dat[i]>=0.0;)
{
x=dat[i]; i++;
y=dat[i]; i++;
if (x<=0.0) continue;
toscr(x,y);
if (e)
{
bmp->Canvas->TextOutA(x,y,AnsiString().sprintf("%.0f C",dat[0]));
bmp->Canvas->MoveTo(x,y);
e=0;
}
else bmp->Canvas->LineTo(x,y);
}
// points
for (i=1;dat[i]>=0.0;)
{
x=dat[i]; i++;
y=dat[i]; i++;
if (x<=0.0) continue;
toscr(x,y);
bmp->Canvas->Ellipse(x-r,y-r,x+r,y+r);
}
}
//---------------------------------------------------------------------------
void draw() // just render of my App
{
bmp->Canvas->Brush->Color=clWhite;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
plot(dat[0],clRed);
plot(dat[1],clGreen);
plot(dat[2],clBlue);
plot(dat[3],clBlack);
plot(out,clMaroon);
Form1->Canvas->Draw(0,0,bmp);
// bmp->SaveToFile("out.bmp");
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner) // init of my app
{
// init backbuffer
bmp=new Graphics::TBitmap;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
// here prepare data (important)
int i;
for (i=0;i<4;i++) minmax(in[i],i==0);
for (i=0;i<4;i++) resample(dat[i],in[i],ymin,ymax);
// here create new data for T=370[C]
interpolate(out,370.0);
// and also include it to the BBOX for rendering
minmax(out,false);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender) // not important just destructor of my App
{
delete bmp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender) // not important just resize event
{
xs=ClientWidth;
ys=ClientHeight;
bmp->Width=xs;
bmp->Height=ys;
draw();
}
//-------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender) // not important just repaint event
{
draw();
}
//---------------------------------------------------------------------------
请参阅函数 TForm1::TForm1(TComponent* Owner)
了解如何使用它。
但是物理有效性值得怀疑 您应该通过 5 次测量来测试这种插值是否会产生有效数据。使用 4 来插值 5 并检查它们是否重叠如果没有,那么这可能需要额外的调整,例如增加插值多项式次数,或者也使用对数刻度进行重采样等......