MATLAB面向对象编程导论
作者:Stuart McGarrity和Adam Sifounakis, MathWorks
在创建软件应用程序时,将软件的各种构建块组织到相关的组中是很重要的。例如,一个自定义数值求解器可能需要几个配置参数和例程来执行它的全部计算。面向对象编程(OOP)允许您将求解器的配置参数(属性)及其函数(方法)分组到单个定义中,或者类.用户正确执行这个求解器所需的一切都在这个类中定义。
对象是类的实例。当程序执行时,对象是基于它的类定义创建的,并按照类定义的方式执行。对象的属性表示它的状态,它的方法表示用户可能执行的所有操作。通过这种方式,代码作者可以很容易地对软件系统的所有相关数据和功能进行分组,用户也可以很容易地找到并使用代码作者开发的所有功能。
下面的示例使用面向对象编程来构建一个应用程序,该应用程序将分析来自传感器数组的传感器数据。
应用示例:分析传感器阵列数据
传感器阵列(图1)是传感器的集合,通常排成一条线,用于对介质(如空气、水或地面)进行采样,用于雷达、声纳或蜂窝通信。通过从空间中的多个点收集时间样本,可以从被采样的介质中提取附加信息。
我们的应用程序使用一个传感器阵列来确定多个远程电磁源(如无线电信标和雷达发射机)的到达方向(DOA)。在这种情况下,我们将尝试估计两个源相对于传感器阵列指向的方向的角度θ1和θ2。
检查数据项和操作
对于这个应用程序,我们需要存储和表示以下数据:
- 传感器和样品的数量
- 采样传感器数据
- 传感器采样率
- 传感器间距
- 远距离光源波长
- 波速
- 传感器数据集名称或描述
我们将使用一种简单的快速傅立叶变换(FFT)技术来估计源的DOA。这种技术可以被分解成多个部分,并作为一组操作实现。将实现少量的实用程序操作,以帮助简化开发工作。例如,我们必须:
- 从合成数据或获取的实时数据创建数据集
- 检查和修改数据集值和参数
- 绘制示例数据以帮助解释和验证
- 计算并绘制数据集的功率谱(通过FFT方法的简单幅度平方)
- 找出功率谱的峰值来估计信号源的DOA
确定了需要表示的数据和需要执行的活动之后,就可以用类属性表示数据,用类方法表示活动。
用类属性表示数据
我们首先定义一个类来描述传感器阵列。这个初始表示只包含数据项,并将它们表示为类属性。
用一个类定义文件在MATLAB中定义一个类,该文件以classdef
关键字并被终止结束
关键字。在类定义块中,附加的关键字块将描述类的不同方面,例如类属性和类方法。图2所示的定义文件描述了一个类悲伤而已
(传感器阵列数据集),所有需要表示的数据项都列在一个属性块中。
创建对象和访问属性
要创建所定义类的对象或实例,可以使用语句
>> s =悲伤;
要设置属性的值,我们指定它的名称就像结构中的字段一样
>> s.NumSensors = 16;
我们可以通过输入对象的名称来显示对象,看到所有可用的属性和当前值。
>> s s = sads with properties: Wavelength: [] c: 300000000 NumSensors: 16 NumSamples: [] Data: [] Spacing: [] SampleRate: [] Name: []
所有的财产NumSensors
而且c
仍然是空的。数据集现在可以被识别为悲伤而已
对象使用类
函数,isa
函数和谁
命令,这在结构中是不可能的。
>> class(s) ans = 'sads'
识别变量类的能力对于创建代码以操作数据集的用户非常重要,因为它可以让他们确定要访问的可用数据项和可以合法执行的操作。
错误检查
如果使用结构表示数据,则可以随时添加新字段名,只需指定新字段名并为其赋值即可。在对算法进行实验和原型设计时,该功能特别方便。但是,如果您拼错了一个字段名,则会悄无声息地添加一个新字段,这可能会导致稍后难以诊断的错误。
与结构不同,不能仅通过指定新属性名并为其赋值来动态地向对象添加新属性。如果拼错了对象属性名,MATLAB会立即发出错误。当对象是由比作者更不熟悉的用户访问时,这种额外的错误检查级别是有用的,这在大型应用程序的开发过程中是常见的。
控制对数据的访问
类使您能够更好地控制属性访问。例如,它们允许禁止修改属性、隐藏属性或动态计算属性。通过在类定义文件中指定属性属性,可以控制对属性的访问。我们对图2中的类定义文件进行扩展,将当前的属性列表划分为多个属性块,每个属性块具有唯一的属性属性:GetAccess
,常数
,依赖
(图3)。
属性来禁止对属性的修改常数
属性。在我们的例子中,我们将设置光速属性c
保持恒定。因为常量属性不会改变,所以可以通过引用类名来访问它们。
>> sad .c ans = 300000000
属性使属性为只读SetAccess
属性为私有。属性可以使属性仅对对其进行操作的方法可见GetAccess
属性设置为私有,就像我们将对波长
财产。
您可以自由更改私有属性的名称或特征,而不影响对象的用户。这种定义软件部分的“黑箱”方法称为封装,它可以防止对象的用户依赖于可能更改和破坏其代码的实现细节或特性。
通过设置属性,可以指定只在请求时计算属性依赖
属性。
然后指定一个get方法,该方法在访问属性时自动调用。看到使用Get和Set方法访问属性有关如何指定类方法的详细信息,请参见本文的第一部分。在我们的应用程序中,我们设置NumSensors
而且NumSamples
属性是相互依赖的。
使用类方法实现操作
方法或可以对对象执行的操作被指定为方法块中的函数列表。一个类可以包含多种类型的方法,每种方法实现不同的目的,每种方法的指定方式也不同。下一节将介绍其中一些类型的方法。
的方法块中添加方法块悲伤而已
定义文件,并在此块中添加每个新方法(图4)。
指定构造函数方法
在我们的示例中,我们将指定一个构造函数方法,该方法允许用户提供在创建对象时使用的参数。构造函数方法通常执行数据初始化和验证。对象现在创建为
>> s = sads(数据,波长,SampleRate,间距,名称);
实现特定于应用程序的方法
我们将添加几个方法来实现要在数据集上执行的特定于应用程序的操作。大多数方法将对象作为输入参数(例如,obj
),并通过引用此变量(例如,obj。NumSamples
),如在这个方法中:
函数mag = magfft(obj, zpt)NumSamples、zpt);...结束
尽管它需要额外的语法,但是通过对象变量引用属性可以帮助它们与局部函数变量区分开来,例如玛格
以上。
调用方法
调用方法就像调用函数一样,将对象作为参数之一传入。我们可以通过调用来估计源的DOA角doa
我们班的方法。
>> angles = doa(s) angles = -10.1642 18.9953
DOA角近似于图1所示的信号源的真实位置,分别为-10°和20°。
使用Get和Set方法访问属性
可以通过指定关联的set和get方法来验证属性或实现相关属性。这里是get方法NumSensors
财产。
函数NumSensors = get.NumSensors(obj) NumSensors = size(obj。2)数据;结束
Get和set方法在访问属性时自动调用,例如with
>> N = s.NumSensors;
重载的MATLAB函数的指定方法
重载允许您重新定义现有的MATLAB函数,通过在方法列表中提供具有该名称的函数来处理对象。在我们的应用程序中,我们将包含一个重载的情节
方法,提供一个函数来可视化数据集,这是许多MATLAB用户所熟悉的(图5)。
> >的情节(s)
这个自定义的plot方法以最合适的方式表示该数据集的信息,用所有可用的信息对其进行注释。它只在为其定义的对象上执行——这是一种比操纵路径中目录的顺序更健壮的方法。
如果您希望为您的类设置专门的行为,您还可以重载基本操作符,甚至通过使用具有特殊名称的方法进行索引。
进一步开发应用程序
我们在这个示例中创建的类表示我们的传感器阵列数据集,并允许我们轻松地对数据执行复杂的、专门的分析,包括主要的测向操作。我们可以使用这个类快速评估基于fft的技术在不同场景中的性能。
我们可以使用额外的OO技术来扩展应用程序。例如,我们可以这样做:
- 用继承定义现有类的子类(重用更广泛的类别的定义来定义更具体的子类别)
- 指定静态方法,让我们为整个类定义一个操作
- 使用带有引用行为的句柄类,使我们能够创建像链表这样的数据结构,或在不复制的情况下处理大型数据集
- 定义事件和监听器,让我们监视对象属性或操作
通过使我们能够进一步定义应用程序中的关系和行为,这些技术增强了我们管理复杂性的能力。
因为它是使用OO技术构建的,所以该应用程序现在足够健壮,可供其他人使用和维护,并且可以在整个组织中与其他应用程序集成。
2020年出版的