Scientific Computing

GNU Radio for Windows Subsystem for Linux

Graphics and sound generally work via X Windows or Wayland in Windows Subsystem for Linux WSL. Networked SDRs (connected to computer via Ethernet) and simulations can work with GNU Radio and GNU Radio Companion on WSL. USB (non-networked) SDRs may or may not work–need an SDR hardware-specific USB to network driver from Windows and additional configuration at best.

Install and run GNU Radio Companion:

apt install gnuradio

gnuradio-companion

Troubleshooting

“ValueError: Namespace Gtk not available” can be fixed by:

apt install python3-gi gobject-introspection gir1.2-gtk-3.0

Despite apt install python3-pyqt5 this may help:

python3 -m pip install pyqt5

GNU radio ImportError fixes

GNU Octave font size fix

If GNU Octave plot fonts are too small or the lines are too thin in GNU Octave plotting, typically the first of these methods will be adequate, the others are for reference.

Octave has multiple graphics “toolkits” or “backends”, and prefers QT. If you don’t want the graphical IDE, start Octave with octave -no-gui instead of octave-cli. Using octave-cli disables the QT backend.

Default plot settings are for qt backend. Avoid setting font sizes in the program itself. Tweaking plots for a aparticular computer display may reduce plot fidelity on other computers with different displays.

The “correct” way to scale plot fonts is thus to change your system defaults. Add this to ~/.octaverc instead of ~/Documents/MATLAB/startup.m so that you don’t disturb Matlab’s plotting defaults.

set(0, "defaulttextfontsize", 24)  % title
set(0, "defaultaxesfontsize", 16)  % axes labels

set(0, "defaulttextfontname", "Courier")
set(0, "defaultaxesfontname", "Courier")

set(0, "defaultlinelinewidth", 2)

adjust 16 to produce the most appealing text labels in:

  • axes tick labels
  • legend key
  • title text

defaultline is the root category for lines, so defaultlinelinewidth is not a typo.


The alternative methods below are not normally needed, but are for reference. PPI adjustments: find your PPI by Internet search or spec sheet. Octave’s PPI estimate is:

get(0, 'screenpixelsperinch')

If Octave’s PPI estimate is too small, this is probably why your plot text is too small–Octave thinks your resolution is much less than it really is.

If still a font size problem, try changing system DPI scaling. On Ubuntu, try Gnome Tweak Tool → Fonts → Scaling Factor Octave GUI settings:

  • → General → Interface → Icon Size: large
  • → Editor Styles → Octave: default
  • → Terminal → Font Size

You can also try changing the graphics toolkit. Usually Qt is the best and most modern.

Octave graphics toolkits available:

available_graphics_toolkits()

Active graphics toolkit:

graphics_toolkit()

Select graphics toolkit to see if font sizes are better. Be sure to open a new figure when trying different graphics toolkits.

Reference: GNU Octave default settings docs


Related: GNU Octave set defaults

Keep program running after disconnect

Screen is a terminal multiplexer program. Screen allows programs to continue running after a remote user disconnects. If a remote connection is lost unintentionally, screen may not allow reconnection by default by the usual

screen -list

screen -r <id>

normally allows reconnecting to a remote session after logging off. When a connection is lost before disconnecting from screen, you may need the “-x” option:

screen -x <id>

A downside of screen is the difficulty scrolling back in history.

Screen is a terminal multiplexer, and some prefer tmux over screen. Another option is using nohup.

CMake FetchContent vs. ExternalProject

Multiple subprojects can be invoked from a top-level superprojects with build systems such as CMake or Meson:

CMake FetchContent and ExternalProject can download subprojects, or the subproject can be included in the top-level project via Git submodule or monorepo approach. This subproject hierarchy works like any other CMake project from the command line or IDEs like Visual Studio.

Meson subproject and CMake ExternalProject keep project namespaces separate. Meson subproject and CMake FetchContent download and configure all projects at configure time. CMake FetchContent comingles the CMake project namespaces. FetchContent can be easier to use than ExternalProject if you control both software projects’ CMake scripts. If you don’t control the “child” project, it may be better to use ExternalProject instead of FetchContent.

For these examples, suppose we have a top-level project “parent” and a “child” project containing a library that is desired in parent. Suppose the child project can be built standalone (by itself) but also may be used directly from other CMake projects.

