aboutsummaryrefslogtreecommitdiffstats
path: root/host/docs/power.dox
blob: 816c748241170003d06e5dd8ba3ac1dcb71cd2c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*! \page page_power Power Level Controls

\tableofcontents

\section power_overview

Starting with UHD 4, UHD comes with reference power level APIs. These allow to
not just set a relative gain level, but configure a USRP to transmit a certain
power, or to estimate received power levels.

The actual transmitted or received power also depends on the transmitted signal
itself. The absolute power setting is thus a *reference power level*.
The reference power level maps a digital signal level (in dBFS) to an absolute,
analog power level (in dBm). The power level setting is the analog power level
that corresponds to a 0 dBFS digital signal.

Note that most USRPs do not support setting reference power levels. Refer to the
individual device manual pages for more information.

\section power_ref_levels RX and TX reference power levels

<b>RX reference power level:</b>

The RX reference power level is defined as such: When a signal with this power
level is applied to the RF input, the digital signal will be at a 0 dBFS power
level.

If a tone with this power level is applied to the RF input, it will be
full-scale in the digital representation.

Example: The reference power level is set to -4 dBm by calling
~~~{.cpp}
U->set_rx_power_reference(-4.0, 0);
~~~

Then, a signal is captured. It turns out the signal is a sine wave with
an amplitude of 0.5, which means its power is 6 dB lower than a signal
with an amplitude of 1.0 (or -6 dBFS). Based on the reference power level, we
can thus infer that the tone injected into the RF port is:

    (-4 dBm - 6 dB) = -10 dBm

<b>TX reference power level:</b>

The TX reference power level is defined as such: When a 0 dBFS signal is
transmitted, it will leave the RF output at the selected reference power level.
In other contexts, this value is sometimes referred to as "peak power level",
because it's the maximum power that can be transmitted.

If a fullscale tone is transmitted, the transmitted analog tone will have the
reference power level.

Example: The reference power level is set to -4 dBm by calling
~~~{.cpp}
U->set_tx_power_reference(-4.0, 0);
~~~

Then, we generate a tone that is a sine wave with amplitude 0.5 and
transmit it using this device and channel. With this amplitude, the
signal is 6 dB lower in power than a sine wave with amplitude 1.0.
Based on the reference power level, we can thus infer that the tone
leaving the RF port has the following absolute power:

    (-4 dBm - 6 dB) = -10 dBm

\section power_amp_rate Amplitude Ranges and Clipping

In practice, it is never possible to cleanly transmit or receive a signal at
0 dBFS, so the reference levels need to be appropriately normalized. Because
all USRPs have a different amplitude range they can transmit/receive before
clipping or distortion occurs, the APIs are designed to be agnostic of the
hardware. The derivation of the actual analog power is thus the responsibility
of the application (i.e., the code that also calls `recv()` and `send()`), which has
access to the sample values. UHD itself doesn't inspect the sample values for
performance reasons, and thus can only manage reference levels.

\section power_tune_owner Retaining gain or power levels across frequency

When tuning a USRP (i.e., changing its frequency) it may be necessary to also
adjust gain stages. Due to physical limitations, the same output power is not
always available (or possible) at different frequencies. This means that the
output power may vary when retuning. The relative gain range is usually the same
across frequencies, though.

UHD will try to maintain the relative gain setting, or the power level setting.
The choice is determined by which API was called last. If the gain level was set
last (i.e., by either calling `set_tx_gain()` or `set_rx_gain()`), then the gain
level will be kept constant after retuning, but the power level will likely have
changed. If the power reference level was set last (by either calling
`set_rx_power_reference()` or `set_tx_power_reference()`), then UHD will attempt
to maintain a constant power reference level, which means UHD will likely have
to modify the relative gain values. To get the exact power level after a retune,
read back the current power reference level (`get_rx_power_reference()` or
`get_tx_power_reference()`).

The following example shows how the APIs behave for reception. For transmission,
the behaviour is the same (just replace 'rx' with 'tx' in the API calls). Note
that the determination of relative gain or power is retained over retunes is
independent for TX and RX.

~~~{.cpp}
// usrp is a multi_usrp object, f0 and f1 are valid frequencies
usrp->set_rx_frequency(f0);
usrp->set_rx_gain(10);
// This should print '10', or the closest coerced value:
std::cout << usrp->get_rx_gain() << std::endl;
// This can print anything, depending on device and calibration data:
std::cout << usrp->get_rx_power_reference() << std::endl;
usrp->set_rx_frequency(f1);
// This should still print '10', or the closest coerced value:
std::cout << usrp->get_rx_gain() << std::endl;
// This can print anything, and possibly not the same value as before
std::cout << usrp->get_rx_power_reference() << std::endl;
usrp->set_rx_power_reference(-20);
// This should print -20, assuming the device can transmit at that power:
std::cout << usrp->get_rx_power_reference() << std::endl;
// This will print the current gain value, whatever that is
std::cout << usrp->get_rx_gain() << std::endl;
usrp->set_rx_frequency(f0);
// This should still print -20, or the closest coerced value
std::cout << usrp->get_rx_power_reference() << std::endl;
// This will print the current gain value, possibly not the same as before
std::cout << usrp->get_rx_gain() << std::endl;
~~~

\section power_implementation Device Implementations of Power Level APIs

Under the hood, this API call will affect any gain stage that it needs to
affect. It is possible to read back the current gain settings by calling
`get_tx_gain()` or `get_rx_gain()`. However, changing the gain settings by calling
`set_tx_gain()` or `set_rx_gain()` will cause the power level to change.

The specific implementation of this API is very device-specific. Refer to the
individual USRP manual pages for more details.

\section power_storage Calibration Table Storage

UHD needs to store calibration tables to be able to map reference power levels
to settings for the individual gain stages of each USRP and/or daughterboard.
These tables can be stored in three different ways:

- Hard-coded as part of UHD. If a gain table is hard-coded as part of UHD, it
  means that the gain table is considered an average table for a given device.
  Its accuracy may vary a lot, as it is not calibrated to a specific device
  and/or environment.
- In the device EEPROM. By storing calibration data in an EEPROM on the device,
  it is possible to use the same calibration data even when using different host
  computers. Calibration data in EEPROMs can also be updated to account for
  different environments, aging of components, or anything else.
- On a file. Calibration data in a file is the most flexible, it can be replaced
  easily. It is however local to the computer that stores the calibration data.

*/
// vim:ft=doxygen: