当前位置:首页 » 编程软件 » soc脚本

soc脚本

发布时间: 2022-08-19 15:01:12

❶ 以前做fpga现在做soc,看什么书有助入门

首先,做IC跟做FPGA用的工具不太一样,所以先要学学相关工具的使用。
然后学学脚本语言的使用方法,这在IC设计中非常有用。
再学学时序分析和验证方面的理论
最重要的是找个高手带一个项目!

❷ 求助考虑SOC时的VASP编译问题

bash脚本、bash终端: 请先执行ulimit -s unlimited 再执行vasp tcsh/csh脚本、tcsh/csh终端: 请先执行unlimit

❸ Perl脚本在数字IC设计中有哪些应用

Perl脚本可以用于生成有规律的代码,如SOC地址仲裁模块verilog代码、不同规格的CRC校验verilog代码、不同规格的FIFO代码。
在芯片设计过程中,所用到的FIFO数量很多,大于100多个很常见,甚至大于500个都是存在的。而不同规格的FIFO基本都是用最基础的RAM模块来搭建实现的,如果依靠人工编写,错误率高而且效率极其低下。因此,使用perl脚本编写不同规格的FIFO代码是可靠高效的方式。
快速生成testbench:在进行功能仿真的时候,需要编写测试案例testbench,可以利用perl脚本快速生成测试案例的大部分代码,手动添加少量verilog,即可快速完成testbench的编写,有效减少工作量。
Verilog代码自动对齐:verilog代码在人工编写时全靠手敲空格符会很累,并且效率低下,采用perl脚本一键对齐,效率高节省体力。
Mole例化连接:有些mole模块的输入输出信号有上百条,依靠手动添加会很繁琐,此时利用perl脚本生成例化模块可以有效提高效率,降低错误率。

❹ 如何为SoC设计选择IP核

SoC设计师常常需要仔细考虑以决定哪种IP核对一个给定的SoC项目最合适。他们必须决定内核的类型(软核或是硬核)、可交付使用内核和相关产品的质量、IP提供商的可靠性和承诺等。本文将就以上每个环节进行讨论,并为如何最好地评估竞争性IP核的特性提供指导。

IP核可以两种形式提供给客户:软核和硬核。两种方式都可使客户获得在功能上经过验证的设计。软核也被称为可综合内核,需要由客户进行综合并在其SoC上实现。而硬核已完全实现(完成了版图设计),可直接用于制造。(从技术上说,一种设计只有生产后才能实现。但是在此情况下,实现的意思是指安排布局并可直接投入生产)。SoC团队只需将硬核像一个单片集成电路片那样置入芯片即可。软核和硬核具有不同的问题和好处。

将IP核整合到一个芯片上需要很多步骤。这个过程是否能够很容易地完成,主要取决于提供的交付成果。另外,客户不仅必须对IP核进行评估,而且还要评估IP提供商。

软核与硬核的对比

1. 性能

由于软核没有实现,因此它天生在功能和实现方面比硬核更加灵活。另一方面,硬核开发者可能要花更多的时间来优化他们的硬核,因为它们要在很多设计中使用。因此,这使人们觉得硬核会提供更高的性能。

事实上,为那些最先进工艺设计的高端、全定制硬核确实能够提供比软核更好的性能。通过使用锁存、动态逻辑、三态信号、定制存储器等,全定制设计团队能实现比完全静态综合的设计更好的结果。对于需要达到现有工艺和设计技术极限性能的SoC来说,全定制硬核能够更好地满足这些要求。

然而,如果性能目标在一个软核范围内,那么硬核的优势就无关紧要了。SoC设计团队能够使用软核来满足性能要求,并利用其固有的灵活性优势。而随着工艺技术的进步,软核的最高频率限制也在提高,使它们成为更多SoC设计师的一种选择。在较低时钟频率下,硬核或许具有硅片面积方面的优势。但是情况往往并不是这样。硬核经常简单地使用ASIC的方法进行固化,使之不能提供速度上的优势。在其他情况下,全定制内核不能根据每一代工艺进行重新优化,所以削弱了频率和尺寸上的优势。

2. 技术独立和可移植性

软核的优势之一是技术独立的,也就是说,Verilog或VHDL不需要使用一种特定的工艺技术或标准的单元库。这意味着同一个IP核能够应用到多种设计中,或现有设计的下一代中。一些软核提供商采用使其内核技术上非独立的设计风格,但是这种方式看不到什么优势。

图1:受IP核影响的开发任务。

另一方面,硬核在技术上是非常特定的。事实上,如果代工厂改变其工艺参数或库,硬核可能就无法正常工作。这就产生了一个风险,因为在工艺参数改变时,IP提供商需要重新对硬核进行验证。

硬核能够移植到新的工艺技术,但是重新优化全定制内核的工作既费事又昂贵。对于一些先进的微处理器内核,这可能要花两年或更长的时间。因此,硬核经常根据新的工艺进行光学调整。虽然这一方法既简单又快速,但是它减少了由设计团队针对现有工艺进行全定制优化的许多优势。

不仅如此,光学调整同时带来了另一个风险,因为它只能保证新的设计满足设计规则,而不能保证准确的时序或功能,而且重新全面验证经过光学调整的IP核是非常困难的。

3. 速度/面积/功率优化

对于要实现的技术来说,硬核通常比可比较的软核运行速度更快。但是即使对于这单种技术来说,硬核也仅仅是针对一组目标而优化。如果目标是在合理的性能上使芯片面积更小,那么对于这种应用来说,为高度可调性能而优化的硬核可能就太大了。

软核是能够被“应用优化”的。为适合特定的嵌入式SoC设计,时序、面积和功率目标可能需要进行调整。例如:如果SoC使用200MHz的时钟,那么设计运行在250MHz的软IP内核可以改为准确地运行在200MHz上。这在得到更小尺寸和更低功率的同时满足了设计约束。

这种应用优化也适用于低层IO时序。软内核的IO约束可以进行调整,以准确配合内核的使用环境。如果硬内核有延迟输出信号,SoC设计师几乎无法改善时序。

如果SoC的速度、面积和功率目标与硬核的目标相符,那么硬核将极具竞争力。但对于大多数设计师来说,软核在为特定的SoC优化方面更具优势。

4. 可定制性

软核相对硬核还具有另外一个优势:编译时间定制化。这些是实现之前的设计选项。

高速缓冲存储器的内存大小就是一种常见的编译时间用户定制项目。根据特定嵌入式应用所需的高速缓冲存储器的大小,软核处理器能够精确地被配置。而硬核在这方面就不能被定制。

另一种在许多软核中应用的定制项目就是指令专用,或选择性支持某种特殊指令。例如,一些SoC可能需要对外部协处理器的支持。然而,在一些不使用这些特性的系统中,多余的硬件可从软核中去掉,以节省面积和功率。

软核还可以包括实现配置参数。这是一种特殊的编译时间定制,可帮助软核更好地配合SoC团队使用的设计风格。例如,微处理器内核经常通过使用门控时钟电路来实现,但这种时钟不能与某些时钟布线工具很好配合。如果处理器内核可提供一种将所有门控时钟变为相等的多路复用器(MUX)的编译时间设置,SoC团队可使实现更为容易。

5. 易于集成

软核很可能更容易被集成到SoC设计团队使用的流程中,除非内部设计小组已经实现了硬核。其原因是SoC设计团队将在他们认可的IP核周围添加RTL模块。这些内核看上去就像另外的SoC模块,也可像它们一样地实现。

另一方面,硬核看上去更像一个黑匣子RAM,特别是在它采用全定制技术实现时。这意味着硬核提供商将需要为该内核提供更多的黑匣子模型,使SoC设计师能够在其周围设计其模块。这本身就比使用软核更困难。例如,全定制硬核也许没有门级网表。这是因为该设计已经在晶体管级完成,而没有使用逻辑门。但是设计团队可能需要通过背注时序运行门级功能仿真,因为缺少门级网表,这将难以进行。

附加提供物

一个有竞争力的软IP核不只是一个Verilog或VHDL源文件的集合。出于同样原因,一个好的硬核也不只是一个版图数据库。今天的IP核包含一系列可交付使用的提供物,可使SoC设计团队将IP核整合到他们的设计中。这些附加提供物的目标是使IP核尽可能容易地整合到设计流程的各个环节。

图1显示了采用不同IP核的SoC开发活动。这里包括了软核和硬核都必需的一些可交付使用的提供物。

1. 文档创建

清晰和简练的文档是大多数技术产品的先决条件。然而,需要参考IP核文档的人差异非常大,这使IP核技术文档创建面临非常大的挑战。

在图1中,每一个开发活动都有不同的文档需求。例如,软件开发者需要了解硬件的可编程特性,但他们可能不关心它是怎样实现的。因此,一组好的文档可使软件开发者更容易发现他们所需的信息,而不致被大量无用的信息困扰。

最后,如果SoC团队要为能复用部分IP核文档的SoC创建文档,IP提供商应该提供可编辑的源文件和引用权。

2. 接口检查器

SoC团队必须设计逻辑,以便与不同信号和IP核协议进行接口。为了确定其设计是否正确,IP提供商能够提供接口检查器模块,以验证所有接口信号和协议的正确运行。它可能与确认不变的静态信号一样简单,也可能像验证多周期总线协议的正确运行一样复杂。

这些检查器通过自动验证给定接口处理类型是否正确运行的工作,大大简化SoC团队的工作。在一个非法处理的情况下,检查器应该报告错误,使SoC设计师能够容易地查明有缺陷的逻辑并排除故障。接口检查器必须在SoC设计环境中准确工作。它们应该能够非常容易地整合到功能仿真中,而不是以一种实际硬件的形式出现。

3. 协议制表器

IP提供商能够提供另一种交付成果使接口验证变得更加容易,这就是协议制表器。这是一个监测接口处理的模块,可观察到各种特殊状况。协议制表器保存所有可见的处理类型并报告没被运行的“边际”(corner case)。IP提供商必须提供一个进行接口完全验证所需的边角情况表。

在开发过程中,协议制表器将帮助SoC团队决定哪些“边际”情况需要继续验证。一旦开发结束,它同时确保通知SoC团队已经执行了所有必需的“边际”情况验证。由于IP提供商对内核接口具有最佳的理解,这个“边际”情况表将比SoC团队能够想象的任何方案更加完善。

4. RAM检查器

如果一个IP核拥有SoC团队必须编译和整合的内部随机存储器,在处理过程中有可能引入瑕疵。排除由深度嵌入式RAM导致的故障对于SoC团队是一件非常困难的事情,因为它经常涉及通过内核模块跟踪故障的工作。RAM检查器能够大大简化排除RAM模块导致的故障的工作。(当SoC团队不得不通过一个IP核来排除故障时,这是一个非常糟的情况。他们应该能够信赖它的正确运行。)

5. 快速仿真模型

对于SoC设计师来说,用一个大型IP核的RTL仿真完整的SoC可能非常缓慢。如果IP提供商能够提供一个周期精确的内核快速功能模型,客户将从更快速仿真、更快速调试及更少地使用仿真授权中获益。即使是一个非周期精确的模型,对于大多数SoC设计和调试已经足够好了。只要最后运行周期精确模型,在开发过程中就可以从快速功能模型中受益。

6. EDA工具支持

另一个内核质量指标是EDA工具的支持情况。由于不同设计团队可能使用不同的工具,支持多种EDA工具的多种形式的可交付使用成果是目前先进内核经常能提供的。

例如,一个IP核使用Verilog设计而成,但那些使用基于VHDL的EDA工具和方法的客户仍会要求VHDL。如果一个内核只针对Verilog,那么SoC团队在使用该内核时,将不得不忍受一个麻烦且容易发生错误的转换过程。

此外,IP提供商应该提供比需求格式更多的东西。不同的EDA工具可能有标准格式的不同实现方法。在以上的例子中,IP提供商不能仅为Verilog客户提供Verilog RTL,它必须支持客户使用特定的Verilog仿真器。否则,该客户可能要调试与IP提供商所用的略微不同的Verilog仿真器相关的设计问题。

这个概念实际上适用于所有交付成果。对于硬核,这个概念同样可在实现阶段应用。硬核必须以一种被SoC团队后端工具所支持的形式提供。而且IP提供商必须支持客户使用的特殊后端工具。

对硬核来说,这个概念在实现阶段同样适用。硬核必须以能被SoC团队后端工具支持的形式提供,而且IP提供商必须支持使用特定的后端工具。

7. EDA脚本实例

为了帮助快速展开各种设计活动,IP提供商应该提供所支持EDA工具的实例脚本。这是IP提供商帮助SoC团队有效地使用IP核进行系统设计的另一种方法。该脚本可能如makefiles一样简单,可实现汇编功能仿真器。这些脚本也可能如一个全套的、针对功能回归执行的自动化设计脚本一样复杂。在任何情况下,实例脚本对于SoC设计师来说总是很有用。

对于软核来说,实例综合脚本几乎是必要的。至少它们应该提供顶层约束、故障路径和多周期路径。如果可能,应该同时提供实现若干工业标准综合方法学的脚本。当然,这些实例脚本越简单,对于SoC设计师来说就越容易理解、进行修改并集成到他们的流程中。

8. 功能内核验证

虽然SoC设计师不会修改软IP核的RTL设计,但是他们确实会改变作为芯片设计常规部分的一些功能。这样的例子包括扫描链接插入、时钟缓存和RAM BIST集成。SoC设计团队需要验证这些改变不会对内核的正确运行产生影响。

验证新设计在功能上与以前设计没有改变的一种方法是采用IP提供商提供的测试基准和测试套件,以全面验证内核是否正确运行。不幸的是,对于许多内核来说,完整的测试套件太大了,以至于不能作为IP核的一部分来提供。因此,大多数IP提供商选用完整验证套件组的子集,它同样能够验证运行。大多数情况下,对于发现那些由以上设计变化类型引起的错误来说,这个子集已经足够了。

然而,形式验证工具对于保证正确运行是一个更彻底的方法。这些工具可精确地验证新设计与老设计的相同之处。支持形式验证工具可使SoC团队无需运行门级回归。

9. 软件协同开发工具

为新系统开发软件的标准方式是,首先生产硬件样片,然后开发运行在上面的软件。然而,在很多情况下这延长了产品上市时间,因此软件开发经常与硬件开发平行进行。

软件开发比硬件开发需要快得多的系统仿真。因此IP提供商必须提供一个非常快的IP核功能模型。这为低层固件的开发提供了足够的性能。

对于更高的仿真速度,有时会使用硬件逻辑仿真器,它可比纯仿真快一个数量级(虽然这仍然比实际硬件慢2至3个数量级)。这些工具非常难用,而且需要特殊的综合。对于计划进行硬件和软件协同开发的SoC设计团队来说,支持这些技术是对IP核的一个关键要求。

❺ labview FPGA模块中控制DIO板卡输出IO量控制继电器吸合,怎么实现IO量自动输出功能

第一步:使用Quartus和Qsys工具完成硬件系统的配置。

该步骤实现SOC最小系统的硬件配置,包括硬核处理器配置、HPS和FPGA之间通信接口总线的选择、HPS外设裁剪、HPS时钟配置和SDRAM配置。该实验中主要用到HPS硬核,以及PIO外设IP核。Qsys工具为用户提供硬件系统的可视化设计,能够自动生成handoff文件,该文件配合bsp-editor工具可以生成preloader。Preloader是HPS的第二阶段引导源,主要作用为:初始化SDRAM接口,配置HPS IO口,加载下一引导源并跳转到它。

实验步骤

1 新建Quartus工程。

1.1 设置工程存放路径,工程名以及顶层文件名,如图1所示。

图1

1.2 选择FPGA器件型号,如图2所示,DE10-Standard板载FPGA型号为5CSXFC6D6F31C6。

图2

1.3 点击next直到finish,未提及的页面均按默认设置即可。

2 在Qsys中配置SOC。

2.1 运行Qsys工具。

在Quartus软件中,通过菜单栏Tools->Qsys打开Qsys工具。刚打开的Qsys工具页面如图3所示。

图3

2.2 添加HPS并完成配置。

在左侧的IP目录中输入hps,选中Arria V/Cyclone V Hard Processor System,双击添加HPS,在弹出的HPS配置页面中进行HPS配置。HPS配置页面如图4所示。

图4

1) 在FPGA Interfaces页面中,General一栏均不勾选,AXI Bridges一栏设为64-bit、64-bit、32-bit,FPGA-to-HPS SDRAM Interface一栏中移除原有接口,Resets一栏中均不勾选。

2)在Peripheral Pins页面中,设置HPS外设引脚复用及模式选择。设置如表1所示。设置完成后页面如图5所示。(本实验其实未用到这些外设)

表1 外设引脚复用及模式选择

外设名称

引脚复用选择

