技术文章及通讯

MATLAB中面向对象编程介绍

Stuart McGarrity和Adam Sifounakis, MathWorks


在创建软件应用程序时,将软件的各种构建块组织到相关的组中是很重要的。例如,一个自定义数值求解器可能需要几个配置参数和例程来执行它的全部计算集。面向对象编程(OOP)允许您将解算器的配置参数(属性)及其函数(方法)分组到单个定义中.用户正确执行此求解器所需的一切都在该类中定义。

对象是类的实例。当程序执行时,对象根据类定义创建,并按照类定义的方式进行操作。对象的属性表示其状态,方法表示用户可能执行的所有操作。通过这种方式,代码作者可以轻松地将软件系统的所有相关数据和功能分组,用户也可以轻松地找到和使用代码作者开发的所有功能。

下面的示例使用面向对象编程构建一个应用程序,该应用程序将分析来自传感器数组的传感器数据。

应用实例:分析传感器阵列数据

传感器阵列(图1)是传感器的集合,通常排成一条线,用于对空气、水或地面等介质进行采样,用于雷达、声纳或蜂窝通信。通过从空间中的多个点收集时间样本,您可以从被采样的介质中提取额外的信息。

图1。一种传感器阵列,以未知角度探测两个遥远的电磁源。

图1。一种传感器阵列,以未知角度探测两个遥远的电磁源。

我们的应用程序使用传感器阵列来确定多个远程电磁源的到达方向(DOA),例如无线电信标和雷达发射机。在这种情况下,我们将尝试估计两个源相对于传感器阵列指向的方向的角度θ1和θ2。

检查数据项和操作

对于这个应用程序,我们需要存储和表示以下数据:

  • 传感器和样品的数量
  • 采样传感器数据
  • 传感器采样率
  • 传感器间距
  • 远源波长
  • 波浪速度
  • 传感器数据集名称或描述

我们将使用一个简单的基于快速傅里叶变换(FFT)的技术来估计源的DOA。这种技术可以被分解成多个部分,并作为一组操作来实现。将实现少量的实用程序操作,以帮助简化开发工作。例如,我们必须:

  • 从合成数据或获取的实时数据创建数据集
  • 检查和修改数据集的值和参数
  • 绘制样本数据以帮助解释和验证
  • 计算并绘制数据集的功率谱(通过简单的FFT方法的幅度平方)
  • 找到功率谱的峰值来估计源的DOA

确定了需要表示的数据和需要执行的活动之后,就可以用类属性表示数据,用类方法表示活动了。

用类属性表示数据

我们首先定义一个类来描述传感器阵列。这个初始表示只包含数据项,并将它们表示为类属性。

在MATLAB中使用类定义文件定义类,该类定义文件以classdef关键字,并由结束关键字。在类定义块中,附加的关键字块将描述类的不同方面,例如类属性和类方法。图2所示的定义文件描述了一个类悲伤而已(传感器阵列数据集),我们需要在属性块中列出的所有数据项。

图2。类定义文件悲伤。M和属性。

图2。类定义文件sads.m与属性。

创建对象和访问属性

要创建所定义类的对象或实例,可以使用语句

>> s =悲伤;

要设置属性的值,可以像指定结构的字段一样指定属性名

>> s.NumSensors = 16;

我们可以通过输入对象的名称来显示对象,查看所有可用的属性和当前值。

>> s s = sads with properties: Wavelength: [] c: 300000000 NumSensors: 16 NumSamples: [] Data: [] Spacing: [] SampleRate: [] Name: []

除了所有的财产NumSensors而且c仍然是空的。数据集现在可以标识为悲伤而已对象使用函数,isa函数,以及命令,这在结构上是不可能的。

>>类(s) ans = '悲伤'

对于创建代码来操作数据集的用户来说,识别变量类的能力非常重要,因为它可以让他们确定要访问的可用数据项以及可以合法执行的操作。

错误检查

如果使用结构来表示数据,则可以随时添加新字段名,只需指定新字段名并为其赋值即可。当您正在试验和原型化算法时,此功能特别方便。但是,如果您拼错了字段名,则会无声地添加一个新字段,这可能会导致稍后难以诊断的错误。

与结构体不同,您不能仅通过指定新属性名并为其赋值来动态地向对象添加新属性。如果拼错了对象属性名,MATLAB会立即报错。当对象被比作者更熟悉的用户访问时,这种额外级别的错误检查非常有用,这在大型应用程序开发过程中很常见。

控制对数据的访问

类使您可以很好地控制属性访问。例如,它们允许您禁止修改属性、隐藏属性或使其动态计算。通过在类定义文件中指定属性属性来控制对属性的访问。我们扩展图2中的类定义文件,将当前的属性列表划分为多个属性块,每个属性块具有唯一的属性属性:GetAccess常数,依赖(图3)。

