[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r5569 - in grc/branches/jblum_work: notes src src/Elements,
jblum <=