[prev in list] [next in list] [prev in thread] [next in thread]
List: gnuradio-discuss
Subject: Re: [Discuss-gnuradio] Python block help
From: Marcus_Müller <marcus.mueller () ettus ! com>
Date: 2017-05-29 22:02:07
Message-ID: 457eed0f-6216-870f-6cce-51608385d335 () ettus ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
Hi Zach,
On 29.05.2017 22:57, Zach Morris wrote:
> Hi Marcus,
>
> Sorry about the trouble with Nabble, I see that my code got cut off. I
> will communicate via the mailing list from now on.
>
> If I understand your explanation correctly, the forecast function
> below tells the scheduler that this block needs at least noutput_items
> on each input port in order to produce noutput_items. In actuality, my
> arbitrary ratio block would produce anywhere between (0,
> noutput_items); would this be a valid implementation of forecast() for
> my arbitrary ratio block?
> def forecast(self, noutput_items, ninput_items_required):
> for i in range(len(ninput_items_required)):
> ninput_items_required[i] = noutput_items
>
yes, that would tell the scheduler that you'll need at least
noutput_items input items to produce noutput_items output items, indeed!
Now, the forecast really is just that: a forecast. If you can't produce
as many samples as promised, the scheduler won't be upset.
>
> This is my general_work() function right now: it just outputs the
> elements in the input vector that are above a threshold. My eventual
> goal is to receive a vector from an FFT and update statistics for each
> frequency 'bin' as long as its power is above a threshold, then output
> the statistics when its power drops below the threshold.
> def general_work(self, input_items, output_items):
> in0 = input_items[0][:len(output_items[0])]
This is **only** OK if you check that len(output_items[0]) <=
len(input_items[0]). You inherently do that with your forecast, but I'd
really recommend explicitly checking that condition.
Also, this the following code is really very redundant:
> out0 = output_items[0]
> ninput_items = len(in0)
well, you set in0 to be of len(output_items[0]).
>
> j = 0
> for i in range(0, ninput_items):
this is very un-pythonic.
> if (in0[i] > self.threshold).all():
> out0[j] = in0[i]
> j += 1
>
I'd just say:
def general_work(self, input_items, output_items):
super_threshold = filter(lambda x: x > self.threshold, in[0])
output_items[0][:] = super_threshold
self.consume_each(len(super_threshold))
return len(super_threshold)
Best regards,
Marcus
> self.consume(0, ninput_items)
> self.produce(0, j)
>
> return 0
>
> If I again understand your explanation, the 'self.consume(0,
> ninput_items)' is correct, because I 'use up' the elements of
> input_items on each loop. However, it sounds like I should either
> return WORK_CALLED_PRODUCE or return ninput_tems. Am I on the right
> track here? Is there a reason to prefer produce() over just returning
> the number of input items I consume?
>
> Thank you for your help.
>
> Zach
>
>
> On Sun, May 28, 2017 at 1:31 PM, Marcus Müller
> <marcus.mueller@ettus.com <mailto:marcus.mueller@ettus.com>> wrote:
>
> Hi Zach,
>
> sorry it took me so long to react:
> so, let's dissect a few things:
>
> First, the general purposes of these functions:
>
> * forecast() is called by the *scheduler* to ask your block "hey,
> if I'd
> need you to produce N items, how much would you need on your 0.
> (and 1.,
> and 2.,⦠if existing) input for that?". The scheduler usually
> repeatedly
> calls that with a decreasing N until the number of samples your block
> requires can be fulfilled by the number of input items that the
> scheduler has ready. If that never happens, usually, something is
> broken.
>
> * consume() is something that *you* call from within a
> (general_)work()
> to signal the scheduler how many items you've consumed from the
> input(s).
>
> * produce() is something that *you* call from within a
> (general_)work()
> to signal the scheduler how many items you've put into the output
> buffer. *If* you use produce, you should return the magic
> WORK_CALLED_PRODUCE values. You usually don't call produce() â you
> just
> return the number of consumed samples instead.
>
> * noutput_items is **not** a variable that you set â it's the info how
> many items you are asked to produce (parameter to forecast()) or how
> many items you're **allowed at most** to produce (when it's the
> parameter to a (general_)work())
>
> Again, the better parts of your mail have been broken by Nabble.
> Abandon
> Nabble. Subscribe directly:
>
> https://lists.gnu.org/mailman/listinfo/discuss-gnuradio
> <https://lists.gnu.org/mailman/listinfo/discuss-gnuradio>
>
> Hope that helps,
> Marcus
>
> On 05/26/2017 07:49 PM, Zach Morris wrote:
> > That worked to create a general block, but I'm still having some trouble with
> > implementing the forecast(), consume() and produce() functions.
> >
> > The goal of the block is to discard elements in an input vector
> that are
> > below a certain threshold, and eventually update some statistics
> based on
> > the remaining elements. For a vector of 256 elements, there could be
> > anywhere between 0 and 256 outputs (the arbitrary ratio you
> mentioned).
> >
> > The default forecast function has a 1:1 ratio:
> >
> > Should I replace "noutput_items" with my "vector_length" parameter, ensuring
> > that we always get (for example) 256 inputs?
> >
> > In the general_work function, I think we want to consume the
> entire input
> > vector once we figure out which elements are above the threshold:
> >
> > I'm not sure about the produce function; do I need to tell the system how
> > many items I produce, or is that covered at the end of general_work:
> >
> >
> > Thank you kindly,
> >
> > Zach
> >
> >
> >
> >
> > --
> > View this message in context:
> http://gnuradio.4.n7.nabble.com/Python-block-help-tp51706p64062.html
> <http://gnuradio.4.n7.nabble.com/Python-block-help-tp51706p64062.html>
> > Sent from the GnuRadio mailing list archive at Nabble.com.
> >
> > _______________________________________________
> > Discuss-gnuradio mailing list
> > Discuss-gnuradio@gnu.org <mailto:Discuss-gnuradio@gnu.org>
> > https://lists.gnu.org/mailman/listinfo/discuss-gnuradio
> <https://lists.gnu.org/mailman/listinfo/discuss-gnuradio>
>
>
> _______________________________________________
> Discuss-gnuradio mailing list
> Discuss-gnuradio@gnu.org <mailto:Discuss-gnuradio@gnu.org>
> https://lists.gnu.org/mailman/listinfo/discuss-gnuradio
> <https://lists.gnu.org/mailman/listinfo/discuss-gnuradio>
>
>
[Attachment #5 (text/html)]
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>Hi Zach,<br>
</p>
<br>
<div class="moz-cite-prefix">On 29.05.2017 22:57, Zach Morris wrote:<br>
</div>
<blockquote
cite="mid:CA+M1yVdvrYAoyFB4v-WxTWkKjOm_0iFkP4+3R_FME-yG9Dp2mg@mail.gmail.com"
type="cite">
<div dir="ltr">Hi Marcus,
<div><br>
</div>
<div>Sorry about the trouble with Nabble, I see that my code got
cut off. I will communicate via the mailing list from now on.</div>
<div><br>
</div>
<div>If I understand your explanation correctly, the forecast
function below tells the scheduler that this block needs at
least noutput_items on each input port in order to produce
noutput_items. In actuality, my arbitrary ratio block would
produce anywhere between (0, noutput_items); would this be a
valid implementation of forecast() for my arbitrary ratio
block?<br>
</div>
<div>
<div>def forecast(self, noutput_items, ninput_items_required):<br>
</div>
<div> for i in range(len(ninput_items_<wbr>required)):</div>
<div> ninput_items_required[i] = noutput_items</div>
<div><br>
</div>
</div>
</div>
</blockquote>
yes, that would tell the scheduler that you'll need at least
noutput_items input items to produce noutput_items output items,
indeed!<br>
<br>
Now, the forecast really is just that: a forecast. If you can't
produce as many samples as promised, the scheduler won't be upset.<br>
<blockquote
cite="mid:CA+M1yVdvrYAoyFB4v-WxTWkKjOm_0iFkP4+3R_FME-yG9Dp2mg@mail.gmail.com"
type="cite">
<div dir="ltr">
<div>
<div><br>
</div>
<div>This is my general_work() function right now: it just
outputs the elements in the input vector that are above a
threshold. My eventual goal is to receive a vector from an
FFT and update statistics for each frequency 'bin' as long
as its power is above a threshold, then output the
statistics when its power drops below the threshold. <br>
</div>
</div>
</div>
</blockquote>
<br>
<blockquote
cite="mid:CA+M1yVdvrYAoyFB4v-WxTWkKjOm_0iFkP4+3R_FME-yG9Dp2mg@mail.gmail.com"
type="cite">
<div dir="ltr">
<div>
<div>def general_work(self, input_items, output_items):<br>
</div>
<div> in0 = input_items[0][:len(output_<wbr>items[0])]</div>
</div>
</div>
</blockquote>
This is **only** OK if you check that len(output_items[0]) <=
len(input_items[0]). You inherently do that with your forecast, but
I'd really recommend explicitly checking that condition. <br>
Also, this the following code is really very redundant:<br>
<blockquote
cite="mid:CA+M1yVdvrYAoyFB4v-WxTWkKjOm_0iFkP4+3R_FME-yG9Dp2mg@mail.gmail.com"
type="cite">
<div dir="ltr">
<div>
<div> out0 = output_items[0]</div>
<div> ninput_items = len(in0)</div>
</div>
</div>
</blockquote>
well, you set in0 to be of len(output_items[0]).<br>
<blockquote
cite="mid:CA+M1yVdvrYAoyFB4v-WxTWkKjOm_0iFkP4+3R_FME-yG9Dp2mg@mail.gmail.com"
type="cite">
<div dir="ltr">
<div>
<div><br>
</div>
<div> j = 0</div>
<div> for i in range(0, ninput_items):</div>
</div>
</div>
</blockquote>
this is very un-pythonic.<br>
<blockquote
cite="mid:CA+M1yVdvrYAoyFB4v-WxTWkKjOm_0iFkP4+3R_FME-yG9Dp2mg@mail.gmail.com"
type="cite">
<div dir="ltr">
<div>
<div> if (in0[i] > self.threshold).all(): </div>
<div> out0[j] = in0[i]</div>
<div> j += 1</div>
<div><br>
</div>
</div>
</div>
</blockquote>
I'd just say: <br>
<br>
def general_work(self, input_items, output_items):<br>
super_threshold = filter(lambda x: x > self.threshold, in[0])<br>
output_items[0][:] = super_threshold<br>
self.consume_each(len(super_threshold))<br>
return len(super_threshold)<br>
<br>
Best regards,<br>
Marcus<br>
<br>
<blockquote
cite="mid:CA+M1yVdvrYAoyFB4v-WxTWkKjOm_0iFkP4+3R_FME-yG9Dp2mg@mail.gmail.com"
type="cite">
<div dir="ltr">
<div>
<div> self.consume(0, ninput_items)<br>
</div>
<div> self.produce(0, j)</div>
<div><br>
</div>
<div> return 0</div>
</div>
<div><br>
</div>
<div>If I again understand your explanation, the
'self.consume(0, ninput_items)' is correct, because I 'use up'
the elements of input_items on each loop. However, it sounds
like I should either return WORK_CALLED_PRODUCE or return
ninput_tems. Am I on the right track here? Is there a reason
to prefer produce() over just returning the number of input
items I consume?</div>
<div><br>
</div>
<div>Thank you for your help.</div>
<div><br>
</div>
<div>Zach</div>
<div><br>
</div>
<div class="gmail_extra"><br>
<div class="gmail_quote">On Sun, May 28, 2017 at 1:31 PM,
Marcus Müller <span dir="ltr"><<a moz-do-not-send="true"
href="mailto:marcus.mueller@ettus.com" \
target="_blank">marcus.mueller@ettus.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex"><span>Hi Zach,<br>
<br>
sorry it took me so long to react:<br>
so, let's dissect a few things:<br>
<br>
First, the general purposes of these functions:<br>
<br>
* forecast() is called by the *scheduler* to ask your
block "hey, if I'd<br>
need you to produce N items, how much would you need on
your 0. (and 1.,<br>
and 2.,… if existing) input for that?". The scheduler
usually repeatedly<br>
calls that with a decreasing N until the number of
samples your block<br>
requires can be fulfilled by the number of input items
that the<br>
scheduler has ready. If that never happens, usually,
something is broken.<br>
<br>
* consume() is something that *you* call from within a
(general_)work()<br>
to signal the scheduler how many items you've consumed
from the input(s).<br>
<br>
* produce() is something that *you* call from within a
(general_)work()<br>
to signal the scheduler how many items you've put into
the output<br>
buffer. *If* you use produce, you should return the
magic<br>
WORK_CALLED_PRODUCE values. You usually don't call
produce() – you just<br>
return the number of consumed samples instead.<br>
<br>
* noutput_items is **not** a variable that you set –
it's the info how<br>
</span>many items you are asked to produce (parameter to
forecast()) or how<br>
<span>many items you're **allowed at most** to produce
(when it's the<br>
parameter to a (general_)work())<br>
<br>
Again, the better parts of your mail have been broken by
Nabble. Abandon<br>
Nabble. Subscribe directly:<br>
<br>
<a moz-do-not-send="true"
href="https://lists.gnu.org/mailman/listinfo/discuss-gnuradio"
rel="noreferrer" \
target="_blank">https://lists.gnu.org/mailman/<wbr>listinfo/discuss-gnuradio</a><br> \
<br> Hope that helps,<br>
Marcus<br>
<br>
On 05/26/2017 07:49 PM, Zach Morris wrote:<br>
</span><span>> That worked to create a general block,
but I'm still having some trouble with<br>
> implementing the forecast(), consume() and
produce() functions.<br>
><br>
> The goal of the block is to discard elements in an
input vector that are<br>
> below a certain threshold, and eventually update
some statistics based on<br>
> the remaining elements. For a vector of 256
elements, there could be<br>
> anywhere between 0 and 256 outputs (the arbitrary
ratio you mentioned).<br>
><br>
> The default forecast function has a 1:1 ratio:<br>
><br>
</span><span>> Should I replace "noutput_items" with my
"vector_length" parameter, ensuring<br>
> that we always get (for example) 256 inputs?<br>
><br>
> In the general_work function, I think we want to
consume the entire input<br>
> vector once we figure out which elements are above
the threshold:<br>
><br>
</span><span>> I'm not sure about the produce function;
do I need to tell the system how<br>
> many items I produce, or is that covered at the end
of general_work:<br>
><br>
><br>
</span>> Thank you kindly,<br>
><br>
> Zach<br>
><br>
><br>
><br>
<span class="gmail-m_-9051442579776840935HOEnZb"><font
color="#888888">><br>
> --<br>
> View this message in context: <a
moz-do-not-send="true"
href="http://gnuradio.4.n7.nabble.com/Python-block-help-tp51706p64062.html"
rel="noreferrer" \
target="_blank">http://gnuradio.4.n7.nabble.co<wbr>m/Python-block-help-tp51706p64<wbr>062.html</a><br>
</font></span>
<div class="gmail-m_-9051442579776840935HOEnZb">
<div class="gmail-m_-9051442579776840935h5">> Sent
from the GnuRadio mailing list archive at Nabble.com.<br>
><br>
> ______________________________<wbr>_________________<br>
> Discuss-gnuradio mailing list<br>
> <a moz-do-not-send="true"
href="mailto:Discuss-gnuradio@gnu.org"
target="_blank">Discuss-gnuradio@gnu.org</a><br>
> <a moz-do-not-send="true"
href="https://lists.gnu.org/mailman/listinfo/discuss-gnuradio"
rel="noreferrer" \
target="_blank">https://lists.gnu.org/mailman/<wbr>listinfo/discuss-gnuradio</a><br> \
<br> <br>
______________________________<wbr>_________________<br>
Discuss-gnuradio mailing list<br>
<a moz-do-not-send="true"
href="mailto:Discuss-gnuradio@gnu.org"
target="_blank">Discuss-gnuradio@gnu.org</a><br>
<a moz-do-not-send="true"
href="https://lists.gnu.org/mailman/listinfo/discuss-gnuradio"
rel="noreferrer" \
target="_blank">https://lists.gnu.org/mailman/<wbr>listinfo/discuss-gnuradio</a><br> \
</div> </div>
</blockquote>
</div>
<br>
</div>
</div>
</blockquote>
<br>
</body>
</html>
_______________________________________________
Discuss-gnuradio mailing list
Discuss-gnuradio@gnu.org
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic