Module fixreal
[hide private]
[frames] | no frames]

Source Code for Module fixreal

  1  # coding=utf-8 
  2   
  3  # 
  4  # 
  5  #    Copyright (C) 2012  Marco Bartolini, marco.bartolini@gmail.com 
  6  # 
  7  #    This program is free software: you can redistribute it and/or modify 
  8  #    it under the terms of the GNU General Public License as published by 
  9  #    the Free Software Foundation, either version 3 of the License, or 
 10  #    (at your option) any later version. 
 11  # 
 12  #    This program is distributed in the hope that it will be useful, 
 13  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 15  #    GNU General Public License for more details. 
 16  # 
 17  #    You should have received a copy of the GNU General Public License 
 18  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 19  # 
 20  """ 
 21  Functions to convert numbers between fixed and floating point representation as 
 22  experienced by simulink users. 
 23  Permits conversion of 8, 16 and 32 bit representation of signed and unsigned 
 24  decimal numbers, with or without binary point. 
 25   
 26  INSTALLATION 
 27  ============ 
 28   
 29  Package can be downloaded from the public git repo as:: 
 30   
 31      $ git clone git://github.com/flyingfrog81/fixreal.git 
 32      $ python setup.py install 
 33   
 34  or installed automatically via pypi:: 
 35   
 36      $ pip install fixreal 
 37   
 38   
 39  USAGE 
 40  ===== 
 41   
 42      >>> import fixreal 
 43      >>> fixreal.real2fix(-0.9921875, fixreal.get_conv(8, 7, True)) 
 44      129.0 
 45      >>> fixreal.real2fix(-3.96875, fixreal.get_conv(8, 5, True)) 
 46      129.0 
 47      >>> fixreal.real2fix(-127, fixreal.get_conv(8, 0, True)) 
 48      129.0 
 49      >>> fixreal.real2fix(1.0078125, fixreal.get_conv(8, 7, False)) 
 50      129.0 
 51      >>> fixreal.real2fix(4.03125, fixreal.get_conv(8, 5, False)) 
 52      129.0 
 53      >>> fixreal.real2fix(129, fixreal.get_conv(8, 0, False)) 
 54      129.0 
 55      >>> fixreal.fix2real(0b10000001, fixreal.get_conv(8, 7, True)) 
 56      -0.9921875 
 57      >>> fixreal.fix2real(0b10000001, fixreal.get_conv(8, 5, True)) 
 58      -3.96875 
 59      >>> fixreal.fix2real(0b10000001, fixreal.get_conv(8, 0, True)) 
 60      -127.0 
 61      >>> fixreal.fix2real(0b10000001, fixreal.get_conv(8, 7, False)) 
 62      1.0078125 
 63      >>> fixreal.fix2real(0b10000001, fixreal.get_conv(8, 5, False)) 
 64      4.03125 
 65      >>> fixreal.fix2real(0b10000001, fixreal.get_conv(8, 0, False)) 
 66      129.0 
 67      >>> conv = fixreal.conv_from_name("fix_8_7") 
 68   
 69  @author: Marco Bartolini 
 70  @contact: marco.bartolini@gmail.com 
 71  @version: 0.8 
 72  """ 
 73   
 74  import struct 
 75  import re 
 76   
77 -class ConversionError(BaseException):
78 """ 79 Raised when conversion types are conflicting 80 """ 81 pass
82
83 -def get_conv(bits, bin_point, signed=False, scaling=1.0):
84 """ 85 Creates a I{conversion structure} implented as a dictionary containing all parameters 86 needed to switch between number representations. 87 @param bits: the number of bits 88 @param bin_point: binary point position 89 @param signed: True if Fix, False if UFix 90 @param scaling: optional scaling to be applied after the conversion 91 @return: a conversion structure that can be applied in both directions of 92 conversion for the given specs. 93 """ 94 conversion_t = {} 95 conversion_t["bits"] = bits 96 conversion_t["bin_point"] = bin_point 97 conversion_t["signed"] = signed 98 conversion_t["scaling"] = scaling 99 conversion_t["dec_step"] = 1.0 / (2 ** bin_point) 100 #dec_max = dec_mask * dec_step 101 conversion_t["dec_mask"] = sum([2 ** i for i in range(bin_point)]) 102 if bits == 8: 103 conversion_t["fmt"] = "B" 104 elif bits == 16: 105 conversion_t["fmt"] = "H" 106 elif bits == 32: 107 conversion_t["fmt"] = "I" 108 else: 109 raise ConversionError("numer of bits not supported: " + str(bits)) 110 if signed: 111 _get_signed_params(conversion_t) 112 else: 113 _get_unsigned_params(conversion_t) 114 return conversion_t
115
116 -def conv_from_name(name):
117 """ 118 Understand simulink syntax for fixed types and returns the proper 119 conversion structure. 120 @param name: the type name as in simulin (i.e. UFix_8_7 ... ) 121 @raise ConversionError: When cannot decode the string 122 """ 123 _match = re.match(r"^(?P<signed>u?fix)_(?P<bits>\d+)_(?P<binary>\d+)", 124 name, flags = re.I) 125 if not _match: 126 raise ConversionError("Cannot interpret name: " + name) 127 params = _match.groupdict() 128 if params['signed'] == 'fix': 129 signed = True 130 else: 131 signed = False 132 bits = int(params['bits']) 133 binary = int(params['binary']) 134 return get_conv(bits, binary, signed)
135
136 -def _get_unsigned_params(conv):
137 """ 138 Fill the sign-dependent params of the conv structure in case of unsigned 139 conversion 140 @param conv: the structure to be filled 141 """ 142 conv["sign_mask"] = 0 143 conv["int_min"] = 0 144 conv["int_mask"] = sum([2 ** i for i in range(conv["bin_point"], 145 conv["bits"])]) 146 conv["int_max"] = sum([2 ** i for i in range(conv["bits"] - 147 conv["bin_point"])])
148
149 -def _get_signed_params(conv):
150 """ 151 Fill the sign-dependent params of the conv structure in case of signed 152 conversion 153 @param conv: the structure to be filled 154 """ 155 conv["sign_mask"] = 2 ** (conv["bits"] - 1) 156 conv["int_min"] = -1 * (2 ** (conv["bits"] - 1 - conv["bin_point"])) 157 conv["int_mask"] = sum([2 ** i 158 for i in range(conv["bin_point"], conv["bits"] - 1)]) 159 conv["int_max"] = sum([2 ** i for i in range(conv["bits"] - 160 conv["bin_point"] - 1)])
161
162 -def fix2real(uval, conv):
163 """ 164 Convert a 32 bit unsigned int register into the value it represents in its Fixed arithmetic form. 165 @param uval: the numeric unsigned value in simulink representation 166 @param conv: conv structure with conversion specs as generated by I{get_conv} 167 @return: the real number represented by the Fixed arithmetic defined in conv 168 @todo: Better error detection and management of unsupported operations and arguments 169 """ 170 res = 0 171 int_val = ((uval & conv["int_mask"]) >> conv["bin_point"]) 172 dec_val = conv["dec_step"] * (uval & conv["dec_mask"]) 173 if conv["signed"] and (uval & conv["sign_mask"] > 0): 174 res = conv["int_min"] + int_val + dec_val 175 else: 176 res = int_val + dec_val 177 return (res / conv["scaling"])
178
179 -def bin2real(binary_string, conv, endianness="@"):
180 """ 181 Converts a binary string representing a number to its Fixed arithmetic representation 182 @param binary_string: binary number in simulink representation 183 @param conv: conv structure containing conversion specs 184 @param endianness: optionally specify bytes endianness for unpacking 185 @return: the real number represented 186 @attention: The length of the binary string must match with the data type defined 187 in the conv structure, otherwise proper erros will be thrown by B{struct} 188 module. 189 """ 190 data = struct.unpack(endianness + conv["fmt"], binary_string)[0] 191 return fix2real(data, conv)
192
193 -def stream2real(binary_stream, conv, endianness="@"):
194 """ 195 Converts a binary stream into a sequence of real numbers 196 @param binary_stream: a binary string representing a sequence of numbers 197 @param conv: conv structure containing conversion specs 198 @param endianness: optionally specify bytes endianness for unpacking 199 @return: the list of real data represented 200 """ 201 size = len(binary_stream) // (conv["bits"] // 8) 202 fmt = endianness + str(size) + conv["fmt"] 203 data = struct.unpack(fmt, binary_stream) 204 data = [fix2real(d, conv) for d in data] 205 return data
206
207 -def real2fix(real, conv):
208 """ 209 Convert a real number to its fixed representation so 210 that it can be written into a 32 bit register. 211 @param real: the real number to be converted into fixed representation 212 @param conv: conv structre with conversion specs 213 @return: the fixed representation of the real number 214 @raise ConverisonError: if conv structre can't handle the real number. 215 @todo: Better error detection and management of unsupported 216 operations and arguments 217 """ 218 if not conv["signed"] and real < 0: 219 raise ConversionError("cannot convert " + 220 str(real) + " to unsigned representation") 221 if real < 0: 222 sign = 1 223 real = real - conv["int_min"] 224 else: 225 sign = 0 226 int_val, dec_val = divmod(abs(real), 1) 227 int_val = int(int_val) 228 int_val = int_val & (conv["int_mask"] >> conv["bin_point"]) 229 val = int_val 230 dec = 0 231 dec = dec_val // conv["dec_step"] 232 if dec > conv["dec_mask"]: 233 dec = conv["dec_mask"] 234 dec_val = dec * conv["dec_step"] 235 val += dec_val 236 if (val - real) > (real - val + conv["dec_step"]): 237 dec -= 1 238 if sign == 1: 239 return conv["sign_mask"] + ((int_val << conv["bin_point"]) & 240 conv["int_mask"]) + dec 241 else: 242 return ((int_val << conv["bin_point"]) & conv["int_mask"]) + dec
243