跳转到内容

位算术#

本主题介绍了在由 VisualApplets 设计生成的 FPGA 流水线中 Bit Width 的行为方式。读完本主题后,您将了解 link Bit Width 如何限制算术结果、如何处理溢出,以及如何使用 cast、clip 和 shift 算子来控制值范围。您还将了解有符号值和无符号值的区别、定点数的工作原理,以及如何从更宽的数据字中提取位域。

关键术语

Bit width 是指链路上每个像素或每个值的位数。Bit width 定义了 value range。例如,一个 8 位无符号链路承载的值从 0 到 255。Arithmetic overflow 意味着算术结果不再能容纳在可用的位数中。结果会发生回绕或丢失高位。

有关链路 Property 和参数依赖关系,请参阅 Parameterization 教程主题。有关链路背后的形式化规则,请参阅用户手册中的 Rules of Links。

每个 link 两个模块(即实例化的算子)之间承载着一个 Bit Width Property。此 Property 定义了生成的 FPGA 流水线针对该连接上的每个像素或值所使用的位数。对于彩色链路,Bit Width 涵盖了所有颜色分量。在带有 ImageProtocol = VALT_SIGNAL的链路上,Bit Width 始终为 1 位。

每个链路每个数据字最多支持 64 位。当某个算子计算出的结果更宽时,您必须在链路宽度超出此限制之前,对数据进行截断、转换或移位。

并非每个算子都接受所有 Bit Width。某些算子仅允许特定的范围,例如 1 到 64 位、8 位、12 位或 16 位。Operator Reference 中的 Supported Link Format 表记录了每个算子的允许值。您也可以在设计窗格中右键单击模块并选择 Help,或者按 F1,来打开算子帮助。这与 Operator Reference 中的内容相同,作为 VisualApplets 中的内置帮助提供。

当出现 Bit Width 冲突时,请首先检查上游算子的输出链路。在允许编辑它的算子上调整 Bit Width Link Property,或者插入一个算子(例如 CastBitWidth, ClipHigh, ClipLow, ShiftLeft或 ConvertPixelFormat )来更改路径上的 Bit Width。

链路属性会在整个管道中传播,直到被某个算子更改。请在相机输出链路上设置宽度,或在处理路径上插入一个 bit width 算子。请参阅 Propagation of Link Properties 教程主题。

Bit Widths for Arithmetic Operations#

Arithmetic 库的算子会 Bit Width 自动。该 Supported Link Format 表格中记录了允许的值,位于 Operator Reference 将这些输出标记为 auto。您通常无法直接在链路上编辑这些输出 bit width 链路属性。如果您希望在算术运算后手动更改 bit width,请使用其他算子,例如 CastBitWidth )与 ClipHigh, ClipLow或者两者都用。下列算术运算符也会改变位宽:

Addition and Subtraction#

即: ADD 算子对所有输入链路上的像素值求和。 SUB 算子用第一个输入减去第二个输入上的像素值。

VisualApplets 根据输入 Bit Width 设置输出 Bit Width。结果比最大值宽一位。如果您在 ADD上混合使用无符号输入和有符号输入,则输出可能需要额外的一位。

添加像素值的 Add 算子

输出 Bit Width 不得超过 64 位。在 ADD 或 SUB之后,检查下游连接上广播的链路宽度。

Multiplication#

即: MULT 算子将其两个输入端的像素值相乘。一个链路上的最大允许输入 Bit Width 为 32 位。输出 Bit Width 等于两个输入 Bit Width 之和。一个 8 位的值乘以一个 8 位的值会产生一个 16 位的结果:

使用 MULT 算子更改 Bit Width

信息

MULT 会占用大量的 FPGA 资源。对于按常数进行 Scaling,Basler 建议 SCALE 或 ShiftLeft 代替。

Division#

即: DIV 运算符将输入链路 I1 的值除以输入链路 I2的值。输出链路 O 承载整数商。输出链路 R 承载余数。两个输出端的除以零操作均未定义。

输入链路 I2 上的 Bit Width 必须小于或等于输入链路 I1上的 Bit Width。对于无符号输入,输出链路 O 上的输出 Bit Width 等于输入链路 I1上的 Bit Width。对于有符号输入,输出链路 O 上的输出 Bit Width 等于输入 Bit Width I1 加一。