project CMAKE_SOURCE_DIR CMAKE_BINARY_DIR PROJECT_SOURCE_DIR
parent ~/foo ~/foo/build ~/foo
child: standalone ~/bar ~/bar/build ~/bar
child: CMake ExternalProject ~/foo/build/child-prefix/src/child ~/foo/build/child-prefix/src/child-build ~/foo/build/child-prefix/src/child
child: CMake FetchContent ~/foo ~/foo/build ~/foo/build/_deps/child-src

FetchContent populates content from the other project at configure time. FetchContent populates the “child” project with default values from the “parent” project. Varibles set in the “child” project generally do not affect the “parent” project unless specifically used from the “parent” project. CMAKE_ARGS and CMAKE_CACHE_ARGS have no effect with FetchContent_Declare. To set a value in the child project from the parent project, set variables in the parent project.

From “parent” project CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project(parent Fortran)

include(FetchContent)
FetchContent_Declare(child
  URL https://github.invalid/username/archive.tar.bz2
)
# it's much better to use a specific Git revision or Git tag for reproducibility

FetchContent_MakeAvailable(child)

# your program
add_executable(myprog main.f90)
target_link_libraries(myprog mylib)  # mylib is from "child"
FetchContent_MakeAvailable
make “child” code configure, populating variables and targets as if it were part of “parent” CMake project.

suppose “child” project CMakeLists.txt contains:

project(child LANGUAGES Fortran)

include(GNUInstallDirs)

add_library(mylib mylib.f90)

target_include_libraries(mylib INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR})

set_property(TARGET mylib PROPERTY Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR})

The child project CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR will be those of parent project. That is, if the parent project is in ~/foo and the build directory is ~/foo/build, then the child project in ~/childcode called by FetchContent will also have CMAKE_SOURCE_DIR of ~/foo and CMAKE_BINARY_DIR of ~/foo/build. So be careful in the child project when using such variables that may be defined by parent projects. This is why projects that aren’t specifically designed to work together may be better joined by ExternalProject. A typical technique within the child project that can operate standalone is to refer to CMAKE_CURRENT_SOURCE_DIR instead of CMAKE_SOURCE_DIR as the latter will break when used from FetchContent.

IMPORTANT: When using if() clauses to determine execution of FetchContent, ensure that the FetchContent stanzas are executed each time CMake is run. Otherwise, the FetchContent targets may fail to be available or may have missing target properties on CMake rebuild.

ExternalProject populates content from the other project at build time. This means the other project’s libraries are not visible until the parent project is built. Since ExternalProject does not combine the project namespaces, ExternalProject may be necessary if you don’t control the other projects.

ExternalProject may not activate without the add_dependencies() statement. Upon cmake --build of the parent project, ExternalProject downloads, configures and builds.

From “parent” project CMakeLists.txt:

project(parent LANGUAGES Fortran)

include(GNUInstallDirs)
include(ExternalProject)

set(mylist "a;b;c")
# passing a list to external project is best done via CMAKE_CACHE_ARGS
# CMAKE_ARGS doesn't work correctly for lists

set_property(DIRECTORY PROPERTY EP_UPDATE_DISCONNECTED true)
# don't repeatedly build ExternalProjects.
# dir prop scope: CMake_current_source_dir and subdirectories

ExternalProject_Add(CHILD
GIT_REPOSITORY https://github.com/scivision/cmake-externalproject
GIT_TAG main
CMAKE_ARGS --install-prefix=${CMAKE_INSTALL_PREFIX}
CMAKE_CACHE_ARGS -Dmyvar:STRING=${mylist}   # need variable type e.g. STRING for this
CONFIGURE_HANDLED_BY_BUILD ON
BUILD_BYPRODUCTS ${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}timestwo${CMAKE_STATIC_LIBRARY_SUFFIX}
)

add_library(timestwo STATIC IMPORTED GLOBAL)
set_property(TARGET timestwo PROPERTY IMPORTED_LOCATION ${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}timestwo${CMAKE_STATIC_LIBRARY_SUFFIX})
set_property(TARGET timestwo PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_INSTALL_FULL_INCLUDEDIR})

add_executable(test_timestwo test_timestwo.f90)  # your program
add_dependencies(test_timestwo CHILD)  # externalproject won't download without this
target_link_libraries(test_timestwo PRIVATE timestwo)
add_dependencies()
make ExternalProject always update and build first
CONFIGURE_HANDLED_BY_BUILD ON
tells CMake not to reconfigure each build, unless the build system requests configure
BUILD_BYPRODUCTS
necessary for Ninja to avoid “ninja: error: “lib” needed by “target”, missing and no known rule to make it”. Note how we can’t use BINARY_DIR since it’s populated by ExternalProject_Get_Property()

