doc: fpga: host: Updated Wideband DDC DUC related documentation

Updated the references to DDC and DUC RFNoC blocks to reflect the
new split between legacy(singlesample) and wideband(multisample)
implementations.
Updated the related manual references as well as the C++ block
controller API comments that are pulled in by doxygen.
Also fixed a minor outdated comment in the FPGA source code.
This commit is contained in:
Niels Garibaldi 2026-08-05 16:01:58 +02:00 committed by mkoop-ni
parent 8d9c53c83e
commit 344c6793ac
11 changed files with 466 additions and 50 deletions

View File

@ -47,12 +47,18 @@ Change Log for Releases
With this update, users can add the DDC and DUC blocks to their custom
FPGA images for bandwidths up to 1600 MHz (2000 MSps).
- Shipping FPGA images:
- Added new shipping FPGA images for x420:
- x420_X4_400
- x420_CG_400
- Added DDC and DUC functionality for all channels to the following
shipping FPGA images:
- x410_X4_400
- x410_CG_400
- x420_X4_400
- x420_CG_400
- x420_X4_1000
- x420_CG_1000
- x440_X4_800
- x440_CG_800
- x440_X4_1600
- x440_CG_1600
For custom designs based on one of these updated rfnoc_image_core.yml

View File

@ -10,8 +10,9 @@
// timed control port commands. For each timed write to REG_TAG_ADDR, the module
// determines which sample in the output word corresponds to the command
// timestamp and asserts the corresponding bit in m_axis_dout_ttags when the
// current timestamp reaches the commanded time. Untimed commands are passed
// through immediately on m_axis_cmd_tdata/tvalid.
// current timestamp reaches the commanded time. Untimed commands are eligible
// on the next accepted output sample transfer. Timed and untimed commands are
// held in the command FIFO, which has 2**CMD_FIFO_SIZE entries.
// NOTE:
// This module has a command stream latency of 4 cycles:
// 1 cycle - add command to FIFO,

View File

@ -605,29 +605,46 @@ As of UHD 4.5, the following USRP X410 images flavors are shipped with UHD:
| FPGA Image Flavor | Number of \n Channels | Bandwidth \n per Channel | QSFP28 Port 0 Interface | QSFP28 Port 1 Interface | DDC/DUC | DRAM |
|-------------------|-----------------------|--------------------------|-------------------------|-------------------------|---------|----------------------------|
| X4_200 | 4 (2 per ZBX) | 200 MHz | 4x 10 GbE (All Lanes) | Unused | Yes | Yes (4 GiB, 4-Ch Replay) |
| UC_200 | 4 (2 per ZBX) | 200 MHz | Unused | 100 GbE | Yes | Yes (4 GiB, 4-Ch Replay) |
| CG_400 | 4 (2 per ZBX) | 400 MHz | 100 GbE | 100 GbE | No | No |
| X4_200 | 4 (2 per ZBX) | 200 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (legacy) | Yes (4 GiB, 4-Ch Replay) |
| UC_200 | 4 (2 per ZBX) | 200 MHz | Unused | 100 GbE | Yes (legacy) | Yes (4 GiB, 4-Ch Replay) |
| CG_400 | 4 (2 per ZBX) | 400 MHz | 100 GbE | 100 GbE | Yes (multisample) | No |
As of UHD 4.10, the following USRP X420 images flavors are shipped with UHD:
As of UHD 4.11, the following USRP X420 images flavors are shipped with UHD:
| FPGA Image Flavor | Number of \n Channels | Bandwidth \n per Channel | QSFP28 Port 0 Interface | QSFP28 Port 1 Interface | DDC/DUC | DRAM |
|-------------------|-----------------------|--------------------------|-------------------------|-------------------------|---------|---------------------------|
| X4_200 | 2 (1 per HBX) | 200 MHz | 4x 10 GbE (All Lanes) | Unused | Yes | Yes (8 GiB, 2-Ch Replay) |
| X4_1000 | 2 (1 per HBX) | 1000 MHz | 4x 10 GbE (All Lanes) | Unused | No | Yes (8 GiB, 2-Ch Replay) |
| CG_1000 | 2 (1 per HBX) | 1000 MHz | 100 GbE | 100 GbE | No | Yes (8 GiB, 2-Ch Replay) |
| X4_200 | 2 (1 per HBX) | 200 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (legacy) | Yes (8 GiB, 2-Ch Replay*) |
| X4_400 | 2 (1 per HBX) | 400 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (multisample) | Yes (8 GiB, 2-Ch Replay*) |
| CG_400 | 2 (1 per HBX) | 400 MHz | 100 GbE | 100 GbE | Yes (multisample) | Yes (8 GiB, 2-Ch Replay*) |
| X4_1000 | 2 (1 per HBX) | 1000 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (multisample) | Yes (8 GiB, 2-Ch Replay*) |
| CG_1000 | 2 (1 per HBX) | 1000 MHz | 100 GbE | 100 GbE | Yes (multisample) | Yes (8 GiB, 2-Ch Replay*) |
As of UHD 4.6, the following USRP X440 images flavors are shipped with UHD:
As of UHD 4.11, the following USRP X440 images flavors are shipped with UHD:
| FPGA Image Flavor | Number of \n Channels | Bandwidth \n per Channel | QSFP28 Port 0 Interface | QSFP28 Port 1 Interface | DDC/DUC | DRAM | Dual-Rate Support |
|-------------------|-----------------------|--------------------------|-------------------------|-------------------------|---------|---------------------------|--------------------------------------------|
| X4_200 | 8 (4 per FBX) | 200 MHz | 4x 10 GbE (All Lanes) | Unused | Yes | No | Yes until UHD 4.10, No with later versions |
| X4_400 | 8 (4 per FBX) | 400 MHz | 4x 10 GbE (All Lanes) | Unused | No | Yes (8 GiB, 8-Ch Replay*) | Yes |
| CG_400 | 8 (4 per FBX) | 400 MHz | 100 GbE | 100 GbE | No | No | Yes |
| X4_1600 | 2 (1 per FBX) | 1600 MHz | 4x 10 GbE (All Lanes) | Unused | No | Yes (8 GiB, 2-Ch Replay) | Yes |
| CG_1600 | 2 (1 per FBX) | 1600 MHz | 100 GbE | 100 GbE | No | No | Yes |
| X4_200 | 8 (4 per FBX) | 200 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (legacy) | No | Yes until UHD 4.10, No with later versions |
| X4_400 | 8 (4 per FBX) | 400 MHz | 4x 10 GbE (All Lanes) | Unused | No | Yes (8 GiB, 8-Ch Replay*) | Yes |
| CG_400 | 8 (4 per FBX) | 400 MHz | 100 GbE | 100 GbE | No | No | Yes |
| X4_800 | 2 (1 per FBX) | 800 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (multisample) | Yes (8 GiB, 2-Ch Replay*) | Yes |
| CG_800 | 2 (1 per FBX) | 800 MHz | 100 GbE | 100 GbE | Yes (multisample) | No | Yes |
| X4_1600 | 2 (1 per FBX) | 1600 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (multisample) | Yes (8 GiB, 2-Ch Replay*) | Yes |
| CG_1600 | 2 (1 per FBX) | 1600 MHz | 100 GbE | 100 GbE | Yes (multisample) | No | Yes |
\* (Implemented as two separate 4-Ch Replay blocks)
<span>*</span> (Implemented as two separate Replay blocks, each providing half the total amount of channels and memory)
The following RFNoC image core configuration files include the multisample
DDC/DUC implementation, but are not shipped as pre-compiled bitfiles:
| USRP Model | FPGA Image Flavor | Number of \n Channels | Bandwidth \n per Channel | QSFP28 Port 0 Interface | QSFP28 Port 1 Interface | DDC/DUC | DRAM |
|------------|-------------------|-----------------------|--------------------------|-------------------------|-------------------------|---------|------|
| X410 | X4_400 | 4 (2 per ZBX) | 400 MHz | 4x 10 GbE (All Lanes) | Unused | Yes (multisample) | Yes (4 GiB, 4-Ch Replay) |
In the DDC/DUC column of the device-specific tables:
- `legacy` denotes the single-sample
DDC/DUC implementation used by images with bandwidths of up to 200 MHz.
- `multisample` denotes the wideband implementation added with UHD 4.11 and
used by images with bandwidths above 200 MHz.
The following list shows some potential use-cases for different FPGA images:
@ -651,7 +668,8 @@ The following list shows some potential use-cases for different FPGA images:
channels on daughterboard 0) and Record/Replay block 1 is connected to Radio
block 1. Cross-connections Record/Replay0 <-> Radio1 and Record/Replay1 <->
Radio0 are not supported by default.
(For USRP X410 this design is available as source, and not shipped as precompiled bitfile)
(For USRP X410 this design is available as source, and not shipped
as precompiled bitfile.)
- `X4_1000`: (USRP X420 only): 1000 MHz analog bandwidth streaming per channel to/from
on-board DRAM using the RFNoC Record/Replay block. Up to 4 x 10 GbE connections may be
used to access the DRAM from an external host computer. Note that 10 GbE is

View File

@ -0,0 +1,81 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1400" height="560" viewBox="0 0 1400 560" role="img" aria-labelledby="title desc">
<title id="title">RFNoC DDC signal path</title>
<desc id="desc">General composition of the digital downconverter: input samples pass through a DDS frequency shifter, CIC decimator, half-band filter cascade, and IQ scaling before reaching the output. A control lane provides frequency, decimation, scaling, and timed command configuration.</desc>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#000000"/>
</marker>
<marker id="control-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#000000"/>
</marker>
<style>
text { font-family: "DejaVu Sans", sans-serif; }
.label { fill: #3a414a; }
.title { font-size: 28px; font-weight: 700; letter-spacing: 0; }
.subtitle { font-size: 15px; fill: #3a414a; }
.box-title { font-size: 22px; font-weight: 700; fill: #3a414a; }
.box-detail { font-size: 18px; fill: #3a414a; }
.annotation { font-size: 14px; fill: #3a414a; }
.small { font-size: 16px; fill: #3a414a; }
.control-title { font-size: 22px; font-weight: 700; fill: #3a414a; }
.control-detail { font-size: 18px; fill: #3a414a; }
</style>
</defs>
<rect width="1400" height="560" fill="#ffffff"/>
<!-- Main signal path -->
<g>
<rect x="48" y="245" width="128" height="112" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="210" y="220" width="240" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="484" y="220" width="210" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="728" y="220" width="260" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="1022" y="220" width="170" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="1230" y="245" width="152" height="112" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
</g>
<!-- Signal connectors -->
<g fill="none" stroke="#000000" stroke-width="3" marker-end="url(#arrow)">
<path d="M 176 301 H 206"/>
<path d="M 450 301 H 480"/>
<path d="M 694 301 H 724"/>
<path d="M 988 301 H 1018"/>
<path d="M 1192 301 H 1226"/>
</g>
<!-- Input and output -->
<text x="112" y="285" text-anchor="middle" class="label" font-size="22" font-weight="700">Input</text>
<text x="112" y="310" text-anchor="middle" class="label" font-size="18">sc16</text>
<text x="112" y="333" text-anchor="middle" class="small">wideband</text>
<text x="1306" y="285" text-anchor="middle" class="label" font-size="22" font-weight="700">Output</text>
<text x="1306" y="310" text-anchor="middle" class="label" font-size="18">sc16</text>
<text x="1306" y="333" text-anchor="middle" class="small">decimated</text>
<!-- Processing blocks -->
<text x="330" y="260" text-anchor="middle" class="box-title">DDS frequency</text>
<text x="330" y="290" text-anchor="middle" class="box-title">shifter</text>
<text x="330" y="330" text-anchor="middle" class="box-detail">complex mixing</text>
<text x="589" y="270" text-anchor="middle" class="box-title">CIC decimator</text>
<text x="589" y="315" text-anchor="middle" class="box-detail">integer decimation</text>
<text x="589" y="340" text-anchor="middle" class="box-detail">CIC gain compensation</text>
<text x="858" y="270" text-anchor="middle" class="box-title">Half-band filters</text>
<text x="858" y="315" text-anchor="middle" class="box-detail">up to NUM_HB stages</text>
<text x="858" y="340" text-anchor="middle" class="box-detail">each stage decimates by 2</text>
<!-- IQ scaling stage -->
<text x="1107" y="270" text-anchor="middle" class="box-title">IQ scaling</text>
<text x="1107" y="330" text-anchor="middle" class="box-detail">filter gain correction</text>
<!-- Control lane -->
<rect x="210" y="145" width="982" height="58" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2" stroke-dasharray="7 5"/>
<text x="260" y="169" class="control-title">Control and timing</text>
<text x="260" y="188" class="control-detail">frequency, decimation, IQ scale, and optional timed commands</text>
<path d="M 330 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
<path d="M 589 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
<path d="M 858 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
<path d="M 1107 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,79 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1400" height="560" viewBox="0 0 1400 560" role="img" aria-labelledby="title desc">
<title id="title">RFNoC DUC signal path</title>
<desc id="desc">General composition of the digital upconverter: input samples pass through a half-band filter cascade, CIC interpolator, IQ scaling, and DDS frequency shifter before reaching the output. A control lane provides frequency, interpolation, scaling, and timed command configuration.</desc>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#000000"/>
</marker>
<marker id="control-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#000000"/>
</marker>
<style>
text { font-family: "DejaVu Sans", sans-serif; }
.label { fill: #3a414a; }
.title { font-size: 28px; font-weight: 700; letter-spacing: 0; }
.subtitle { font-size: 15px; fill: #3a414a; }
.box-title { font-size: 22px; font-weight: 700; fill: #3a414a; }
.box-detail { font-size: 18px; fill: #3a414a; }
.annotation { font-size: 14px; fill: #3a414a; }
.small { font-size: 16px; fill: #3a414a; }
.control-title { font-size: 22px; font-weight: 700; fill: #3a414a; }
.control-detail { font-size: 18px; fill: #3a414a; }
</style>
</defs>
<rect width="1400" height="560" fill="#ffffff"/>
<!-- Main signal path -->
<g>
<rect x="48" y="245" width="128" height="112" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="210" y="220" width="260" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="504" y="220" width="210" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="748" y="220" width="210" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="992" y="220" width="210" height="162" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
<rect x="1240" y="245" width="152" height="112" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2"/>
</g>
<!-- Signal connectors -->
<g fill="none" stroke="#000000" stroke-width="3" marker-end="url(#arrow)">
<path d="M 176 301 H 206"/>
<path d="M 470 301 H 500"/>
<path d="M 714 301 H 744"/>
<path d="M 958 301 H 988"/>
<path d="M 1202 301 H 1236"/>
</g>
<!-- Input and output -->
<text x="112" y="285" text-anchor="middle" class="label" font-size="22" font-weight="700">Input</text>
<text x="112" y="310" text-anchor="middle" class="label" font-size="18">sc16</text>
<text x="112" y="333" text-anchor="middle" class="small">baseband</text>
<text x="1316" y="285" text-anchor="middle" class="label" font-size="22" font-weight="700">Output</text>
<text x="1316" y="310" text-anchor="middle" class="label" font-size="18">sc16</text>
<text x="1316" y="333" text-anchor="middle" class="small">wideband</text>
<!-- Processing blocks -->
<text x="340" y="270" text-anchor="middle" class="box-title">Half-band filters</text>
<text x="340" y="315" text-anchor="middle" class="box-detail">up to NUM_HB stages</text>
<text x="340" y="340" text-anchor="middle" class="box-detail">each stage interpolates by 2</text>
<text x="609" y="270" text-anchor="middle" class="box-title">CIC interpolator</text>
<text x="609" y="315" text-anchor="middle" class="box-detail">integer interpolation</text>
<text x="609" y="340" text-anchor="middle" class="box-detail">CIC gain compensation</text>
<text x="853" y="270" text-anchor="middle" class="box-title">IQ scaling</text>
<text x="853" y="330" text-anchor="middle" class="box-detail">filter gain correction</text>
<text x="1097" y="260" text-anchor="middle" class="box-title">DDS frequency</text>
<text x="1097" y="290" text-anchor="middle" class="box-title">shifter</text>
<text x="1097" y="330" text-anchor="middle" class="box-detail">complex mixing</text>
<!-- Control lane -->
<rect x="210" y="145" width="992" height="58" rx="6" fill="#f2f3f5" stroke="#000000" stroke-width="2" stroke-dasharray="7 5"/>
<text x="260" y="169" class="control-title">Control and timing</text>
<text x="260" y="188" class="control-detail">frequency, interpolation, IQ scale, and optional timed commands</text>
<path d="M 340 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
<path d="M 609 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
<path d="M 853 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
<path d="M 1097 203 V 220" fill="none" stroke="#000000" stroke-width="2" marker-end="url(#control-arrow)"/>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -2311,6 +2311,7 @@ When the AXI-Stream Payload Context interface is used, the NoC Shell will expose
\anchor axi_stream_data_simple_interface_anchor
### AXI-Stream Data (Simple Interface)
The AXI-Stream Data interface provides another simple user interface. It uses an AXI-Stream data interface but does not require the user to packetize header information. It also supports timestamps, EOB, and EOV. The following abbreviations are used below:

View File

@ -104,7 +104,6 @@ user property (e.g., it can also set a command time). Direct access of user
properties is thus often not necessary, and can be considered a lower-level API
than directly calling block APIs.
\anchor props_propprop
### Property Propagation
By itself, these relationships between properties are already useful to describe

View File

@ -19,6 +19,8 @@ parameters:
# 2 that can support the given RF_BW, assuming each of the NIPC parallel
# chains supports 200 MHz of RF bandwidth (with a corresponding sampling rate
# of 250 MSps). If RF_BW is not provided or is zero, NIPC defaults to 1.
# NIPC == 1 selects the legacy single-sample implementation. Values greater
# than 1 select the multisample implementation used by wideband images.
NIPC: >-
${ 1 << ((max(1, -(-int(config.device.parameters.get('RF_BW', 200))
// 200)) - 1).bit_length()) }

View File

@ -19,6 +19,8 @@ parameters:
# 2 that can support the given RF_BW, assuming each of the NIPC parallel
# chains supports 200 MHz of RF bandwidth (with a corresponding sampling rate
# of 250 MSps). If RF_BW is not provided or is zero, NIPC defaults to 1.
# NIPC == 1 selects the legacy single-sample implementation. Values greater
# than 1 select the multisample implementation used by wideband images.
NIPC: >-
${ 1 << ((max(1, -(-int(config.device.parameters.get('RF_BW', 200))
// 200)) - 1).bit_length()) }

View File

@ -18,16 +18,122 @@ namespace uhd { namespace rfnoc {
*
* \ingroup rfnoc_blocks
*
* The DDC Block is a multi-channel digital downconverter (DDC) with built-in
* frequency shift. The number of channels as well as the maximum decimation is
* configurable in the FPGA, the block controller will read out registers to
* identify the capabilities of this block.
* # Overview
*
* The DDC is a multi-channel digital downconverter with a built-in DDS
* frequency shifter. It is commonly placed directly after a radio block to
* select a channel from a wider-band input and reduce the sampling rate before
* the data is sent to another RFNoC block or to the host.
*
* The block processes signed complex 16-bit samples (`sc16`). Each channel has
* an independent frequency shift and decimation setting. The number of
* channels and the maximum supported decimation are configured in the FPGA at
* synthesis time.
* The block controller reads these maximum capabilities, stored in capability
* registers, during initialization.
*
* # Features
*
* - Per-channel frequency shifting with optional timed commands.
* - Integer decimation using a CIC filter followed by a configurable cascade
* of half-band filters.
* - IQ scaling to compensate for the gain of the decimation filters.
* - Independent rate and frequency configuration for every channel.
*
* # Theory of Operation
*
* <img src="ddc_signal_path.svg" width="1000" >
*
*
* The total decimation is the product of the CIC decimation and the half-band
* decimation stages. With `NUM_HB` half-band stages and a CIC limit of
* `CIC_MAX_DECIM`, the maximum supported decimation is
* \f$\mathrm{CIC\_MAX\_DECIM} \times 2^{\mathrm{NUM\_HB}}\f$.
*
* # FPGA Compile-Time Configuration
*
* The DDC FPGA block is configured through the following parameters:
*
* - `NUM_PORTS`: Number of independent DDC channels.
* - `NUM_HB`: Number of half-band filter stages in each channel.
* - `CIC_MAX_DECIM`: Maximum decimation through CIC filter stage in each channel.
* - `NIPC`: Number of samples processed per clock cycle. `NIPC == 1` selects
* the legacy single-sample implementation. Values greater than one select
* the multisample implementation, which processes samples in parallel for
* wideband images.
*
* The in-tree DDC YAML descriptor derives `NIPC` from the configured RF
* bandwidth. Each parallel processing chain is sized for approximately
* 200 MHz of RF bandwidth, with the resulting value rounded up to a power of
* two. Customized FPGA images may choose a different value based on their
* clock rates and resource budget.
*
* # Runtime Configuration
*
* This block exposes two user-configurable configuration parameters per
* channel:
*
* - `freq`: Frequency shift in Hz. The `set_freq()` convenience method should
* be preferred over setting the property directly because it also handles a
* command time.
* - `decim`: Integer decimation value.
*
* The decimation value can be changed at runtime, but a change is applied only
* between bursts. Once a decimation value has been applied, it remains in
* effect for the entire burst.
*
* The legacy single-sample DDC and the multisample (wideband) DDC react
* differently to timed and untimed frequency-shift commands:
*
* - **Legacy single-sample implementation:**
* - **Untimed commands:** Configure the frequency shift for the next IQ
* sample processed by the DDC and all subsequent samples until the next
* frequency change. If the DDC has not processed data since the command
* was issued, a subsequent untimed command overwrites the earlier one.
* - **Timed commands:** Follow the standard timed-command mechanism. The
* command is held until the IQ sample corresponding to its timestamp is
* processed, and the new frequency shift applies to that sample and all
* subsequent samples until the next frequency change.
*
* - **Multisample (wideband) implementation:** Timed and untimed commands are
* stored in the same 32-entry FPGA command queue. Commands are applied only
* when the DDC is actively processing data, and only the command at the
* front of the queue can be applied.
* - **Untimed commands:** An untimed command waits for all commands already
* ahead of it in the queue, including timed commands. It is then applied
* on the next data transfer. Consequently, successive untimed commands
* are not collapsed or skipped; each remains active for at least one data
* transfer containing `NIPC` IQ samples.
* - **Timed commands:** A timed command waits in the queue until it reaches
* the front and its requested timestamp has been reached. It is applied
* starting with the data transfer containing the IQ sample corresponding
* to that timestamp and remains active until the next frequency change.
*
* In the multisample implementation, timed frequency shifts have word-level
* rather than sample-level granularity. One word is one data transfer containing
* `NIPC` samples (see [NIPC](@ref axi_stream_data_simple_interface_anchor)).
* Therefore, if the requested timestamp falls within a word, the new frequency
* shift will be applied to samples earlier in that same word. For example, if
* the timestamp corresponds to the third sample in a word of eight samples,
* the new frequency shift will be applied to all eight samples in that word,
* including the first two samples preceding the requested timestamp, and to
* all subsequent samples until the next frequency change. The exact sample-level
* transition is not guaranteed.
*
* # Register Maps and Compatibility
*
* The DDC has two register-map generations:
*
* - Compatibility major 0 is the legacy single-sample register map, used by
* implementations for bandwidths up to 200 MHz.
* - Compatibility major 1 is the multisample register map, used by the
* wideband implementation.
*
* The block controller reads the FPGA compatibility number from
* `RB_COMPAT_NUM` and selects the corresponding register map. An unsupported
* major version is rejected. `REG_ADDRS_V0` and `REG_ADDRS_V1` contain the
* version-specific addresses used by the controller.
*
* This block has two user properties per channel:
* - `freq`: The frequency shift at the input. Note: A convenience method
* set_freq() is provided to set this property. It also takes care of the
* command time, which set_property() does not, and thus should be preferred.
* - `decim`: The decimation value
*/
class UHD_API ddc_block_control : public noc_block_base
{
@ -70,13 +176,21 @@ public:
/*! Set the DDS frequency
*
* This block will shift the signal at the input by this frequency before
* decimation. The frequency is given in Hz, it is not a relative frequency
* to the input sampling rate.
* decimation. The frequency is specified in Hz rather than as a normalized
* frequency; the valid range is from -get_input_rate()/2 to
* +get_input_rate()/2.
*
* Note: When the rate is modified, the frequency is kept constant. Because
* the FPGA internally uses a relative phase increment, changing the input
* sampling rate will trigger a property propagation to recalculate the
* phase increment based off of this value.
* Note: When the sample rate is modified, the frequency shift is kept
* constant.
* Because the FPGA internally uses a relative phase increment, changing
* the input sampling rate will trigger a property propagation to
* recalculate the phase increment based off of this value.
*
* For the multisample implementation, timed and untimed frequency
* commands are queued in a 32-entry FPGA queue. While the DDC is actively
* processing data, queued commands are processed one at a time; an untimed
* command is applied on the next transfer, while a timed command also waits
* for its requested timestamp.
*
* This function will coerce the frequency to a valid value, and return the
* coerced value.

View File

@ -19,16 +19,122 @@ namespace uhd { namespace rfnoc {
*
* \ingroup rfnoc_blocks
*
* The DUC Block is a multi-channel digital upconverter (DUC) with built-in
* frequency shift. The number of channels as well as the maximum interpolation
* is configurable in the FPGA, the block controller will read out registers to
* identify the capabilities of this block.
* # Overview
*
* The DUC is a multi-channel digital upconverter with a built-in DDS
* frequency shifter. It is commonly placed directly before a radio block to
* increase the sampling rate and shift a signal to the desired transmit
* frequency.
*
* The block processes signed complex 16-bit samples (`sc16`). Each channel has
* an independent frequency shift and interpolation setting. The number of
* channels and the maximum supported interpolation are configured in the FPGA
* at synthesis time.
* The block controller reads these maximum capabilities, stored in capability
* registers, during initialization.
*
* # Features
*
* - Per-channel frequency shifting with optional timed commands.
* - Integer interpolation using a cascade of half-band filters followed by a
* CIC interpolator.
* - IQ scaling to compensate for the gain of the interpolation filters.
* - Independent rate and frequency configuration for every channel.
*
* # Theory of Operation
*
* <img src="duc_signal_path.svg" width="1000" >
*
*
* The total interpolation is the product of the CIC interpolation and the
* half-band interpolation stages. With `NUM_HB` half-band stages and a CIC
* limit of `CIC_MAX_INTERP`, the maximum supported interpolation is
* \f$\mathrm{CIC\_MAX\_INTERP} \times 2^{\mathrm{NUM\_HB}}\f$.
*
* # FPGA Compile-Time Configuration
*
* The DUC FPGA block is configured through the following parameters:
*
* - `NUM_PORTS`: Number of independent DUC channels.
* - `NUM_HB`: Number of half-band filter stages in each channel.
* - `CIC_MAX_INTERP`: Maximum interpolation through CIC filter stage in each channel.
* - `NIPC`: Number of samples processed per clock cycle. `NIPC == 1` selects
* the legacy single-sample implementation. Values greater than one select
* the multisample implementation, which processes samples in parallel for
* wideband images.
*
* The in-tree DUC YAML descriptor derives `NIPC` from the configured RF
* bandwidth. Each parallel processing chain is sized for approximately
* 200 MHz of RF bandwidth, with the resulting value rounded up to a power of
* two. Customized FPGA images may choose a different value based on their
* clock rates and resource budget.
*
* # Runtime Configuration
*
* This block exposes two user-configurable configuration parameters per
* channel:
*
* - `freq`: Frequency shift in Hz. The `set_freq()` convenience method should
* be preferred over setting the property directly because it also handles a
* command time.
* - `interp`: Integer interpolation value.
*
* The interpolation value can be changed at runtime, but a change is applied
* only between bursts. Once an interpolation value has been applied, it remains
* in effect for the entire burst.
*
* The legacy single-sample DUC and the multisample (wideband) DUC react
* differently to timed and untimed frequency-shift commands:
*
* - **Legacy single-sample implementation:**
* - **Untimed commands:** Configure the frequency shift for the next IQ
* sample processed by the DUC and all subsequent samples until the next
* frequency change. If the DUC has not processed data since the command
* was issued, a subsequent untimed command overwrites the earlier one.
* - **Timed commands:** Follow the standard timed-command mechanism. The
* command is held until the IQ sample corresponding to its timestamp is
* processed, and the new frequency shift applies to that sample and all
* subsequent samples until the next frequency change.
*
* - **Multisample (wideband) implementation:** Timed and untimed commands are
* stored in the same 32-entry FPGA command queue. Commands are applied only
* when the DUC is actively processing data, and only the command at the
* front of the queue can be applied.
* - **Untimed commands:** An untimed command waits for all commands already
* ahead of it in the queue, including timed commands. It is then applied
* on the next data transfer. Consequently, successive untimed commands
* are not collapsed or skipped; each remains active for at least one data
* transfer containing `NIPC` IQ samples.
* - **Timed commands:** A timed command waits in the queue until it reaches
* the front and its requested timestamp has been reached. It is applied
* starting with the data transfer containing the IQ sample corresponding
* to that timestamp and remains active until the next frequency change.
*
* In the multisample implementation, timed frequency shifts have word-level
* rather than sample-level granularity. One word is one data transfer containing
* `NIPC` samples (see [NIPC](@ref axi_stream_data_simple_interface_anchor)).
* Therefore, if the requested timestamp falls within a word, the new frequency
* shift will be applied to samples earlier in that same word. For example, if
* the timestamp corresponds to the third sample in a word of eight samples,
* the new frequency shift will be applied to all eight samples in that word,
* including the first two samples preceding the requested timestamp, and to
* all subsequent samples until the next frequency change. The exact sample-level
* transition is not guaranteed.
*
* # Register Maps and Compatibility
*
* The DUC has two register-map generations:
*
* - Compatibility major 0 is the legacy single-sample register map, used by
* implementations for bandwidths up to 200 MHz.
* - Compatibility major 1 is the multisample register map, used by the
* wideband implementation.
*
* The block controller reads the FPGA compatibility number from
* `REG_COMPAT_NUM` and selects the corresponding register map. An unsupported
* major version is rejected. `REG_ADDRS_V0` and `REG_ADDRS_V1` contain the
* version-specific addresses used by the controller.
*
* This block has two user properties per channel:
* - `freq`: The frequency shift at the input. Note: A convenience method
* set_freq() is provided to set this property. It also takes care of the
* command time, which set_property() does not, and thus should be preferred.
* - `interp`: The interpolation value
*/
class UHD_API duc_block_control : public noc_block_base
{
@ -60,14 +166,21 @@ public:
/*! Set the DDS frequency
*
* This block will shift the signal at the input by this frequency before
* decimation. The frequency is given in Hz, it is not a relative frequency
* to the input sampling rate.
* This block applies the frequency shift after interpolation. The frequency
* is specified in Hz rather than as a normalized frequency; the valid range
* is from -get_output_rate()/2 to +get_output_rate()/2.
*
* Note: When the rate is modified, the frequency is kept constant. Because
* the FPGA internally uses a relative phase increment, changing the input
* sampling rate will trigger a property propagation to recalculate the
* phase increment based off of this value.
* Note: When the sample rate is modified, the frequency shift is kept
* constant.
* Because the FPGA internally uses a relative phase increment, changing
* the input sampling rate will trigger a property propagation to
* recalculate the phase increment based off of this value.
*
* For the multisample implementation, timed and untimed frequency
* commands are queued in a 32-entry FPGA queue. While the DUC is actively
* processing data, queued commands are processed one at a time; an untimed
* command is applied on the next transfer, while a timed command also waits
* for its requested timestamp.
*
* This function will coerce the frequency to a valid value, and return the
* coerced value.