链路规则

在 VisualApplets 中创建的任何图表都是算子实例(模块)的网络。它可以组合多个子网络。

与其他编程语言一样,您在 VisualApplets 中创建的图表也必须遵循一组规则,包括允许、不允许和受限制的结构。 以下部分定义了连接模块的基本规则。

算子类型

首先,让我们来看看您将使用的不同类型的算子。

有关算子类型和同步的实用指导,请参阅 Operator Types and Synchronization 教程主题。

在 VisualApplets 中,您有三种 类型的算子:

通用类型 “O”(圆形):
更复杂的类型 “M”(方形): 在旧版本的
VisualApplets 和文档中的某些示例
中为椭圆形:
特殊类型 “P”(方形): 在旧版本的
VisualApplets 和文档中的某些示例
中为椭圆形:

表 4. 算子类型


您可以通过算子的形状来判断它属于通用 “O” 类型,还是属于更复杂的 “M” 或 “P” 类型。 (有关特定算子类型的信息,请查看 Operator Reference 中该算子的文档。)

O 型算子的功能相对简单。因此,

  • O 型算子不会改变输入和输出之间的像素/数据数量。所有输入链路的输入像素/数据数量等于输出像素/数据数量, 即对于每个输入值,算子都会输出一个对应的值。

  • O 型算子可能会在输入和输出之间引入延迟。但是,该延迟在延迟平衡(latency balancing)过程中会自动得到补偿。

  • O 型算子可以按需进行串联或并联链接。

M 型算子的功能更为复杂:

  • 它们可以改变输入和输出之间的像素/数据数量。

  • 它们可能会延迟输出。

  • 链接 M 型算子时,需要注意链路规则以及所链接算子的功能。

  • M 型算子可能会阻塞输入。

  • 图表中的每个源算子(例如 CameraGrayAreaBase)都是 M 型算子。

  • 图表中的每个最终目标算子(例如 DmaToPC)都是 M 型算子。

P 型算子类似于 M 型算子,但

  • P 型算子不会降低带宽。(有关此问题的更多信息,请参阅 'Infinite Sources / Connecting Cameras'。)

  • P 型算子不会生成多于输入端提供的数据量的数据。

  • P-type 算子绝不会主动阻塞输入。(有关 P-type 算子阻塞行为的详细信息,请参阅 “P-Type 算子”。)

在下文中,如果未提及针对 P-type 算子的例外情况,则为 M-type 算子定义的所有规则同样适用于 P-type 算子。

O 型网络

O-type 网络是 O-type 模块的组合。 在 O-type 网络中,模块可以串联或并联组合。 O-type 网络总是以 M-type 或 P-type 模块开始和结束。 在此定义的基础上,可以定义一条重要规则:

[提示] O-Type 网络规则

在 O-type 网络中,无论其多么复杂,每个 O-type 模块都必须由相同的 M-type 或 P-type 模块提供源。 它可以通过其他 O-type 模块甚至 O-type(子)网络连接到此源。 (请注意,此规则不适用于信号链路。)

下图显示了一个包含模块并联和串联的 O-type 网络。 如您所见,所有 O-type 模块均由同一个 M-type 模块(M_source)提供源。

O-Type 网络

图 53. O-Type 网络


相比之下,下一张图显示了一个违反 O-Type 网络规则的 O-type 网络,因为 ADD 模块由不同的 M-type 模块(M_source_0 和 M_source_1)提供源。

错误的 O-Type 网络

图 54. 错误的 O-Type 网络


VisualApplets(2.2 及更高版本)会在设计图中直接可靠地指出何时违反了同步规则。 相应的链路会以紫色高亮显示。 高亮显示的范围从接收未正确同步数据的算子一直延伸到对应的 M 算子 源。

在 VisualApplets 2.2 及更高版本中显示未正确同步的数据流

图 55. 在 VisualApplets 2.2 及更高版本中显示未正确同步的数据流


DRC 1 和 DRC 2 会显示相应的警告。

例如,针对上述设计,DRC 1 会产生以下警告:

[重要] 例外情况:信号链路

O-type 网络规则不适用于传输信号链路的 O-type 算子(请参阅 “信号链路的不同规则”)。

M 型网络