具有无符号输入链路的 DIV 算子的 Bit Width

DIV 执行整数除法。它本身不会保留小数位。对于定点除法,请在除法运算前使用 ShiftLeft 运算符。

有关小数值的详细信息,请参阅本主题的 Fixed-Point Arithmetic 部分。

信息

DIV 会占用大量的 FPGA 资源。如果要除以 2 的幂,请使用 ShiftRight 代替。

Handling Arithmetic Overflow with Clip and Cast Operators#

Arithmetic overflow 发生在结果超出当前 bit width 可以表示的范围时。在 8 位无符号链路上,范围是 0 到 255。总和 200 + 100 等于 300。如果没有足够的输出位数,存储的值将是错误的。溢出表现为不正确的像素值:

位溢出

Arithmetic overflow 不应与由 Overflow 运算符位于 同步方式 库处理的溢出条件相混淆: Overflow 运算符用于处理不可停止数据源的流控制。有关 Overflow 算子,请参阅 可停止与不可停止的数据流 教程主题。

您可以使用以下运算符修复算术溢出:

ClipHigh and ClipLow#

即: ClipHigh 运算符将值限制在可配置的最大值以内。任何超出最大值的输入值都会被替换为最大值。 ClipLow 运算符的工作原理类似,用于处理可配置的最小值。

使用 ClipHigh 和 ClipLow 以将值保持在目标范围内 在……之前 同时减少 bit width。使用模块参数配置剪切限制。有效范围取决于 Bit Width 输入 link property 以及输入 link 使用的是有符号还是无符号 Arithmetic。

截图显示 ClipHigh 将所有大于 255 的像素值设为 255:

ClipHigh 算子计算所有像素值以使其适合该范围

CastBitWidth#

即: CastBitWidth 算子会更改 link Bit Width。您可以在算子的输出 link 上设置 Bit Width link property。

当输出 Bit Width 大于输入 Bit Width 时,算子会保留该值并在最高位位置补位。对于有符号值, CastBitWidth 执行符号扩展。

当输出 Bit Width 小于输入 Bit Width 时, CastBitWidth 会丢弃最高位。因此,无法在输出 Bit Width 内表示的值将被修改。由于此操作会永久移除位,因此可能会丢失后续处理所需的息。

当减小 link Bit Width 时,Basler 建议按此顺序执行以下步骤:

  1. 插入 ClipHigh 和 ClipLow 将 Bit Width 值限制在目标范围内。
  2. 插入 CastBitWidth 以减小 Bit Width。

另请参阅 Parameterization 教程主题。

Example: Add Pixels and Narrow the Result#

此示例将两个 8 位无符号像素流相加,并返回一个 8 位结果用于后续处理:

  1. 将两条 8 位图像路径连接到 ADD 算子。
  2. 检查输出 link。 ADD 产生一个 9 位结果。
  3. 插入 ClipHigh 之后使用算子 ADD。将最大值设为 255。
  4. 插入 CastBitWidth 之后使用算子 ClipHigh。将输出 Bit Width 设为 8。
  5. 运行 Design Rules Check Level 1 并确认所有链路都有效。

如果没有 ClipHigh, CastBitWidth 将仅丢弃第九位,因此大的总和会产生错误的像素值。

ClipHigh 和 CastBitWidth 的组合可防止产生不正确的结果数据

Signed and Unsigned Values#