模式选择

EMAC1

HPS I/O Set 0

RGMII

QSPI

HPS I/0 Set 0

1SS

SDIO

HPS I/0 Set 0

4-bit Data

USB1

HPS I/0 Set 0

SDR

UART0

HPS I/0 Set 0

No Flow Control

(注:表中未提及的外设即Unused,无需设置)

图5 Peripheral Pins页面设置

  • 在HPS Clocks页面中,确认下Input Clocks->External Clock Sources 中的时钟频率为25MHz,其它无需设置,默认即可。

  • 在SDRAM页面中,参考图6-11更改该页面下所有子页面中的参数。(本实验未用到SDRAM,所以不设置也可)

    图6

    图7

    图8

    图9

    图10

    图11

    5) 至此,HPS设置完毕,点击finish离开HPS设置页面。

    2.3 添加并设置其它Qsys元件

    本实验通过HPS控制FPGA部分的IO口,以此来控制连接在FPGA IO引脚LED灯的亮灭。所以整个SOC只需包含HPS和PIO,即Qsys中还需要添加PIO外设。

    添加PIO外设。在IP目录中输入PIO,选中PIO双击添加外设,设置页面如图12所示,本实验通过PIO控制4个LED,故宽度为4。

    图12

    2.4 配置Qsys系统元件

  • 修改元件名称。本实验把pio_0重命名为led_pio。

  • 导出外设的顶层I/O接口。在Export一栏下相应位置双击,导出led_pio的顶层I/O接口,命名为fpga_led_pio,导出hps_0的h2f_reset接口,命名为hps_0_h2f_reset,如图13所示。

    图13

  • 连接Qsys外设接口。外设的接口信号之间没有连接,需要根据系统要求手动进行连接。各个外设之间的信号连接c如表2所示。连接好后如图14所示。

    表2 元件信号连接关系

    需要连接的

    被连接的

    元件

    信号名

    元件

    信号名

    led_pio

    clk

    clk_0

    clk

    reset

    clk_0

    clk_reset

    s1

    hps_0

    h2f_lw_axi_master

    hps_0

    h2f_lw_axi_clock

    clk_0

    clk

    h2f_lw_axi_master

    led_pio

    s1

    图14

    4)配置Qsys的地址映射。Qsys中添加的元件及外设都需要分配对应的基地址。这里我们采用自动分配的方式,在Qsys菜单中选择System->Assign Base Address,完成基地址自动分配。

    5)生成Qsys系统。Save保存Qsys文件,命名为soc_led.qsys。然后点击菜单Generate->Generate HDL,弹出如图15设置框,按图设置好后点击Generate,Qsys将生成与硬件系统相关的一系列文件。

    图15

    3 完成Quartus工程编译

    3.1 在Quartus工程中添加Qsys产生的系统模块。

    1)Quartus中点击菜单Assignments->Settings,弹出设置框,选中左侧Files一栏,添加Qsys文件soc_led.v和soc_led.qip,添加完成后如图16所示。

    图16

    2)新建顶层文件。本实验采用的顶层文件类型为bdf(Block Diagram/Schematic File)。点击菜单File->New,选择Design Files中的Block Diagram/Schematic File后点击OK,点击菜单File->Save As将该文件保存到工程目录下,命名为top.bdf。在该原理图空白处右键Insert->Symbol,选择Qsys生成的soc_led.bsf,将该模块插入到顶层原理图文件中。选中插入的元件,右键点击Generate Pins for Symbol Ports,为元件添加输入输出端口,如图17所示。

    图17

    3.2 工程分析综合后分配引脚

    完成以上步骤后,需要分配引脚,包括HPS外设默认引脚分配以及FPGA部分引脚分配,在分配引脚之前,工程必须通过分析综合,否则引脚分配会出错。

    图18

    然后按2)所示Tcl Scripts工具执行上面编写的脚本,完成FPGA部分LED引脚的分配。

    3.3 工程编译。

    完成以上所有操作后,可以点击菜单Processing->Start Compilation对工程进行完全编译。编译成功后会生成FPGA编程所需的.sof文件。

    4 完成FPGA编程。

    这里只介绍采用JTAG方式完成FPGA编程方式,注意这种方式下,FPGA编程电路断电后就丢失。

    点击菜单Tools->programmer,打开编程工具,选择连接至计算机的DE10开发板,如图19所示。Close硬件设置框。编程页面中Mode选择JTAG,点击Auto Detect按钮,在弹出的器件选择框中选择相应的器件型号,DE10-Standard板载FPGA型号应选择5CSXFC6D6。选中FPGA设备,点击Change FIle,选中编译生成的top.sof文件,如图20所示。然后勾选Program/Configure,如图21所示。最后点击Start按钮开始编程。

    图19

    图20

    图21

    实验细节注意:

    在分配引脚之前必须先对工程进行分析综合(Analysis and Synthesis)

    第二步:使用SOCEDS完成HPS软件开发

    说明:

    该步骤完成HPS软件部分的开发,SOC EDS提供了全套的软件开发工具。本实验只是通过HPS控制FPGA部分的IO口,系统架构简单,采用裸机开发方法。DS-5为SoC FPGA裸机开发提供了两套编译工具:ARM Compiler 和 Altera Baremetal GCC。本实验采用ARM Compiler。

    实验步骤

    1 运行软件开发工具DS-5。

    打开Embedded_Command_Shell.bat,输入eclipse &命令回车,打开DS-5开发软件。如图1所示。 DS-5界面如图2所示。

    图1

    图2

    2 新建C Project

    点击菜单File->New->C Project,弹出工程配置框如图3所示,按图完成设置,注意编译工具链选择ARM Compiler 5

    图3

    3 工程编译选项设置

    3.1 添加HWLIB路径

    因为本实验用到了SOC EDS提供的HWLIB中的API访问硬件,所以要在项目编译选项中添加HWLIB路径。HWLIB所在路径为:<SOC EDS安装路径>ipalterahpsaltera_hpshwlibinclude 和 <SOC EDS安装路径>ipalterahpsaltera_hpshwlibincludesoc_cv_av

    操作:在DS-5左侧的Project Explorer中选中LedWater工程,右键点击Properties。弹出的对话框按图4设置,完成HWLIB路径的添加。

    图4

    3.2为工程编写分散文件scatter。

    scatter文件为连接器指定映像的内存映射。本实验中,映像文件的加载区和执行区都在HPS的片内RAM上,而HPS片内RAM的地址映射为0xFFFF0000-0xFFFFFFFF,所以编写分散文件内容如下,分散文件编写完成后添加到编译选项中。

    OCRAM 0xFFFF0000 0x1000

    {

    APP_CODE +0

    {

    *(+RO, +RW, +ZI)

    }

    ARM_LIB_STACKHEAP 0xFFFF8000 EMPTY 0x8000

    {}

    }

    操作:点击菜单File->New->Other,弹出对话框,按图5操作。打开新建的scat文件,输入上面的分散文件内容。在DS-5左侧的Project Explorer中选中LedWater工程,右键点击Properties。弹出的对话框按图6设置,完成scat文件路径的添加。

    图5

    图6

    4 生成硬件设备描述头文件。

    利用SOC EDS提供的swinfo2header工具,将Qsys硬件系统信息转换为软件开发所需的设备描述头文件。

    操作:在嵌入式命令行shell中cd到soc_led.sopcinfo所在目录,然后输入如下命令:sopc-create-header-files soc_led.sopcinfo --single hps_0.h --mole hps_0如图7所示,同目录下将会生成名为hps_0.h的头文件,将其拷贝至软件工程目录下。

    图7

    5 编写main.c

    为工程新建main.c文件,输入main.c代码,代码如下:

    #include "hwlib.h"

    #include "socalsocal.h"

    #include "socalhps.h"

    #include "hps_0.h"

    void delay(int delay_time)

    {

    int k;

    for(k=0; k<delay_time; k++) ;

    }

    int main()

    {

    int i = 0x1;

    while(1)

    {

    alt_write_word( ALT_LWFPGASLVS_OFST+LED_PIO_BASE, i );

    if( (i&0xf) == 0x8 ) i=0x1;

    else

    i = i<<1;

    delay(100000000);

    }

    return 1;

    }

    6 工程编译连接

    在DS-5左侧的Project Explorer中选中LedWater工程,右键点击Build Project,生成可执行文件ledWater.axf。

    7 生成preloader

    裸机工程中,preloader即u-boot-spl。在shell中输入bsp-editor启动工具,如图8所示。在打开的bsp-editor工具中,点击菜单File->New HPS BSP,选择handoff文件目录,如图9所示。设置中取消勾选WATCHDOG_ENABLE选项,如图10所示,因为我们没有在裸机应用程序中用到看门狗。设置完成后点击generate,产生我们设置的preloader源代码,生成的源代码路径显示在Information栏中。Shell中cd到preloadre源代码目录下,输入make -j8 (多线程编译提高编译效率),如图11所示,回车生成preloader二进制文件,需要等待几分钟。在<Quartuas工程目录>softwarespl_bspuboot-socfpgaspl目录下,可以看到已经生成了u-boot-spl二进制文件。将其拷贝至LedWater工程目录下。

    图8

    图9

    图10

    图11

    8 编写调试脚本

    为LedWater工程新建调试脚本,步骤如图12所示。打开新建的文件输入以下内容。

    reset system

    stop

    wait 30s

    set semihosting enabled false

    loadfile "$sdir/u-boot-spl" 0x0

    set semihosting enabled true

    delete

    tbreak spl_boot_device

    run

    wait

    loadfile "$sdir/Debug/ledWater.axf"

    Start

    图12

    完成以上所有操作后,工程目录应该如图13所示。

    图13

    9 工程调试。

    1) 在进行工程调试前,首先要确保板卡连接至计算机,并先下载硬件sof文件至fpga。然后新建调试配置项,选中LedWater工程,右键选择Debug As->Debug Configurationz,弹出会话框,按图14和图15设置。设置完成后点击Debug开始调试。

    图14

    图15

    2)进入调试页面后,如图16所示,点击红圈中Continue图标,开始运行main程序,DE10开发板上的4个LED灯依次循环点亮。

  • 编写fpga部分的外设引脚分配脚本。根据硬件板卡的实际连接关系,编写引脚分配脚本,本实验用到DE10-Standard板卡上的4个LED,参考原理图,编写脚本如下:

    set_location_assignment PIN_AA24 -to fpga_led_pio_export[0]

    set_location_assignment PIN_AB23 -to fpga_led_pio_export[1]

    set_location_assignment PIN_AC23 -to fpga_led_pio_export[2]

    set_location_assignment PIN_AD24 -to fpga_led_pio_export[3]

    set_location_assignment PIN_AF14 -to clk_clk

  • 菜单点击Processing->Start->Start Analysis & Synthesis开始分析综合。

  • 分析综合完成后,点击菜单Tools->Tcl Scripts,弹出脚本运行框,如图18所示。分别运行hps_sdram_p0_parameters.tcl和hps_sdram_p0_pin_assignments.tcl。

❻ 如何调bcm 芯片sdk初始化

SDK初始化前,需要对SDK的架构有所了解,具体如下图;可以看出SDK的代码结构是一个层次化分明的架构,这里对各层的作用和详细工作机制不阐述了,具体可以参见SDK的介绍文档。

SDK代码的结构图

SDK根据上述架构,BCM模式启动的时候进行的初始化包括以下几个步骤:

1. 根据操作系统(linux、vxworks或unix等)不同调用sal_core_init()和sal_appl_init()两个函数的对应版本,分别对Core SAL和Appl SAL两部分进行初始化;linux系统下的sal_core_init()函数的主要工作时调用了函数sal_dpc_init()创建DPC(Deferred Procere Call)的信号量和线程;sal_appl_init()函数的linux版本则直接返回,没有做任何工作;这两个函数虽然意义很大,但是值得我们研究的内容不多。

2. 然后调用sal_thread_create创建一个运行BCM模式的线程,并调用diag_shell()函数完成对BCM模式的数据进行初始化、命令行进行注册、设备探测和挂载、芯片初始化、客户命令注册、重启动和BCM模式退出等操作,主要通过调用diag_init()函数、sysconf_init()函数、diag_rc_set()函数、sysconf_probe()函数、sysconf_attach()函数、bcm_init()函数、custom_cmd()和sal_reboot()等函数实现,下面详细介绍下该函数的执行流程;

a. diag_init()调用cmdlist_init()函数、init_symtab()函数、sal_srand()函数、gvar_init()函数和sh_bg_init()函数等来完成命令行注册、芯片的寄存器和表项软件数据内存分配、随机数种子获取、全局变量初始化和所有设备可执行任务的内存分配(最多10条)和记录等工作;

b. sysconf_init()函数除了初始化管理接口的调式函数外还调用soc_cm_init()函数来完成SOC的配置的管理接口的初始化;

c. sysconf_probe()函数调用bde_create()函数和sysconf_chip_override()函数完成探测已经挂载的设备并建立对应的配置管理项,包括为每个设备的分配id等工作;

d. 然后对每个unit调用sysconf_attach()函数来对soc_cm_device_init ()初始的管理接口的设备挂载一些中断处理函数,注册PCI读写函数等,用管理接口的结构体的指针函数成员形式保存,以便可以删除和添加这些处理函数,并调用soc_cm_device_init()函数通过在里面再调用soc_attach()函数来对每一个unit建立并初始化芯片的soc_control_t structure信息及对其访问的互斥体;soc_attach()函数调用soc_feature_init函数、soc_intr_disable()函、soc_cmic_uc_msg_start函数、soc_info_config()函数(这个函数下面会继续调用)、soc_dcb_unit_init()函数和soc_counter_verify()函数分别进行支持特性赋值、关闭中断、开启对设备的CMIC的UC信息、soc信息初始化、CPU收发包缓存DCB初始化和各种counter寄存器软件记录特定初始化,并对SOC_CONTROL(unit)和SOC_PERSIST(unit)两个保存芯片设备信息的结构体一些成员进行赋值;

e. 调用diag_rc_set()函数来设置对每个芯片初始化配置的脚本文件名称和热启动的初始化配置脚本名称,如果没有指定全部用默认的配置;然后解析脚本中的配置项,运用脚本进行配置初始化(包括MMU的配置);

f. 然后对每个芯片调用bcm_init()函数开始芯片的初始化工作,其首先调用bcm_attach()函数对BCM_CONTROL(unit)信息的部分成员进行赋值,包括设备类型、设备名称和unit号等;然后调用_bcm_api_xlate_port_init()函数建立lport和bcm port的映射关系;并调用芯片各功能模块的初始化函数(trident是bcm_esw_init ()函数)来对各模块进行初始化;

g. 然后调用custom_cmd()函数加载BCM模式下用户配置的命令加载进去;

h. 这样整个SDK就初始化完毕,BCM模式就会提示BCM>等来等待用户输入命令;然后进入一个死循环一直调用sh_process()函数解析用户配置的命令,然后调用对应的SDK接口下发到驱动;

i. 如果用户输入退出命令,会调用sh_exit函数来处理,包括可选的是否回收已经分配的资源等任务;

j. 如果用户输入重启的命令则调用sal_reboot()函数linux版本是通过exit(0)实现。

另外,SDK为上层的初始化提供了调用接口system_init()函数对BCM交换芯片进行初始化,这部分是咱们应该重点关注的部分,当然该接口在BCM模式下用init命令也是可以被调用到的。下面详细讲解下:

a. 首先调用soc_reset_init()函数,ESW芯片里这个函数调用soc_do_init()函数来完事情;soc_do_init()函数会根据是否是重启动设备进行的配置不一样;

(1) 如果是热启动的设备则先调用soc_dma_abort()关闭所有DMA并调用soc_linkscan_config()函数设置CMIC(CPU Management InterfaceController)查询端口link状态,如果设置项为空则表示关闭端口link状态扫描;然后如果是初始化soc有失败标记的话调用soc_dma_abort()函数、soc_counter_stop()函数、soc_mem_scan_stop函数、soc_i2c_detach()函数和soc_l2x_stop()函数(有些其他芯片还调用soc_cmic_uc_msg_stop函数等)分别禁止所有的中断、禁止计数行为、禁止内存扫描动作、释放I2C
驱动内存、结束L2X(应该是用于mac地址学习和老化对CPU进行中断通知)相关线程和停止等;然后调用soc_info_config()函数来初始化芯片端口的各种信息,包括芯片型号、各种类型端口的位图、芯片称号、mod数目、端口数目、hg口的位置、堆叠口位置、CPU口队列数目、用于时间同步端口数目、端口最大支持速率、meter pools、入端口QOS支持的队列数目等信息,另外对trident芯片支持QOS三级调度,所以还会调用soc_trident_num_cosq_init()对各个端口支持的队列数做特殊初始化,最后调用soc_esw_dport_init()函数对User
to physical port map的映射及对user port的逆映射;总之soc_reset_init()函数偏重于对芯片信息、端口属性和QOS队列属性等初始化;然后调用soc_feature_init()函数和soc_dcb_unit_init()函数完成芯片特性支持添加和CPU收发包缓存DCB的初始化工作;然后调用soc_dma_attach()函数和soc_dma_init()函数对中断进行重新初始化,然后对通过PCI设置CMIC_CONFIG使能高级的DMA模式,包括Scatter/gather,
reload, annaligned transfers(这里具体含义不太明白),然后开启一些中断;然后是对MAC_CTRL寄存器读写配置一些MAC层的收发使能;然后是设置MAC表项、MPLS表项、vlan和egress vlan、 L3表项的一些hash冲突的级别,接着使能MAC地址学习和老化通知、 重新获取L3转发表项的长度和表项大小信息即可完成整个热启动的过程;

