本例首先在MATLAB中用M文件实现Newton插值和绘图,并用库编译器生成.NET类库,然后在VB.NET编程环境中使用该类库进行编程。本实例在设计上考虑了计算与绘图,以及可变输入参数、有返回值等多种情况。[大谦MATLAB,dqmatlab点com]
编写M文件
在MATLAB中编写Newton插值法的M文件Newton.m,如下所示。
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实现绘图。函数的输入参数可变,只有两个参数时,利用给定的一组数据进行绘图;有四个参数时,绘给定数据的图形,然后叠加插值点的图形。两种情况下绘得的图形都予以保存。
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所示。单击“确定”按钮,进行引用。
图3-1 “添加引用”对话框
然后重复上面的过程,添加对MWArray组件的引用,该组件位于
matlabroot\toolbox\dotnetbuilder\bin\win64\v4.0
该组件的名称为MWArray.dll。
设计程序界面。试图让编写的.NET程序具备下面的功能:
输入用于插值训练的向量数据X和Y;
输入插值点位置和插值多项式的阶次;
在界面上绘制给定数据的图形;
进行插值计算;
在界面上绘制插值点的图形。
图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类库引入名字空间。
Imports System
Imports MathWorks.MATLAB.NET.Utility
Imports MathWorks.MATLAB.NET.Arrays
Imports Newton
初始化类
在窗体类的New过程中可以对程序用到的数据进行初始化。在该过程中创建一个Newton类库的Newtonclass类的实例ntNewton。
首先,声明ntNewton对象的类型。
Dim ntNewton As Newton.Newtonclass
然后,在New过程中创建类的实例。
Public Sub New()
'此调用时Windows窗体设计器所必需的
InitializeComponent()
'在InitializeComponent()调用之后添加任何初始化
ntNewton=New Newton.Newtonclass
End Sub
输入数据
在界面上单击左右两个“添加”按钮时,会将其左侧文本框中的数据输入到上面的列表框中去。X列表框和Y列表框中的数据将用于插值训练。
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库编译器创建的类库进行处理。
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中,现在将该图形显示在界面上的图片框中来。
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型并显示在界面上。
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方法与前面的不同,前面只有两个输入参数,这里有四个。这里涉及到参数个数可变情况下的用法。
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所示。
图3-3 用4阶多项式进行Newton插值并绘图