'Problem with using numpy.float32 value in if clause

I have a simple test application for GNUradio where I try top convert a input in range -180...180 to range 0...360. I've written python code and QA code for that, but cannot seem to get the if-else statements to work properly.

The problem seems to be that the if clause only sees the first element of the test src_data vector because I use input_elements[0][0]. I tried using input_elements[0], but in that case I get and error about comparing array to integer. How to solve this problem?

The block in python is as follows:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 
# Copyright 2018 <+YOU OR YOUR COMPANY+>.
# 
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# 
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
# 

import numpy
from gnuradio import gr

class convert_ff(gr.sync_block):
    """
    docstring for block convert_ff
    """
    def __init__(self):
        gr.sync_block.__init__(self,
            name="convert_ff",
            in_sig=[numpy.float32],
            out_sig=[numpy.float32])


    def work(self, input_items, output_items):
    print input_items[:][0]
    out = output_items[0]
    
    if input_items[0][0] < 0:
        out[:]=360+input_items[0]
        print "negative value processed"
    else:
        out[:]=input_items[0]

    return len(output_items[0])

And the QA code is as follows:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 
# Copyright 2018 <+YOU OR YOUR COMPANY+>.
# 
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# 
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
# 

from gnuradio import gr, gr_unittest
from gnuradio import blocks
from convert_ff import convert_ff

class qa_convert_ff (gr_unittest.TestCase):

    def setUp (self):
        self.tb = gr.top_block ()

    def tearDown (self):
        self.tb = None

        def test_001_t (self):
        src_data = (20,90,180,280,-20,-90,-190)
        print "This is source data"
        print src_data
        expected_result = (20,90,180,280,340,270,170)
        src=blocks.vector_source_f(src_data)
        convert=convert_ff()
        snk=blocks.vector_sink_f()
        self.tb.connect(src,convert)
        self.tb.connect(convert,snk)
        self.tb.run ()
        # check data
        self.assertFloatTuplesAlmostEqual(expected_result, result_data, 6)


if __name__ == '__main__':
    gr_unittest.run(qa_convert_ff, "qa_convert_ff.xml")


Solution 1:[1]

Generally to extend an "if" statement to a numpy.array, the best solution is to use a mask which is obtained for instance by comparing an array to an integer (or to another array of the same size):

mask = input_items[0] < 0

the mask is an boolean array of the same dimension. Then, you can act only on a selection of your array using the mask:

out[mask] = 360+input_items[mask]

numpy.logical_not() is a fast way to obtain the not mask:

out[numpy.logical_not(mask)] = input_items[numpy.logical_not(mask)]

So your work function should be:

def work(self, input_items, output_items):
    print input_items[:][0]
    out = output_items[0]

    mask = input_items[0] < 0
    out[mask] = 360+input_items[mask]
    out[numpy.logical_not(mask)] = input_items[numpy.logical_not(mask)]

    return len(output_items[0])

you can do even shorter, not storing the mask:

def work(self, input_items, output_items):

    out = input_items[0].copy()
    out[out < 0] += 360.  
    return out

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1