Difference between revisions of "UHD Python API"
MartinBraun (Talk | contribs) |
MartinBraun (Talk | contribs) (→FAQ) |
||
(10 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
== What's the UHD Python API? == | == What's the UHD Python API? == | ||
− | As the name suggests, it exposes the UHD API into Python. We use | + | As the name suggests, it exposes the UHD API into Python. We use <code>pybind11</code> |
to generate a Python module which exposes most of the C++ API, and some extra | to generate a Python module which exposes most of the C++ API, and some extra | ||
− | features. | + | features. The Python API is part of stable releases. |
− | |||
− | |||
− | |||
− | The | + | The USRP Hardware Driver and USRP Manual covers most information about the UHD Python API and can be found here: https://files.ettus.com/manual/page_python.html |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | API | + | |
− | + | ||
− | + | ||
− | https:// | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
== How can I use it? == | == How can I use it? == | ||
− | In order to test the Python API, check out the | + | In order to test the Python API, check out the <code>master</code> branch and build it like always. When running CMake, make sure that the Python API was enabled (<code>-DENABLE_PYTHON_API=ON</code>). |
− | + | ||
− | + | ||
The output from CMake should look something like this: | The output from CMake should look something like this: | ||
Line 97: | Line 44: | ||
</pre> | </pre> | ||
− | Once it's built and installed, you'll be able to import the | + | Please refer to the [https://files.ettus.com/manual/page_python.html USRP Manual] for extended instructions especially when installing on Windows. |
− | module | + | Once it's built and installed, you'll be able to import the <code>uhd</code> Python |
+ | module. | ||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
Line 106: | Line 54: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | We have some examples in | + | We have some examples in <code>[https://github.com/EttusResearch/uhd/tree/master/host/examples/python host/examples/python]</code>. The examples are very |
simple, but concise. | simple, but concise. | ||
+ | |||
+ | ==Example: pyuhd_rx_to_file.py== | ||
+ | This Python example is based on the C++ example <code>uhd/host/examples/rx_samples_to_file.cpp</code>. | ||
+ | |||
+ | <syntaxhighlight lang="python"> | ||
+ | import uhd | ||
+ | import numpy as np | ||
+ | import argparse | ||
+ | |||
+ | def parse_args(): | ||
+ | parser = argparse.ArgumentParser() | ||
+ | parser.add_argument("-a", "--args", default="", type=str) | ||
+ | parser.add_argument("-o", "--output-file", type=str, required=True) | ||
+ | parser.add_argument("-f", "--freq", type=float, required=True) | ||
+ | parser.add_argument("-r", "--rate", default=1e6, type=float) | ||
+ | parser.add_argument("-d", "--duration", default=5.0, type=float) | ||
+ | parser.add_argument("-c", "--channels", default=0, nargs="+", type=int) | ||
+ | parser.add_argument("-g", "--gain", type=int, default=10) | ||
+ | return parser.parse_args() | ||
+ | |||
+ | def main(): | ||
+ | args = parse_args() | ||
+ | usrp = uhd.usrp.MultiUSRP(args.args) | ||
+ | num_samps = int(np.ceil(args.duration*args.rate)) | ||
+ | if not isinstance(args.channels, list): | ||
+ | args.channels = [args.channels] | ||
+ | samps = usrp.recv_num_samps(num_samps, args.freq, args.rate, args.channels, args.gain) | ||
+ | with open(args.output_file, 'wb') as f: | ||
+ | np.save(f, samps, allow_pickle=False, fix_imports=False) | ||
+ | |||
+ | if __name__ == "__main__": | ||
+ | main() | ||
+ | </syntaxhighlight> | ||
== What about documentation? == | == What about documentation? == | ||
Line 113: | Line 94: | ||
Documentation is currently pretty sparse. The best we can do right now is to ask | Documentation is currently pretty sparse. The best we can do right now is to ask | ||
users to infer the documentation from the C++ API. For example, the Python has | users to infer the documentation from the C++ API. For example, the Python has | ||
− | an object called | + | an object called <code>MultiUSRP</code> which is an equivalent of the C++ <code>multi_usrp</code> API. |
The methods on both classes are the same, and take the same arguments. | The methods on both classes are the same, and take the same arguments. | ||
+ | |||
+ | ==FAQ== | ||
+ | '''Does it support Python 2 and 3?''' | ||
+ | |||
+ | Starting with UHD 4, Python 2 support has been removed. | ||
+ | |||
+ | '''Does it require GNU Radio?''' | ||
+ | |||
+ | No. | ||
+ | |||
+ | '''Does it use SWIG?''' | ||
+ | |||
+ | No, it uses <code>pybind11</code>. It also doesn't require the C API. Pybind11 is vendored with UHD so as to not require installing another dependency. | ||
+ | |||
+ | '''How does this relate to the Python API in gr-uhd?''' | ||
+ | |||
+ | It serves an entirely different purpose. This Python API is for people writing standalone applications for USRPs that *don't* use GNU Radio. <code>gr-uhd</code> is staying the way it is, and is going nowhere. If you're using GNU Radio, you probably don't care about this. | ||
+ | |||
+ | '''Are the UHD Python API and the gr-uhd Python API compatible?''' | ||
+ | |||
+ | Short answer: No. Long answer: There are very few cases where it makes sense to mix these APIs, so no. However, this means that a <code>TimeSpec</code> from the <code>Boost.Python</code> API is not convertible into a <code>time_spec_t</code> from the <code>gr-uhd</code> API. | ||
+ | |||
+ | |||
+ | '''Does it support RFNoC API?''' | ||
+ | |||
+ | For sure! | ||
+ | |||
+ | '''What's the streaming performance?''' | ||
+ | |||
+ | Worse than straight C++, but not a lot, thanks to NumPy. You can run <code>host/examples/benchmark_rate.py</code> if you want to see for yourself. | ||
+ | Overall, <code>recv()</code> calls are pretty efficient if you've pre-allocated a NumPy array, because we can cast that to a straight pointer (and also skip any type checking!) and then it's not that different from a <code>recv()</code> call in a C++ app. However, consuming the data is limited by how fast you can handle that in Python. |
Latest revision as of 02:59, 10 February 2022
Contents
What's the UHD Python API?
As the name suggests, it exposes the UHD API into Python. We use pybind11
to generate a Python module which exposes most of the C++ API, and some extra
features. The Python API is part of stable releases.
The USRP Hardware Driver and USRP Manual covers most information about the UHD Python API and can be found here: https://files.ettus.com/manual/page_python.html
How can I use it?
In order to test the Python API, check out the master
branch and build it like always. When running CMake, make sure that the Python API was enabled (-DENABLE_PYTHON_API=ON
).
The output from CMake should look something like this:
-- ###################################################### -- # UHD enabled components -- ###################################################### -- * LibUHD -- * LibUHD - C API -- * LibUHD - Python API -- * Examples -- * Utils -- * Tests -- * USB -- * B100 -- * B200 -- * USRP1 -- * USRP2 -- * X300 -- * N230 -- * OctoClock -- * Manual -- * API/Doxygen -- * Man Pages -- -- ###################################################### -- # UHD disabled components -- ###################################################### -- * GPSD -- * E100 -- * E300
Please refer to the USRP Manual for extended instructions especially when installing on Windows.
Once it's built and installed, you'll be able to import the uhd
Python
module.
>>> import uhd
>>> my_usrp = uhd.usrp.MultiUSRP("type=b200")
>>> my_usrp.set_rx_gain(70)
We have some examples in host/examples/python
. The examples are very
simple, but concise.
Example: pyuhd_rx_to_file.py
This Python example is based on the C++ example uhd/host/examples/rx_samples_to_file.cpp
.
import uhd
import numpy as np
import argparse
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--args", default="", type=str)
parser.add_argument("-o", "--output-file", type=str, required=True)
parser.add_argument("-f", "--freq", type=float, required=True)
parser.add_argument("-r", "--rate", default=1e6, type=float)
parser.add_argument("-d", "--duration", default=5.0, type=float)
parser.add_argument("-c", "--channels", default=0, nargs="+", type=int)
parser.add_argument("-g", "--gain", type=int, default=10)
return parser.parse_args()
def main():
args = parse_args()
usrp = uhd.usrp.MultiUSRP(args.args)
num_samps = int(np.ceil(args.duration*args.rate))
if not isinstance(args.channels, list):
args.channels = [args.channels]
samps = usrp.recv_num_samps(num_samps, args.freq, args.rate, args.channels, args.gain)
with open(args.output_file, 'wb') as f:
np.save(f, samps, allow_pickle=False, fix_imports=False)
if __name__ == "__main__":
main()
What about documentation?
Documentation is currently pretty sparse. The best we can do right now is to ask
users to infer the documentation from the C++ API. For example, the Python has
an object called MultiUSRP
which is an equivalent of the C++ multi_usrp
API.
The methods on both classes are the same, and take the same arguments.
FAQ
Does it support Python 2 and 3?
Starting with UHD 4, Python 2 support has been removed.
Does it require GNU Radio?
No.
Does it use SWIG?
No, it uses pybind11
. It also doesn't require the C API. Pybind11 is vendored with UHD so as to not require installing another dependency.
How does this relate to the Python API in gr-uhd?
It serves an entirely different purpose. This Python API is for people writing standalone applications for USRPs that *don't* use GNU Radio. gr-uhd
is staying the way it is, and is going nowhere. If you're using GNU Radio, you probably don't care about this.
Are the UHD Python API and the gr-uhd Python API compatible?
Short answer: No. Long answer: There are very few cases where it makes sense to mix these APIs, so no. However, this means that a TimeSpec
from the Boost.Python
API is not convertible into a time_spec_t
from the gr-uhd
API.
Does it support RFNoC API?
For sure!
What's the streaming performance?
Worse than straight C++, but not a lot, thanks to NumPy. You can run host/examples/benchmark_rate.py
if you want to see for yourself.
Overall, recv()
calls are pretty efficient if you've pre-allocated a NumPy array, because we can cast that to a straight pointer (and also skip any type checking!) and then it's not that different from a recv()
call in a C++ app. However, consuming the data is limited by how fast you can handle that in Python.