应用实例

本例首先在MATLAB中用M文件实现Newton插值和绘图,并用库编译器生成.NET类库,然后在VB.NET编程环境中使用该类库进行编程。本实例在设计上考虑了计算与绘图,以及可变输入参数、有返回值等多种情况。[大谦MATLAB,dqmatlab点com]

编写M文件

在MATLAB中编写Newton插值法的M文件Newton.m,如下所示。

code.matlab
function s=Newton(x,y,x0,nn)
%Newton插值,x与y为已知的插值点及其函数值
%x0为要求的插值点的x坐标值。nn为Newton插值多项式的阶数
nx=length(x);
ny=length(y);
if nx~=ny
	warning('矢量x与y的长度应该相同。')
	return
end
m=length(x0);
%按照公式,对要求的插值点x0的每个元素进行计算
for i=1:m
	t=0.0;
	j=1;
	yy=y;
	kk=j;
	%求各级均差
	while(kk<=nn)
		kk=kk+1;
		for k=kk:nx
			yy(k)=(yy(k)-yy(kk-1))/(x(k)-x(kk-1));
		end
	end
	%求差值结果
	t=yy(1);
	for k=2:nn
		u=1.0;
		jj=1;
		while(jj<k)
			u=u*(x0(i)-x(jj));
			jj=jj+1;
		end
		t=t+yy(k)*u;
	end
	s(i)=t;
end

编写M文件Draw.m实现绘图。函数的输入参数可变,只有两个参数时,利用给定的一组数据进行绘图;有四个参数时,绘给定数据的图形,然后叠加插值点的图形。两种情况下绘得的图形都予以保存。

code.matlab
function Draw(x,y,varargin)
switch nargin
case 2
   	plot(x,y);
   	saveas(gcf,'D:\temp1.bmp');
case 4
   	plot(x,y);
   	hold on
   	x0=varargin{1};
   	y0=varargin{2};
   	plot(x0,y0,'+');
   	saveas(gcf,'D:\temp2.bmp');
   	hold off
otherwise
   	error('参数个数错误。')
end

创建.NET类库

注意: MATLAB库编译器创建.NET类库之前,以本书采用的MATLAB 2023b版本为例,需要先安装微软Visual Studio 10.0以上版本(本书基于Visual Studio 2022),并且MATLAB要在安装该软件以后再安装。

在MATLAB命令窗口键入

libraryCompiler

打开库编译器。在工具栏中的“TYPE”列表框中选择“.NET Assembly”选项,单击“EXPORTED FUNCTIONS”列表框右边的加号按钮,添加前面创建的M文件Newton.m和Draw.m,在“Packing Options”部分选择“Runtime included in package”单选钮,编译器下面部分自动生成一个名为Class1的类,添加的2个M文件成为该类的2个方法。修改类名为Newtonclass,保存工程,名为Newton.prj。

单击工具栏中的“Package”按钮,打包类库。生成的文件和目录,包括:

for_redistribution目录 – 包含安装应用程序和MATLAB运行时的文件。

for_testing目录 – 包含mcc创建的所有文件,用于测试安装。

for_redistribution_files_only目录 – 包含应用程序重新发布所需要的文件。

PackagingLog.txt – 编译器生成的日志文件。

在VB.NET编程环境中使用类库

在VB.NET中创建名为NETDEMO_Newton的VB.NET工程。然后按照下面的步骤使用刚刚创建的NET类库编程。

引用类库。在“项目”菜单中单击“添加引用…”选项,打开“添加引用”对话框,单击“浏览”按钮,浏览到类库所在目录,找到类库文件Newton.dll,如图3-1所示。单击“确定”按钮,进行引用。

Document Image

图3-1 “添加引用”对话框

然后重复上面的过程,添加对MWArray组件的引用,该组件位于

matlabroot\toolbox\dotnetbuilder\bin\win64\v4.0

该组件的名称为MWArray.dll。

设计程序界面。试图让编写的.NET程序具备下面的功能:

输入用于插值训练的向量数据X和Y;

输入插值点位置和插值多项式的阶次;

在界面上绘制给定数据的图形;

进行插值计算;

