干货速递|用需求在环仿真扩展基于模型的系统工程实践:起落架系统案例

news2024/11/18 21:40:15

摘要

仿真已经成为大多数行业大规模采用基于模型的系统工程(MBSE)和基于模型的设计(MBD)工具的至关重要的因素。与此同时,实用的需求工程工具在以文档需求规格为主的生命周期管理之外并未得到显著发展,这使得需求并未得益于基于模型的仿真工具。需求在环(RIL)仿真已被提议用来扩展MBSE和MBD框架,允许系统工程师用一种正式的语言来描述文本需求,并且可以与系统模型一起执行和仿真。需求在环仿真可允许基于需求语义生成离散时间系统行为,以及检查状态机等其他行为模型是否符合相关的系统需求。本文介绍了需求在环仿真的原则,并通过起落架系统案例讲述了其所具备的优势。这项工作尤其彰显了STIMULUS工具所具备的强大实力,包括检测现实系统中错误的,缺失的或冲突的需求,以及测试其基于模型的需求规格是否符合相关需求。

引言

来自汽车、铁路、航空电子、国防、航天、能源或医疗等关键安全领域的所有行业标准,都将需求置于开发和验证流程的核心,其中需求工程工具通常用来管理以文档为主的需求规格的生命周期。为了克服纯文本需求规格在处理系统日益增加的复杂性方面的限制,我们推出了基于模型的系统工程(MBSE)[1]和基于模型的设计(MBD)[2]工具,并在大多数行业中进行了大规模的采用。仿真显然是成功实现上述需求的关键因素,因为其为早期分析和验证打开了机遇之门。

然而,基于模型的系统工程和需求工程工具之间的耦合仍然十分微弱。当前的行业实践通常仅限于需求和模型之间的可追溯性流程。从仿真的角度来看,需求的执行语义基本上还尚未得到利用,尽管我们已在这个领域开展了一系列的研究工作[3]。

需求在环仿真[4]旨在将实时功能需求转变为形式化的,但仍然是文本的,可执行的模型。这些模型可以作为更大模型的一部分进行整合,通常是作为原理图捕获的系统架构,并与其他行为模型协同仿真。执行引擎依赖于约束求解技术来生成离散时间仿真,其中我们通常将需求解读为信号上的约束。

需要值得注意的是,需求和其他行为模型通常携带互补信息,因为它们捕获了不同的抽象级别。举例来说,安全需求可能会指定系统应该做什么,例如,在给定的延迟内对环境中的某些STIMULUS做出反应。因此,需求通常是部分的且非确定性的。相比之下,传统的行为模型,如状态机等,可能会更专注于如何进行反应,从而以更确定性的方式确保这种反应延迟。

需求在环仿真的应用包括两个方面。一方面,形式化需求可以作为系统的许多不同行为的生成器,以调试和验证在开发流程的早期阶段的"内容"。另一方面,一旦模型可用,无论是详细的需求规格还是实现模型,相关需求都可以作为观察者用来开展测试和验证的"方法"与"工具"。

在本文中,我们介绍了需求在环仿真的基本要素,并且我们在起落架客户案例[5]中阐述了它的使用,该案例提供了一个具有代表性大小和复杂性的现实系统。我们展示了识别错误的,缺失的和冲突的需求以及验证可执行模型与其需求的能力。由于起落架的需求规格同时使用了文本需求,状态机以及原理图的混合信息,因此我们利用STIMULUS工具捕获了完整的需求规格,并探讨了其与第三方工具(如需求管理,MBSE或MBD工具等)的集成。

需求在环的基本要素

需求在环仿真致力于解决动态系统的功能需求。起落架客户案例中的一个典型示例是以下的高级需求:“当操作杆命令为放时,所有起落架均应在15秒内完全展开,并且所有舱门应关闭。”此类需求通常描述了系统随时间变化的逻辑和数值属性的组合。它们与非功能需求(如可用性或可靠性等)形成鲜明对比,后者并不受需求在环支持。

建模功能需求

进行需求在环仿真的前提是能够捕获此类需求的精确语义。为此,STIMULUS提供了一套预定义的句子模板,可以自由组合以构建文本需求,如图1所示。句子模板可支持多种语言版本,用户可以扩展预定义模板集以适应特定领域的需求。
图1. 使用模板需求规格化的起落架系统需求

