操作流程图外文翻译资料

 2022-12-24 05:12

Operating a Flowgraph

The basic data structure in GNU Radio is the flowgraph, which represents the connections of the blocks through which a continuous stream of samples flows. The concept of a flowgraph is an acyclic directional graph with one or more source blocks (to insert samples into the flowgraph), one or more sink blocks (to terminate or export samples from the flowgraph), and any signal processing blocks in between.

A program must at least create a GNU Radio top_block, which represents the top-most structure of the flowgraph. The top blocks provide the overall control and hold methods such as start, stop, and wait.

The general construction of a GNU Radio application is to create a gr_top_block, instantiate the blocks, connect the blocks together, and then start the gr_top_block. The following program shows how this is done. A single source and sink are used with a FIR filter between them.

from gnuradio import gr, blocks, filter, analog

class my_topblock(gr.top_block):

def __init__(self):

gr.top_block.__init__(self)

amp = 1

taps = filter.firdes.low_pass(1, 1, 0.1, 0.01)

self.src = analog.noise_source_c(analog.GR_GAUSSIAN, amp)

self.flt = filter.fir_filter_ccf(1, taps)

self.snk = blocks.null_sink(gr.sizeof_gr_complex)

self.connect(self.src, self.flt, self.snk)

if __name__ == '__main__':

tb = my_topblock()

tb.start()

tb.wait()

The tb.start() starts the data flowing through the flowgraph while the tb.wait() is the equivalent of a threads join operation and blocks until the gr_top_block is done.

An alternative to using the start and wait methods, a run method is also provided for convenience that is a blocking start call; equivalent to the above start followed by a wait.

Latency and Throughput

By default, GNU Radio runs a scheduler that attempts to optimize throughput. Using a dynamic scheduler, blocks in a flowgraph pass chunks of items from sources to sinks. The sizes of these chunks will vary depending on the speed of processing. For each block, the number of items it can process is dependent on how much space it has in its output buffer(s) and how many items are available on the input buffer(s).

The consequence of this is that often a block may be called with a very large number of items to process (several thousand). In terms of speed, this is efficient since now the majority of the processing time is taken up with processing samples. Smaller chunks mean more calls into the scheduler to retrieve more data. The downside to this is that it can lead to large latency while a block is processing a large chunk of data.

To combat this problem, the gr_top_block can be passed a limit on the number of output items a block will ever receive. A block may get less than this number, but never more, and so it serves as an upper limit to the latency any block will exhibit. By limiting the number of items per call to a block, though, we increase the overhead of the scheduler, and so reduce the overall efficiency of the application.

To set the maximum number of output items, we pass a value into the start or run method of the gr_top_block:

tb.start(1000)

tb.wait()

or

tb.run(1000)

Using this method, we place a global restriction on the size of items to all blocks. Each block, though, has the ability to overwrite this with its own limit. Using the set_max_noutput_items(m) method for an individual block will overwrite the global setting. For example, in the following code, the global setting is 1000 items max, except for the FIR filter, which can receive up to 2000 items.

tb.flt.set_max_noutput_items(2000)

tb.run(1000)

In some situations, you might actually want to restrict the size of the buffer itself. This can help to prevent a buffer who is blocked for data from just increasing the amount of items in its buffer, which will then cause an increased latency for new samples. You can set the size of an output buffer for each output port for every block.

WARNING: This is an advanced feature in GNU Radio and should not be used without a full understanding of this concept as explained below.

To set the output buffer size of a block, you simply call:

tb.blk0.set_max_output_buffer(2000)

tb.blk1.set_max_output_buffer(1, 2000)

tb.start()

print tb.blk1.max_output_buffer(0)

print tb.blk1.max_output_buffer(1)

In the above example, all ports of blk0 are set to a buffer size of 2000 in items (not bytes), and blk1 only sets the size for output port 1, any and all other ports use the default. The third and fourth lines just print out the buffer sizes for ports 0 and 1 of blk1. This is done after start() is called because the values are updated based on what is actually allocated to the blocks buffers.

NOTES:

  1. Buffer length assignment is done once at runtime (i.e., when run() or start() is called). So to set the max buffer lengths, the set_max_output_buffer calls must be done before this.
  2. Once the flowgraph is started, the buffer lengths for a block are set and cannot be dynamically changed, even during a lock()/unlock(). If you need to change the buffer size, you will have to delete the bl

    剩余内容已隐藏,支付完成后下载完整资料


    操作流程图

    GNU Radio中的基本数据结构是流程图,它表示连续的采样流流过的模块如何连接。 流程图的概念是非循环方向图,其具有一个或多个源块(用于将样本插入到流程图中),一个或多个宿块(用于终止或从流程图导出采样),以及其间的任何信号处理模块。

    程序必须至少创建一个GNU Radio top_block,它代表流程图的最顶层结构。顶部块提供整体控制和保持方法,例如“run”,“stop”和“wait”。

    GNU Radio应用程序的一般构造是创建gr_top_block,实例化块,将块连接在一起,然后启动gr_top_block。以下程序显示了如何完成此操作。单个源和接收器与它们之间的FIR滤波器一起使用。

    from gnuradio import gr, blocks, filter, analog

    class my_topblock(gr.top_block):

    def __init__(self):

    gr.top_block.__init__(self)

    amp = 1

    taps = filter.firdes.low_pass(1, 1, 0.1, 0.01)

    self.src = analog.noise_source_c(analog.GR_GAUSSIAN, amp)

    self.flt = filter.fir_filter_ccf(1, taps)

    self.snk = blocks.null_sink(gr.sizeof_gr_complex)

    self.connect(self.src, self.flt, self.snk)

    if __name__ == '__main__':

    tb = my_topblock()

    tb.start()

    tb.wait()

    tb.start()启动流经流程图的数据,而tb.wait()相当于线程的join操作,并阻塞直到gr_top_block完成。

    除了使用start和wait方法之外,还提供了run方法,以方便阻塞启动调用; 相当于上面的run后跟wait。

    延迟和吞吐量

    默认情况下,GNU Radio运行一个尝试优化吞吐量的调度程序。使用动态调度程序,流程图中的块将项目块从源传递到接收器。这些块的大小将根据处理速度而变化。对于每个块,它可以处理的项目数取决于它在输出缓冲区中的空间大小以及输入缓冲区中可用的项目数。

    这样做的结果是,通常可以调用一个块来处理大量的项目(数千个)。就速度而言,这是有效的,因为现在大部分处理时间都用于处理样本。较小的块意味着更多调用调度程序以检索更多数据。这样做的缺点是,当一个块处理大量数据时,它可能导致大的延迟。

    为了解决这个问题,gr_top_block可以传递一个块将要接收的输出项数量的限制。一个块的输出项数量可能会少于这个数字,但永远不会更多,因此这个参数可以作为任何块将展示的延迟的上限。但是,通过限制每次调用块的项数,我们会增加调度程序的开销,从而降低应用程序的整体效率。

    要设置最大输出项数,我们将值传递给gr_top_block的start或run方法:

    tb.start(1000)

    tb.wait()

    or

    tb.run(1000)

    使用此方法,我们对所有块的项目大小设置全局限制。 但是,每个块都能够以自己的限制覆盖它。 对单个块使用set_max_noutput_items(m)方法将覆盖全局设置。 例如,在以下代码中,全局设置最多为1000个项目,FIR过滤器除外,它最多可以接收2000个项目。

    tb.flt.set_max_noutput_items(2000)

    tb.run(1000)

    在某些情况下,您可能实际上想要限制缓冲区本身的大小。 这有助于防止被阻止数据的缓冲区仅增加其缓冲区中的项目数量,这将导致新样本的延迟增加。 您可以为每个块设置每个输出端口的输出缓冲区大小。

    警告:这是GNU Radio中的一项高级功能,如果没有完全理解此概念,则不应使用此功能,如下所述。

    要设置块的输出缓冲区大小,只需调用:

    tb.blk0.set_max_output_buffer(2000)

    tb.blk1.set_max_output_buffer(1, 2000)

    tb.start()

    print tb.blk1.max_output_buffer(0)

    print tb.blk1.max_output_buffer(1)

    在上面的示例中,blk0的所有端口都设置为项目(而不是字节)中的缓冲区大小2000,而blk1仅设置输出端口1的大小,任何和所有其他端口使用默认值。 第三行和第四行只打印出blk1的端口0和1的缓冲区大小。 这是在调用start()之后完成的,因为值是根据实际分配给块缓冲区的内容更新的。

    注释:

    1.缓冲区长度分配在运行时完成一次(即,调用run()或start()时)。因此,要设置最大缓冲区长度,必须在此之前完成set_max_output_buffer调用。

    2.一旦启动了流程图,即使在lock()/ unlock()期间,也会设置块的缓冲区长度,并且无法动态更改。如果需要更改缓冲区大小,则必须删除该块并重建它,因此必须断开连接并重新连接块。

    3.这会影响吞吐量。大缓冲区旨在以延迟为代价提高程序的效率和速度。限制缓冲区的大小可能会降低性能。

    4.实际缓冲区大小实际上基于系统的最小粒度。通常,这是页面大小,通常为4096字节。这意味着使用此命令指定的任何缓冲区大小将向上舍入到最接近的粒度(例如,页面大小)。在流程图启动后调用max_output_buffer(port)时,您将获得缓冲区中实际分配的项目数,这可能与最初指定的项目不同。

    元数据信息

    介绍

    元数据文件具有标题形式的额外信息,其携带关于文件中的样本的元数据。原始的二进制文件不携带额外信息,必须精细处理。系统状态的任何变化(例如接收器的采样率或频率)都不会与文件本身中的数据一起传送。标题解决了这个问题。

    我们使用gr :: blocks :: file_meta_sink编写元数据文件,并使用gr :: blocks :: file_meta_source读取元数据文件。

    元数据文件具有标题,该标题包含有关文件中的一段数据的信息。标题结构将在下一节中详细介绍。元数据文件始终以描述数据基本结构的标头开头。它包含有关项目大小,数据类型(如果它是否复杂),段的采样率,段的第一个样本的时间戳以及有关标题大小和段大小的信息的信息。

    头文件的第一个静态部分包含以下信息。

    bull;version:(char)版本号(通常设置为METADATA_VERSION)

    bull;rx_rate :( double)Stream的采样率

    bull;rx_time :( pmt :: pmt_t对 - (uint64_t,double))时间戳(来自UHD的格式)

    bull;size:(int)项大小(以字节为单位) - 反映向量长度(如果有)

    bull;type:(int)数据类型(下面的枚举)

    bull;cplx:(bool)如果数据很复杂,则为true

    bull;strt:(uint64_t)相对于当前标头的数据开始

    bull;bytes:(uint64_t)后续数据段的大小(以字节为单位)

    标头的可选附加部分将信息存储在任何接收的标签中。与标题关联的两个主要标记是:

    bull;rx_rate:流的采样率。

    bull;rx_time:段中第一个项目的时间戳。

    这些标签的灵感来自UHD标签格式。

    标题提供了足够的信息来处理和处理数据。但需要注意的是,数据类型永远不会在文件中发生变化。应该很少需要这个,因为GNU Radio块只能在构造函数中设置其IO签名的数据类型,因此之后数据类型的更改将无法识别。

    我们还有一个额外的标题段是可选的。这可以在开始时由用户指定一些应该与数据一起传输的额外元数据来加载。它每当看到一个流标记时也会增长,因此字典将包含来自流程图的标记中的任何键:值对。

    元数据文件的类型

    GNU Radio目前支持两种类型的元数据文件:

    bull;内联:标题与同一文件中的数据内联。

    bull;detached:标题位于数据的单独头文件中。

    内联方法是标准版本。使用分离的标头时,标头只是在分离的头文件中背靠背插入。然后,dat文件是标准的原始二进制格式,不会中断数据。

    更新数据头

    虽然始终有一个标题可以启动元数据文件,但它们也会全面更新。有两个事件触发新标头。我们将段定义为与最后一个头相关联的数据单元。

    触发新标头的第一个事件是为给定的段写入了足够的样本。此数字定义为最大段大小,是我们传递给file_meta_sink的参数。它默认为100万个项目(项目,而不是字节)。达到该项目数时,将生成新标头并启动新段。这使我们以后更容易操纵数据,并有助于防止灾难性数据丢失。

    触发新段的第二个事件是是否观察到新标记。如果标记是标题中的标准标记,则标题值将更新,标题和当前附加内容将写入文件,并且该段将再次开始。如果看到来自附加组件的标签,则更新与该标签相关联的值;如果看到新标记,则会将新的键:值对添加到extras字典中。

    当看到新标签时,我们会生成一个新段,以便确保该段中的所有样本都由标头定义。如果采样率发生变化,我们会创建一个新段,其中所有新样本都处于新的速率。此外,在UHD设备的情况下,如果观察到段丢失,它将生成新的时间戳作为“rx_time”的标签。我们创建了一个反映此更改的新文件段,以保持采样时间的准确性。

    实现

    元数据文件使用gr :: blocks :: file_meta_sink创建。默认行为是创建一个带有内联标题的单个文件作为元数据。可以设置一个选项以切换到分离的标题模式。

    使用gr :: blocks :: file_meta_source将元数据文件读入流程图。此源读取元数据文件,默认情况下使用可设置选项内联,以使用分离的标头。来自段的数据被转换为标准流输出。额外标头中的rx_rate和rx_time以及所有键:值对将转换为标签并添加到流标签界面。

    结构

    文件元数据由静态强制标头和动态可选附加标头组成。 每个标题都是一个单独的PMT字典。 通过构建密钥:值对的PMT字典(pmt :: make_dict)来创建标头,然后将字典序列化为要写入文件的字符串。 标题始终与标题版本预定的长度相同(必须已知)。 然后,标题将指示是否有额外数据要作为单独的序列化字典提取。

    要使用PMT创建和提取标头信息,我们使用PMT运算符。 例如,我们在C 中创建标题的简化版本,如下所示:

    const char METADATA_VERSION = 0x0;

    pmt::pmt_t header;

    header =

您需要先支付 30元 才能查看全部内容!立即支付

课题毕业论文、文献综述、任务书、外文翻译、程序设计、图纸设计等资料可联系客服协助查找。