When I started using GNU Radio Companion (GRC) to develop Nutaq demonstration projects, I found it to be a fast and easy to use development environment. In GRC you can use a few user-input widgets to implement a signal monitoring GUI in just a few minutes. However, I thought that the data flow was mostly linear: source blocks connected to processing blocks connected to sinks blocks without any feedback mechanisms. Yes, the user could look at the GUI time/FFT scopes and dynamically change the project’s parameters, but this kind of feedback limited the range of possible applications.
If I wrote my application directly in Python, I could use any kind of feedbacks or algorithms I wanted, but I like the model-based approach of GRC. The GRC approach lets you easily understand a design in just a few minutes (instead of reading hundreds of lines of code and trying to connect the dots to see the big picture).
Another approach would be to develop my own custom blocks that performed more complex algorithms or integrated state machines into my data flow1. This approach is more appealing but lines of code still need to be written and the resulting GRC graph won’t be self-explanatory.
Recently, I found out about the existence of probe blocks in the Measurement Tools module2. With these blocks, streams can be converted into variables. And, once you have access to the variables, you can use algorithms and mathematical operations to apply feedback to the project parameters – exactly what I was looking for!
Figure 1: Probe Signal block
The Probe Signal block converts a data stream into a variable. To access the current stream values, the level function must be called. The function is asynchronous to the data flow; it can only monitor the current value of the data flow, not every sample of it. Other blocks like the Probe Signal Vector and Probe Rate are available to respectively poll a vector stream value and the average throughput of a stream.
In a Python project, the Probe Signal Ievel function needs to be executed to acquire the current value:
val = self.probe.level()
Since this function cannot be called directly in a GRC project, the Function Probe block needs to be used.
Figure 2: Function Probe block
The Function Probe block can be used to call another block function at a specified rate. Figure 2 shows a configuration that calls the level function of the probe block 100 times each second and stores the returned value in the variable cos_ampl. The Value parameter is the default value of the cos_ampl variable before the first function call. The variable is accessible by the other blocks and can be used as a dynamic input parameter.
Stream probing example
Figure 3: Basic project using probe blocks
Figure 3 shows a simple project built with the Probe Signal and Function Probe blocks. A triangle signal source is probed with the Probe Signal block. The Function Probe blocks read the current triangle waveform values and stores it into the cos_ampl variable. The cos_ampl variable is used as the dynamic input parameter in the Amplitude property of the cosine Signal Source block.
As the triangle waveform changes value, the Function Probe block will poll the value 100 times each second and update the cosine waveform amplitude. The following video shows the running project and proves that the probe block behavior matches the expected one.