模板参数既可以参考标量表达式也可以参考语句,例如,“当…时”模板的条件和<主体>参数。每个模板的语义都通过等式和/或状态机进行形式化定义。例如,“是”模板定义了多态的数学等式,而“当…时”模板定义了状态机,当条件为真时,激活<主体>语句,如图2所示。

请添加图片描述图2. “当…时”模板的语义

仿真需求

执行需求的形式化语义的能力是需求在环仿真面临的主要挑战。STIMULUS的执行引擎源于Lutin[6],这是一种原创语言,其完美结合了约束和正则表达式,以指定通用测试场景,以及Lurette[7],这是一种执行引擎,可以从Lutin模型自动生成许多测试向量。此外,作者还指出了在需求工程中使用此类工具的巨大优势[12]。

STIMULUS按如下方式将这些原则扩展到了相关需求中:

  • 需求规格语言对约束和状态机进行了完美结合,采用了模式自动机[8]的同步语义,以正确处理分层和并行组合;
  • 编译器将一组采用这种语言进行表达的需求转化为一组有时钟的约束,遵循Lucid Synchron[9]的原始转化模式;
  • 模拟器将时钟解译为一个控制结构,以收集每个控制点[4]处的活动约束集,这可能会在执行每个(离散时间)步骤时有所变化;
  • 求解器计算活动约束的可能解空间,这是一组强耦合的布尔、数值和时间方程[10]的集合,并选择其中一个解来计算系统输出;
  • 调试器允许检查信号值、活动需求的亮点,以及改编自[11]的高

级探索特性,以解释为什么信号在精确的时间点有给定的值。
在此背景下,仿真意味着生成满足需求约束的执行追踪,即可能的系统行为。由于需求规格本质上通常是部分的,因此并非确定性的,这样的行为并非唯一。运行多次仿真将产生多种不同的行为,这对于测试自动化至关重要,相关内容将在第4节中进行深入探讨。

图3显示了图1中由STIMULUS生成的高级需求可能的执行追踪。由于我们并未指定起落架的伸出序列,舱门和起落架可能会经历不同的状态(定义为枚举类型),但一旦HandleCommand输入切换为放,舱门和起落架在预期的延迟内达到他们预期的状态(分别为关闭和展开)。

本文的一个主要目标是展示如何将这个高级需求细化为更低级别的需求,这些需求将指定起落架收回和伸出序列的详细信息。
请添加图片描述图3. 图1中需求的可能的执行追踪

调试需求

尽管需求的声明性质可提供如原子性、可组合性或可测试性等的众多优势,但是,声明性语言通常更难以进行调试。由于找出bug的原因比修复它需要花费时间更长,因此STIMULUS提供了多种调试功能来探索仿真的空间和时间维度。

标准的调试功能已根据相关需求进行了适应,比如高亮显示活动/非活动需求,或者在任何时间点监控任何变量。此外,许多原创功能专门针对需求的声明性质给出了解决方案,以支持检测三种类型的错误:

  1. 错误的需求(正确性):仿真运行良好,但仿真图并未显示预期的行为,这意味着一个或多个需求并未传达出架构师的真正意图。在这种情况下,高级探索功能有助于在任何时间点从任何变量中找出所涉及的需求。
  2. 缺失的需求(完整性):仿真运行良好,但部分仿真图包含了虚线,意味着在这些时间段内,没有活动的需求对它们进行定义。这可能是为了留下一些自由度以进行实施选择,或者可能是缺失需求的迹象。
  3. 冲突的需求(一致性):仿真在某个时间点停止,意味着其中有一组需求是存在矛盾的,也就是说,一组约束没有解。在这种情况下,求解器可自动报告冲突需求的最小集合。

其他建模方面

一些其他建模特性提高了形式化需求规格的一致性,以及它们在第三方工具中的集成。

原理图语言可允许定义系统架构,这与任何MBSE或MBD工具类似。系统定义接口(输入、输出、参数)和行为,既可以是原理图,也可以是需求和状态机的组合,或者是外部的FMI组件。原理图可以从其他工具导入,而形式化的需求可以与需求管理工具同步。

术语表允许定义可以在不同组件之间进行分享的系统变量。对于每个变量,术语表可选地指定数据类型、物理单位和/或物理维度、数值范围或某些默认行为。类型系统支持推断和多态性,这对于构建通用库,以及在不提供任何类型信息的情况下检查需求的一致性都是非常实用的。

需求在环仿真对起落架需求的处理

起落架系统[5]旨在根据航空器驾驶员的指令,控制三个起落架的伸出和收回序列。其主要由三部分组成。航空驾驶员界面提供了一个操纵装置来指挥起落架的位置,以及作为显示机械状态的显示器。数字部分负责将航空器驾驶员的指令转化为电子命令,传递给物理部分。物理部分由三套起落设备组成,包括起落架、舱门,以及一些如电磁阀、模拟开关、液压缸,以及用于捕获机械状态的传感器等的电机设备。
请添加图片描述图4. 起落架系统架构

图4的原理图介绍了航空器驾驶员、数字部分和物理部分之间的交互。考虑到安全原因,数字部分是一个冗余系统,其运行两个实例的相同计算模块。这个模块包括伸出和收回序列的控制器,以及负责识别和消除无效传感器的健康监控系统。

整个架构在STIMULUS中以层次化的原理图进行指定。术语表定义了所有的连接/接口信号,并且结构类型允许信号的复用,例如,DoorsClosedSensors是一个3x3的布尔矩阵,用于捕获每个起落架套装的三重传感器。

形式化的需求可以分配给系统架构的任何级别。例如,图1的高级需求分配给了数字部分,并且详细的细化需求可以分配给基础组件,如控制器和物理设备等。

物理部分的需求

原始需求规格以自由文本的形式介绍了物理设备的行为。对于每台设备,此行为已经被捕获为一组形式化的需求,在此可以单独进行仿真。例如,模拟开关的自由文本描述如图5所示。
请添加图片描述图5. 模拟开关非形式化需求规格
请添加图片描述图6. 模拟开关的形式化需求

图6给出了模拟开关的形式化需求,而图7显示了一个可能的仿真。HandleMove信号的行为受到约束,以发出随机脉冲,而输入信号是具有随机值的自由变量。每次发出HandleMove信号时,开关都会关闭,输入信号会传输到输出信号。

然而,对仿真图进行深入观察会发现一个错误的行为,因为在t=50s时的HandleMove脉冲应该将开关保持在关闭状态,直至t=70s。将第二个需求的条件替换为“状态变为关闭或HandleMove变为真”可以解决这个问题。
请添加图片描述图7. 可能的模拟开关需求的仿真结果

数字部分的需求

原始的伸出序列需求规格在图8中给出。其本身并不是一组需求,而是一个标准的情景,因为其描述了在完成一个完整的伸出序列过程中,数字控制器发送的命令序列以及物理部分的反应。此外,附注特别说明,这个标准的序列可以在任何时候被反向命令打断,而且这个序列会在被打断的地方恢复。

尽管这个需求规格非常全面,但其并没有提供统一且可测试的需求来描述系统在任何时间点应执行的操作。深入分析此类需求是一个非常艰难的过程,并没有什么神奇的简单方法:我们是通过不断地试验、错误和修正进行的。然而,事实证明,仿真在检测连续的错误和向图9中的形式化需求集合进展的过程中是至关重要的。

伸出序列。起落架的伸出可分解为一系列基本动作。当起落架锁定于收起位置,且舱门锁定于关闭位置时,若航空器驾驶员将操纵杆设置为“放”,则软件应产生以下一系列动作。

  1. 激励常规电磁阀将指令单元分离,从而向作动电磁阀传递液压力。
  2. 激励舱门开启电磁阀。
  3. 当三个舱门均抵达开启位置时,激励起落架释放电磁阀。
  4. 当三个起落架被锁定,停止激励起落架释放电磁阀。
  5. 停止激励舱门开启电磁阀。
  6. 激励舱门关闭电磁阀。
  7. 当三个舱门均抵达关闭位置且锁定,停止激励舱门关闭电磁阀。 最终停止
  8. 激励常规电磁阀。
    请添加图片描述图8. 传出序列的非形式化需求规格
    请添加图片描述图9. 伸出序列的形式化需求

需求仿真分析