(2) 在不是热启动的情况下,会首先调用调用soc_info_config()函数、soc_feature_init()函数和soc_dcb_unit_init()函数来完成信么MMU、芯片特性支持和DCB初始化工作;然后调用soc_endian_config() 函数和soc_pci_burst_enable()函数来完成硬件大小端和支持PCI读写突发情形的使能;然后是调用soc_reset()函数来完成对芯片的一些配置,包括端口的phy配置和mac配置(比如寄存器有XLPORT_XMAC_CONTROL),及还会调用相应芯片的soc_reset_bcm56840_a0()函数完成对CPU口和出入方向属性的一些配置,如CMIC_XGXS1_PLL_CONTROL_*、CMIC_MISC_CONTROL、CMIC_SOFT_RESET_REG、ING_CONFIG_2、EGR_CONFIG_2、ING_Q_BEGIN和EGR_Q_BEGIN等寄存器;然后和热启动一样,通过PCI设置CMIC_CONFIG使能高级的DMA模式,对MAC_CTRL寄存器读写配置一些MAC层的收发使能就退出了soc_do_init()函数;

b. 然后调用soc_misc_init()函数对芯片的初始化信息进行核实判断,最终根据函数指针调用芯片相应的函数,trident调用的则是_soc_trident_misc_init()函数;_soc_trident_misc_init()函数首先_soc_trident_ser_init()函数对IFP、EFP、VFP和UDF等tcam表项的表项大小、起始地址等信息进行软件获取并记录,然后调用_soc_trident_clear_all_memory函数对CPU_COS_MAP_ONLY、FP_GLOBAL_MASK_TCAM、FP_GM_FIELDS、FP_TCAM、FP_UDF_TCAM、L2_USER_ENTRY_ONLY、L3_DEFIP_128_ONLY、L3_DEFIP_ONLY、L3_TUNNEL、MY_STATION_TCAM_ENTRY_ONLY、VFP_TCAM、VLAN_SUBNET_ONLY、EFP_TCAM、FP_GLOBAL_MASK_TCAM_Xm、FP_GLOBAL_MASK_TCAM_Ym、L3_ECMP_XM、L3_ECMP_YM、EGR_IPMC_CFG2、EGR_VLAN_CONTROL_1、_XLPORT_MIB_RESET等表项进行清空;然后_soc_trident_misc_init()函数继续对CPU_PBM、CPU_PBM_2m、ISBS_PORT_TO_PIPE_MAPPINGm、EGR_ING_PORTm、XLPORT_CONFIGr、XLPORT_MODE_REG、IARB_MAIN_TDMm、EGR_PERQ_XMT_COUNTERS_BASE_ADDR、MISCCONFIG、ING_BYPASS_CTRL、EGR_BYPASS_CTRL、EGR_ENABLE、EPC_LINK_BMAP、ING_CONFIG_64、EGR_CONFIG_1、EGR_VLAN_CONTROL_1、ING_EN_EFILTER_BITMAP、SW2_FP_DST_ACTION_CONTROL、RTAG7_FLOW_BASED_HASH、RTAG7_HASH_ECMP、CMIC_I2C_STAT、CMIC_RATE_ADJUST_I2C、CMIC_RATE_ADJUST_INT_MDIO等寄存器或表项进行初始化赋值操作,并调用_trident_lep_init对端口进行点灯操作,还调用_soc_trident_fcoe_config_init对芯片的FCOE功能进行初始化;

c. 然后调用soc_mmu_init()函数对MMU进行初始化,和soc_misc_init()函数一样,也是根据不同的芯片挂载不同的函数指针,这里会调用_soc_trident_mmu_init()函数对trident芯片的MMU进行初始化;包括GH、PG、SSP、SP、Port Min、PORT_MAX_SHARED_CELL、Queue Min等的划分,MMU port到phy port的映,及MCQ_CONFIG、OP_THR_CONFIG、OP_VOQ_PORT_CONFIG、OVQ_DROP_THRESHOLD0、OVQ_DROP_THRESHOLD_RESET_LIMIT、OVQ_FLOWCONTROL_THRESHOLD、OVQ_MCQ_CREDITS、MCQ_FIFO_BASE_REG、PORT_PAUSE_ENABLE0_64、INPUT_PORT_RX_ENABLE0_64、S3_CONFIG、S2_CONFIG、S2_S3_ROUTING等voq和Qos相关功能的MMU相关寄存器初始化;

d. 然后调用soc_l2x_start函数开启对MAC地址学习和老化的信息通知功能,主要是创建一个线程;

e. 然后调用bcm_init()函数对芯片进一步初始化,实际对trident芯片调用的是bcm_esw_init()函数,该函数再调用_bcm_esw_init()函数,该函数主要的是分别调用bcm_esw_linkscan_enable_set()函数、_bcm_moles_init()函数和bcm_esw_rcpu_init()函数,来实现关闭端口状态扫描、初始化芯片各个模块、初始化RCPU机制的主控模块:然后_bcm_esw_init()函数调用_bcm_esw_switch_init()函数来实现对CPU队列的初始化和对芯片的一些特殊控制信息,主要是通过调用bcm_esw_switch_rcpu_encap_priority_map_set()函数和bcm_esw_switch_control_set()函数来设置的。其中的_bcm_moles_init()函数调用芯片转发流程的各个模块的初始化函数,具体如下图:

此处内容较多但是非常重要,希望感兴趣的同学能查看对应代码实际学习下相关内容,只提一点,bcm_esw_l2_init函数会调用_bcm_l2_bp_init函数对l2_user_etry表项设置BPDU报文上CPU的规则;

f. 然后对unit的每个端口调用bcm_port_stp_set()函数、bcm_port_autoneg_set()函数和bcm_stat_clear()函数分别设置端口的STP的状态为转发、是否自动协商和清楚端口统计;

g. 然后调用bcm_linkscan_enable_set函数来定期查询端口的link状态;

h. 部分芯片还会调用bcm_linkscan_register注册trunk口的link状态查询回调函数;

❼ 汽车发动机开环和闭环的区别

动态系统建模被各领域广泛应用,例如电动汽车,能源系统,航空航天。我们本文提到动态系统主要是被控对象,对被控对象进行建模是因为我们希望了解这个系统(被控对象)的物理特性以及接受一些外部输入(力,扭矩,电流等等)时会有什么样的动态响应,基于此从而可以更好的给出控制输入得到我们期望的系统的输出,以及理解系统的退化或最大化提升系统效率。

这些动态系统的行为是由多物理场复杂的交互作用决定的,因此系统行为和系统响应建模通常需要复杂的第一原理支撑,仿真时也需要大量的计算(例如有限元模型)。

这也是本文的出发点,提供数据驱动(主要介绍深度学习和系统辨识)的模型降阶(Reced Order Modeling)提速的方法,通过数据得到具有一定保真度的数据模型,在捕捉到系统动态特性的同时也提升仿真速度。

本文中将涉及多个 demo,数据以及脚本文件,若您感兴趣进一步获取这些链接,可以在文末填写反馈问卷,获取这些链接。

动态系统

动态系统包含状态空间 S, 时间集 T 和一个映射(规则)来描述状态随时间的演变规则 R:S×T→S。例如给定一个时刻 t 的状态 st ,通过这个规则可以计算后面一个或几个时刻状态 st+1=R(st),st+2=R(R(st)) 等等。动态系统通常可以用随时间变化的方程或方程组来描述。尤其对于连续时间系统,可以通过微分方程来表示。

我们先看一个简单的常微分系统(ODE), [链接1]

其中 y(t) 是系统状态。例如:一个简单二自由度线性系统,

