OP25 Should a Raspberry Pi Zero be fast enough for OP25?

Status
Not open for further replies.

Papagei

Newbie
Joined
Oct 3, 2018
Messages
72
Hello all!

I am trying to get OP25 running on a Raspberry Pi Zero.

I can get OP25 to run, and I can get the audio piped over the network to my desktop PC so I can hear it. However, I have to turn the sample rate for rx.py way down to get OP25 to detect any transmissions, and even then, it doesn't detect nearly as many transmissions as when running on my desktop PC.

It sort of feels like the Pi Zero is not quite fast enough to run OP25, but I'm not sure that's what's going on.

Is there something else I should tweak or check?

I run the same radio, antenna, antenna location, version of OP25, etc on my desktop PC under Linux and it works just fine.

Hardware:
The radio is from rtl-sdr.com a couple of years ago. It says "DVB-T + DAB + FM + SDR" and "RTL2832U R820T2 TCXO" on the front. The QA sticker is marked 2015-12.

The antenna is a small telescoping whip, about 10 inches long, on a base with about 3 feet of thin co-ax and an SMA connector. It came in a kit with the radio. I put it on the frame of the window in my office, indoors.

The Pi is a "Raspberry Pi Zero 1.3 KN3G", per the bag it came in. (Note it is not a Zero W - it does not have Wi-Fi.)

Storage is a new 16 GB Class 10 MicroSD card, Micro Center brand.

Power is either from a USB wall supply rated at 5 V 1.5 A, or a USB battery bank rated at 5 V 2.1 A, with the same results on both.

The power cable came with the 1.5 A wall supply, and I have used it with that supply to charge an Android tablet several times.

I have an HDMI cable hooked up from the Pi to an Asus monitor.

There is an Adafruit 2991 4-port USB hub connected to the Pi. That supports the RTL-SDR stick and Ethernet adapter. If I am using the Pi console, it also supports a keyboard and mouse.

The USB-to-Ethernet adapter is a J5Create JUE120. Raspbian detects it as "ASIX AX88772B".

The Ethernet runs at 100 megabits from the Pi Zero to a switch, and then at 1 gigabit from the switch to my desktop PC.

Software:
I am using Raspbian "Stretch" from 9 October 2018.
I replaced systemd with sysvinit, using packages offered through the default apt repositories. I have also updated all the other installed packages to the latest versions offered in the default apt repositories. The root filesystem is about 40% full.

I am using boatbod's version of OP25, as cloned from Github in September 2018, plus some modifications of my own.
I run this same version of OP25 on a Linux desktop PC and it works fine for me.

Observations:
python uses 97-98% of the CPU on the Pi Zero when OP25 is running, per top .
It doesn't seem to matter whether it is "scanning", or actively receiving a particular transmission. The CPU usage also doesn't change when I adjust the sampling rate to rx.py .

The CPU speed throttles up to a maximum of 1000 MHz when OP25 is running, per vcgencmd get_config arm_freq .

When I have X up, I don't ever get the "lightning bolt" low-power warning on the screen.

I have used a USB inline multimeter on the Pi Zero power supply. The Pi Zero plus all peripherals except the radio never draws more than approximately 0.55 A. With the radio included, the whole setup never draws more than approximately 0.85 A.

The CPU temperature runs around 47-48 C (116-118 F) at idle, and around 52-53 C (125-127 F) with OP25 running.

Tweaks I have tried:
Turning down the sample rate (-S) argument to rx.py, in steps of 24,000, to between 1,440,000 and 1,920,000 - some improvement, but not much
As I turn it down, "tsbks" count up faster in the OP25 terminal, and it detects more transmissions on various talkgroups. However, the audio quality gets worse to nonexistent. (On my desktop PC, I use 2,400,000.)

Shutting down some of the daemons I don't need, like Bluetooth and DHCP - no change

Running "headless" via SSH, with keyboard and mouse disconnected from the Pi - no change

Shutting off X completely and just running OP25 in a text console over the network - no change

Running with no audio output, just watching the terminal window to see how often OP25 detects a transmission - no change

Using pypy instead of python - no change
I went back to python for further testing.

Updating some of the Python libraries on the PI, including numpy, via pip - no change