The imported library ext is used in the “parent” project just like any other library.


“child” project CMakeLists.txt includes:

project(child Fortran)

include(GNUInstallDirs)

add_library(timestwo STATIC timestwo.f90)
set_property(TARGET timestwo PROPERTY Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR})

Configure “child” Fortran_MODULE_DIRECTORY so that it’s not necessary for “parent” to introspect “child” directory structure.

We have created live ExternalProject examples:


CMake can detect if a project is “top level” that is, NOT via FetchContent using PROJECT_IS_TOP_LEVEL.


target_link_directories() is generally NOT preferred because library name collisions can occur, particularly with system libraries.


Reference: CMake staff comparison of multiple project with CMake

ARRL LoTW recent users list

The ARRL Logbook of the World (LoTW) provides a weekly list of recent users in CSV format. This list is used by other services such as PSK Reporter to show recent users of LoTW with an “L” icon. Note that the callsign is for the current holder of the LoTW account, not necessarily the original licensee.

Diagnose CTest failures from logs

CTest automatically logs test outputs to:

${CMAKE_BINARY_DIR}/Testing/Temporary/LastTest.log

If you have a test failure and want to diagnose, first copy this file somewhere else to work with it, in case it gets overwritten. This file is usually quite useful with nice formatting even when running many tests in parallel.

A simple list of all “failed” and “not run” tests are in:

${CMAKE_BINARY_DIR}/Testing/Temporary/LastTestsFailed.log

“Not run” tests are those that have FIXTURES_REQUIRED that itself failed or did not run.

At the time of running CTest, one can also use the -O option like:

ctest -O test.log

“ctest -O” only logs what is printed to the screen during the CTest run. If the “ctest -V” option wasn’t used, the extra useful information as in LastTest.log such as the command line run will be missing in “test.log”.

Rename and cleanup conda Python environment

Rename Python conda environment “old” to “new” by copying the environment and deleting the original environment:

conda create --name new --clone old

conda remove --name old --all

Each Miniconda/Anaconda environment consumes disk space. One may wish to delete old, unused conda environments to free disk space. Conda environment disk size can be checked by listing all environment paths

conda env list

This will show entries like:

py37 ~/miniconda3/envs/py37

Print the disk size of a conda environment:

  • Linux / macOS: du -sh ~/miniconda3/envs/py37
  • Windows: dir miniconda3/envs/py37

Linux control groups tips

Linux control groups can limit any user’s CPU, memory or other resource usage. Control groups can be used to test program behavior under constrained resources. Control groups v2 are recommended in general with a new architecture and better performance. By default with RHEL 8, we need to enable cgroups-v2.

Although setting up persistent control groups is straightforward, it’s possible to create a transient commend line initiated control group using systemd-run. This use can be good for diagnosing program behavior–for example, does a program’s memory use blow up then come down faster than “top” might show. An example use constraining a program to 2 GB of RAM is like:

systemd-run --scope -p MemoryMax=2G -p MemorySwapMax=0 ./my_program

The flag --user did not work–we needed to type the sudo password despite running as the standard user.

Another way to set hardware/firmware-based limits for more intensive benchmarks is to simply use a device with less RAM, edit BIOS/UEFI to only enable a limited amount of RAM, or on Linux use GRUB kernel mem= parameter to constrain the available RAM. Ensure the swap/paging file is turned off.

Clean delete untracked files from Git repo.

Sometimes files are accidentally spilled into a Git repo. Before the files are git add, they are “untracked”. If the files match a pattern in “.gitignore” they will not appear in Git operations generally. Untracked, non-ignored files show with:

git status --porcelain

like

?? oops.txt

where the question marks indicate the file is untracked.

These files may be interactively removed (deleted) by:

git clean -id

When there are files spilled in multiple directories, the “filter by pattern” options lets you select files to retain. The updated display shows files to be deleted. When satisfied, select “Clean”–there’s no recovering those files trivially, so be sure of your choices.

To clean files matching patterns in .gitignore, add the “-x” option like:

git clean -xid

That’s useful for cleaning up in source builds, perhaps from Makefile or LaTeX.