Author: jblum Date: 2007-05-29 07:06:43 -0600 (Tue, 29 May 2007) New Revision: 5565
Added: grc/branches/jblum_work/README.txt Removed: grc/branches/jblum_work/license/README.txt Modified: grc/branches/jblum_work/notes/clean.sh 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 grc/branches/jblum_work/src/SignalBlockDefs/SignalBlockTree.py Log: math expression parser: handles lists and more recursive operations, experimented with tool tips for entry boxes Copied: grc/branches/jblum_work/README.txt (from rev 5541, grc/branches/jblum_work/license/README.txt) =================================================================== --- grc/branches/jblum_work/README.txt (rev 0) +++ grc/branches/jblum_work/README.txt 2007-05-29 13:06:43 UTC (rev 5565) @@ -0,0 +1,13 @@ +Hello! + +Thank you for downloading GNU Radio Companion. +This program is free software. +A GPL license is distributed with this program. +This license covers all the source code/python files. +You will also find a "creative common license" for the grc icon. + +Intructions for GRC are available at: +http://gnuradio.org/trac/wiki/GNURadioCompanion + +If you have questions, problems, suggestions, or want to contribute, +please email me at jblum at jhu dot edu Deleted: grc/branches/jblum_work/license/README.txt Modified: grc/branches/jblum_work/notes/clean.sh =================================================================== --- grc/branches/jblum_work/notes/clean.sh 2007-05-29 11:37:08 UTC (rev 5564) +++ grc/branches/jblum_work/notes/clean.sh 2007-05-29 13:06:43 UTC (rev 5565) @@ -1,8 +1,6 @@ #!/bin/bash -cd ../src +cd .. pwd rm -rf `find ./ -type f -name "*.pyc"` rm -rf `find ./ -type f -name "*py~"` -chmod a-x `find ./ -type f -name "*"` -chmod a+x Run.py FlowGraphApp.py - +rm -rf `find ./ -type f -name "*.bak"` Modified: grc/branches/jblum_work/notes/notes.txt =================================================================== --- grc/branches/jblum_work/notes/notes.txt 2007-05-29 11:37:08 UTC (rev 5564) +++ grc/branches/jblum_work/notes/notes.txt 2007-05-29 13:06:43 UTC (rev 5565) @@ -3,6 +3,7 @@ -usrp dual and quad souce -blks blocks, add filesave for message reports -combine add/mult with add/mult vector +-selector blocks ############ Known Problems: #################### -in vars window, stop_editing doesnt work @@ -14,7 +15,7 @@ ############ Features to Add: #################### -save settings after close (working directory) -create sub-flow graphs to be used in larger flow graphs --math expressions for taps generators +-tool tips for entry boxes (like on math parsing exceptions) -stdin/out communication protocal (non graphical) -include dtd in saved flow graphs Modified: grc/branches/jblum_work/src/DataType.py =================================================================== --- grc/branches/jblum_work/src/DataType.py 2007-05-29 11:37:08 UTC (rev 5564) +++ grc/branches/jblum_work/src/DataType.py 2007-05-29 13:06:43 UTC (rev 5565) @@ -76,7 +76,9 @@ base_type = 'number' def parse(self): ''' Evaluate the math expressions in the data type. ''' - return self.parser(MathExprParser.eval_expr(DataType.parse(self))) + 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 class Int(Number): ''' The integer data type. ''' @@ -255,7 +257,6 @@ base_type = 'vector' def parse(self): elements = MathExprParser.eval_expr(DataType.parse(self)) - if type(elements)!= type(list()): elements = [elements] return map(lambda v: self.parser(v), elements) class ByteVector(Vector, Byte): Modified: grc/branches/jblum_work/src/Elements/GraphicalParam.py =================================================================== --- grc/branches/jblum_work/src/Elements/GraphicalParam.py 2007-05-29 11:37:08 UTC (rev 5564) +++ grc/branches/jblum_work/src/Elements/GraphicalParam.py 2007-05-29 13:06:43 UTC (rev 5565) @@ -47,7 +47,8 @@ self.label.set_size_request(140,30) self.label.show() self.pack_start(self.label, False) - self.set_markup = lambda m: self.label.set_markup(m) + self.set_markup = lambda m: self.label.set_markup(m) + self.tp = None class EntryParam(InputParam): """ Provide an entry box for strings and numbers. """ @@ -59,6 +60,10 @@ input.show() self.pack_start(input, False) self.get_text = input.get_text + # tool tip fun # + self.tp = gtk.Tooltips() + self.tp.set_tip(self.entry, "") + self.tp.disable() class FileParam(EntryParam): """ Provide an entry box for filename and a button to browse for a file. """ @@ -133,6 +138,9 @@ 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) def get_markup(self): """ Create a markup to display the Param as a label on the SignalBlock. Modified: grc/branches/jblum_work/src/MathExprParser.py =================================================================== --- grc/branches/jblum_work/src/MathExprParser.py 2007-05-29 11:37:08 UTC (rev 5564) +++ grc/branches/jblum_work/src/MathExprParser.py 2007-05-29 13:06:43 UTC (rev 5565) @@ -34,15 +34,23 @@ _WHITESPACE = (' ', '\t', '') -_CONSTANTS = { +_CONSTANTS = { #constans must be lower case 'pi' : _number(cmath.pi), 'e' : _number(cmath.e), 'j' : _number(1j), + + 'hamming' : gr.firdes.WIN_HAMMING, #filter windows + 'hann' : gr.firdes.WIN_HANN, + 'blackman' : gr.firdes.WIN_BLACKMAN, + 'rectangular' : gr.firdes.WIN_RECTANGULAR, + 'kaiser' : gr.firdes.WIN_KAISER, } ######################################################### ## Complex mathematical functions ######################################################### + +#TODO: make *_v functions recursive def _complex_abs_v(*args): ''' Compute the abs of a complex number or vector. ''' @@ -72,6 +80,43 @@ ''' Get the angle of the complex number (radians). ''' return _number(math.atan2(arg.imag, arg.real)) +def _handle_filter(filter, *filter_args): + ''' Pass the filter arguments to the filter function. + 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)) + return list(filter(*filter_args)) + _FUNCTIONS = { 'pow' : lambda b, p: b**p, 'sqrt' : cmath.sqrt, @@ -103,6 +148,16 @@ 'log' : cmath.log, #optional 2nd argument as base 'ln' : lambda z: cmath.log(z), #only allow natural log 'exp' : cmath.exp, + + 'band_pass' : lambda *args: _handle_filter(gr.firdes.band_pass, *args), #taps generators + 'band_reject' : lambda *args: _handle_filter(gr.firdes.band_reject, *args), + 'complex_band_pass' : lambda *args: _handle_filter(gr.firdes.complex_band_pass, *args), + 'gaussian' : lambda *args: _handle_filter(gr.firdes.gaussian, *args), + 'high_pass' : lambda *args: _handle_filter(gr.firdes.high_pass, *args), + 'hilbert' : lambda *args: _handle_filter(gr.firdes.hilbert, *args), + '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), } def _handle_operation(op, arg1, arg2): @@ -118,19 +173,14 @@ result = list() for i,arg1_elem in enumerate(arg1): arg2_elem = arg2[i] - if op == '+': result.append(arg1_elem + arg2_elem) - elif op == '-': result.append(arg1_elem - arg2_elem) - else: raise Exception('Error in vector +/- vector') + result.append(_handle_operation(op, arg1_elem, arg2_elem)) return result # scalar times vector # if not arg1_is_list and arg2_is_list and op == '*': - return map(lambda elem: arg1 * elem, arg2) - # vector times scalar # - if arg1_is_list and not arg2_is_list and op == '*': - return map(lambda elem: elem * arg2, arg1) - # vector divided by scalar # - if arg1_is_list and not arg2_is_list and op == '/': - return map(lambda elem: elem/arg2, arg1) + return map(lambda elem: _handle_operation(op, arg1, elem), arg2) + # vector times/divided scalar # + if arg1_is_list and not arg2_is_list and op in ('*', '/'): + return map(lambda elem: _handle_operation(op, elem, arg2), arg1) # non vectored operations # if not arg1_is_list and not arg2_is_list and \ type(_number()) == type(arg1) == type(arg2): #non vector operations @@ -273,14 +323,16 @@ 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 Exception('Function "%s" has no arguments.'%(function)) args = nested_elements[i+1] if not _is_list(args): args = [args] try: ans = _FUNCTIONS[function](*args) - except: raise Exception('Function "%s" with arguments "%s" failed'%(function, nested_elements[i+1])) - # ans cannot be a tuple! - if type(ans) == type(tuple()): ans = list(ans) - nested_elements = nested_elements[0:i] + [ans] + nested_elements[i+2:] + except Exception, e: + raise Exception('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, ',']) + nested_elements = nested_elements[0:i] + ans_with_commas[0:-1] + nested_elements[i+2:] # simplify operations # for operator in _ORDER_OF_OPS: while operator in nested_elements: @@ -289,7 +341,7 @@ 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 not arg1 or not arg2: raise Exception('Operator "%s" is missing argument'%(operator)) + if arg1 == None or arg2 == None: raise Exception('Operator "%s" is missing argument.'%(operator)) ans = _handle_operation(operator, arg1, arg2) nested_elements = nested_elements[0:i-1] + [ans] + nested_elements[i+2:] # convert comma separated elements into a list # @@ -302,14 +354,16 @@ if last_element and not _is_comma(last_element): raise Exception('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.') last_element = element - if len(vector) == 1: return vector[0] #return single number + 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 def eval_expr(expr_str): ''' Evaluate a mathematical expression string with numbers, and operators. - Numbers will all be parsed. Operators are ^, *, /, -, +. - Raise an exception on failue. ''' + Raise an exception on failue. + Return a list containing the parsed expression. ''' separated_elements = _separate_expression(expr_str) #print "separated", separated_elements rectified_elements = _rectify_minus(separated_elements) @@ -317,8 +371,12 @@ nested_elements = _nest_elements(rectified_elements) #print "nested", nested_elements simplified = _simplify_nested_elements(nested_elements) + if not _is_list(simplified): simplified = [simplified] #keep it in list form return simplified if __name__ == '__main__': - print eval_expr('') + ''' Evaluate expressions passed by argv(1). ''' + import sys + if len(sys.argv) > 1: print eval_expr(sys.argv[1]) + else: print "No expressions passed!" \ No newline at end of file Modified: grc/branches/jblum_work/src/SignalBlockDefs/SignalBlockTree.py =================================================================== --- grc/branches/jblum_work/src/SignalBlockDefs/SignalBlockTree.py 2007-05-29 11:37:08 UTC (rev 5564) +++ grc/branches/jblum_work/src/SignalBlockDefs/SignalBlockTree.py 2007-05-29 13:06:43 UTC (rev 5565) @@ -190,9 +190,9 @@ try: get_signal_block(None, (0,0), 0, tag[0], '') if tag[0] in tags_set: # remove redundant tags # - print 'Removing redundant tag "%s" in category "%s"...'%(tag[0], category) - tags_to_remove.append(tag) - else: tags_set.add(tag[0]) + print 'Removing redundant tag "%s" in category "%s"...'%(tag[0], category) + tags_to_remove.append(tag) + else: tags_set.add(tag[0]) except (ImportError, AttributeError), e: print e, " in %s! -> continuing..."%tag[0] tags_to_remove.append(tag) @@ -204,7 +204,7 @@ if len(tags) == 0: print 'Removing category "%s", it was emptied...'%category cats_to_remove.append((category,tags)) -for cat in cats_to_remove: TAGS.remove(cat) +for cat in cats_to_remove: SB_TREE.remove(cat) class TagNotFoundException(Exception): _______________________________________________ Commit-gnuradio mailing list [email protected] http://lists.gnu.org/mailman/listinfo/commit-gnuradio