一旦所有软件和物理需求都已形式化并分配给系统架构中的适当组件,我们就可以仿真完整的系统行为。从建模的角度来看,这就是与现有的MBSE/MBD工具的连接发挥其全部作用的地方,因为系统架构通常可以根据相应的需求由STIMULUS导入。由于需求的分配被保留,系统架构师可以在他们的标准MBSE工具中对架构进行建模,并在非常早期的阶段在STIMULUS中对其进行仿真,而无需等待更详细的行为模型。

可能的仿真如图10所示。HandleCommand信号首先从放切换到收,然后,在收回序列完成之前,切换回放,以激活伸出序列。我们可以看到,反指令得到了妥善的管理。收起序列一直运行到所有的舱门都打开,所有的起落架都在操纵以回收。然后启动了伸出序列。由于所有的舱门都已经打开,伸出序列立即开始操纵以展开起落架,一旦展开起落架,就完成了相应的序列,关闭了舱门。
请添加图片描述图10. 可能的起落架需求仿真

图1中的高级需求,作为数字部分的观察者,也得到了满足。换言之,伸出序列的详细需求是对其的优异细化。

然而,图11中的第一个安全性需求在时间t=10.3s处遭到违反,因为数字部分向舱门发送了相互矛盾的指令。在一个时间点,物理系统被要求同时打开和关闭舱门。STIMULUS会自动报告这个冲突,并给出精确的诊断,从而识别出一组冲突的需求和冲突的瞬间。
请添加图片描述图11. 伸出和收回序列的安全需求

由于篇幅原因以及作者对游戏感的缺乏,读者被邀请代入系统架构师的角色,提出一个详细的修改需求以避免这种冲突的建议。在第二步中,读者被邀请在不进行任何仿真测试的情况下,思考他们对这种改变抱有多大的信心。

针对需求进行模型测试
一旦验证通过,形式化需求可以转化为观察者,用来测试任何模型的需求规格,或者起落架的软硬件实现。对于硬件在环(Hardware-In-the-Loop)仿真,观察者被导出为FMI组件以监控测试工作台并记录违反的需求。对于模型或软件在环(Model- or Software-In-the-Loop)仿真,FMI组件被从第三方MBSE/MBD工具导入STIMULUS,以构建测试套件并自动化回归测试。

在这个客户案例中,我们已经将一些数字和物理组件建模为状态机,其中一些是由原始论文[5]提供的,以便根据需求测试需求规格模型。尤其是,我们返回到伸出序列的原始需求规格,因为人们可能认为,使用状态机对这个序列及其中断进行建模是非常直观的。

图12展示了STIMULUS的分层状态机模型,其中包含一个恢复转换(由空箭头标示)。如预期的那样,对于完整的伸出序列的名义场景,状态机工作正常。然而,这个模型并未正确处理反向指令,许多需求观察者在此类仿真中遭到违反。

与原始需求规格中的表述不同,序列不应该“从中断的地方继续”。实际上,恢复状态依赖于舱门和起落架的物理状态,并且应该为序列的每个状态都添加特定的传入转换。再次,我们让读者提出新的需求规格,并找出缺失的转换条件。最后,我们还指出,一个明智的原理图控制器实际上可以从形式化的需求中得出,并提供一个优异的备选状态机。
请添加图片描述图12. 伸出序列的初级状态机需求规格

可执行需求和模型的结合为基于模型的测试提供了一个良好的框架。特别是,形式化需求有助于设置一个测试线束来自动化回归测试。在这项工作中:

我们将数字控制器视为被测系统(SUT)。其可以是一个模型,例如状态机,或一个外部的FMI组件;
我们将航空器驾驶员视为测试案例。命令可以被建模为约束,以生成各种测试场景(常规,反向命令);
我们将物理部分视为测试存根。其可以是需求和状态机的结合,并对SUT环境进行仿真;
我们将数字控制器的需求视为测试预言,作为观察者执行。
我们的结果显示了对初始起落架和舱门位置的广泛探索,以及它们对伸出和收回序列执行的影响,这些序列通常总是满足图1的高级需求。

结论
本客户案例展示了对需求在环仿真的使用,对调试和验证具有实际复杂性的典型网络物理系统功能需求规格的应用。

研究结果表明,需求在环(RIL)仿真非常适合基于模型的系统工程方法,因为可以以一种一体化和一致性的方式来设计需求、架构和行为模型。尤其是,可以将给定系统的需求细化为其子系统的更低级别需求,直至定义行为模型。在细化过程的任何步骤,都会进行仿真以检查全局系统架构的一致性以及低级别需求和/或模型与高级别需求的合规性。