Changing the CPU frequency governor from "ondemand" to "performance" - no change

Cloning a fresh copy of OP25 from github (as of 12 Feb 2019), and building it without any of my own changes - no change

Tweaks I have not tried:
Anything involving config.txt on the Pi.
I am still running with the stock config.txt. (Among other things, this sets the CPU speed and overclocking options.)

Moving to Python 3.
OP25 depends on gnuradio, and the default Raspbian repositories supply gnuradio 3.7, which doesn't support Python 3. gnuradio 3.8 does, but I haven't tried building it yet.

Going back to systemd .
I don't really want to do this, but maybe it will make a difference.

Conclusion:

I know people have made OP25 run on a Pi 3. I thought people have made it run on a Pi Zero, but maybe not.

Thanks for your help!
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,316
Location
Talbot Co, MD
The RPi3 prefers low sample rates (certainly well under 1Mhz) and the Pi Zero has a much lower spec cpu. I'd recommend you go as low as you can with the sample rate as long as op25 still functions. Try "-S 57600"
 

Papagei

Newbie
Joined
Oct 3, 2018
Messages
72
I'd recommend you go as low as you can with the sample rate as long as op25 still functions. Try "-S 57600"
That seems to be helping, thanks! I have tried values like 48000 and 96000; OP25 seems to be detecting the right amount of traffic, and I can hear the audio at least intermittently (more below).

I did try turning it down to 24000, and that was the only setting that brings python down to less than 97%-98% CPU usage - it ran around 92% or so. At that setting, OP25 still kind of worked, but I don't think it was detecting all of the transmissions being made, so I have gone back up a little.

I had initially been reluctant to turn the sample rate down that far, because when OP25 starts, this gets printed to standard output before the curses interface comes up...
Code:
linux; GNU C++ version 6.2.0 20161010; Boost_106100; UHD_003.009.005-0-unknown

gain: name: LNA range: start 0 stop 0 step 0
setting gain LNA to 47
supported sample rates 250000-2560000 step 24000
...so I figured that values below 250000 wouldn't work. I do know that values below 250000 cause OP25 to print a line like Invalid sample rate: 24000 Hz to stderr, while values above 250000 don't. But there is a definite difference in how OP25 behaves between -S 24000 and -S 250000 , so I think the option is doing something. Maybe I should just ignore that "supported sample rates" line.

I am now having a slightly different problem. I can get clear audio from OP25, but only for a few seconds at a time. I hear a few seconds of clear audio, a few seconds of silence, a few seconds of clear audio, etc. It doesn't matter whether OP25 is playing through the HDMI audio on the Pi Zero (the only "onboard" audio it has), or over the network.

If I tell OP25 to send audio over the network (using -w -W 192.168.1.2), I can hear it on my desktop PC, but only intermittently. If I use nc -kluvw 1 192.168.1.3 23456 | aplay -c1 -f S16_LE -r 8000 on the desktop, I hear a few seconds of audio, and then it stops until I stop and restart the whole nc | aplay command. If I use audio.py on the desktop, I hear a few seconds of audio, then a pause, then a few more seconds of audio, then a pause, and so on.

Interestingly, if I do nc -kluvw 1 192.168.1.3 23456 >audio.bin on the desktop, let OP25 run for 30-60 seconds (long enough to hear several transmissions), then stop the nc command and do aplay -c1 -f S16_LE -r 8000 <audio.bin on the desktop, all of the audio OP25 heard, from all of the transmissions, plays just fine.

The intermittent audio happens with both the OP25 I cloned from Github a couple of days ago, and with the version I have modified.

This one feels more like a network problem than anything else, but maybe it's CPU again. I intend to keep fiddling with it.

Thanks for your help!
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,316
Location
Talbot Co, MD
Insufficient cpu :(

The choppy audio happens because samples are not being decoded fast enough to keep the pcm buffer full in real time. By delaying the playback you are catching more data in the buffer before it has to be sent to aplay in real time.
 

Papagei

Newbie
Joined
Oct 3, 2018
Messages
72
Insufficient cpu :(
Well, poop. At least I know it for sure, now.

Can OP25 give me any numbers that will tell me how short of CPU I am?

If I'm only a few percent short of what I need, I'll try things that cost me time, but not money: overclocking the Pi Zero, or playing with the Linux kernel's scheduler, or maybe building my own kernel, or switching distros. (I have Arch mostly installed on another micro SD card; it has a very slightly newer kernel than Raspbian, and seems to have fewer daemons running by default.)

If I'm short by (say) 50% or more, then I need a different board, which means I get to spend money.

Thanks!
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,316
Location
Talbot Co, MD
Well, poop. At least I know it for sure, now.

Can OP25 give me any numbers that will tell me how short of CPU I am?

If I'm only a few percent short of what I need, I'll try things that cost me time, but not money: overclocking the Pi Zero, or playing with the Linux kernel's scheduler, or maybe building my own kernel, or switching distros. (I have Arch mostly installed on another micro SD card; it has a very slightly newer kernel than Raspbian, and seems to have fewer daemons running by default.)

If I'm short by (say) 50% or more, then I need a different board, which means I get to spend money.

Thanks!
Not really. 'top' and other utilities are just going to say you're at 100%.

Presumably you're not trying to run any gnuplots as they are very cpu hungry.
 

KA1RBI

Member
Joined
Aug 15, 2008
Messages
799
Location
Portage Escarpment
any numbers that will tell me how short of CPU I am?

I'd like to see a "top -H" from your system...

First determine the PID of the python process (perhaps using "ps ax") then with the PID (example 12345) do
top -H -p 12345
then with the "top" window displayed hit the "t" key if necessary to get the lines sorted by processor time. For best results allow a minute or so for the numbers to settle...

Please post the result as well as a copy of the stderr messages...

Max
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,316
Location
Talbot Co, MD
I'd like to see a "top -H" from your system...

First determine the PID of the python process (perhaps using "ps ax") then with the PID (example 12345) do
top -H -p 12345
then with the "top" window displayed hit the "t" key if necessary to get the lines sorted by processor time. For best results allow a minute or so for the numbers to settle...

Please post the result as well as a copy of the stderr messages...

Max
When you capture the numbers you really want two sets od data:- one with voice decode in process and one with it idle on the control channel.
 

Papagei

Newbie
Joined
Oct 3, 2018
Messages
72
Presumably you're not trying to run any gnuplots as they are very cpu hungry.
Correct. This was all with X totally shut off, and OP25 just running either on the text console or via SSH, so no gnuplots were active.

I'd like to see a "top -H" from your system...
When you capture the numbers you really want two sets od data:- one with voice decode in process and one with it idle on the control channel.
Here we go. I forgot to get stderr, though. :(

The idle ones were easy to get; I just put one talkgroup that doesn't talk very often in the whitelist, and ran top for about 75 seconds, with a 3-second update interval. For the ones with decoding happening, I waited until an EMT was giving a patient report (because they tend to stay keyed up for a while), pushed H to hold OP25 on that channel, ran top for several iterations on a 3-second update interval, and then canceled top when the transmission ended. The data I have posted here are from when I am pretty sure a voice decode was still happening.

The OP25 command line for all of these was ./rx.py --args 'rtl' -N 'LNA:47' -S 48000 -f 856.7375e6 -o 25000 -q -2 -T trunk.tsv -V -2 -w -W 192.168.1.3 >/tmp/scanner_stderr. The top command line was similar to top -b -n 25 -H -p 12345 >top.txt, with 12345 replaced by the PID of the main Python process.

I ran rx.py as a regular user on one virtual console, and top as root on another virtual console.

This was with unmodified boatbod OP25, as cloned from github on 13 Feb 2019. It is running on Raspbian 9, as updated (apt-get update) earlier today, 14 March 2019. uname -a says Linux raspberrypi 4.14.98+ #1200 Tue Feb 12 20:11:02 GMT 2019 armv6l GNU/Linux.

Stock OP25 at idle:
Code:
top - 20:46:48 up 52 min,  3 users,  load average: 2.50, 2.15, 1.91
Threads:  22 total,   4 running,  18 sleeping,   0 stopped,   0 zombie
%Cpu(s): 82.8 us, 17.2 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   443844 total,    10104 free,    82544 used,   351196 buff/cache
KiB Swap:   102396 total,   101884 free,      512 used.   348952 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 2764 pi        20   0  352444  95936  45488 R 15.8 21.6   0:19.02 fir_filter_ccc1
 2762 pi        20   0  352444  95936  45488 S 10.6 21.6   0:11.18 rtl_source_c2
 2765 pi        20   0  352444  95936  45488 R  8.6 21.6   0:10.16 multiply_cc12
 2767 pi        20   0  352444  95936  45488 S  8.3 21.6   0:09.59 pfb_arb_resamp1
 2770 pi        20   0  352444  95936  45488 S  7.6 21.6   0:09.07 gardner_costas1
 2763 pi        20   0  352444  95936  45488 S  6.3 21.6   0:07.42 fix_cc4
 2769 pi        20   0  352444  95936  45488 S  5.3 21.6   0:06.15 feedforward_ag2
 2768 pi        20   0  352444  95936  45488 S  4.6 21.6   0:05.58 fir_filter_ccf1
 2766 pi        20   0  352444  95936  45488 S  3.3 21.6   0:03.77 fir_filter_ccf1
 2776 pi        20   0  352444  95936  45488 S  3.3 21.6   0:03.94 python
 2758 pi        20   0  352444  95936  45488 S  3.0 21.6   0:03.47 python
 2759 pi        20   0  352444  95936  45488 S  2.6 21.6   0:03.13 python
 2761 pi        20   0  352444  95936  45488 S  2.3 21.6   0:02.66 sig_source_c15
 2771 pi        20   0  352444  95936  45488 S  2.3 21.6   0:02.45 diff_phasor_cc2
 2775 pi        20   0  352444  95936  45488 R  2.3 21.6   0:02.72 p25_frame_asse2
 2772 pi        20   0  352444  95936  45488 S  2.0 21.6   0:02.51 complex_to_arg2
 2774 pi        20   0  352444  95936  45488 R  2.0 21.6   0:02.33 fsk4_slicer_fb1
 2777 pi        20   0  352444  95936  45488 S  2.0 21.6   0:02.65 optimize_c3
 2773 pi        20   0  352444  95936  45488 S  1.7 21.6   0:02.30 multiply_const2
 2760 pi        20   0  352444  95936  45488 S  1.3 21.6   0:01.19 python
 2744 pi        20   0  352444  95936  45488 S  0.0 21.6   0:07.61 python
 2757 pi        20   0  352444  95936  45488 S  0.0 21.6   0:00.00 python

Sorting by the most popular threads, over the entire time top was running - the two numbers are the minimum and maximum %CPU reported by top for that thread:
Code:
fir_filter_ccc1 10.5 17.5
rtl_source_c2    5.3 11.5
rtl_source_c2    5.3 11.5
optimize_c3      1.6 10.5
multiply_cc12    5.3 9.5
pfb_arb_resamp1  5.3 8.9
gardner_costas1  5.3 8.6
fix_cc4          5.3 7.0
feedforward_ag2  5.2 5.6
sig_source_c15   2.0 5.3
python           0.0 5.3
fsk4_slicer_fb1  1.6 5.3
fir_filter_ccf1  3.0 5.3
fir_filter_ccf1  3.0 5.3
p25_frame_asse2  0.0 2.6
complex_to_arg2  0.0 2.6
multiply_const2  0.0 2.3
diff_phasor_cc2  0.0 2.3

Stock OP25 while receiving:
Code:
top - 20:56:48 up  1:02,  3 users,  load average: 3.05, 3.15, 2.58
Threads:  22 total,   3 running,  19 sleeping,   0 stopped,   0 zombie
%Cpu(s): 96.7 us,  3.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   443844 total,     9412 free,    82436 used,   351996 buff/cache
KiB Swap:   102396 total,   101884 free,      512 used.   349052 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 2834 pi        20   0  351428  97008  46344 R 80.9 21.9   1:07.24 p25_frame_asse2
 2817 pi        20   0  351428  97008  46344 S  6.6 21.9   0:10.57 python
 2818 pi        20   0  351428  97008  46344 R  5.3 21.9   0:25.59 python
 2819 pi        20   0  351428  97008  46344 S  4.0 21.9   0:20.92 python
 2836 pi        20   0  351428  97008  46344 R  3.6 21.9   0:19.27 python
 2808 pi        20   0  351428  97008  46344 S  0.3 21.9   0:07.82 python
 2816 pi        20   0  351428  97008  46344 S  0.0 21.9   0:00.00 python
 2820 pi        20   0  351428  97008  46344 S  0.0 21.9   0:11.08 sig_source_c15
 2821 pi        20   0  351428  97008  46344 S  0.0 21.9   0:43.60 rtl_source_c2
 2822 pi        20   0  351428  97008  46344 S  0.0 21.9   0:30.44 fix_cc4
 2823 pi        20   0  351428  97008  46344 S  0.0 21.9   1:18.80 fir_filter_ccc1
 2824 pi        20   0  351428  97008  46344 S  0.0 21.9   0:43.33 multiply_cc12
 2825 pi        20   0  351428  97008  46344 S  0.0 21.9   0:15.51 fir_filter_ccf1
 2826 pi        20   0  351428  97008  46344 S  0.0 21.9   0:38.03 pfb_arb_resamp1
 2827 pi        20   0  351428  97008  46344 S  0.0 21.9   0:23.73 fir_filter_ccf1
 2828 pi        20   0  351428  97008  46344 S  0.0 21.9   0:25.52 feedforward_ag2
 2829 pi        20   0  351428  97008  46344 S  0.0 21.9   0:36.28 gardner_costas1
 2830 pi        20   0  351428  97008  46344 S  0.0 21.9   0:09.98 diff_phasor_cc2
 2831 pi        20   0  351428  97008  46344 S  0.0 21.9   0:10.08 complex_to_arg2
 2832 pi        20   0  351428  97008  46344 S  0.0 21.9   0:08.52 multiply_const2
 2833 pi        20   0  351428  97008  46344 S  0.0 21.9   0:07.37 fsk4_slicer_fb1
 2835 pi        20   0  351428  97008  46344 S  0.0 21.9   0:10.98 optimize_c3

Sorting by the most popular threads, over the entire time top was running:
Code:
p25_frame_asse2 10.0 80.9
fir_filter_ccc1  0.0 16.4
python           0.0 10.0
fix_cc4          0.0 10.0
rtl_source_c2    0.0 9.2
rtl_source_c2    0.0 9.2
multiply_cc12    0.0 9.2
pfb_arb_resamp1  0.0 7.9
gardner_costas1  0.0 7.2
fir_filter_ccf1  0.0 5.0
fir_filter_ccf1  0.0 5.0
feedforward_ag2  0.0 5.0
sig_source_c15   0.0 2.3
optimize_c3      0.0 2.3
complex_to_arg2  0.0 2.3
multiply_const2  0.0 2.0
diff_phasor_cc2  0.0 2.0
fsk4_slicer_fb1  0.0 1.6

In other news, I gave up on trying to make OP25 run under Arch on the Pi Zero. Arch offers some prebuilt packages for gnuradio and osmocom, but when you put them all together, they don't seem to be quite what OP25 needs. I could have probably fixed it by installing everything from source, but I decided not to do that.

Thanks for your help!
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,316
Location
Talbot Co, MD
From memory, Arch has issues with cmake version, but if you drop back to an earlier one it works ok.

Can't say I've ever seen rtl_source_c2 show up in a top listing before; it suggests to me that USB transfers are a bottleneck on the PiZ, which isn't surprising since we know that sample size is a big factor affecting cpu utilization on the Pi3b. Also, p25_frame_assembler_impl is the thread that hosts the audio codec, so it's quite expected for that to be the highest utilization when audio decoding is taking place.
 

KA1RBI

Member
Joined
Aug 15, 2008
Messages
799
Location
Portage Escarpment
For improving the "idle" case there may not be a lot of low-hanging fruit - but the voice decode does seem to show some CPU hogging.

I haven't done detailed benchmarking but it's possible the OP25 fixed point codec might help the situation (or might not).

To enable the fixed point codec locate and comment out the following line in rx.py

Code:
os.environ['IMBE'] = 'soft'

To comment out the line add a "#" (hash mark) at the front of the line

Code:
#os.environ['IMBE'] = 'soft'

This is only effective for P25 Phase I...

Max
 
Status
Not open for further replies.
Top