Hi Patric,
first off, the `consume_each` call needs to go behind any read on the
input buffer. You really tell the system at this point: I'm finally done
with these items, do whatever. Since GR is a multi-threaded system, this
may cause trouble because the samples you want to read are already
overwritten.
The best place to check for specifics about Python blocks is here:
https://github.com/gnuradio/gnuradio/blob/main/gnuradio-runtime/python/gnuradio/gr/gateway.py
This is the interface that is implemented. The `forecast` method is
implemented in L153ff. It is different from the C++ version.
I guess Python blocks (and embedded Python blocks even more) are
considered simple blocks for beginners. Unfortunately, this is not how
they're treated by developers. Also, they are leaky abstractions over
their C++ originals.
To rephrase the new issue:
- You insert a known pattern and expect corresponding output.
- Actual output is all zeros. (The screenshot is missing).
So let's comment on your `general_work`.
> def general_work(self, input_items, output_items):
> # Firstly check, if input_items has a sufficient amount of items
> if len(input_items[0]) >= self.buffer_len:
> # Then consume exactly self.buffer_len items
> self.consume_each(self.buffer_len)
`consume_each` should go after the last use of `input_items`.
> # Now only output a fraction of the input items, say the first
> self.out_items, on output port[0]
> output_items[0] = input_items[0][:self.out_items]
This is probably the line causing issues. Try
`output_items[0][0:self.out_items] = input_items[0][0:self.out_items]`
The difference is the left hand indexing. Now, you write items to
positions in an array. Previously, you overwrote the array and replaced
it with a new one. Thus, the output buffer was still full of zeros.
This behavior is very unpythonic. It makes perfect sense though from a
C++ block perspective. You pass pointers or references to a data
structure and write data to it in C++. You wouldn't normally do that in
Python.
Cheers
Johannes
On 23.01.22 19:27, Patric Müller wrote:
Hello everyone and hello Johannes,
first of all, a huge thanks for the quick and detailed response, it is
really helpful. After implementing your suggested changes and additional
tinkering, I am still facing two issues:
The `forecast` method expects estimates. The scheduler will call
`general_work` anyways at some point, if the system is unable to fulfill
your forecast requirement. `set_output_multiple` is much more strict.
In your case I'd start with:
`ninput_items_required[0] = noutput_items`
I've changed the `forecast`method accordingly, however I still get the
same errors. If I use
`ninput_items_required[0] = noutput_items`
then I receive:
`TypeError: 'int' object does not support item assignment`
I've checked the type and value of `ninput_items_required` and sure
enough, it is of `<class 'int'>` and has a value of `1`.
My next thought was that it may not be a <class 'list'>, since I only
have one input port, so I also tried:
`ninput_items_required = noutput_items`
This yields me with:
`Unable to cast Python instance to C++ type (compile in debug mode for
details)`
For now and since it isn't strictly necessary, I've commented the
`forecast` method.
At the end of `general_work` report these values to the system:
- consumed items via `consume_each`
- produced items via `return integer_with_number_of_consumed_items`.
I have changed my code accordingly. My `general_work` function now looks
like this:
def general_work(self, input_items, output_items):
# Firstly check, if input_items has a sufficient amount of items
if len(input_items[0]) >= self.buffer_len:
# Then consume exactly self.buffer_len items
self.consume_each(self.buffer_len)
# Now only output a fraction of the input items, say the first
self.out_items, on output port[0]
output_items[0] = input_items[0][:self.out_items]
else:
# if we do not have enough input_items, set empty output
output_items[0] = []
# finally, return len(output_items[0]), which is either equal to
`out_items` or `0`
return len(output_items[0])
It runs and I did some tests. I have created a signal of length 1024,
which is composed of a random sequence with length 312 and a cosine
signal with a length of 712 both muxed together. Next follows the python
block and the signal is compared before and after by using time sinks.
Screenshot of the flowgraph:
I would expect that I should only observe the random sequence (first 312
samples) in the `processed signal` time sink. However the time sink only
shows zeros, which is probably due to a coding error.
In order to investigate, I took a look at the content of
`output_items[0]` and also at the length. The length is 312, which seems
fine, since I specified it with `self.out_items`. The contents also seem
fine, it is definitely not zero and matches the content of
`input_items[0]`.
Since everything "seems" fine, I am not sure on how I could debug this
further. My complete code, including the Debug statements, can be found
here:
https://pastebin.com/HRMzp0zA
Thanks for taking your time and looking into this!
Kind regards,
Patric