任何不仅将 M-type 模块用作源和目标, 而且将其用于中间图像处理的模块网络,都称为 M-type 网络。 在 M-type 网络中,M-type 模块可以并联或串联。 M-type 模块也可以进行无限制的分支。 M-type 网络可能会变得相当复杂,因为 M-type 模块的并行连接可能需要同步图像 尺寸和同步时序。 (请记住:M-type 模块可以更改输入和输出之间的像素/数据数量;它们也可能会延迟输出。)

下图显示了一个非常简单的 M-type 网络示例。 此图表中的 M-type 模块仅串联或分支。 由于图表中唯一的 O-type 网络由同一个 M-type 模块(ImageBuffer)提供源, 因此该图表遵循我们迄今为止了解的所有图表规则:

M-type 和 O-type 网络

图 56. M-type 和 O-type 网络


在大多数情况下,M-type 网络要复杂得多。 如果与上面的示例相反,M-type 模块是并联连接的 (即合并的路径由不同的 M-type 源提供源), 则我们必须同步时序和图像尺寸。 这是通过使用多个输入的 M-type 算子来完成的。

具有多个输入的 M 型算子

如果要合并由不同 M-type 源提供源的网络,则必须使用具有多个输入的 M-type 算子。 (不能使用具有多个输入的 O-type 算子,因为这会违反如上所述的 O-type 网络规则。) 但在深入探讨同步之前,让我们先总体了解一下具有多个输入的 M-type 算子。

具有多个输入的 M-type 算子可以有两类输入:

  • 同步输入

  • 异步输入

同步输入与同步输入组

如果模块的某些输入是同步的,则这些同步输入共同构成一个同步输入组。 因此,同步输入组是一组同步输入。 同步输入组的输入必须始终通过由 O 型算子组成的任意网络,由同一个 M 型源提供。 一个 M 型算子可以拥有任意数量的同步输入组。

在下图所示的示例中,展示了带有同步输入组的 M 型算子的使用方式。 RemoveImage 算子的两个输入均由同一个 M 型源(ImageBuffer)提供。 这两个输入共同构成了同步输入组。 RemoveImage 算子不允许在其输入端口使用不同的 M 型源。

带有一个同步输入组的 M 型算子

图 57:带有一个同步输入组的 M 型算子


异步输入

异步输入是非同步的。 它们可以通过由 O 型算子组成的任意网络,由不同的 M 型源提供。 此外,某些具有多个输入的 M 型算子实际上必须由不同的 M 型源提供。 具有多个输入的 M 型算子是否必须由不同的 M 型源提供,取决于算子自身的特性。 您可以在算子参考中找到有关所有算子的详细信息。 一个 M 型算子可以拥有任意数量的异步输入。

以下屏幕截图展示了带有两个异步输入的 M 型算子的典型示例。 SYNC 模块的两个输入由不同的 M 型源提供,即 DRAM0 和 DRAM1。

带有异步输入的 M 型算子

图 58:带有异步输入的 M 型算子


SYNC 模块后面是一个 MergePixel 算子。 如果没有中间的 SYNC 算子,则无法使用该算子来合并两个 M 型源。

[重要] M 型算子输入

M 型模块的输入可以由不同的 M 型源提供。

但是,同步输入组的输入必须通过由 O 型算子组成的任意网络,由同一个 M 型源提供。

每个具有多个输入的 M 型算子的文档中都详细解释了该算子可能需要或必需的输入。 有关所有算子的全面说明,请参阅算子参考。

不同图像尺寸的同步

M 型算子可以对其输入处的不同图像维度进行同步。 一个重要的示例是 SYNC 算子。 有关该算子的详细说明,请参阅算子参考。

时序同步

对于 O 型网络,VisualApplets 会自动执行时序同步。

对于 M 型网络,同步必须由 M 型算子执行。

如果时序同步设计不正确,

  • 将会发生所谓的死锁情况,

  • 带宽不足,或者

  • 数据将丢失。

[警告] 确保正确的时序同步

由于时序同步取决于您在 VisualApplets 中实现的算法的行为,因此您必须确保图表中的时序同步是正确的。