其中 A 是一个 2x2 的矩阵。初始条件 x0 = [2; 0], 可以通过求解 ODE 方程得到的相应的二维输出 x(t),包含两个状态,时序和动态图如下:

图表 1 系统输出x(t):

x0 = [2; 0];

A = [-0.1 -1; 1 -0.1];

trueModel = @(t,y) A*y; % 定义系统函数,此处就是一个状态空间方程

numTimeSteps = 2000;

T = 15;

odeOptions = odeset(RelTol=1.e-7);

t = linspace(0, T, numTimeSteps);

[~, xTrain] = ode45(trueModel, t, x0, odeOptions);

后面(在介绍 Neural ODE 部分)我们会尝试利用这个系统的数据 xTrain 进行深度学习模型的训练来得到这个系统的数据代理模型(Surrogate Model),这种思路也可以同样用于复杂系统。

既然数据驱动,有很多机器学习和深度学习算法可以用,那动态系统建模有什么特殊性呢,不是都适用吗?

目前工程中已经用到很多稳态(静态)模型。例如在发动机排放标定,通过 DoE 试验时我们会将发动机维持在不同的稳态工况(转速恒定,扭矩恒定等等),通过试验数据建模得到用于标定的稳态数据模型[链接2]。

稳态工况下,对于方程(1)这样一个简单系统,其中 y(t)' 可以看作 0,到达平衡点,于是 y(t) 和 u(t) 关系恒定,不再在时间维度上与历史状态 y(t-1),y(t-2) 等等有关,因此稳态模型针对稳态工况是非常准的。

而在瞬态工况下通常 y(t)' 非零,因此方程(1)在求解系统输出 y(t) 时不仅由当前时刻的输入 u(t) 决定,还取决于 y(t-1),y(t-2),u(t-1), u(t-2) 等等,这就是动态系统的特殊性,当前输出不仅依赖于当前的输入,还依赖于系统过去的行为(历史输入和历史输出)。我们在下一篇关于系统辨识的文章中会基于示例详细说明这一点。

不考虑动态系统,单纯从系统建模来说,通常有如下的两个方向:基于第一原理的和基于数据驱动的。

第一原理建模是领域工程师都比较熟悉的,例如可以使用 M 脚本语言,Simulink 或 Simscape 建模语言从物理原理进行系统模型的创建。

那什么情况下搭建系统会考虑使用或部分使用数据代理模型(Surrogate Model)?


  • 物理系统原理比较复杂或者不够清晰,无法构建第一原理模型

  • 数据获取相对简单

  • 第一原理物理模型过于复杂,求解耗时,在控制开发时有时效要求,需要加速仿真计算

  • 可以看到右半部分主要是基于数据驱动的建模手段,其中针对动态系统的建模主要是系统辨识和神经网络/深度学习。也是本系列两个方向。

    本文介绍神经网络的几种用于动态系统建模的模型,下一篇文章会介绍系统辨识的几种模型。

    前馈神经网络(Feedforward Neural Network)

    前神经网络大家都不陌生,各神经元分层排列。如图2

    图2 简单前馈神经网络示意图

    每层神经元只接受上层输出,结果只传给下一层,没有反馈。稍微复杂点的如图3。

    图3 squeeze net MATLAB 示例

    前馈神经网络是相对于循环神经网络(Recurrent Neural Network)而言,后者具有反馈,后面我们也会介绍。

    那么问题来了,前馈神经网络因为没有反馈,如何表达动态系统(Dynamic System)的时间状态依赖呢?

    通常主要手段使用不同尺度的滑动窗口来构建衍生特征从而表征系统在时间上的动态。

    电池 SoC 预测示例

    我们以电池管理系统为例,通过使用深度学习来估计电池的荷电状态 SoC(State of Charge)。

    本示例主要介绍 SoC 数据驱动的建模方法,在即使不清楚电池电化学模型以及物理非线性特性的情况下,依然可以进行 SoC 估计。我们可以通过实验室中收集到的实测数据进行一个前馈神经网络代理模型训练实现 SoC 估计[1]。

    脚本和数据[链接3]

    图表4 数据集预览和模型的5个输入1个输出

    数据准备

    我们利用实测数据通过预处理得到训练数据集 cdsTrain,我们看其中一条数据记录:

    preview(cdsTrain)

    ans = 1×2 cell array

    {5×669956 double} {1×669956 double}

    数据包含五个特征,分别是电压 V、电流 I、温度 T、滑动平均电压 V_avg、滑动平均电流 I _avg,其中后面两个衍生特征用于表征动态信息。

    搭建模型

    接下来我们构建神经网络模型,结构比较简单,三层全连接网络,一个输出的 Feedforward Neural Network模型。

    layers =[sequenceInputLayer(numFeatures,"Normalization","zerocenter")

    fullyConnectedLayer(numHiddenUnits)

    tanhLayer % HyperbolicTangent

    fullyConnectedLayer(numHiddenUnits)

    leakyReluLayer(0.3) % 激活函数

    fullyConnectedLayer(numResponses)

    clippedReluLayer(1) % 激活函数

    regressionLayer];

    设置训练选项并训练

    options =trainingOptions('adam', ... % Adam optimizer

    'MaxEpochs',Epochs,...

    'ExecutionEnvironment','cpu',...%可以选择GPU

    'InitialLearnRate',InitialLearnRate, ...

    'LearnRateSchele','piecewise', ...

    'LearnRateDropPeriod',LearnRateDropPeriod,...

    'LearnRateDropFactor',LearnRateDropFactor,...

    'ValidationData', {X,Y}, ...

    'ValidationFrequency',validationFrequency,...

    'MiniBatchSize',miniBatchSize, ...

    'CheckpointPath', NET_Path);

    图表 5 训练过程 Loss 变化

    导入测试数据验证模型在测试集上的准确度

    图表 6 深度学习模型的预测值与实测值比较

    仿真测试以及代码生成

    Simulink 中的深度学习推断模块[链接8]支持将我们训练好的模型作为 block 参数, 一起作为被控对象集成到整个电池管理系统中。

    图表 7 电池管理系统和电池的系统模型

    图中所示的 BMS 的 Simulink 模型可以监控电池状态,确保运行安全,还有一个电池模型用于仿真电池的动态和负荷。上面训练的深度学习 SoC 预测器和其他电池平衡逻辑 Block 一样嵌入在 BMS 中可以闭环仿真,以及后面做代码生成与硬件在环。

    图表 8 Simulink 中原生的用于深度学习推断的 Block 和 BMS 中的闭环测试 SoC 预测效果

    图表 9 deep learning 模块的 C 代码生成

    上面这个示例我们利用衍生特征(通过时间滑窗构建时域依赖的特征,也可以通过不同长度的滑窗构建多尺度的时域特征),将前馈神经网络用于动态系统的建模。

    Temporal convolutional network (TCN)

    TCN 的主要构成是一个扩展因果卷积层。任何一个时刻的计算输出都是基于多个历史时刻的输入。

    它用于构建动态系统的逻辑和前面介绍的衍生特征是类似的,都是考虑了历史的多个时间步的输入,因此也可以用于建模动态系统。

    TCN 从之前的时间步构建依赖,通常需要将多个卷积层叠加在一起。为了获得更长期的依赖关系,卷积层的膨胀因子呈指数级增加,如下图所示。

    假设第 k 个卷积层的膨胀因子为2⁽ᵏ⁻¹⁾ ,步长为 1,则该网络的考虑到的依赖的时间窗的大小可计算为 R=(f-1)(2ᵏ-1)+1,其中 f 为过滤器大小,K 为卷积层数。图中对应的 f=2,K=4, 于是 R=16, 也就是当前时刻输出可以考虑到前面 16 个时刻步长输入。

    与循环网络(RNN)相比,TCN 的缺点之一是它在推理期间占用更大的内存。计算下一个时间步需要整个原始序列。下图是一个经典的 TCN 模型结构(结合残差网络):[链接4]

    for i = 1:numBlocks

    dilationFactor = 2^(i-1);

    layers = [

    convolution1dLayer(filterSize,numFilters,DilationFactor=dilationFactor,Padding="causal",Name="conv1_"+i)

    layerNormalizationLayer

    spatialDropoutLayer(dropoutFactor)

    convolution1dLayer(filterSize,numFilters,DilationFactor=dilationFactor,Padding="causal")

    layerNormalizationLayer

    reluLayer

    spatialDropoutLayer(dropoutFactor)

    additionLayer(2,Name="add_"+i)];

    % Add and connect layers.

    lgraph =addLayers(lgraph,layers);

    lgraph =connectLayers(lgraph,outputName,"conv1_"+i);

    一般的 TCN 架构(如[1]中所述)由多个残差块组成,每个残差块包含两组具有相同扩张因子的扩张因果卷积层,然后是归一化层、ReLU 激活层和空间 dropout 层。

    网络将每个块的输入加到该块的输出上(当输入和输出之间的通道数量不匹配时,对输入进行 1 × 1 的卷积),并应用最终的激活函数。

    循环神经网络: LSTM/Gru

    循环网络的结构与前馈神经网络不同,它带有一个指向自身的环,用来表示它可以传递当前时刻处理的信息给下一时刻使用,我们选取 LSTM 来介绍,结构如下,

    LSTM 之所以可以用于动态系统建模,是因为 LSTM 和动态系统有类似的特性:对于时刻 t, LSTM 使用当前网络的状态 (ht-1,ct-1) 和当前的输入 xt来计算网络输出 ht,同时更新当前网络的状态 (ht,ct),ht 也叫输出状态,就是当前时刻 t 的 LSTM 网络的输出,ct 称为 cell state,包含学习来的历史时刻的状态信息。每个时间步 LSTM 都会对 ct进行更新:添加信息或移除信息,主要通过四个门函数(f,g,i,o)来实现,将前面的计算过程示意性的描述一下:

    其中,上面方程中的 Wf,g,i,o, Rf,g,i,o, bf,g,i,o是这些门函数各自的可学习参数,主要包括针对输入 xt 的权重,针对上一时刻输出状态(同时也是当前时刻的输入)ht-1 的权重,以及偏置,这些可学习参数本身是无状态的,被所有时刻共享。训练的过程就是优化这些学习参数的过程。

    总结一下:当前时刻的输出 ht不仅依赖于当前的输入xt,还依赖于当前的状态 (ht-1,ct-1)。它可以根据训练选择性的记住每一时刻的“重要”信息,并且利用这个信息作为状态,结合当前输入 xt 进行输出状态 ht预测。

    电机温度预测示例

    接下来我们使用数据结合 LSTM 模型来搭建永磁同步电机(PMSM)的一个代理模型(Surrogate Modeling),用于电机不同位置的温度预测。

    类似 Demo [链接5]

    理解数据集

    数据集来自多片时长不同的数据。从数据中可以看到 PMSM 不同位置温度与电气系统和热系统对应的工况参数的相互影响。

    同时环境温度的变化也会对电机不同位置温度以及相应需求扭矩所需的电流电压有影响。

    我们使用环境温度、冷却液温度、电压、电流作为输入,输出为不同位置 PMSM 的温度。

    数据预处理与特征工程

    同样作为一个动态系统,我们通过对初始数据再进行不同尺度滑窗实现衍生特征生成,所有特征结合在一起作为 LSTM 的输入(尽管 LSTM 本身也具有考虑时间依赖关系的特性)。

    % create derived features using raw voltages and currents derivedinputs =computedrivedfeatures(tt_data); % check the noise in the data tt_data=[tt_data derivedinputs]; Vnames=tt_data.Properties.VariableNames; s1=620;s2=2915;s3=4487;s4=8825; % preprocess exponentially weighted moving average [t_s1,t_s2,t_s3,t_s4]=preprocmovavg(tt_data,s1,s2,s3,s4,Vnames); % preprocess exponentially weighted moving variance [t_v1,t_v2,t_v3,t_v4]=preprocmovvar(tt_data,s1,s2,s3,s4,Vnames); % attach features to the original table predictors=[tt_data,t_s1,t_s2,t_s3,t_s4,t_v1,t_v2,t_v3,t_v4,tt_profileid]; responses=[tt(:,9:12) tt_profileid]; VResponsenames=responses.Properties.VariableNames;

    准备训练数据和验证数据

    holdOuts =[657258]; % define profiles that are withheld from training. [xtrain,ytrain]= prepareDataTrain(predictors,responses,holdOuts);

    我们将使用第 58 条记录作为验证集,其中包括 4.64 小时的数据。

    validationdata =58; [xvalidation, yvalidation]= prepareDataValidation(predictors,responses,validationdata); numResponses = size(ytrain{1},1); featureDimension = size(xtrain{1},1); numHiddenUnits=125;

    上面的 DAG 网络可以对许多复杂的系统进行建模。通过上面的结构(左右两支)帮助我们对依赖于时间历史的物理行为动态行为以及含状态的行为进行建模。

    查看预测结果

    如图所示,红色和蓝色分别代表了实测数据和模型预测结果,右侧图像显示的是他们的残差,可以看到大部分误差在 1% 以内,预测效果比较理想。模型在瞬态变化较快和较慢的工况下都能和实测数据保持一致,说明模型也保持了一定的保真度。

    将模型导出 Simulink

    我们将训练好的模型保存为 .mat 文件,并将其导入 Simulink Deep Neural Network Predict 模块[链接9],这样我们就有了一个只有 50Kbyte 大小可以预测温度的代理模型(Surrogate Model)用于仿真。

    Neural Ordinary Differential Equations:神经网络 ODE

    这是 NIPS 2018 年最佳论文[2]提出的一种新的网络层。当然这个要理论上介绍还是比较复杂,我们可以通过应用场景直观的解释一些 Neural ODE 如何实现动态系统建模。

    试想我们有一个动态系统,因为系统动力学过于复杂,我们没有真正的物理模型,但我们可以不断地通过测量得到系统的初始状态 y(t0),动态输 入 u(t0), u(t1),…, 与动态输出 y(t1),y(t2),…,y(tn)。接下来我们想是否可以实现这样一个微分方程:

    使得这个微分方程正好代表了我们的系统,也就是说在系统输入 y(t0) 的初始条件下通过求解(例如使用 ode45)这个微分方程得出的解 yp(t) 和我们实测结果是吻合的。但如何基于已有的数据 y(t0),序列 u(t) 和序列 y(t) 得到 f 呢?如果我们将 f 用一个神经网络 F(θ) 替代,即

    我们现在有数据 u(t), y(t)。我们不断地利用数据训练参数θ,使得上述方程的解 yp(t1), yp(t2),...,yp(tn) 与实测 y(t)是吻合的,那就可以得到这个动态系统的微分方程模型了,从而可以用于后续系统仿真与预测。如何理解 yp(t) 与实测 y(t) 的接近度,也就是损失函数? 我们简单介绍一下训练时 Loss 函数计算。对于方程,我们在知道系统初始状态 y(t0),可以通过很多数值积分求解器(例如常用的 ode45)得到任何时刻的推断输出 yp(t) (当然前提是系统的输入 u(t)也是已知).

    θ 是神经网络 F 的静态参数。对于所有时刻都是不变的。我们就可以方便得到损失函数的值

    其中 L 可以是任何自定义的损失函数。于是我们可以进行参数 θ 的训练。当然关于梯度计算与反向传播会有相对复杂的数学推导,论文提出了伴随方法(Adjoint Method)来实现这一过程,此处不做详细论述。

    对应于上述过程,MATLAB中提供了dlode45 [链接10],用于建模方程右侧非线性函数F的同时,计算 ODE 的时序解。

    即 dlode45 接收一个含参神经网络 F(θ)、需要计算输出结果的时刻序列 [t0, t1,…,tN]、系统的 t0 时刻的初始状态 yt0、神经网络参数的一组值,就可以计算出时刻 [t1,…,tN] 所对应的输出状态。

    使用 Neural ODE 为系统建模示例

    我们通过一个示例介绍如何使用Neural ODE为动态系统建模。[链接6]

    我们就借用文章刚开始的简单二自由度线性系统,x' (t)=Ax(t), 其中A是一个 2x2 的矩阵。我们用这个已知的系统产生一些数据,利用这些数据来训练一个 Neural ODE 的方程,使得这个基于数据训练好的系统(Neural ODE 方程)能够接近已知的这个动态系统。

    生成物理系统的数据 xTrain 作为真值

    x0 = [2; 0];

    A = [-0.1 -1; 1-0.1];

    trueModel = @(t,y)A*y;

    [~, xTrain] =ode45(trueModel, t, x0, odeOptions);

    xTrain 两个自由度的可视化

    定义和初始化神经网络 F(t,x(t),θ) 的参数 θ

    neuralOdeParameters.fc1= struct;

    sz = [hiddenSizestateSize];

    neuralOdeParameters.fc1.Weights= initializeGlorot(sz, hiddenSize, stateSize);

    neuralOdeParameters.fc1.Bias = initializeZeros([hiddenSize 1]);

    neuralOdeParameters.fc1

    ans = 包含以下字段的 struct:

    Weights: [20×2 dlarray]

    Bias: [20×1 dlarray]

    同样

    neuralOdeParameters.fc2

    ans = 包含以下字段的 struct:

    Weights: [2×20 dlarray]

    Bias: [2×1 dlarray]

    定义神经网络模型 F(t,x(t),θ) 函数

    function y = odeModel(~,y,theta)

    y =tanh(theta.fc1.Weights*y + theta.fc1.Bias);

    y =theta.fc2.Weights*y + theta.fc2.Bias;

    end

    结合定义好的 F(t,x(t),θ) 作为 dlode45 的输入来构建代理模型函数

    function X =model(tspan,X0,neuralOdeParameters)

    X = dlode45(@odeModel,tspan,X0,neuralOdeParameters,DataFormat="CB");

    end

    定义模型梯度函数

    主要用于训练过程计算损失以及对应待训练参数的梯度

    function [gradients,loss] =modelGradients(tspan,dlX0,neuralOdeParameters,targets)

    % Compute predictions.

    dlX = model(tspan,dlX0,neuralOdeParameters);

    % Compute L1 loss.

    loss =l1loss(dlX,targets,NormalizationFactor="all-elements",DataFormat="CBT");

    % Compute gradients.

    gradients =dlgradient(loss,neuralOdeParameters);

    end

    训练模型

    不断地迭代训练,创建 miniBatch,并进行损失函数计算和自动微分,通过调用 adam 求解器进行参数学习

    for iter=1:numIter

    % Create batch

    [dlx0, targets] = createMiniBatch(numTrainingTimesteps,neuralOdeTimesteps, miniBatchSize, xTrain);

    % Evaluatenetwork and compute gradients

    [grads,loss] = dlfeval(@modelGradients,timesteps,dlx0,neuralOdeParameters,targets);

    % Update network

    [neuralOdeParameters,averageGrad,averageSqGrad] =adamupdate(neuralOdeParameters,grads,averageGrad,averageSqGrad,iter,...

    learnRate,gradDecay,sqGradDecay);

    % Plot loss

    currentLoss =double(extractdata(loss));

    测试模型

    选取新的初始条件作为训练好的模型的输入,来进行和物理系统输出的对比

    x0Pred1 =sqrt([2;2]);

    x0Pred2 =[-1;-1.5];

    x0Pred3 = [0;2];

    x0Pred4 = [-2;0];

    可以看到模型对于新的初始条件依然表现优异。因此神经网络 ODE 在构建动态系统上很有潜力,目前在发动机建模上也有一些示例应用。

    NARX(nonlinear autoregressive network with exogenous inputs)反馈神经网络

    在深度学习网络爆发之前,在浅层神经网络的场景中,NARX 反馈神经网络是经常用于动态系统建模的,它具有反馈连接,即输出 y(t) 依赖于系统之前时刻的输出 y(t-1),y(t-2) 等等和输入。

    其中网络 F 主要是通过一个前馈神经网络实现。

    如下图,其中F即为第一层隐含层前馈网络,其中输入和输出可以是多维的。

    跟其他反馈神经网络类似(前面介绍的 LSTM),它的训练过程与推断过程有些区别。网络本身的输出需要被反馈到前馈神经网络的输入。在训练时,因为我们能够拿到整段输出真实的数据,因此,我们会用当前时刻真实的输出值作为训练时模型输入而不是反馈预测的输出,换句话说,在训练时我们会把网络作为开环去训练。

    这有两个好处。一是前馈网络的输入更准确。第二,生成的网络具有纯前馈架构,静态反向传播变得可用。当我们进行未来多步推断时,因为这种情况我们只能用推断的数据进行下一时刻预测,所以这次我们才把网络闭环,用于推断。

    磁悬浮系统的 NARX 建模示例

    接下来我们使用 narx 神经网络来对动态系统进行建模的示例[链接7]。示例系统是一个磁悬浮系统。目标是控制悬浮在电磁铁上方的磁铁的位置,在电磁铁的位置上,磁铁受到限制,只能在垂直方向上移动,如下图所示,

    系统的运动方程为:

    其中 y(t) 是磁铁在电磁铁上方的距离,i(t) 是经过电磁铁的电流,M 是磁铁的质量,g 是重力常数。其中 β 为粘性摩擦系数,由磁体运动材料决定;α 为场强常数,由电磁铁上导线匝数和磁体强度决定。我们搜集了系统输入 u(t)-施加在电磁铁上的电压和系统输出 y(t)-永磁体的位置,对应两个时间序列。

    搭建网络和准备数据

    d1 = [1:2];

    d2 = [1:2];

    narx_net =narxnet(d1,d2,10); % 使用narxnet功能创建NARX开环串联网络,10个隐藏层神经元

    [p,Pi,Ai,t] =preparets(narx_net,u,{},y); % 用preparets准备数据

    其中 y(t) 是一个反馈信号,既是输入,也是输出,训练时我们既可以拿到当前时刻数据,也可以拿到后面时刻的数据,所以可以用于开环训练,当推断时我们会将输出接到输入作为闭环进行推断。

    训练网络

    narx_net =train(narx_net,p,t,Pi); % 训练网络得到训练好的网络

    验证开环网络推断效果

    yp =sim(narx_net,p,Pi);

    e =cell2mat(yp)-cell2mat(t);

    可以看到误差很小。因为我们用的开环训练,所以推断结果是用前面时刻的真实输出数据(而非推断输出反馈),所以这里的误差是 one-step-ahead 推断误差。

    测试闭环推断效果

    如果要看网络真实准确度的表现,需要将开环的输出作为反馈接到输入,然后进行多步预测。

    narx_net_closed =closeloop(narx_net);

    现在可以使用闭环执行 900 个时间步的迭代预测。在这个闭环网络中只需要两个初始输入和两个初始输出作为初始条件。

    y1 = y(1700:2600);

    u1 = u(1700:2600);

    [p1,Pi1,Ai1,t1] = preparets(narx_net_closed,u1,{},y1);

    yp1 =narx_net_closed(p1,Pi1,Ai1);

    从闭环预测的结果看,蓝线是磁铁的实际位置,红线是 NARX 神经网络预测的位置。即使网络预测的时间步预测了 900 步,预测依然是非常准确的。闭环多步预测准确的前提就是开环下单步推断误差要小。

    总结

    本文主要介绍了动态系统的特性和用于动态系统建模的神经网络模型从而可以实现模型降阶(Reced Order Modeling),包括前馈神经网络,TCN,循环神经网络,神经网络 ODE, NARX 网络和相应的一些手段,并结合示例与场景进行了说明这些手段的有效性。

    在后续文章我会来介绍系统辨识(System Identification)的一些示例,欢迎继续关注。

    本文中涉及到的多个 demo,数据以及脚本文件,若您感兴趣,可以通过扫描填写下面这个反馈问卷,或点击”阅读原文“进一步获取这些链接。

    获取文中示例链接

    参考文献

    [1] Vidal, C., Kollmeyer, P., Naguib, M., Malysz, P. et al., “Robust xEV Battery State-of-Charge Estimator Design Using a Feedforward Deep Neural Network,” SAE Technical Paper 2020-01-1181, 2020, doi:10.4271/2020-01-1181.

    [2] Ricky T. Q. Chen*, Yulia Rubanova*, Jesse Bettencourt*, David Duvenaud University of Toronto, Vector Institute “Neural Ordinary Differential Equations”

    编辑:谢雅洁 校对 :向映姣

热点内容
100台电脑无盘服务器 发布:2024-05-08 22:12:08 浏览:868
iso手机解压缩 发布:2024-05-08 22:06:12 浏览:315
如何选择好的服务器 发布:2024-05-08 21:53:01 浏览:397
linux无密码登陆 发布:2024-05-08 21:52:55 浏览:508
收件服务器和发件服务器如何设定 发布:2024-05-08 21:47:55 浏览:834
搭建节点ip用什么服务器 发布:2024-05-08 21:46:58 浏览:126
派什么编程 发布:2024-05-08 21:25:43 浏览:340
手机作为存储设备 发布:2024-05-08 21:23:34 浏览:493
苹果x配置如何看 发布:2024-05-08 21:15:34 浏览:32
易语言加密文件夹 发布:2024-05-08 21:15:33 浏览:695