图3。类定义文件悲伤。M具有属性属性。

图3。类定义文件sads.m属性属性。

属性来禁止修改属性常数属性。在我们的例子中,我们将设置光速属性c保持不变。因为常量属性不会改变,所以可以通过引用类名来访问它们。

>> sads.c ans = 300000000

属性使属性为只读SetAccess属性为private。属性可以使属性仅对对其操作的方法可见GetAccess属性设置为private,就像我们将对波长财产。

您可以自由地更改私有属性的名称或特征,而不会影响对象的用户。这种定义软件的“黑盒”方法称为封装,可以防止对象的用户依赖于可能改变并破坏其代码的实现细节或特性。

通过设置属性,指定仅在请求时计算属性依赖属性。

然后指定一个get方法,该方法在访问属性时自动调用。看到“使用Get和Set方法访问属性”小节中有关如何指定类方法的详细信息。在我们的应用程序中,我们设置NumSensors而且NumSamples属性是依赖的。

用类方法实现操作

方法或可以在对象上执行的操作被指定为方法块中的函数列表。一个类可以包含多种类型的方法,每种方法实现不同的目的,每种方法都有不同的指定。下面一节将介绍其中一些类型的方法。

方法中添加一个方法块悲伤而已定义文件并在此块中添加每个新方法(图4)。

图4。类定义文件悲伤。m带有方法,显示在MATLAB编辑器中。为了便于查看,代码折叠特性用于隐藏大部分代码。

图4。类定义文件sads.m方法,显示在MATLAB编辑器中。为了便于查看,代码折叠特性用于隐藏大部分代码。

指定构造函数方法

在我们的示例中,我们将指定一个构造函数方法,该方法允许用户提供在创建对象时使用的参数。构造函数方法通常执行数据初始化和验证。对象现在是用

>> s = sads(数据,波长,SampleRate,间距,名称);

实现特定于应用程序的方法

我们将添加几个方法来实现在数据集上执行的特定于应用程序的操作。大多数方法将对象作为输入参数(例如,obj),并通过引用该变量来访问对象属性(例如,obj。NumSamples),如此方法:

函数mag = magfft(obj, zpt)NumSamples、zpt);...结束

尽管它需要额外的语法,但通过对象变量引用属性可以帮助将它们与局部函数变量区分开来,例如玛格以上。

调用方法

方法像函数一样被调用,对象作为参数之一传入。我们可以通过调用。来估计源的DOA角doa类的方法。

>>角度= doa(s)角度= -10.1642 18.9953

DOA角近似于图1所示的源的真实位置,即-10°和20°。

使用Get和Set方法访问属性

您可以通过指定相关的set和get方法来验证属性或实现相关属性。的get方法NumSensors财产。

函数NumSensors = get.NumSensors(obj) NumSensors = size(obj. NumSensors)2)数据;结束

当访问属性时,会自动调用Get和set方法,例如

>> N = s.NumSensors;

为已有的MATLAB函数重载指定方法

重载允许您通过在方法列表中提供具有该名称的函数来重新定义现有的MATLAB函数以处理对象。在我们的应用程序中,我们将包含一个重载的情节方法,提供了一个函数来可视化许多MATLAB用户所熟悉的数据集(图5)。

> >的情节(s)
图5。专门用于传感器阵列数据集的重载绘图方法。

图5。专门用于传感器阵列数据集的重载绘图方法。

这个自定义的绘图方法以最适合此数据集的方式表示信息,用所有可用信息对其进行注释。它只在定义了它的对象上执行——这是一种比操纵路径中目录顺序更健壮的方法。

如果您希望类具有专门的行为,还可以通过使用具有特殊名称的方法重载基本操作符甚至索引。

进一步开发应用程序

我们在本例中创建的类表示我们的传感器阵列数据集,并允许我们轻松地对数据执行复杂的专门分析,包括主要的测向操作。我们可以使用这个类来快速评估基于fft的技术在不同场景下的性能。

我们可以使用额外的OO技术来扩展应用程序。例如,我们可以这样做:

  • 通过继承定义现有类的子类(重用更广泛类别的定义来定义更具体的子类别)
  • 指定静态方法,让我们为整个类定义一个操作
  • 使用带有引用行为的句柄类,使我们能够创建像链表这样的数据结构,或在不复制数据的情况下处理大型数据集
  • 定义事件和监听器,让我们监视对象属性或操作

这些技术使我们能够进一步定义应用程序中的关系和行为,从而增强了我们管理复杂性的能力。

因为它是使用OO技术构建的,所以该应用程序现在足够健壮,可以供其他人使用和维护,并且可以与整个组织中的其他应用程序集成。

2020年出版的

查看相关功能的文章

查看相关行业的文章