commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r5569 - in grc/branches/jblum_work: notes src src/Elem


From: jblum
Subject: [Commit-gnuradio] r5569 - in grc/branches/jblum_work: notes src src/Elements
Date: Tue, 29 May 2007 23:33:13 -0600 (MDT)

Author: jblum
Date: 2007-05-29 23:33:12 -0600 (Tue, 29 May 2007)
New Revision: 5569

Modified:
   grc/branches/jblum_work/notes/notes.txt
   grc/branches/jblum_work/src/DataType.py
   grc/branches/jblum_work/src/Elements/GraphicalParam.py
   grc/branches/jblum_work/src/MathExprParser.py
Log:
added functions to math expr parser, support for float and int arguments, tool 
tip display

Modified: grc/branches/jblum_work/notes/notes.txt
===================================================================
--- grc/branches/jblum_work/notes/notes.txt     2007-05-30 03:09:35 UTC (rev 
5568)
+++ grc/branches/jblum_work/notes/notes.txt     2007-05-30 05:33:12 UTC (rev 
5569)
@@ -11,13 +11,16 @@
 -blocks need to fix themselves when they go out of bounds, like in a resize
 -socket controllers should be intelligent on shrinkage
 -the nested data variables should indicate that they are nested data -> 
variable_data
+-rearanging variables doesnt have a handler
+-changing an enum doesnt call update for params with variable datatypes 
 
 ############   Features to Add:        ####################
 -save settings after close (working directory)
 -create sub-flow graphs to be used in larger flow graphs
--tool tips for entry boxes (like on math parsing exceptions)
 -stdin/out communication protocal (non graphical)
 -include dtd in saved flow graphs
+-immediate display of tool tips in entry boxes
+-help window for functions in the math expression parser
 
 ############   wxPython Features:      ####################
 -dump wx running graph to png?
@@ -28,8 +31,8 @@
         self.Bind(wx.EVT_CHOICE, self.scale, self.scaling_chooser)
         selection = event.GetSelection()
 
-############   User Opts:      ####################
---
+############   User Prefs:     ####################
+--save scrollbar positions (hidden pref)
 
 ############   Uninteresting Features: ####################
 -add the concept of a current working directory

Modified: grc/branches/jblum_work/src/DataType.py
===================================================================
--- grc/branches/jblum_work/src/DataType.py     2007-05-30 03:09:35 UTC (rev 
5568)
+++ grc/branches/jblum_work/src/DataType.py     2007-05-30 05:33:12 UTC (rev 
5569)
@@ -35,6 +35,7 @@
                self.set_data(data)             
                self.max = max
                self.min = min
+               self.msg = ''
        def set_data(self, data):
                ''' Store the data as a string. '''
                self.data = str(data)           
@@ -49,14 +50,14 @@
                If min or max was specified, 
                the parsed value must be less than or equal to min and/or 
                greater than or equal to max. If the parsed value is a vector, 
-               then the value is the length of the vector.     '''
-               try:
+               then the value is the length of the vector.     '''             
+               try: 
                        value = self.parse() 
-                       # for vector/string data types we check if len(obj) is 
in range
-                       if type(value) in (type(list()),type(str())): value = 
len(value)        
-                       return (self.max == None or (self.max != None and value 
<= self.max)) and\
-                                               (self.min == None or (self.min 
!= None and value >= self.min))
-               except: return False                    
+                       self.msg = ''
+                       return True
+               except Exception, e: 
+                       self.msg = str(e)
+                       return False    
        def get_type(self):
                ''' Get a string describing the specific data type.     '''
                return self.type
@@ -66,6 +67,11 @@
        def get_num_bytes(self):
                ''' How man bytes in this data type?    '''
                return self.num_bytes
+       def verify_bounds(self, value):
+               ''' Is the value within the bounds of this data type.
+                       Raise an exception if not.      '''
+               if self.max != None and value > self.max: raise 
ValueError('Value "%s" was greater than the max "%s".'%(value, self.max))
+               if self.min != None and value < self.min: raise 
ValueError('Value "%s" was greater than the min "%s".'%(value, self.min))
 
 
#############################################################################################
  
 #      Regular Types
@@ -77,16 +83,18 @@
        def parse(self):
                ''' Evaluate the math expressions in the data type.     '''
                elements = MathExprParser.eval_expr(DataType.parse(self))