Link Property Arithmetic 用于定义生成的 FPGA 流水线是否将数值视为 Signed 或 Unsigned。对于 Signed,硬件采用二进制补码(two's complement)表示法。您在设计时可以在 VisualApplets 中设置此 Property。

符号位是配置的 Bit Width 的一部分。

9 位值,其中 1 位保留用于符号信息

即: CastType operator 会更改输出 link 上的 Arithmetic Link Property。位模式保持不变。生成的 FPGA 逻辑不会改变存储的位模式,因此该 operator 不占用 FPGA 资源。

根据 Arithmetic 设置,相同的位模式可以表示不同的十进制值。数值 1010 在 4 位无符号 link 上等于 10。在 4 位有符号 link 上的相同模式则等于 −6。

使用 CastType 当下游 operator 需要不同的 Arithmetic 类型且数值范围仍然匹配时,可以使用此 operator。

CastType 将算术值从有符号更改为无符号

Checking Whether a Value Fits to a Bit Range#

在 VisualApplets 中,参数值(例如 CONST operator 的模块参数)是以十进制数输入和显示的。但是,连接到 operator 的 link 只能存储特定位范围内的值。因此,请确保参数值符合所连接 link 的 Bit Width。

无符号 Links

n 位无符号 link 只能表示正值和零。有效范围为:

0 到 2^n − 1

例如,8 位无符号 link 可以存储从 0 到 255 的值:

8 位无符号的最大值

在具有 ImageProtocol = VALT_SIGNAL的 link 上,Arithmetic 始终为 Unsigned.

有符号 Links

n 位有符号 link 可以同时表示正值和负值。有效范围为:

−2^(n-1) 到 2^(n-1) − 1

例如,8 位有符号 link 可以存储从 −128 到 127 的值。

8 位有符号数的最大值

最高有效位用作符号位,用于指示该值是正数还是负数。

Fixed-Point Arithmetic#

VisualApplets 用于创建可在 FPGA 上实现的图像处理设计。与在 PC 上运行的软件不同,FPGA 硬件通常不处理浮点数(例如 0.5 或 1.25)。相反,计算通常使用整数执行。

为了在仍使用整数 Arithmetic 的同时表示小数值,VisualApplets 使用了定点数表示法。这允许在硬件中高效地存储和处理诸如 Scaling 因子、增益或亚像素坐标之类的数值。

本节介绍:

  • 为什么需要定点数表示。
  • 如何在整数位模式中存储小数值。
  • Q 格式如何定义小数点的位置。
  • Bit Width 如何影响可用值范围和精度。
  • 算子选择如何影响计算准确性。

链路上传输的每个值都存储为位序列。硬件将这些位解释为整数值。

例如,以下位模式表示整数值 5:

00000101 = 5

然而,图像处理应用通常需要小数值,例如: 0.5, 1.25或 12.75.

由于 FPGA 不存储浮点数,因此这些值使用定点格式表示。在定点表示中,位模式仍存储为整数,但您可以为小数点定义一个固定位置。

存储的整数值仍然是 5,但它被解释为:

5 / 2^2 = 1.25

因为保留了两位用于小数部分。

您可以将其视为 虚拟小数点 固定在预定义的位置。在二进制 Arithmetic 中,这种划分被称为二进制点,位于位权之间 2^0 和 2^-1本教程沿用了人们熟悉的术语 虚拟小数点。FPGA 使用整数执行所有计算,而您则根据所选的定点格式来解释结果。

Q Format and Bit Allocation#

定点数通过将某些位分配给整数部分、某些位分配给小数部分来表示小数值。虚拟小数点的位置使用 Q format 进行描述。

Q 格式写作:

Qm.n

其中:

  • m 是整数位数
  • n 是小数位数

对于有符号值,符号位包含在整数部分中。

例如:

Q4.4

意味着:

  • 4 个整数部分位
  • 4 个小数部分位
  • 总共 8 位

小数位数决定了所表示值的精度。

可表示的最小步长为:

1 / 2^n

其中 n 是小数部分的位数。

示例:

Format 小数位 最小步长
Q6.2 2 0.25
Q4.4 4 0.0625
Q2.6 6 0.015625

小数位数越多,相邻值之间的差值就越小,从而精度越高。

总 Bit Width 是固定的。因此,用于小数部分的位将不再可用于整数部分。

因此:

  • 更多的小数位数可提供更高的精度,但会缩减可用的整数范围。
  • 较少的小数位数可提供更大的整数范围,但精度较低。

在选择 Q 格式时,请权衡所需的数值范围与所需的精度。

在定点数中,每一位都代表 2 的幂。

虚拟小数点左侧的位表示整数:

..., 2^3, 2^2, 2^1, 2^0

右侧的位表示小数:

2^-1, 2^-2, 2^-3, ...

例如,在 Q4.4 格式中:

Bit position:  7   6   5   4   3    2     1      0
Weight:      2^3  2^2  2^1  2^0  2^-1  2^-2  2^-3  2^-4

位置 2^0 位定义了虚拟小数点的位置。此位置不存储在硬件中;它由所选的 Q 格式定义,并且必须在整个设计中得到一致的解释。

Example: Q4.4#

在 Q4.4 格式中,4 位用于整数部分,4 位用于小数部分。

位模式

0 0 0 0 . 1 0 0 0

包含一个 1 位于第一个小数位。此位置表示值 2^-1,等于 0.5.

因此,该位模式表示:

0 * 2^0 + 1 * 2^-1 + 0 * 2^-2 + 0 * 2^-3 + 0 * 2^-4 = 0.5

尽管表示的值为 0.5,但 FPGA 仅存储对应的整数值:

Stored integer value: 8
Represented real value: 0.5

这是因为 Q4.4 使用了 4 个小数位。存储的整数值的解释方式为:

Real value = Stored integer / 2^4
           = 8 / 16
           = 0.5

设 F 即小数部分的位宽。

要将实数值转换为其定点表示形式:

FixedPoint = round(RealValue * 2^F)

示例:

FixedPoint = round(0.5 * 2^4)
           = round(8)
           = 8

生成的位模式:

0000.1000

要将定点值转换回实数值:

RealValue = FixedPoint / 2^F

示例:

RealValue = 8 / 2^4
          = 8 / 16
          = 0.5

Operators and Design Rules#

运算符仅处理整数位模式。在定点 Arithmetic 中,虚拟小数点的位置由 Q 格式决定,并且必须在整个设计过程中进行跟踪。

以下运算符通常用于调整 Scaling 并保持预期的 Q 格式:

  • 即: ShiftLeft 和 ShiftRight 运算符将输入位模式向左或向右移动可配置的位数。左移将值乘以 2^Shift;右移将其除以 2^Shift。这些运算符通常用于 Arithmetic 操作之后,以恢复所需的 Q 格式。
  • SCALE 或 ShiftLeft:请使用这些运算符代替 MULT 当将值乘以 2 的常数幂时。它们执行相同的 Scaling 操作,但通常需要更少的 FPGA 资源。
  • 即: MULT 运算符将两个输入值相乘。输出 Bit Width 等于输入 Bit Width 的总和。在定点 Arithmetic 中,结果中的小数位数也是两个操作数小数位数的总和。

示例#

将 Q4.4 值与另一个 Q4.4 值相乘会产生 Q8.8 结果:

Q4.4 * Q4.4 -> Q8.8

该结果提供更高的精度,但如果设计需要 Q4.4 值,则可能需要后续的 ShiftRight 操作或 Bit Width 缩减。

某些算子假定采用特定的定点格式。例如,三角算子,如 SIN, COS, TAN)及其反函数期望其输入和输出具有预定义的小数位数。