在界面上绘制插值点的图形。

Document Image

图3-2 设计程序界面

如图3-2设计程序的界面。窗体的Text属性值为“Newton插值”,FormBorderStyle属性的值为FixedSingle,MaximizeBox属性的值为False。在界面上添加1个框架控件、2个列表框控件、5个标签控件、5个文本框控件、1个图片框控件和5个命令按钮控件。各控件的属性如表3-4所示。

表3-4 控件及其属性

对象类型 名 称 属 性 值
框架 frmData Text=给定的数据
标签 lblDataX Text=X
标签 lblDataY Text=Y
标签 lblPosX Text=插值点的位置
标签 lblPosY Text=插值处的计算值
标签 lblPolyNum Text=多项式的次数
列表框 lstDataX
列表框 lstDataY
文本框 txtDataX
文本框 txtDataY
文本框 txtPosX
文本框 txtPosY
文本框 txtPolyNum
图片框 picGraph BackColor=White BoderStyle=Fixed3D SizeMode=StretchImage
按钮 btnAddX Text=添加
按钮 btnAddY Text=添加
按钮 btnPlot Text=绘给定数据的图形
按钮 btnCompute Text=插值计算
按钮 btnPlotPos Text=绘插值点的图形

引入名字空间

分别为MATLAB工具集、数据转换集和Newton类库引入名字空间。

code.vb.net
Imports System
Imports MathWorks.MATLAB.NET.Utility
Imports MathWorks.MATLAB.NET.Arrays
Imports Newton

初始化类

在窗体类的New过程中可以对程序用到的数据进行初始化。在该过程中创建一个Newton类库的Newtonclass类的实例ntNewton。

首先,声明ntNewton对象的类型。

code.vb.net
Dim ntNewton As Newton.Newtonclass

然后,在New过程中创建类的实例。

code.vb.net
Public Sub New()
	'此调用时Windows窗体设计器所必需的
	InitializeComponent()
	'在InitializeComponent()调用之后添加任何初始化
	ntNewton=New Newton.Newtonclass
End Sub

输入数据

在界面上单击左右两个“添加”按钮时,会将其左侧文本框中的数据输入到上面的列表框中去。X列表框和Y列表框中的数据将用于插值训练。

code.vb.net
Private Sub btnAddX_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _					Handles btnAddX.Click
    '将数据X输入到X列表框中
    lstDataX.Items.Add(txtDataX.Text)
    txtDataX.Clear()
End Sub
Private Sub btnAddY_Click(ByVal sender Ad System.Object, ByVal e As System.EventArgs)  _
Handles btnAddY.Click
    '将数据X输入到X列表框中
    lstDataY.Items.Add(txtDataY.Text)
    txtDataY.Clear()
End Sub

获取数据

进行绘图和插值计算之前,首先要获取给定的数据。下面的代码首先从列表框中获取数据,然后将它们转化为MATLAB数据类型。只有转化为MATLAB数据类型以后,才能利用MATLAB库编译器创建的类库进行处理。

code.vb.net
Dim intPoints As Integer
Dim intI as integer
Dim numDataX As MWNumericArray
Dim numDataY As MWNumericArray
Dim numPoints As MWNumericArray
Private Sub GetData()
    If lstDataX.Items.Count<>lstDataY.Items.Count Then
        MsgBox("给定的数据不配对,请检查数据。")
        Exit Sub
    End If
    intPoints=lstDataX.Items.Count
    Dim dblDataX() As Double=New Double(intPoints-1){}
    Dim dblDataY() As Double=New Double(intPoints-1){}
    '获得向量数据X和Y的值
    For intI=0 To lstDataX.Items.Count-1
        dblDataX(intI)=CDbl(lstDataX.Items(intI))
        dblDataY(intI)=CDbl(lstDataY.Items(intI))
    Next
    '将本地类型转换为MATLAB数据类型
    numDataX=New MWNumericArray(dblDataX)
    numDataY=New MWNumericArray(dblDataY)
End Sub

绘给定数据的图形

