边缘计算

使用 NVIDIA Holoscan 的 HoloHub 开发流式传感器应用程序

平均每车包含 100 多个传感器,用于监测和响应重要信息。从过热的引擎到低胎压和不稳定的转向,传感器可以提供自动数据、洞察和控制。它们使驾驶行为对乘客和路上的其他人都更安全。当然,传感器并不局限于汽车。

您当地机场的雷达系统跟踪飞机和其他大型物体,引导航班安全地进入空中和地面。你口袋里的手机使用设备上的无线电和天线,通过以太网络将你的声音发送给另一个国家的朋友,没有噪音或干扰。外科医生使用实时内腔摄像头来检测异常,识别病变组织,并对军团进行分类。

在每种情况下,传感器从环境中收集信息,而计算机分析和处理生成的数据流。实时处理和分析的结果可用于向操作员提供反馈或自动关闭控制回路。

建筑传感器处理应用面临的挑战

传统的传感器处理系统是硬件定义的,并且通常与前端传感器紧密耦合。对传感器、计算机或预先存在的应用程序的修改可能需要在整个应用程序框架中进行非平凡的升级。

例如,如果您正在为实时计算机视觉任务设计的框架上运行应用程序,那么随着应用程序目标的扩展,轻松添加其他数据源(如语音)通常是一项挑战。

用 AI 推理模型扩充现有传感器处理应用程序可能更具挑战性,因为您可能需要学习新的工具和软件库,以及如何优化实时流性能。

NVIDIA Holoscan 概述

NVIDIA Holoscan 是一个实时、低延迟和传感器无关的软件开发套件,用于原型、构建、部署和扩展流式传感器应用程序。 Holoscan 最初是为 医疗 AI 使用案例 引入的,现在正用于多个行业的更广泛的应用,以实现边缘的高性能计算。使用 Holoscan , C ++或 Python 开发人员构建一个相关节点的连接图,称为运算符,以定义应用程序。

Diagram shows multiple connected operators with one set running in parallel.
图 1 。定义应用程序的运算符连接图

这些运算符是灵活的,易于编程或修改,由独立的常用任务组成。例如,网络运营商可用于促进 UDP 以太网数据包直接接收到 GPU 而无需占用 CPU 。另一个操作员可以执行 AI 推理,例如 NVIDIA TensorRT 优化 YOLO 对象检测器。最后一个操作员可以使用 cuFFT 在 C ++中执行 GPU 加速 FFT 。

实现运算符后,您可以指定数据如何连接到运算符和从运算符中连接出来。然后,可以保存这些运算符以供其他应用程序管道将来使用。

Holoscan 抽象了数据移动,并提供了一组简单的 API ,以在高速传感器数据之上使用现有 NVIDIA SDK 构建应用程序。 Holoscan 使您能够从多个传感器领域构建端到端、多模式、 AI 驱动的软件管道。

有关 Holoscan 的更多信息,特别是当前 Holoscan SDK v0.4 版本中引入的功能,请参见 Rapidly Building Streaming AI Apps with Python and C++ Holoscan

HoloHub 的无线电、雷达等参考应用

HoloHub 是一个新的 GitHub 存储库,托管参考 Holoscan 应用程序和操作员。 HoloHub 旨在成为一个全面、丰富的预制运营商集合。它包括如何使用和扩展它们的示例和端到端应用程序。我们欢迎贡献!

除了作为 Holoscan SDK v0.4 的一部分发布的参考应用程序外,以下是 HoloHub 上发布的前两个参考应用程序,它们都是用 Python 编写的:

  • SDR FM 解调应用: 使用软件定义无线电( SDR )进行调频解调
  • 简单的雷达管道应用: 传统雷达信号处理流水线

虽然这些示例侧重于 Holoscan Python API ,但 C ++示例严格遵循相同的语法和设计原则。 Holoscan 的一个驱动理念是,数据科学家和性能工程师可以在同一个底层框架(基于 C ++的 Holoscan )上共同工作。

以下是一些示例,向您展示如何构建和部署 Holoscan 管道。

软件定义的收音机: FM 解调

我们都熟悉汽车的收音机;你移动一个转盘,调到你最喜欢的电台,然后调高音量!收音机使用硬件元件进行从无线电波到语音的模拟解码。随着 SDR 的出现,就像廉价的 RTL-SDR 一样,您现在有了一种机制来实现以前由硬件定义的软件问题。

基于软件的 FM 解调(也称为收听广播)是信号处理应用的“ Hello World ”示例。许多初学者已经学会了用它编程加速器。由于其相对简单, FM 解调可以作为一种快速检查,您可以使用 SDR 捕获无线电波,然后实时解调和回放结果。

In this Holoscan example ,您使用 RTL-SDR USB 加密狗和 SoapySDR 驱动程序来收集、流式传输和缓冲复杂值的无线电样本。然后,该数据被传递到 FM 解调和重采样运算符,该运算符使用 cuSignal. 。解调后的输出被放置在 Python 队列中,该队列通过 PyAudio 触发播放。

Diagram starts from receiving the IQ stream and goes through buffering in GPU memory, converting to a cuPy array, FM demodulation, polyphase resampling, and finally being written to the PyAudio queue.
图 2 : Holoscan 软件计算管道

Holoscan 应用程序首先由Application类组成,其中定义了现成和自定义运算符,以及它们之间的连接方式。以下代码示例显示了 FMDemod Application类:

class FMDemod(Application): 
 
   def __init__(self): 
  	super().__init__() 
 
   def compose(self): 
  	src = SignalGeneratorOp(self, CountCondition(self, 500), name="src") 
  	demodulate = DemodulateOp(self, name="demodulate") 
  	resample = ResampleOp(self, name="resample") 
  	sink = SDRSinkOp(self, name="sink") 
 
   self.add_flow(src, demodulate) 
   self.add_flow(demodulate, resample) 
   self.add_flow(resample, sink) 

Application类的compose函数用于定义 Holoscan 管道中使用的运算符。在此示例中,有四个自定义运算符:

  • SignalGeneratorOp:将 SDR 中的复值张量数据带到 GPU ,并将其暴露给 Holoscan 。
  • DemodulateOp:使用 cuSignal 对输入数据执行 FM 解调。
  • ResampleOp:将 SDR 采样率降至 48 kHz ,即计算机音频输出的采样率,以便使用 cuSignal 进行播放。
  • SDRSinkOp:连接到 PyAudio 以进行实时音频播放。

源运算符SignalGeneratorOp包括一个附加参数,用于控制 Holoscan 图中源节点的调度和运行时间。CountCondition选项在给定次数内运行源(在本例中为 500 次)。 Holoscan 文档中讨论了其他调度选项,这些选项在切换之前运行给定的源节点,例如BinaryCondition

使用add_flow(<input>, <output>)连接操作员,创建图形。

在本例中,这些运算符以线性方式连接:

  • SignalGeneratorOp输出馈送DemodulateOp
  • DemodulateOp输出馈送ResampleOp
  • ResampleOp输出馈线SDRSinkOp

自定义运算符基于Operator Holoscan 类,由以下主要函数组成:

  • __init__:定义自定义运算符中使用的参数。
  • setup:定义自定义操作员的输入和输出连接。
  • compute:执行数据转换、计算或连接到外部库。

为了更好地理解如何构建自定义运算符,这里有DemodulateOp详细介绍。

Class DemodulateOp(Operator): 
 
   def __init__(self, *args, **kwargs): 
  	# Need to call the base class constructor last 
  	super().__init__(*args, **kwargs) 
 
   def setup(self, spec: OperatorSpec): 
  	spec.input(“rx_sig”) 
  	spec.output("sig_out") 
 
   def compute(self, op_input, op_output, context): 
  	sig = op_input.receive("rx_sig") 
  	print("In Demodulate – Got: ", sig[0:10]) 
  	op_output.emit(uSignal.fm_demod(sig), "sig_out") 

在本例中,setup函数定义操作员输入和输出端口。在这种情况下,一个数据流进入操作员,一个离开操作员。

操作员执行的大部分工作都在compute功能中完成。在这里,您可以通过op_input.receive(<name_of_input>)访问和处理传入的数据,并对该数据运行某种类型的操作。在本例中,我使用 uSignal 的fm_demod函数执行 FM 解调。完成后,您将使用op_output.emit(<data>, <name_of_output>)输出结果。

简单的雷达信号处理管道

雷达系统最初是在第二次世界大战期间开发的,目的是帮助探测和跟踪敌机。他们对盟军在不列颠战役中的成功起到了重要作用。

从概念上讲,雷达的工作原理是发射已知信号,等待信号从物体上反弹并返回接收器。考虑时间增量和位置以及其他信号处理技术,以测量目标的位置和速度。

Diagram starts with generating a signal or waveform, which is then sent through steps like MTI filtering, a range-doppler map, and CFAR analysis before being displayed.
图 3 。 Holoscan 的教科书式雷达处理管道

这里,将生成的波形与接收信号进行匹配滤波,以确定是否接收到发送信号。从那里,您可以执行各种过滤操作,以移除静止或缓慢移动的对象(称为 clutter ),并提高分辨率。最后,分析检测目标并在屏幕上显示候选位置。

在这 Holoscan 示例 ,您在源运营商中使用 CuPy 动态生成流数据,但您可以轻松利用网络运营商来摄取 UDP 以太网。与前面的 FM 解调示例一样, cuSignal 和 CuPy 用于构建特定于应用程序的运算符。

与 FM 解调示例不同,此 Holoscan 管道包含具有多个输入和输出的运算符。下面的代码示例显示了如何在 Python 中实现这一点。setup函数中指定了多个输入,可以通过op_input.receive(<name_of_input>)compute函数中访问关联的数据对象。

class PulseCompressionOp(Operator): 
 
   def __init__(self, *args, **kwargs): 
  	super().__init__(*args, **kwargs) 
 
   def setup(self, spec: OperatorSpec): 
  	spec.input("x") 
  	spec.input("waveform") 
  	spec.output("X") 
 
   def compute(self, op_input, op_output, context): 
  	x = op_input.receive("x") 
  	waveform = op_input.receive("waveform") 
<code omitted for brevity> 

接下来的步骤

FM 解调和雷达示例目前不包括 AI 推断步骤。然而, Holoscan 的灵活性使您能够在现有图形中添加新运算符,而不会对应用程序性能或其可维护性产生负面影响。

当雷达管线当前处于离线状态并使用模拟数据时,您可以添加一个网络运营商,如前所述,而不会对计算管线的其余部分产生负面影响。有关具有 AI 推理和实时数据摄取的参考应用程序的更多信息,请参见 NVIDIA Holoscan SDK v0.4

要了解有关为各种领域构建流式 AI 管道的更多信息,请加入 Building High-Speed Sensor AI Pipelines using NVIDIA Holoscan 上 NVIDIA GTC 的 Holoscan Developer Day 和培训实验室。 GTC 是人工智能和元宇宙时代的开发者大会,是 free to attend ,将于 3 月 20-23 日举行。

 

Tags