打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
10.1 更新过程

向量作为数组和其他数据结构

  • 使您能够解决涉及仔细处理数组下标的问题
  • 介绍结构、单元格和单元阵列的用法

在MATLAB中,数组只是向量的另一个名称。那么,为什么要用一章的大部分篇幅来讲解数组,而我们在本书的大部分时间里都在使用向量呢?当我们关注通过下标处理单个元素,而不是作为一个整体处理向量时,谈论数组(而不是向量)是有帮助的。因此,在本章的前三节中,我们将看到一些问题,这些问题最好通过将向量视为数组来解决,通常借助for循环。在本章的最后三节中,我们将讨论其他更高级的数据结构。

10.1 更新过程

在第8章(更新过程)中,我们考虑了计算罐装橙汁在冰箱冷却时的温度的问题。这是一个更新过程的示例,其中主变量在一段时间内被重复更新。现在我们研究一下如何更普遍地解决这个问题。

一罐温度为25°C的橙汁放在冰箱里,环境温度为10°C。我们想知道橙汁的温度在一段时间内是如何变化的。解决这类问题的一个标准方法是将时间周期分成若干小步,每小步的长度为 dt, 如果 是第 步开始时的温度,我们可以用下面的模型从 得到 :

其中K是一个常数参数,取决于罐头的绝缘性能和橙汁的热性能。假设选择了单位,时间以分钟为单位。

10.1.1 单位时间步长

我们首先用单位时间步长求解,即 。最简单的方法是使用标量表示时间和温度,就像我们在第八章看到的那样 (虽然我们没有使用单位时间步长):

K = 0.05;
F = 10;
T = 25% initial temperature of OJ
for time = 1:100 % time in minutes
T=T-K * (T - F); % dt = 1
if rem(time, 5) == 0
disp( [time T] )
end
end;

注意,使用rem每5分钟显示一次结果:当time是5的整数倍时,它除以5的余数为零。

虽然这无疑是编写脚本最简单的方法,但我们不能轻易地绘制温度随时间的曲线图。为了做到这一点,时间和T必须是向量。for循环的索引必须用作t的每个元素的下标。下面是脚本(update1.m):

 K = 0.05;
F = 10;
time = 0:100% initialize vector time
T = zeros(1,101); % pre-allocate vector T
T(1) = 25% initial temperature of orange juice
for i = 1:100 % time in minutes
T(i+1) = T(i) - K * (T(i) - F); % construct T
end;
disp([ time(1:5:101)'  T(1:5:101)' ]); % display results
plot(time, T), grid
  • 语句 time = 0:100为time设置了一个(行)向量,其中time(1)的值为0分钟,time(101)的值为100分钟。这是必要的,因为MATLAB向量的第一个下标必须是1。
  • 语句T = zero(101)为温度设置了一个对应的(行)向量,其中每个元素初始化为0(同样必须有101个元素,因为第一个元素代表时间为0时的温度)。这个过程称为预分配。
  • T的第一个元素设为橙汁的初始温度。这是时刻0的温度。
  • for循环计算T(2)的值,…T(101)。这种安排确保温度T(i)对应于时间(i)。
  • 冒号操作符用于每隔5分钟显示结果

10.1.2 非单位时间步长

在式 中取并不总是合适或足够准确。在 MATLAB 中,生成解向量的标准方式是使用更一般的符号来表示,以适应几乎任何 dt(时间步长)的值。

设初始时间为a,最终时间为b,如果我们想要时间步长为dt,那么这样的步长为m = (b − a)/dt , 第i步结束时的时间是a + i dt

下面是实现这个方案的脚本 update2.m,它具有一些附加功能。它会提示您输入 dt 的值,并检查该值是否得到了步长数 m 的整数值。它还会要求您输入输出间隔 opint(以分钟为单位,在这些间隔内结果以表格形式显示),并检查该间隔是否是 dt 的整数倍。尝试使用相同的示例值运行脚本,例如 dt = 0.4opint = 4

K = 0.05;
F = 10;
a = 0% 初始时间
b = 100% 终止时间
load train

dt = input('dt: ');
opint = input('output interval (minutes): ');

if opint/dt ~= fix(opint/dt)
    sound(y, Fs)
    disp('output interval is not a multiple of dt!')
    return
end

m = (b - a) / dt; % m 步,每步长度为 dt

if fix(m) ~= m
    sound(y, Fs)
    disp('m is not an integer - try again!')
    return
end

T = zeros(1,m+1); % 预分配 (m+1) 个元素的向量
time = a:dt:b;
T(1) = 25% 初始温度

for i = 1:m
    T(i+1) = T(i) - K * dt * (T(i) - F);
end

disp([time(1:opint/dt:m+1)' T(1:opint/dt:m+1)'])
plot(time, T), grid

  • 向量 T 和 time 必须分别具有 m + 1 个元素,因为有 m 个时间步长,我们还需要一个额外的元素用于每个向量的初始值。

  • 向量 T 是用于存储温度值的向量,而 time 是用于存储时间值的向量。由于包括初始值,所以需要 m + 1 个元素来存储 m 个时间步长的数据。

  • 在这段代码中,通过 T = zeros(1,m+1)time = a:dt:b 进行了预分配,确保向量 T 和 time 具有适当的长度。

10.1.3 使用函数

解决这个问题的一个非常好的方法是编写一个函数来完成。这样做可以更容易地为不同的 dt 值生成结果表格,比如从命令行中使用这个函数。以下是被重写为函数 cooler.mupdate2.m

function [time, T, m] = cooler(a, b, K, F, dt, T0)
    m = (b - a) / dt; % m 步,每步长度为 dt

    if fix(m) ~= m
        disp('m is not an integer - try again!');
        return
    end

    T = zeros(1, m + 1); % 预分配 (m+1) 个元素的向量
    time = a:dt:b;
    T(1) = T0; % 初始温度

    for i = 1:m
        T(i+1) = T(i) - K * dt * (T(i) - F);
    end
end

通过将 update2.m 重写为函数 cooler.m,我们可以更方便地从命令行中调用该函数,并为不同的 dt 值生成结果表格。

函数 cooler 接受六个参数:a、b、K、F、dt 和 T0。这些参数分别代表初始时间、终止时间、常数 K、常数 F、时间步长和初始温度。

在函数体内部,我们进行计算并返回了时间向量 time、温度向量 T 和步数 m。

下面是使用函数生成不同 dt 值的结果表格的示例代码:

dt = 1;
[t, T, m] = cooler(01000.0510, dt, 25);
table(:, 1) = t(1:5/dt:m+1)';
table(:, 2) = T(1:5/dt:m+1)';

dt = 0.1;
[t, T, m] = cooler(01000.0510, dt, 25);
table(:, 3) = T(1:5/dt:m+1)';

format bank
disp(table)

    0         25.00         25.00
          5.00         21.61         21.67
         10.00         18.98         19.09
         15.00         16.95         17.07
         20.00         15.38         15.50
         25.00         14.16         14.28
         30.00         13.22         13.33
         35.00         12.49         12.60
         40.00         11.93         12.02
         45.00         11.49         11.57
         50.00         11.15         11.22
         55.00         10.89         10.95
         60.00         10.69         10.74
         65.00         10.53         10.58
         70.00         10.41         10.45
         75.00         10.32         10.35
         80.00         10.25         10.27
         85.00         10.19         10.21
         90.00         10.15         10.16
         95.00         10.11         10.13
        100.00         10.09         10.10

在这个示例代码中,我们首先使用 dt = 1 调用 cooler 函数,并将结果保存在变量 t、T 和 m 中。然后,我们从结果中选择每隔 5 分钟的数据,并保存到表格中的第一列。

接着,我们使用 dt = 0.1 调用 cooler 函数,并将结果保存在变量 t、T 和 m 中。然后,我们选择每隔 5 分钟的数据,并保存到表格中的第三列。

最后,我们使用 format bank 命令将表格中的数值格式设置为货币格式,并使用 disp 函数显示表格。


使用生成向量输出变量的函数的优势是,即使在函数内部忘记预分配向量(使用 zeros 函数),MATLAB 在从函数返回之前会自动清除任何先前版本的输出向量。

变量 table 是一个二维数组(或矩阵)。回想一下,冒号操作符可以用于指示矩阵中的所有元素(行或列)。因此,table(:,1) 表示每一行和第一列的元素,也就是整个第一列。向量 t 和 T 是行向量,因此在插入到 table 的第一列和第二列之前,它们必须被转置。第三列的插入方式类似。

对于 dt = 0.1,结果在第三列中会更加精确。这是因为当时间步长减小(dt = 0.1)时,计算的间隔更小,导致更多的数据点被用于计算温度的变化。因此,结果更加精确。

当 dt 值较大时,数据点之间的时间间隔变大,可能会导致温度变化的细节被忽略,从而使结果不够准确。通过使用更小的 dt 值,我们可以获得更精确的温度值。然而,这也会增加计算的时间,因为计算的时间步长更小。因此,在选择 dt 值时,需要权衡精确性和计算效率之间的关系。

10.1.4 精确解

在给定的问题中,我们有一个冷却问题,需要计算温度随时间的变化。根据给定的公式:

其中,是时间 时刻的温度,是初始温度, 是环境温度,是一个常量。

要将这个精确解添加到表的第四列中,我们可以使用向量化的方式,如下所示:

table(:,4) = 10 + (T(1)-10)*exp(-0.05 * t(1:5/dt:m+1)');

其中,table 表示我们的表格,t 是一个时间向量,m 是时间步数。

在给定的例子中,我们假设每个单位时间的增量dt等于5。通过这个精确解,我们可以生成一个类似于如下这样的增加了精确解的完整表格:

     0         25.00         25.00         25.00
          5.00         21.61         21.67         21.68
         10.00         18.98         19.09         19.10
         15.00         16.95         17.07         17.09
         ...
         
         95.00         10.11         10.13         10.13
        100.00         10.09         10.10         10.10

注意,随着时间步长dt的减小,数值解会越来越接近精确解。这是因为当dt趋近于0时,精确解的方程可以从数值解的方程中推导出来。因此,在数值计算中,通过减小时间步长dt,我们可以使数值结果更加准确,逼近精确解。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Matlab简单教程:循环
(转)对梯度下降法的简单理解
matlab主成分分析
cocos2dx果冻效果模拟
夏天手机发烫卡顿?这款软件,真是神器!
MatLab入门及解方程
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服