-               if len(elements) == 1: elements = elements[0]
-               return self.parser(elements)    #an error will be raised if 
length is not 1
-
+               if len(elements) == 1: num = elements[0]
+               else: raise SyntaxError('Expected a single number.')
+               parsed = self.parser(num)       
+               self.verify_bounds(parsed)
+               return parsed
 class Int(Number):
        ''' The integer data type.      '''
        type = 'int'
        num_bytes = gr.sizeof_int       
        def parser(self, value):
-               ''' Return the real part cast as an int.        '''
-               return int(complex(value).real)
+               ''' Return an int value or raise error. '''
+               return MathExprParser.verify_int(value)
 
 class Byte(Int):
        ''' The byte data type is identical to int in this case.        '''
@@ -103,8 +111,8 @@
        type = 'float'
        num_bytes = gr.sizeof_float
        def parser(self, value):
-               ''' Return the real part cast as a float.       '''
-               return float(complex(value).real)
+               ''' Return a float value or raise error.        '''
+               return MathExprParser.verify_float(value)
 
 class Complex(Number):
        ''' The complex data type.      '''
@@ -123,6 +131,11 @@
        def __init__(self, data='', min=None, max=None):
                ''' String data type contructor. Default value is blank string. 
'''
                DataType.__init__(self, data, min, max)
+       def parse(self):
+               ''' Verify the the string's length is in bounds.        '''
+               string = DataType.parse(self)
+               self.verify_bounds(len(string))
+               return string
                        
 class Hex(DataType):
        ''' The hex data type.  '''
@@ -256,7 +269,9 @@
        Do not use, this is a base class only.          '''
        base_type = 'vector'
        def parse(self):
+               '''     Verify that the length of the vector is within bounds.  
'''
                elements = MathExprParser.eval_expr(DataType.parse(self))
+               self.verify_bounds(len(elements))
                return map(lambda v: self.parser(v), elements)
 
 class ByteVector(Vector, Byte):
@@ -300,10 +315,10 @@
 if __name__ == '__main__':
        print "put things here to test DataTypes"
        dt = String('2fsg56', min=3, max=5)
-       print dt.is_valid(),dt.parse()
+       print dt.is_valid()
        dt = IntVector('2, 3,', min=3, max=5)
-       print dt.is_valid(),dt.parse()
+       print dt.is_valid()
        dt = Hex('0xfe', min=0, max=254)
-       print dt.is_valid(), dt.parse()
+       print dt.is_valid()
        
        
\ No newline at end of file

Modified: grc/branches/jblum_work/src/Elements/GraphicalParam.py
===================================================================
--- grc/branches/jblum_work/src/Elements/GraphicalParam.py      2007-05-30 
03:09:35 UTC (rev 5568)
+++ grc/branches/jblum_work/src/Elements/GraphicalParam.py      2007-05-30 
05:33:12 UTC (rev 5569)
@@ -63,7 +63,7 @@
                # tool tip fun #
                self.tp = gtk.Tooltips()
                self.tp.set_tip(self.entry, "")
-               self.tp.disable()
+               self.tp.enable()
                
 class FileParam(EntryParam):
        """ Provide an entry box for filename and a button to browse for a 
file.        """
@@ -136,12 +136,13 @@
                if old_data != new_data: data_type.set_data(new_data)
                #       Set the markup on the label, red for errors in 
cooresponding data type. #
                cname = self.get_cname()
-               if not data_type.is_valid(): self.input.set_markup('<span 
foreground="red"><b>'+cname+'</b></span>')
-               else: self.input.set_markup(cname)      
-               #if self.input.tp: 
-               #       self.input.tp.enable()
-               #       self.input.tp.set_tip(self.input.entry, new_data)
-       
+               if not data_type.is_valid(): 
+                       self.input.set_markup('<span 
foreground="red"><b>'+cname+'</b></span>')
+                       if self.input.tp: 
self.input.tp.set_tip(self.input.entry, data_type.msg)
+               else: 
+                       self.input.set_markup(cname)    
+                       if self.input.tp: 
self.input.tp.set_tip(self.input.entry, str(data_type.parse()))
+
        def get_markup(self):
                """ Create a markup to display the Param as a label on the 
SignalBlock. 
                If the data type is an Enum type, use the cname of the Enum's 
current choice.   
@@ -180,13 +181,14 @@
                                        if len(head) >= suggested_length: 
dt_str = head
                                        else: dt_str = 
tail[0:suggested_length-len(head)] + '...' + head
                        elif self.get_data_type().get_base_type() == 
Vector().get_base_type(): #vector types
-                               #       only keep the first X elements of the 
list,                     
-                               X = 4   #display more for non complex vectors   
                                
+                               for i,e in enumerate(data): data[i] = to_str(e)
+                               #       only keep the first X elements of the 
list:                     
+                               X = (100/len(str(data))) + 1    #display more 
for non complex vectors                                   
                                dt_str = '['            #       replace the 
removed elements with a '...' 
-                               for i,e in enumerate(data):
-                                       if i < X or i > len(data)-2:    #leave 
one on the end 
-                                               dt_str = dt_str + to_str(e)
-                                               if i < len(data)-1 and i+1 != 
X: dt_str = dt_str + ', '
+                               for i,f in enumerate(data):
+                                       if i < X or i+1 == len(data):   #leave 
one on the end 
+                                               dt_str = dt_str + f
+                                               if i < len(data)-1 and (i+1 != 
X or X+1 == len(data)): dt_str = dt_str + ', '
                                        elif i == X: dt_str = dt_str + ' ... '
                                dt_str = dt_str + ']'
                        elif self.get_data_type().get_type() == 
Hex().get_type(): dt_str = hex(data) #hex, base 16

Modified: grc/branches/jblum_work/src/MathExprParser.py
===================================================================
--- grc/branches/jblum_work/src/MathExprParser.py       2007-05-30 03:09:35 UTC 
(rev 5568)
+++ grc/branches/jblum_work/src/MathExprParser.py       2007-05-30 05:33:12 UTC 
(rev 5569)
@@ -48,32 +48,56 @@
        
 #########################################################
 ##     Complex mathematical functions 
-#########################################################      
+#########################################################
 
-#TODO: make *_v functions recursive
+def verify_float(num):
+       ''' Verify that the complex number has no imaginary part.
+               Raise an exception if the imaginary part is non zero.
+               Return the value as a float.    '''
+       try: c_num = complex(num)       #ensure that the num can be complex
+       except ValueError: raise ValueError('"%s" is not a number.'%(num,))
+       if num.imag != 0: raise ValueError('Expected a float but found 
"%s".'%(c_num,))
+       return float(c_num.real)
+
+def verify_int(num):
+       ''' Verify that the complex number has no imaginary part.
+               Verify that the complex number has no decimal part.
+               Otherwise raise an exception.
+               Return the value as a int       '''
+       f_num = verify_float(num)
+       if f_num - int(f_num) != 0: raise ValueError('Expected an integer but 
found "%s".'%(f_num,))
+       return int(f_num)
        
 def _complex_abs_v(*args):
        ''' Compute the abs of a complex number or vector.      '''
        sum = 0
-       for arg in args: sum = sum + arg.real*arg.real + arg.imag*arg.imag
+       for arg in args: 
+               if _is_list(arg): sum = sum + _complex_abs_v(*arg)
+               else: sum = sum + arg.real*arg.real + arg.imag*arg.imag
        return _number(sum**0.5)
 
 def _complex_real_v(*args):
        ''' Get the real part of a number or vector.    '''
        result = list()
-       for arg in args: result.append(_number(arg.real))
+       for arg in args: 
+               if _is_list(arg): result.append(_complex_real_v(*arg))
+               else: result.append(_number(arg.real))
        return result
 
 def _complex_imag_v(*args):
        ''' Get the imaginary part of a number or vector.       '''
        result = list()
-       for arg in args: result.append(_number(arg.imag))
+       for arg in args:  
+               if _is_list(arg): result.append(_complex_imag_v(*arg))
+               else: result.append(_number(arg.real))
        return result
 
 def _complex_conj_v(*args):
        ''' Get the complex conjugate of a number or vector.    '''
        result = list()
-       for arg in args: result.append(arg.conjugate())
+       for arg in args:  
+               if _is_list(arg): result.append(_complex_conj_v(*arg))
+               else: result.append(_number(arg.conjugate()))
        return result
 
 def _complex_arg(arg):
@@ -85,36 +109,27 @@
                Format the arguments to floats and ints.
                Raise errors for invalid filter arguments.
                Return a list of taps.  '''
-       filter_args = list(filter_args)
-       if filter in (gr.firdes.band_pass, gr.firdes.band_reject, 
gr.firdes.complex_band_pass):
-               arg_lens = (5, 6, 7)
-               floats = (0, 1, 2, 3, 4, 6)
-               ints = ()
-       elif filter in (gr.firdes.high_pass, gr.firdes.low_pass):
-               arg_lens = (4, 5, 6)
-               floats = (0, 1, 2, 3, 5)
-               ints = ()       
-       elif filter in (gaussian,):
-               arg_lens = (4,)
-               floats = (0, 1, 2)
-               ints = (3,)     
-       elif filter in (hilbert,):
-               arg_lens = (1, 2, 3)
-               floats = (2,)
-               ints = (0,)             
-       elif filter in (root_raised_cosine,):
-               arg_lens = (5,)
-               floats = (0, 1, 2, 3)
-               ints = (4,)             
-       elif filter in (window,):
-               arg_lens = (3,)
-               floats = (2,)
-               ints = (1,)                     
-       if len(filter_args) not in arg_lens: raise Exception('Invalid number of 
arguments for "%s".'%filter)    
-       for i,arg in enumerate(filter_args):    
-               #TODO: raise exception for floats/ints with non-zero imaginary?
-               if i in floats: filter_args[i] = float(abs(arg))
-               if i in ints: filter_args[i] = int(abs(arg))    
+       filter_args = list(filter_args) #make filter args a list
+       filter_props = {        # map a filter to filter argument properties:
+               # (allowed lengths of args), (args that are floats), (args that 
are ints)
+               gr.firdes.band_pass : ((5, 6, 7), (0, 1, 2, 3, 4, 6), ()),
+               gr.firdes.band_reject : ((5, 6, 7), (0, 1, 2, 3, 4, 6), ()),
+               gr.firdes.complex_band_pass : ((5, 6, 7), (0, 1, 2, 3, 4, 6), 
()),
+               
+               gr.firdes.high_pass : ((4, 5, 6), (0, 1, 2, 3, 4, 6), ()),
+               gr.firdes.low_pass : ((4, 5, 6), (0, 1, 2, 3, 4, 6), ()),
+               
+               gr.firdes.gaussian : ((4,), (0, 1, 2), (3,)),
+               gr.firdes.hilbert : ((1, 2, 3), (2,), (0,)),
+               gr.firdes.root_raised_cosine : ((5,), (0, 1, 2, 3), (4,)),
+               gr.firdes.window : ((3,), (2,), (1,)),
+       }
+       arg_lens, floats, ints = filter_props[filter]
+       # handle the filter arguments #
+       if len(filter_args) not in arg_lens: raise SyntaxError('Invalid number 
of arguments for "%s".'%filter)  
+       for i,arg in enumerate(filter_args):
+               if i in floats: filter_args[i] = verify_float(arg)
+               if i in ints: filter_args[i] = verify_int(arg)  
        return list(filter(*filter_args))
 
 _FUNCTIONS = {
@@ -158,13 +173,19 @@
        'low_pass' : lambda *args: _handle_filter(gr.firdes.low_pass, *args),
        'root_raised_cosine' : lambda *args: 
_handle_filter(gr.firdes.root_raised_cosine, *args),
        'window' : lambda *args: _handle_filter(gr.firdes.window, *args),
+       
+       'floor' : lambda f: _number(math.floor(verify_float(f))),
+       'ceil' : lambda f: _number(math.ceil(verify_float(f))),
+       'radians' : lambda f: _number(math.radians(verify_float(f))),
+       'degrees' : lambda f: _number(math.degrees(verify_float(f))),
+       'fmod' : lambda f1, f2: _number(math.fmod(verify_float(f1), 
verify_float(f2))),
 }
 
 def _handle_operation(op, arg1, arg2):
        ''' Handle basic operations specified in the order of operations.
                All calculations are complex, some vector operations are 
supported.
                Return the number/list representing the result. '''
-       if op not in _ORDER_OF_OPS: raise Exception('Unknown operator: 
"%s"'%(op))      
+       if op not in _ORDER_OF_OPS: raise NameError('Unknown operator: 
"%s".'%(op))     
        arg1_is_list = _is_list(arg1)
        arg2_is_list = _is_list(arg2)
        # addition and subtraction of vectors #
@@ -191,12 +212,13 @@
                elif op == '*':
                        return arg1 * arg2
                elif op == '/':
-                       return arg1 / arg2
+                       try: return arg1 / arg2
+                       except ZeroDivisionError: raise 
ZeroDivisionError('Cannot divide "%s" by 0.'%(arg1,))
                elif op == '+':
                        return arg1 + arg2
                elif op == '-':
                        return arg1 - arg2
-       raise Exception('Operation of "%s" cannot be performed on "%s", 
"%s"'%(op, arg1, arg2))
+       raise ArithmeticError('Operation of "%s" cannot be performed on "%s", 
"%s".'%(op, arg1, arg2))
 
 #########################################################
 ##     Boolean tests for special characters and symbols
@@ -278,7 +300,9 @@
                if i == 0 and element == '-':   #first element was a minus
                        rectified_elements.extend(['-1', '*'])
                elif i != 0 and element == '-': #minus found!
-                       if _is_operator(elements[i-1]) or 
_is_open_bracket(elements[i-1]):      #negative implied
+                       if _is_operator(elements[i-1]) or \
+                       _is_open_bracket(elements[i-1]) or \
+                       _is_comma(elements[i-1]):       #negative implied
                                if elements[i-1] != '^': 
rectified_elements.extend(['-1', '*'])
                                else: #^ proceeds - in order of ops, remove the 
^ and append ^- as a special operator
                                        rectified_elements.pop()        #remove 
last element
@@ -299,11 +323,11 @@
                        nested_elements.append(_nest_elements(elements, 
element))
                elif _is_close_bracket(element):        
                        if element != _get_oposing_bracket(open_bracket):       
#matching open/close brackets?
-                               raise Exception('Expected "%s", but found 
"%s"'%(_get_oposing_bracket(open_bracket), element))
+                               raise SyntaxError('Expected "%s", but found 
"%s".'%(_get_oposing_bracket(open_bracket), element))
                        return nested_elements
                else: nested_elements.append(element)
        if open_bracket:        #any unclosed bracket pairs? 
-               raise Exception('Expected "%s", but found 
nothing'%(_get_oposing_bracket(open_bracket),))
+               raise SyntaxError('Expected "%s", but found 
nothing.'%(_get_oposing_bracket(open_bracket),))
        return nested_elements
        
 def _simplify_nested_elements(nested_elements):
@@ -323,12 +347,12 @@
        for function in _FUNCTIONS.keys():
                while function in nested_elements:
                        i = nested_elements.index(function)                     
        
-                       if i+1 == len(nested_elements): raise 
Exception('Function "%s" has no arguments.'%(function))
+                       if i+1 == len(nested_elements): raise 
SyntaxError('Function "%s" has no arguments.'%(function))
                        args = nested_elements[i+1]
                        if not _is_list(args): args = [args]
                        try: ans = _FUNCTIONS[function](*args)
                        except Exception, e: 
-                               raise Exception('Function "%s" with arguments 
"%s" failed.\n\t%s'%(function, nested_elements[i+1], e))
+                               raise ValueError('Function "%s" with arguments 
"%s" failed.\n\t%s'%(function, nested_elements[i+1], e))
                        if not _is_list(ans): ans = [ans]       # ans must be a 
list
                        ans_with_commas = list()
                        for an in ans: ans_with_commas.extend([an, ','])
@@ -341,21 +365,24 @@
                        if i > 0: arg1 = nested_elements[i-1]
                        if i+1 < len(nested_elements): arg2 = 
nested_elements[i+1]
                        #raise error if arg1 or arg2 is None
-                       if arg1 == None or arg2 == None: raise 
Exception('Operator "%s" is missing argument.'%(operator))
+                       if arg1 == None or arg2 == None: raise 
SyntaxError('Operator "%s" is missing argument.'%(operator))
                        ans = _handle_operation(operator, arg1, arg2)
-                       nested_elements = nested_elements[0:i-1] + [ans] + 
nested_elements[i+2:]                
+                       if not _is_list(ans): ans = [ans]       # ans must be a 
list
+                       ans_with_commas = list()
+                       for an in ans: ans_with_commas.extend([an, ','])
+                       nested_elements = nested_elements[0:i-1] + 
ans_with_commas[0:-1] + nested_elements[i+2:]                
        # convert comma separated elements into a list #
        vector = list() 
        last_element = None
        for element in nested_elements:
                if not _is_comma(element): 
                        if not _is_list(element) and not _is_number(element) 
and element not in _CONSTANTS.values(): 
-                               raise Exception('Unknown symbol "%s"'%(element))
+                               raise NameError('Unknown symbol 
"%s".'%(element))
                        if last_element and not _is_comma(last_element): 
-                               raise Exception('Expected comma, but found 
"%s"'%(element))
+                               raise SyntaxError('Expected comma, but found 
"%s".'%(element))
                        vector.append(element)
                elif _is_comma(element) and _is_comma(last_element):
-                       raise Exception('Commas must be separated by 
non-commas.')
+                       raise SyntaxError('Commas must be separated by 
non-commas.')
                last_element = element
        if len(vector) == 1 and not _is_comma(last_element) and not 
_is_list(vector[0]): return vector[0]       #return single number
        return vector   #otherwise return vector





reply via email to

[Prev in Thread] Current Thread [Next in Thread]