在接下来的示例中,我们将仔细探讨时序同步。

  1. 独立源的同步

    让我们来看一个简单的双相机拼接示例,如 图 59,“独立源的同步” 所示。 在该示例中,两个相机用作数据源。 ImageBuffer 算子将缓冲数据。 最后,M 型算子 InsertLine 将两个相机的行复用到一个输出链路中。 该算子会合并两个并行链路。

    独立源的同步

    图 59. 独立源的同步


    想象一下,如果两个相机不同步会发生什么。 假设一个相机的帧率高于另一个相机。 InsertLine 算子将严格按行复用,即依次使用各个输入。 由于帧率不同,其中一个 DRAM 缓冲区实际上需要缓存数据。其 Fill 级别将不断增加。 一旦发生溢出状况,将无法再缓冲更多数据,从而导致数据丢失。

    [重要] 确保相等的 Data Rate

    因此,如果合并异步流,请确保行率/帧率/像素率相等且可以同步。

  2. 来自同一源的数据同步

    某些 M 型算子在输出结果之前会产生延迟。 一个典型的例子是算子 FIRkernelNxM,它用于我们在后续图形中探讨的图表中。 该算子输出一个像素以及周围的邻域像素以形成一个内核。 为了输出相邻像素,算子必须等待输入端提供这些相邻像素。 它将存储中间结果。 在我们的示例中,FIRkernelNxM 算子只有在向算子输入了四整行之后才能输出第一个结果。 因此,该算子在其当前配置下会产生四个图像行的延迟。

    让我们仔细看看这个示例。

    前提条件

    首批像素从相机通过缓冲区发送到分支。 在此处,数据被复制并转发到 SYNC 和 FIRkernelNxM 模块。 如前所述,FIRkernelNxM 具有四行的延迟,因此无法立即输出首批像素:

    SYNC 处的死锁,图 a

    图 60. SYNC 处的死锁,图 a


    死锁

    SYNC 算子尝试同步两个输入。 由于第二个输入没有数据进来,它会在第一个输入处生成一个 STOP 信号。 此 STOP 信号在流水线中向后传播直至缓冲区。 现在,我们遇到了死锁情况: 内核算子需要更多数据才能输出数据,但由于 SYNC 阻止了所有后续输入,因此没有可用的新数据。

    SYNC 处的死锁,图 b

    图 61. SYNC 处的死锁,图 b


    解决死锁

    为了解决死锁问题,我们必须在上层路径中添加一个缓冲区,以便可以补偿内核算子的延迟,如下所示:

    已解决的死锁

    图 62. 已解决的死锁


    避免死锁

    最好的解决方案是完全避免同步。这通常是可行的。 在下面的解决方案示例中,图表中仅存在 M 型算子的串行流水线,因此在合并处不需要同步。

    已避免死锁

    图 63. 避免死锁


带宽瓶颈

M 型网络中的另一个重要现象是,算子中的带宽会减少,并且这种限制可能会在模块网络中向后传播。 以下示意图展示了将产生带宽限制的情况。

带宽限制

图 64. 带宽限制


在此图表中,ModuloCount 和 RemoveLine 算子的组合将删除每隔一行的数据。 正如我们在“Applet 的带宽”中所了解到的,最大带宽取决于所使用的 Parallelism。 在 RemoveLine 算子之后,所需带宽已减少了一半。 因此,我们可以使用算子 PARALLELdn(“向下并行”)将 Parallelism 减少一半。 然而,这也将使每隔一行的上半路径中的带宽减少一半。

在 RemoveLine 算子处删除一行的同时,没有像素馈送到 PARALLELdn 模块中。 图表输入端提供的完整 Parallelism 可用于两条路径。 相比之下,当某一行未被 RemoveLine 算子移除时,当前行的像素将被转发到 PARALLELdn 的输入端。 此时,PARALLELdn 将把 Parallelism 减少二,即与输入相比,它需要两倍的时钟周期来输出一个值。 因此,PARALLELdn 算子将在每第二个时钟周期阻塞其输入。 由于第一个 Branch 和 PARALLELdn 算子之间没有使用缓冲区,该阻塞信号会沿着流水线向后传播。 因此,上半路径也会在每第二个时钟周期被阻塞。

解决此问题的方法是在 PARALLELdn 算子之前添加一个额外的 FIFO,该 FIFO 能够缓冲至少一行数据,从而补偿峰值和空闲期。 下图展示了此解决方案:

已补偿的带宽限制

图 65. 已补偿的带宽限制


P 型算子

P 型算子与 M 型算子相似,但有一个例外: 它们无法主动阻塞输入。

尽管如此,当处理流水线上游的模块阻塞其输入时,输入阻塞会沿线路向后传播。如果 P 型算子位于线路更下游的位置,则 P 型算子的输入端口也会被阻塞(被动阻塞)。 P 型算子会将阻塞信息向后传播到处理流水线上的下一个模块。

示例: 与将数据馈送到算子中所需的时间相比,M 型算子 PARALLELdn 输出结果需要更多时间。 因此,它会不时阻塞输入。 相比之下,P 型算子 PARALLELup 的输出带宽总是高于输入带宽。 在将无限源与 P 型和 M 型算子连接时,这种行为非常重要。 有关无限源的详细说明将在接下来的“无限源 / 连接相机”中介绍。

无限源 / 连接相机

无限源是无法被 VisualApplets 流控制停止的算子。 相机算子就是一个例子。 在它们的输入链路上,这些算子接收来自相机的数据。在它们的输出链路上,它们将这些数据转发给图表中的后续模块。 由于相机算子内部没有缓冲区,且它们无法指示相机停止传输,因此这些算子被称为无限源。

有关可停止和不可停止数据流的实际指导,请参见 可停止和不可停止的数据流教程主题。

无限源只能连接到接受无限源的 M 型算子。 个别 M 型算子是否可以连接到无限源在該算子的各自文档中进行了说明(请参见算子参考)。 如果将无限源连接到不接受无限源的 M 型算子,DRC 级别 2 将生成错误:

无限源连接错误

图 66. 无限源连接错误


所有 P 型和 O 型算子都可以连接到无限源。 无限源信息将在算子之间传播,直到流水线中的某个算子将无限源数据流转换为可控的数据流。 通常,这些转换算子是缓冲区。 缓冲区算子能够在输出端使用流控制,并在无需阻塞输入的情况下缓冲输入数据流。

因此,如果我们交换前一个示例中的算子,DRC 级别 2 将不会生成错误:

无限源连接正常

图 67. 无限源连接正常


某些转换算子的行为可以更改,以决定它们是否接受无限源。 这些算子包含一个名为 InfiniteSource 的参数,该参数可以设置为 Enabled 或 Disabled。

未连接到无限源的转换算子必须设置为 Disabled。

连接到非无限源的无限源转换模块 (Buffer1)

图 68. 连接到非无限源的无限源转换模块 (Buffer1)


[警告] 警告

如果相应模块的参数 InfiniteSource 设置为 Enabled,则该模块必须连接至无限源。

未连接至无限源的转换算子必须设置为 Disabled。

[提示] 提示

如果不确定,请始终将参数设置为 Disabled,并在 DRC 2 级检查后更改有问题的模块。

有关模块参数化的详细说明,请参见 “Module Properties”。

信号链路的不同规则

信号链接传输在每个时钟周期都有效的单比特信号数据。 带有信号传输输入链接的模块的链接规则与目前所述的链接规则在两个方面有所不同:

  • 所有具有信号链接输入的 O 型和 M 型模块都可以由不同的 M 型源提供源。

  • 带有信号链接输入的模块始终可以连接至无限源。

具有信号链接输入的 O 型模块,由不同的 M 型模块提供源

图 69:具有信号链接输入的 O 型模块,由不同的 M 型模块提供源


有关信号链接的更多信息,请参见 “Image Protocols, Image Dimensions and Data Structure”。

总结

在本章中,您已了解了链接规则。 在实施 VisualApplets 应用程序时,链接规则最为重要。

O 型网络始终以 M 型模块开始和结束。 每个 O 型模块必须通过其他 O 型模块的任意网络由相同的 M 型或 P 型模块提供源。 不同 M 型源的合并只能由 M 型模块执行。

M 型网络可以按串行顺序任意链接,也可以任意分支。 在模块中合并不同的 M 型源需要进行时序同步和图像尺寸同步。 具有多个输入的 M 型模块可以具有同步输入组。 同步输入组必须通过任意 O 型网络由相同的 M 型源提供源。

时序同步将同步存在时间延迟的不同源。 时序同步需要了解用户的实现情况。 不佳的时序同步将导致死锁或缓冲区溢出。

无限源无法由集成的流控制进行控制。 只有允许连接至无限源的 M 型算子才可以连接至无限源。

对于具有信号链接输入的模块,通用同步规则适用,但有两个修改: 信号链接输入(M 型 和 O 型模块的输入)可以由不同的 M 型源提供源。 带有信号链接输入的模块始终可以连接至无限源。

[警告] 警告

VisualApplets 无法检测逻辑同步错误,因为它们取决于用户项目的实现。 请仔细阅读每个 M 型算子的文档,以了解其在时序和延迟方面的行为。