在界面上单击“绘给定数据的图形”按钮时,绘制给定数据的图形。利用下面的代码进行处理。首先获取数据,然后调用类库中类的Draw方法绘图。Draw方法绘图的时候已经将绘好的图形保存在C盘的temp1.bmp中,现在将该图形显示在界面上的图片框中来。

code.vb.net
Private Sub btnPlot_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _
      Handles btnPlot.Click
    '获取数据
    GetData()
    '绘给定数据的图形
    ntNewton.Draw(numDataX, numDataY)
    '在图片框中显示图形
    picGraph.ImageLocation="D:\temp1.bmp"
End Sub

插值计算

在界面上单击“插值计算”按钮时进行插值计算。进行插值计算以前,需要首先输入给定数据,以及插值点的位置和插值多项式的阶次。需要注意的是,插值多项式的阶次不能大于给定数据的组数。

下面的代码实现插值计算。首先获取数据,进行必要的数据类型转换以后,调用类库类的Newton方法进行计算。将该方法的返回值指定为MWNumericArray数据类型,然后转换为本地double型并显示在界面上。

code.vb.net
Private Sub btnCompute_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
      Handles btnCompute.Click
    Dim dblPosX As Double
    Dim intPolyNum As Integer
    Dim numPosX As MWNumericArray
    Dim numPosY As MWNumericArray
    '获取数据
    GetData()
    '获取插值点位置数据并转换为MATLAB数据类型
    dblPosX=CDbl(txtPosX.Text)
    numPosX=New MWNumericArray(dblPosX)
    '获取用于插值计算的多项式的阶次数据并
    '转换为MATLAB数据类型
    intPolyNum=CInt(txtPolyNum.Text)
    numPoints=New MWNumericArray(intPolyNum)
    '进行插值计算并指定数据类型
    numPosY=CType(ntNewton.Newton(numDataX,numDataY,numPosX,numPoints), _
      MWNumericArray)
    '转换数据类型并显示
    txtPosY.Text=CStr(CDbl(numPosY))
End Sub

绘插值点的图形

在界面上单击“绘插值点的图形”按钮时,绘制给定数据的图形和插值点处的图形。插值点处的图形用十字星形表示。利用下面的代码进行处理。首先获取数据,然后调用类库类的Draw方法绘图。Draw方法绘图的时候已经将绘好的图形保存在C盘的temp2.bmp中,现在将该图形显示在界面上的图片框中来。

注意:这里使用Draw方法与前面的不同,前面只有两个输入参数,这里有四个。这里涉及到参数个数可变情况下的用法。

code.vb.net
Private Sub btnPlotPos_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _					Handles btnPlotPos.Click
    Dim dblPosX As Double
    Dim dblPosY As Double
    Dim numPosX As MWNumericArray
    Dim numPosY As MWNumericArray
    '获取数据
    GetData()
    '获取插值点位置数据并转换为MATLAB数据类型
    dblPosX=CDbl(txtPosX.Text)
    numPosX=New MWNumericArray(dblPosX)
    dblPosY=CDbl(txtPosY.Text)
    numPosY=New MWNumericArray(dblPosY)
    '绘给定数据的图形并叠加插值点的图形
    ntNewton.Draw(numDataX,numDataY,numPosX,numPosY)
    '在图片框中显示图形
    picGraph.ImageLocation="D:\temp2.bmp"
End Sub

测试程序

注意:编译前必须对VB.NET的编译器进行设置,必须与打包.NET类库时所用的MATLAB同为32位或64位,否则会出错。

现在运行程序,利用Newton插值函数求解下列问题:

给定表3-5所示的数据,利用4次牛顿插值多项式插值计算0.596处的值。

表3-5 已知数据表

X 0.4 0.55 0.65 0.80 0.90 1.05
Y 0.41075 0.57815 0.69675 0.88811 1.02652 1.25382

在程序中分别输入向量X和Y的数据,单击“绘给定数据的图形”按钮,绘给定数据的线形图。

据题意,插值点的位置为0.596,插值多项式的阶次为4,输入它们,单击“插值计算”按钮,算得该处的计算值。单击“绘插值点的图形”按钮,绘插值点的图形,如图3-3所示。

Document Image

图3-3 用4阶多项式进行Newton插值并绘图