C++最小二乘法拟合-(线性拟合和多项式拟合)(二)

2014-11-24 11:12:24 · 作者: · 浏览: 2
值的x /// \param y 观察值的y /// \param length x,y数组的长度 /// \param poly_n 期望拟合的阶数,若poly_n=2,则y=a0+a1*x+a2*x^2 /// \param isSaveFitYs 拟合后的数据是否保存,默认是 /// template void polyfit(const std::vector & x,const std::vector & y,int poly_n,bool isSaveFitYs=true); template void polyfit(const T* x,const T* y,size_t length,int poly_n,bool isSaveFitYs=true);

这两个函数都用模板函数形式写,主要是为了能使用于float和double两种数据类型


2.fit类的MFC示范程序

下面看看如何使用这个类,以MFC示范,使用了开源的绘图控件Hight-Speed Charting,使用方法见http://blog.csdn.net/czyt1988/article/details/8740500

新建对话框文件,

对话框资源文件如图所示:

\

加入下面的这些变量:

	std::vector
                                       
                                         m_x,m_y,m_yploy;
	const size_t m_size;
	CChartLineSerie *m_pLineSerie1;
	CChartLineSerie *m_pLineSerie2;
                                       

由于m_size是常量,因此需要在构造函数进行初始化,如:

ClineFitDlg::ClineFitDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(ClineFitDlg::IDD, pParent)
	,m_size(512)
	,m_pLineSerie1(NULL)


初始化两条曲线:

CChartAxis *pAxis = NULL; 
pAxis = m_chartCtrl.CreateStandardAxis(CChartCtrl::BottomAxis);
pAxis->SetAutomatic(true);
pAxis = m_chartCtrl.CreateStandardAxis(CChartCtrl::LeftAxis);
pAxis->SetAutomatic(true);
m_x.resize(m_size);
m_y.resize(m_size);
m_yploy.resize(m_size);
for(size_t i =0;i
                                       
                                        SetSeriesOrdering(poNoOrdering);//设置为无序
m_pLineSerie1->AddPoints(&m_x[0], &m_y[0], m_size);
m_pLineSerie1->SetName(_T("线性数据"));
m_pLineSerie2 = m_chartCtrl.CreateLineSerie();	
m_pLineSerie2->SetSeriesOrdering(poNoOrdering);//设置为无序
m_pLineSerie2->AddPoints(&m_x[0], &m_yploy[0], m_size);
m_pLineSerie2->SetName(_T("多项式数据"));
                                       

rangf是随机数生成函数,实现如下:

double ClineFitDlg::randf(double min,double max)
{
	int minInteger = (int)(min*10000);
	int maxInteger = (int)(max*10000);
	int randInteger = rand()*rand();
	int diffInteger = maxInteger - minInteger;
	int resultInteger = randInteger % diffInteger + minInteger;
	return resultInteger/10000.0;
}

运行程序,如图所示

\

线性拟合的使用如下:

void ClineFitDlg::OnBnClickedButton1()
{
	CString str,strTemp;
	czy::Fit fit;
	fit.linearFit(m_x,m_y);
	str.Format(_T("方程:y=%gx+%g\r\n误差:ssr:%g,sse=%g,rmse:%g,确定系数:%g"),fit.getSlope(),fit.getIntercept()
		,fit.getSSR(),fit.getSSE(),fit.getRMSE(),fit.getR_square());
	GetDlgItemText(IDC_EDIT,strTemp);
	SetDlgItemText(IDC_EDIT,strTemp+_T("\r\n------------------------\r\n")+str);
	//在图上绘制拟合的曲线
	CChartLineSerie* pfitLineSerie1 = m_chartCtrl.CreateLineSerie();	
	std::vector
                                       
                                         x(2,0),y(2,0);
	x[0] = 0;x[1] = m_size-1;
	y[0] = fit.getY(x[0]);y[1] = fit.getY(x[1]);
	pfitLineSerie1->SetSeriesOrdering(poNoOrdering);//设置为无序
	pfitLineSerie1->AddPoints(&x[0], &y[0], 2);
	pfitLineSerie1->SetName(_T("拟合方程"));//SetName的作用将在后面讲到
	pfitLineSerie1->SetWidth(2);
}
                                       

需要如下步骤:

声明Fit类,用于头文件在czy命名空间中,因此需要显示声明命名空间名称czy::Fit fit;把观察数据输入进行拟合,由于是线性拟合,可以使用LinearFit函数,此函数把观察量的x值和y值传入即可进行拟合拟合完后,拟合的相关结果保存在czy::Fit里面,可以通过相关方法调用,方法在头文件中都有详细说明

运行结果如图所示:

\


多项式拟合的使用如下:

void ClineFitDlg::OnBnClickedButton2()
{
	CString str;
	GetDlgItemText(IDC_EDIT1,str);
	if (str.IsEmpty())
	{
		MessageBox(_T("请输入阶次"),_T("警告"));
		return;
	}
	int n = _ttoi(str);
	if (n<0)
	{
		MessageBox(_T("请输入大于1的阶数"),_T("警告"));
		return;
	}
	czy::Fit fit;
	fit.polyfit(m_x,m_yploy,n,true);
	CString strFun(_T("y=")),strTemp(_T(""));
	for (int i=0;i
                                       
                                         yploy;
	fit.getFitedYs(yploy);
	CChartLineSerie* pfitLineSerie1 = m_chartCtrl.CreateLineSerie();	
	pfitLineSerie1->SetSeriesOrdering(poNoOrdering);//设置为无序
	pfitLineSerie1