这提供了一个有效的基于模型的测试框架,其中需求轮流捕获被测试系统、测试预言、测试用例或测试存根。测试执行引擎充分利用约束求解技术来探索各种环境场景和被测试系统的可能反应,从而实现全自动回归测试。尽管仿真无法确保探索的穷尽性,但其似乎是手动测试的有限覆盖率和自动证明工具的有限采用率之间的有效权衡。

最后,这项研究的一个有趣结果涉及到故障分析。传感器模型已经扩展了概率故障,通过仿真验证健康监控系统的需求。这一研究工作的初步成果非常鼓舞人心,为这一领域未来工作的开展打开了机遇之门。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1386080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CSS】首个字符占用多行,并自定义样式

效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>首字母大写</title><style&…

消息的发送与接收

消息的发送与接收 消息的发送与接收不仅仅是在于聊天功能的实现。其实还有很多种情况也算"消息的发送与接收"。而且我们还可以通过多种方法去实现。我们可以基于实际情况来选择。 WebSocket实现 node做后端。找了好多&#xff0c;前端页面总是用到了jQuery&#x…

AMC8历年详细考点分类,都熟悉了考高分不成问题(2024年也适用)

还有四天&#xff0c;2024年AMC8美国数学思维活动&#xff08;竞赛&#xff09;就要正式开始了&#xff0c;这两天有多位家长咨询六分成长&#xff0c;想了解AMC8的主要考点&#xff0c;或者说经常考的内容。 根据2000-2023年这23年的真题分析&#xff0c;AMC8试题的考点可以分…

Java开发+Intellij-idea+Maven+工程构建

Java开发Intellij-ideaMaven工程构建 Intellij-idea是一款流行的Java集成开发环境&#xff0c;它支持Maven作为项目管理和构建工具。Maven可以帮助开发者自动下载项目依赖的jar包&#xff0c;执行编译、测试、打包等生命周期任务。本资源将介绍如何在Intellij-idea中创建、导入…

MATLAB二维与三维绘图实验

本文MATLAB源码&#xff0c;下载后直接打开运行即可[点击跳转下载]-附实验报告https://download.csdn.net/download/Coin_Collecter/88740747 一、实验目的 掌握图形对象属性的基本操作。掌握利用图形对象进行绘图操作的方法。 二、实验内容 利用图形对象绘制曲线&#xff…

亚信安慧AntDB超融合框架——数智化时代数据库管理的新里程碑

在信息科技飞速发展的时代&#xff0c;亚信科技AntDB团队提出了一项颠覆性的“超融合”理念&#xff0c;旨在满足企业日益增长的复杂混合负载和多样化数据类型的业务需求。这一创新性框架的核心思想在于融合多引擎和多能力&#xff0c;充分发挥分布式数据库引擎的架构优势&…

钉钉逐浪AI Agent

文&#xff5c;郝 鑫 编&#xff5c;刘雨琦 “大公司代表落后生产力&#xff0c;是慢半拍的”&#xff0c;“小创新靠大厂&#xff0c;大创新仍然要靠小厂”&#xff0c;这是以李彦宏和王小川为代表的创业老炮&#xff0c;在2023年总结出来的创新规律&#xff0c;从移动互…

图形化编程:以Scratch引领少儿编程思维启蒙之旅

在21世纪科技飞速发展的今天&#xff0c;编程教育已经成为培养未来人才的重要途径。而“少儿编程”这一概念的提出&#xff0c;正是为了让孩子们从小接触并理解计算机逻辑&#xff0c;锻炼他们的创新思维与问题解决能力。其中&#xff0c;图形化编程以其直观易懂、趣味性强的特…

手把手教你VS code文件如何在顶部自动生成作者,修改日期等信息

1、安装插件KoroFileHeader 2、左下角选择管理---设置---输入"fileheader"---点击"在setting.json中编辑" 输入"fileheader"-点击"在setting.json中编辑" fileheader 必须的基础配置: 头部注释模板与函数注释模板 复制&#xff1a;…

C++(1) —— 基础语法入门

目录 一、C初识 1.1 第一个C程序 1.2 注释 1.3 变量 1.4 常量 1.5 关键字 1.6 标识符命名规则 二、数据类型 2.1 整型 2.2 sizeof 关键字 2.3 实型&#xff08;浮点型&#xff09; 2.4 字符型 2.5 转义字符 2.6 字符串型 2.7 布尔类型 bool 2.8 数据的输入 三…

【C++】static_cast和dynamic_cast使用详解

目录 一、static_cast二、dynamic_cast三、总结如果这篇文章对你有所帮助&#xff0c;渴望获得你的一个点赞&#xff01; 一、static_cast static_cast 是 C 中的一种类型转换操作符&#xff0c;用于执行编译时的类型转换。它主要用于在不损失 const 限定的前提下进行各种合法…

【WSL】Win10 使用 WSL2 进行 Linux GPU 开发

1. GPU 驱动 先安装 驱动 参考 https://docs.nvidia.com/cuda/wsl-user-guide/index.html 使用 https://www.nvidia.com/Download/index.aspx 提供的兼容 GeForce 或 NVIDIA RTX/Quadro 显卡在系统上安装 NVIDIA GeForce Game Ready 或 NVIDIA RTX Quadro Windows 11 显示驱动…

Eclipse的安装与使用

Eclipse的安装与使用 “工欲善其事&#xff0c;必先利其器”&#xff0c;高效的开发工具&#xff0c;不但能带来高体验的开发环境&#xff0c;还能带来高效的纠错与开发提示等功能&#xff0c;下面介绍一种Java常用的开发工具——Eclipse。 1.1 Eclipse的安装与启动 Eclipse的…

MK-米客方德TF卡和SD卡的区别

TF卡和SD卡的区别 TF卡也叫MicroSD卡&#xff0c;以MK-米客方德的TF卡和SD卡为例&#xff0c;TF卡和SD卡的区别如下&#xff1a; 1、物理尺寸&#xff1a; TF卡&#xff1a;TF卡是一种较小尺寸的存储卡&#xff0c;也被称为MicroSD卡。其尺寸为15mm 11mm 1mm。 SD卡&#x…

k8s--动态pvc和pv

目录 前情回顾 动态pv 实验模拟 步骤一&#xff1a;在stor01节点上安装nfs&#xff0c;并配置nfs服务 接下来在matser01上配置 步骤二&#xff1a;创建 Service Account&#xff0c;用来管理 NFS Provisioner 在 k8s 集群中运行的权限和动态规则 步骤三&#xff1a;使用 Deploy…

python实现网络爬虫代码_python如何实现网络爬虫

python实现网络爬虫的方法&#xff1a;1、使用request库中的get方法&#xff0c;请求url的网页内容&#xff1b;2、【find()】和【find_all()】方法可以遍历这个html文件&#xff0c;提取指定信息。 python实现网络爬虫的方法&#xff1a; 第一步&#xff1a;爬取 使用reque…

基于ssm的疫苗预约系统论文

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装疫苗预约系统软件来发挥其高效地信息处理的作用&#xff0c…

SpringCloud.03.网关Gateway

目录 网关Gateway的概念&#xff1a; 准备 使用 方式一 因为配置了网关所以可以直接通过gateway发送请求 方式二 修改配置前&#xff1a;http://localhost:8082/provider/run 方式三(动态路由) 导入配置类 网关Gateway的概念&#xff1a; Spring Cloud Gateway 是 Spri…

如何统一给文件夹名加后缀?这个方法教你一键搞定

随着计算机的普及&#xff0c;我们每天都会处理大量的文件和文件夹。有时候&#xff0c;为了更好地管理和分类文件&#xff0c;我们会给文件夹统一加上后缀。给文件加上后缀后最直接的好处就是方便文件管理。当我们给文件夹加上后缀时&#xff0c;我们可以很容易地根据后缀来判…

如何创作出优秀的电子邮件营销(EDM)?

EDM出现的时间很早&#xff0c;是非常传统的一种推广方式。即便是其他推广方式的蓬勃兴起&#xff0c;EDM依旧深受很多行业的喜爱。主要源于它极高的性价比&#xff0c;据可靠数据&#xff0c;EDM的投资回报比达1&#xff1a;48。 那一封优秀的EDM应该是怎么样的呢&#xff1f;…