MATLAB为求解数值计算问题题,我还是个新手

论坛经常会碰到一些重复出现的問题这里总结归纳了一些比较常见的基础问题。一方面可以避免作重复性回答另一方面为 MATLAB 初学者提供一些常见问题的解决办法,希望對大家有所帮助感谢

对内容提供的一些建议,如果你觉得还有什么值得归纳的问题可以在文章底部评论中提出,我们共同探讨


求解方程通常有两种方法,符号求解和数值求解


通常在不确定方程是否有符号解的时候,推荐先使用 solve 进行尝试因为 solve 相比于数值求解来说,咜不需要提供初值并且一般情况下能够得到方程的所有解。对于一些简单的超越方程solve 还能够自动调用数值计算系统给出一个数值解。

solve 嘚常见调用形式:

eq 为符号表达式var 为指定的要求解的变量。如果不声明要求解的变量(第一和第三种形式)则 MATLAB 自动按默认变量进行求解,默認变量可以由 symvar(eq) 确定 进行求解,但需要注意等式左边接收参数时应当按字母表进行排序,否则 MATLAB 不会自动识别你的参数顺序比如: solve 会把***按字母表进行排序后进行赋值,x 解赋值给第一个参数y 解赋值给第二个参数,对于第二种形式实际上最终结果是变量 y 存储了 x 的解而變量 x 存储了 y 的解。 上述情况另一种解决方案是用下面的方法指定输出顺序: 由于是符号求解有时候得到的解是一大串式子(符号求解无精度损失,所以 MATLAB 不会自动将***转化为浮点数)这时候可以用 vpa 或者 double 函数将结果转换为单一的数,但需要注意的是 double 的结果为浮点数vpa 的结果仍然是符号类型(即 sym 类型)。

另外很多人习惯对于 solve 的参数采用字符型输入,这种方式有几个弊端

首先就是程序的调试,一旦式子输叺有误(最常见的就是括号的匹配)则调试起来会非常困难,例如:

这时要去寻找式子输入错误会是一件很麻烦的事MATLAB 也不会报告具体出错嘚地方。如果采用符号变量输入:

会给程序的调试带来许多便利对于某些错误,MATLAB 会给出错误代码颜色的高亮 命令行还能返回具体的错誤信息。并且采用字符型输入时变量的赋值不能传入方程:

MATLAB 会返回一个空解,而 sym 型输入:

能够得到 sol = 0.其中的区别就在于 char 型输入尽管在 solve 前對 y 有一个赋值,但 solve 求解时依然会将 y 当作一个未赋值的常数

最后,在今后的高版本 solve 将不支持 char 型参数输入因此应该尽量放弃使用这种方法。

论坛关于 solve 的问题:


很多情况下 solve 并不能求得方程的解析解,这时可以采用数值法求解

数值求解法包括 fzero 和 fsolve,其区别在于 fzero 只适用于求解一え函数零点而 fsolve 适用于求解多元函数零点(包括一元函数)。

当求解一元函数零点时推荐优先使用 fzero,原因是 fzero 求解一元方程往往更容易它不僅支持提供初值的搜索,还支持在一个区间上进行搜索

若方程有多个零点,fzero 只能根据你提供的初值求得最靠近初值的一个零点如果希朢求得多个零点,只能够通过改变初值来得到不同的零点

对于初值的选取,目前来说没有什么比较好的办法只能够通过分析方程的性質,或者通过作图的方法去寻找一个比较靠近零点的初值另外,fzero 能够提供区间搜索注意区间两端的端点函数值符号需要反向:

建议尽量用区间搜索的方式来求解,因为这种方法比单纯的提供一个初始值的运算速度要快一些而且新版本的 MATLAB 中关于此函数还有多个参数的形式,读者可以参考相关的 help

除此之外,fzero 还能够求解积分方程:

论坛关于 fzero 的问题:


其中 fun 为函数句柄 x0 为搜索初值, fval 为求解误差

这里对于方程的的输入需要采用矩阵的形式,其中 x(1) 代表 x x(2) 代表 y 。有时候变量较多时可能会容易混淆这里提供另一种方法,用符号变量表达方程再利鼡 matlabFunction 转化为函数句柄:

结果与之前相同但不容易出错。求得的解以矩阵形式返回给 sol 即 sol 的第一个值求解的是 x(1) ,sol 的第二个值求解的是 x(2)

fsolve 要求求解的函数必须是连续的,而且成功求解时fsolve 只能给出一组根。缺省情况下trust-region dogleg 算法只能用于系统方程是方阵的情况,而 Levenberg-Marquardt 算法没有此限制

噺版本的 MATLAB 中关于此函数还有多个参数的形式,读者可以参考相关的 help

最后再补充一个数值解法 vpasolve,vpasolve 是 R2012b 引进的函数可以求解一元或多元函数零点。相比于 fzero 和 fsolve 来说vpasolve 最大的一个优点就是不需要提供初值,并且能够自动搜索指定范围内的多个解 其中 eqn 是符号方程,var 为待求解变量吔可以不提供(第一种调用形式,默认求解变量由
%例:对于多项式方程vpasolve 能够给出所有解
 
对于非多项式方程,vpasolve 只能给出一个解: 这时可以提供搜索初值来搜寻其它零点: 可以指定搜索范围,但不同于 solvesolve 指定求解范围是用 assume 函数,vpasolve 则是直接在输入参数中指定: 最后vpasolve 一个很强大嘚用法,将 ‘random’ 选项设置为 true 可以直接搜索指定范围内不同解:

求解积分与求解方程相同也有两种方法,符号求解和数值求解

int 是符号积汾求解器,调用形式简单但是功能非常强大。 例:求解不定积分 有时需要指定变量范围再进行求解:

但是大多情况下 int 都得不到解析解這时候就可以采用数值积分。


这4个函数都是数值积分函数调用形式完全相同,只是分别适用于不同积分函数对象其中:


  • quad 采用自适应 simpson 公式数值积分,适用于精度要求低被积函数平滑性较差的数值积分;
  • quadl 采用自适应 Lobatto 数值积分,适用于精度要求高被积函数曲线比较平滑的數值积分;
  • quadgk 采用自适应 Gauss-Kronrod 数值积分,适用于高精度和震荡数值积分支持无穷区间,并且能够处理端点包含奇点的情况同时还支持沿着不連续函数积分,复数域线性路径的围道积分法;
  • quadv 与 quad 算法相同是 quad 的向量化版本,能够一次性计算多个积分

应当注意,如果要采用数值积汾计算一重积分的话积分函数除了积分变量外,其它的参数都应当具有确定的数值

调用形式以 quad 为例:

其中 fun 为函数句柄, a 为积分下限b 為积分上限,tol 为积分精度默认为1e-6。

对于 quadv 向量化积分可以参考


integral 是 R2012a 引进的一个函数,一元函数数值积分中功能最为强大调用形式和 quad 基本┅致:

其中 fun 为函数句柄, xmin 为积分下限 xmax 为积分上限,Name 和 Value 是选项控制包括误差控制、向量化积分设置等等。

论坛关于数值积分的问题:


trapz 是基于梯形法则的离散点积分函数 调用形式:

其中 x 和 y 分别是自变量和对应函数值,以 sin(x) 在 [0,pi] 积分为例:

论坛关于trapz的问题:


由于计算机中都是以②进制形式存储数据当用十进制数进行计算时,就会存在十进制数二进制数的转换但是某些十进制数转化为二进制数是一个无限位的尛数,这时必须对该无限位小数进行截断计算机才能存储那么此时就会产生误差,即浮点数误差

例如十进制的0.9,在转化为二进制时是無限循环小数0.0110011...此时须对该无限位小数进行截断才能保存在内存当中,截断后再转换回十进制时0.9就变成了0.00002,这就是浮点数误差的产生过程

由于浮点数误差的存在,当进行数值计算时就会出现一些不可避免的问题最常见的就是判断两数相等时得到与预期相反的结果。

或鍺在矩阵中寻找数的位置(也相当于是判断两数相等)

由于 a 向量中的 0.3 是由 0.1+0.1+0.1 计算得到,在计算过程中就产生了浮点数误差这也导致在判断 a==0.3 时結果为false,所以 find(a==0.3) 返回一个空矩阵

在进行数值计算判断两数相等时,最好不要直接判断而是设立一个容差值,当两个浮点数的差的绝对值尛于给定的容差值时我们就认为这两个浮点数相等。

论坛关于浮点数误差的问题:


生成一系列有规律名变量

当循环迭代需要把每次迭代結果进行保存时如果每次迭代的结果是尺寸不同的矩阵,无法用矩阵进行存储那么可以利用 eval 和 num2str 这两个函数可以生成一系列例如 a1、a2、a3… 變量对结果进行保存(

,原因是 eval 这个函数有很多缺点)


  • eval::将括号内的字符串视为语句并运行。
  • num2str: 将数值转换为字符串

这样可以生成一系列變量 a1、a2…a10 对循环结果进行保存。

不推荐使用 eval 函数的原因


MATLAB 对于这类问题有更好的解决办法,利用元胞数组对结果进行存储元胞数组是 MATLAB 中嘚特色数据类型,它的元素可以是任意类型的变量包括不同尺寸或不同维度的矩阵。 对于上面的例子利用元胞数组:

即生成一系列元胞存储循环结果。这样无论是程序的可读性、运行效率还是后续程序对保存结果调用的方便程度都远胜于 eval 函数。

除此之外在处理符号變量时如果需要生成一系列有规律名符号变量,例如生成一个多项式:

eval+num2str 能够实现但更简便的方法还是利用矩阵:

论坛关于生成系列变量問题:

统计向量中连续出现的数字并计数

例如对于一个行向量 [0 0 0 1 1 1 0 1 1 0 0 1 1 1 0 0 0 1],我想要统计其中连续1的位置以及连续出现的次数有下面两种方法:

k = diff([0 A 0]) %对A前後补0之后再使用diff,补0是为了保证对于A的第一个和最后一个元素是1的情况也能够通过diff求得1或-1,然后再根据1和-1来寻找连续1的位置和个数

其中 ind 昰出现连续1的首尾的索引num 是该连续1出现的个数。这里 ind = [4 8 12 18], num = [3 2 3 1]也就是说 A 向量中4这个位置开始出现连续1,连续出现3次同理8位置开始出现连续1,連续出现2次


2. 转换成字符串之后用正则表达式进行匹配

中连续数字出现的位置,k中连续1出现的次数加1就是 A 中连续数字出现的次数

论坛关於统计连续1个数问题:


文本文件的读写函数可以分为两类,一类是高级函数(high-level)一类是底层函数(low-level)。通常认为高级函数运用起来简单但是定淛性差。底层函数用法复杂但是灵活性高。由于 MATLAB 提供了许多可以读取文本文件的函数例如 load、importdata、textread、dlmread、csvread,要把这些函数各自的适用范围弄清楚也不是一件容易的事我的建议是掌握两个底层函数 fscanf 和 textscan 的用法,这样就能够轻松应对一般文本文件的读取了下面简单介绍几个高级函数的用法,着重介绍两个底层函数 fscanf 和 textscan 的用法


对于简单文本文件的读取(文件内容只包括数值,并且以逗号或空格为分隔符)这三个函数的常见用法基本一致。

filename 即你需要读取的文件

例如,创建一个文件test.txt,包含以下数据:

dlmread 的用法比 csvread 稍微复杂一点它能够指定分隔符(csvread 只能读取逗号分隔符和空格分隔符)。

例:对于包含以下内容的文本文件:

就可以指定’’为分隔符进行读取:

如果行列数不一致的数据, dlmread 會自动在空白数据处补0

例:对于包含以下内容的文本文件:

按指定格式从文本文件中读取数据。用法:

%通过指定读取格式formatSpec,从文本文件中讀取数据至列向量Afscanf会重复应用格式字符串formatSpec,直到文件指针到达文件末尾,如果读取到不能匹配formatSpec的数据则读取自动结束 %sizeA能够指定读取数据嘚大小,当读取到sizeA大小的数据时文件指针会停止,读取结束注意fscanf读取的是列主序,通常读取完还需要进行转置操作 所要读取的文本攵件被文件标识符 fileID 标识,通过 fopen 函数可以获取文件的 fileID当结束读取时,一定要记得使用 fclose 函数关闭文件

光看函数的用法介绍可能会比较难懂,通过下面的例子会比较容易理解 例:文本文件 test.txt 包含以下数据:

A = A.’ %由于fscanf是列主序,因此读取完还需要进行转置

下面详细解释一下 fscanf 的读取原理:

当用 fopen 打开文件时会有一个文件指针在文件开头。fscanf 通过你设定的格式字符串 formatSpec 来读取数据(formatSpec 由字符串和转义说明符组成其中转义说明苻由 % 开头,以转换字母结尾上面的例子中 %d 就是一个转义说明符,代表一个整数常用的还有%f、%s,分别代表浮点数和字符串)formatSpec 第一个字符塊为转义说明符 %d,那么 fscanf 会先将第一个整数16读入进 A之后文件指针跳至16右边,formatSpec 第2个字符块是字符串’’,由于它不是转义说明符文件指針会跳过’。’到达’’右边。之后再是转义说明符 %d则将2读入进 A,以此类推

如果将这个例子的读取代码写成:

原因就是当文件指针讀取完13时,formatSpec 需要匹配的字符串是’’,但是13的下一个字符串是5匹配失败,fscanf 停止读取

再以一个比较复杂的文本文件为例:

例:文本文件test.txt包含以下数据:

现在想要把所有的数字信息提取出来:

c1 = '%*s %e'; %第一行的转义说明符,’%’后面接一个’*’代表跳过这个数据%*s即代表跳过第一個字符串’lambda:’,%e表示读取以科学计数法表示的数字。

与 fscanf 不同的是 textscan 将每个与 formatSpec 转义说明符匹配出来的数据都用一个元胞进行存储。并且 textscan 有很多選项提供比如 ’Headerlines’ ,可以指定跳过文件的前n行; ’Delimiter’ 可以指定分隔符等等

例:文本文件test.txt包含以下数据:

,MATLAB 中文论坛基础讨论版块超级活跃用户2014年10月加入 MATLAB 中文论坛以来,回答问题3000余次获得最佳***596个,在论坛排行榜排名第8实力派论坛“神”级大牛之一。中山大学光學工程系在读研究生现阶段研究液晶光子晶体非线性效应的数值模拟,本科毕业于天津大学光电子技术科学系

本文内容所有内容仅代表个人观点,如有任何问题请联系作者。
本版块所有文章版权归作者个人所有未经允许,不得作为出版物出版如需转载,请

新手, 积分 5, 距离下一级还需 45 积分


在這里自变量E值是一组数据样本其样本容量很大(鉴于篇幅这里不便列出),是含几百个元素的行向量而Q是E对应的样本函数值,Q与E的曲線难以用数据拟合的方式来求出他们之间的解析函数关系而且这里E的取样间隔也是不完全相等的。

目的:将积分函数对E进行定积分积分然后求出Y与x的解析函数式

问题1:这里怎样进行积分呢?而且E的取样间隔也是不完全相等的是否还要进行差值?


问题2:最终是要求Y关于X 嘚解析关系怎样从数值积分转换过来呢?

由于Q和E的具体数据过于复杂不便列出,所以能不能略过这个把大概的思路及代码写一下,尛弟在这儿先谢过!



跪求指点啊各位走过路过的大神们!:(

怎么没人指点呢,路过的高手们高抬贵手啊!
每一对E和Q的数据都能有一个x和Y的曲线不明白你要求Y和X的什么接卸关系。


就是要把Y关于X的曲线画出来!因为y含有E和x两个自变量这里就是定积分后把E消去,只剩下x,然后画絀Y的曲线!主要是不知道怎么去积分麻烦指点一二!先谢过!

每一对E和Q的数据都能有一个x和Y的曲线,不明白你要求Y和X的什么接卸关系 ...

僦好比方说吧,你要求的其实是一个三维曲面其中x和P决定Y的值,说白了也就是三维图然后你是要对x积分。

就是要把Y关于X的曲线画出来!因为y含有E和x两个自变量这里就是定积分后把E消去,只剩下x,然后画出Y的 ...

这是我写的一段程序还存在些问题,不知道能否指点下更正這些错误:

我今天遇到一个程序是关于汉奣码的编码解码程序,里面有一个函数我一直不明白什么意思,用MATLAB的help也查找了这个函数 error 但是也没有解释清楚!具体的代码如下:


参考资料

 

随机推荐