# # Copyright 2008 Free Software Foundation, Inc. # # This file is part of GNU Radio # # GNU Radio 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. # # GNU Radio 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 GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # #A macro to apply an index to a key index_key = lambda key, i: "%s_%d"%(key, i+1) def _register_access_method(destination, controller, key): """ Helper function for register access methods. This helper creates distinct set and get methods for each key and adds them to the destination object. """ def set(value): controller[key] = value setattr(destination, 'set_'+key, set) def get(): return controller[key] setattr(destination, 'get_'+key, get) def register_access_methods(destination, controller): """ Register setter and getter functions in the destination object for all keys in the controller. @param destination the object to get new setter and getter methods @param controller the pubsub controller """ for key in controller.keys(): _register_access_method(destination, controller, key) ################################################## # Input Watcher Thread ################################################## from gnuradio import gru class input_watcher(gru.msgq_runner): """ Input watcher thread runs forever. Read messages from the message queue. Forward messages to the message handler. """ def __init__ (self, msgq, controller, msg_key, arg1_key='', arg2_key=''): self._controller = controller self._msg_key = msg_key self._arg1_key = arg1_key self._arg2_key = arg2_key gru.msgq_runner.__init__(self, msgq, self.handle_msg) def handle_msg(self, msg): if self._arg1_key: self._controller[self._arg1_key] = msg.arg1() if self._arg2_key: self._controller[self._arg2_key] = msg.arg2() self._controller[self._msg_key] = msg.to_string() ################################################## # Shared Functions ################################################## import numpy import math def get_exp(num): """ Get the exponent of the number in base 10. @param num the floating point number @return the exponent as an integer """ if num == 0: return 0 return int(math.floor(math.log10(abs(num)))) def get_clean_num(num): """ Get the closest clean number match to num with bases 1, 2, 5. @param num the number @return the closest number """ if num == 0: return 0 sign = num > 0 and 1 or -1 exp = get_exp(num) nums = numpy.array((1, 2, 5, 10))*(10**exp) return sign*nums[numpy.argmin(numpy.abs(nums - abs(num)))] def get_clean_incr(num): """ Get the next higher clean number with bases 1, 2, 5. @param num the number @return the next higher number """ num = get_clean_num(num) exp = get_exp(num) coeff = int(round(num/10**exp)) return { -5: -2, -2: -1, -1: -.5, 1: 2, 2: 5, 5: 10, }[coeff]*(10**exp) def get_clean_decr(num): """ Get the next lower clean number with bases 1, 2, 5. @param num the number @return the next lower number """ num = get_clean_num(num) exp = get_exp(num) coeff = int(round(num/10**exp)) return { -5: -10, -2: -5, -1: -2, 1: .5, 2: 1, 5: 2, }[coeff]*(10**exp) def get_min_max(samples): """ Get the minimum and maximum bounds for an array of samples. @param samples the array of real values @return a tuple of min, max """ scale_factor = 3 mean = numpy.average(samples) rms = numpy.max([scale_factor*((numpy.sum((samples-mean)**2)/len(samples))**.5), .1]) min_val = mean - rms max_val = mean + rms return min_val, max_val def get_min_max_fft(fft_samps): """ Get the minimum and maximum bounds for an array of fft samples. @param samples the array of real values @return a tuple of min, max """ #get the peak level (max of the samples) peak_level = numpy.max(fft_samps) #separate noise samples noise_samps = numpy.sort(fft_samps)[:len(fft_samps)/2] #get the noise floor noise_floor = numpy.average(noise_samps) #get the noise deviation noise_dev = numpy.std(noise_samps) #determine the maximum and minimum levels max_level = peak_level min_level = noise_floor - abs(2*noise_dev) return min_level, max_level