在将链路连接到此类算子之前,请在算子参考的 Arithmetics Library 中验证所需的格式。

设计指南

在每个阶段记录 Q 格式。在乘法或除法之后,使用 ShiftRight 或 Bit Width 调整(如果需要)以恢复预期的格式。

Displaying Fixed-Point Values in Simulation#

您可以使用 VisualApplets 中的仿真功能来验证定点值是否在构建 applet 之前按预期进行了解释、Scaling 和传播。在 Simulation Probe Viewer 中,链路值保持为整数,但您可以通过设置 fractional bits、选择有符号/无符号十进制以及可选地应用 scaling factor 来将其显示为定点数。这仅影响显示,不影响硬件。要在 VisualApplets 中通过仿真检查定点值:

  1. 在处理管线的起点添加一个 Simulation Source。
  2. 将一个 Simulation Probe 添加到算子的输出链路。
  3. 通过 Analysis → Start Simulation 启动仿真。
  4. 打开您在步骤 2 中添加的探针的 Simulation Probe Viewer。
  5. 在 Simulation Probe Viewer 中,选择有符号或无符号十进制显示。
  6. 设置 fractional bits 的数量以匹配您的 Q 格式。
  7. 可选择设置用于单位转换的 Scaling 因子,例如将弧度转换为度。

因此,您可以看到 Simulation Probes 如何将小数位考虑在内:

Simulation Probe:显示考虑了小数位的结果。

有关 VisualApplets 中仿真的更多信息,请参阅用户手册中的 Simulation。

Extracting Bit Fields with SelectBitField#

即: SelectBitField 算子从输入值中提取连续的位范围并将其复制到输出。当您只需要更宽数据字特定部分时,请使用此算子。

按照以下方式配置算子:

  • 设置输出 Bit Width 在输出链路(link)上。这决定了提取多少位。
  • 设置 BitOffset 参数。这指定了要复制到输出的选定字段的最低有效位 (LSB) 的位置。选定的位成为输出值的第 0 位(最低有效位)。

对于灰度图像, BitOffset 必须在以下范围内:

0 ... Input Bit Width - Output Bit Width

如果输入使用 signed 算术,则提取的位始终作为无符号值输出。

SelectBitField: Dependencies of the Input and Output Link Bit Width and the BitOffset Module Parameter

Widening Bit Width for Downstream Software#

许多相机产生像素数据的 Bit Width 例如每像素 10 或 12 位。然而,图像处理软件和图像文件格式通常使用标准数据宽度,例如 8、16 或 32 位。

因此,通常在将相机数据传输到主机的 PC 之前将其转换为 16 位像素。您可以通过以下方式执行此操作:

Using ConvertPixelFormat#

要加宽 Bit Width,您可以插入一个 ConvertPixelFormat 算子,介于图像源或缓冲区与 DmaToPC.

插入后 ConvertPixelFormat 算子,打开输出链路 Property 并设置 Bit Width 更改为 16.

例如,当将 9 位像素数据转换为 16 位时,算子会将每个像素值向左移动 7 位,并在新创建的最低有效位位置插入零。这样可以在使数据适应 16 位格式的同时,保留相对亮度范围。

使用 ConvertPixelFormat 算子拓宽 Bit Width

Using ShiftLeft#

作为替代方案,您还可以插入一个 ShiftLeft 算子并设置 Shift 参数为 7。

左移 7 位会产生与将 9 位值转换为 16 位值相同的 Scaling 效果:

9-bit value << 7

随后,输出链路将传输 16 位像素值。

使用 ShiftLeft 算子拓宽 Bit Width

Using CastBitWidth#

如果您想在不改变数值的情况下增加 Bit Width,请插入一个 CastBitWidth operator. Choose this option if downstream software requires a wider Bit Width, but no scaling of the pixel values is desired.

要使用 CastBitWidth 算子更改 Bit Width,请更改 CastBitWidth 算子输出链路上的 Bit Width:

使用 CastBitWidth 算子拓宽 Bit Width

与不同, ConvertPixelFormat 或 ShiftLeft, CastBitWidth 不会移动像素数据。相反,它会添加额外的最高有效位,同时保留原始值。

使用 DRC 验证您的设计#

更改 Bit Width 或插入算术算子后,运行 Analysis → Design Rules Check Level 1。级别 1 会在 DRC log 中报告 Bit Width 不匹配和参数冲突。受影响的模块和链路会在设计窗格中高亮显示。

运行 设计规则检查 2 级 在构建之前。Level 2 可估算 FPGA 资源使用情况。较宽的中间结果和诸如以下的算子 MULT 和 DIV 之类的算子会增加资源消耗。

阅读 DRC 日志以及高亮显示的模块和连线。有关完整的工作流程,请参阅 从空白设计到运行 Applet 教程主题。

关键术语

处理 Bit Width 时,Basler 建议采取以下做法:

  • 在每个算术算子之后,检查下游链路上已传播的 Bit Width 。
  • 在转换为较窄的宽度之前,请先对值进行剪切。
  • 尽早为宿主软件规划 Bit Width 更改,例如在 DMA 之前采用每像素 16 位。
  • 使用 ShiftLeft 和 ShiftRight 尽可能使用二的幂 Scaling,而不是 MULT 和 DIV 。
  • 当参数值无法固定时,请参考 Operator Reference。