1import os.path 2import numpy as np 3import itertools 4import Tools 5import math 6 7import numpy as np 8 9def q31accuracy(x): 10 return(np.round(1.0*x * (1<<31))) 11 12def q15accuracy(x): 13 return(np.round(1.0*x * (1<<15))) 14 15def q7accuracy(x): 16 return(np.round(1.0*x * (1<<7))) 17 18def Q31toF32(x): 19 return(1.0*x / 2**31) 20 21def Q15toF32(x): 22 return(1.0*x / 2**15) 23 24def Q7toF32(x): 25 return(1.0*x / 2**7) 26 27# Those patterns are used for tests and benchmarks. 28# For tests, there is the need to add tests for saturation 29 30# For benchmarks 31NBSAMPLES=256 32 33def cartesian(*somelists): 34 r=[] 35 for element in itertools.product(*somelists): 36 r.append(element) 37 return(r) 38 39# Fixed point division should not be called with a denominator of zero. 40# But if it is, it should return a saturated result. 41def divide(f,r): 42 e = 0 43 a,b=r 44 45 if f == Tools.Q31: 46 e = 1.0 / (1<<31) 47 a = 1.0*q31accuracy(a) / (2**31) 48 b = 1.0*q31accuracy(b) / (2**31) 49 if f == Tools.Q15: 50 e = 1.0 / (1<<15) 51 a = 1.0*q15accuracy(a) / (2**15) 52 b = 1.0*q15accuracy(b) / (2**15) 53 if f == Tools.Q7: 54 e = 1.0 / (1<<7) 55 a = 1.0*q7accuracy(a) / (2**7) 56 b = 1.0*q7accuracy(b) / (2**7) 57 58 if b == 0.0: 59 if a >= 0.0: 60 return(1.0,0) 61 else: 62 return(-1.0,0) 63 64 k = 0 65 while abs(a) > abs(b): 66 a = a / 2.0 67 k = k + 1 68 # In C code we don't saturate but instead generate the right value 69 # with a shift of 1. 70 # So this test is to ease the comparison between the Python reference 71 # and the output of the division algorithm in C 72 if abs(a/b) > 1 - e: 73 a = a / 2.0 74 k = k + 1 75 76 return(a/b,k) 77 78 79def initLogValues(format): 80 if format == Tools.Q15: 81 vals=np.linspace(np.float_power(2,-15),1.0,num=125) 82 elif format == Tools.F16: 83 vals=np.linspace(np.float_power(2,-10),1.0,num=125) 84 else: 85 vals=np.linspace(np.float_power(2,-31),1.0,num=125) 86 87 88 ref=np.log(vals) 89 if format==Tools.Q31 : 90 # Format must be Q5.26 91 ref = ref / 32.0 92 if format == Tools.Q15: 93 # Format must be Q4.11 94 ref = ref / 16.0 95 return(vals,ref) 96 97def normalizeToOne(x): 98 s = 0 99 while (abs(x)>1): 100 x = x /2.0 101 s = s + 1 102 return(int(s),x) 103 104def writeTests(config,format): 105 106 a1=np.array([0,math.pi/4,math.pi/2,3*math.pi/4,math.pi,5*math.pi/4,3*math.pi/2,2*math.pi-1e-6]) 107 a2=np.array([-math.pi/4,-math.pi/2,-3*math.pi/4,-math.pi,-5*math.pi/4,-3*math.pi/2,-2*math.pi-1e-6]) 108 a3 = a1 + 2*math.pi 109 angles=np.concatenate((a1,a2,a3)) 110 refcos = np.cos(angles) 111 refsin = np.sin(angles) 112 113 114 vals=np.linspace(0.0,1.0,1024) 115 sqrtvals=np.sqrt(vals) 116 117 # Negative values in CMSIS are giving 0 118 vals[0] = -0.4 119 sqrtvals[0] = 0.0 120 121 if format != Tools.F64 and format != 0 and format != 16: 122 angles=np.concatenate((a1,a2,a1)) 123 angles = angles / (2*math.pi) 124 config.writeInput(1, angles,"Angles") 125 126 config.writeInput(1, vals,"SqrtInput") 127 config.writeReference(1, sqrtvals,"Sqrt") 128 129 config.writeReference(1, refcos,"Cos") 130 config.writeReference(1, refsin,"Sin") 131 132 133 # For benchmarks 134 samples=np.random.randn(NBSAMPLES) 135 samples = np.abs(Tools.normalize(samples)) 136 config.writeInput(1, samples,"Samples") 137 138 numerator=np.linspace(-0.9,0.9) 139 numerator=np.hstack([numerator,np.array([-1.0,1.0])]) 140 denominator=np.linspace(-0.9,0.9) 141 denominator=np.hstack([denominator,np.array([-1.0,1.0])]) 142 143 samples=cartesian(numerator,denominator) 144 numerator=[x[0] for x in samples] 145 denominator=[x[1] for x in samples] 146 147 result=[divide(format,x) for x in samples] 148 149 resultValue=[x[0] for x in result] 150 resultShift=[x[1] for x in result] 151 152 config.setOverwrite(False) 153 config.writeInput(1, numerator,"Numerator") 154 config.writeInput(1, denominator,"Denominator") 155 config.writeReference(1, resultValue,"DivisionValue") 156 config.writeReferenceS16(1, resultShift,"DivisionShift") 157 config.setOverwrite(False) 158 159 160 vals,ref=initLogValues(format) 161 config.writeInput(1, vals,"LogInput") 162 config.writeReference(1, ref,"Log") 163 164 config.setOverwrite(False) 165 166 # Testing of ATAN2 167 angles=np.linspace(0.0,2*math.pi,1000,endpoint=True) 168 angles=np.hstack([angles,np.array([math.pi/4.0])]) 169 if format == Tools.Q31 or format == Tools.Q15: 170 radius=[1.0] 171 else: 172 radius=np.linspace(0.1,0.9,10,endpoint=True) 173 combinations = cartesian(radius,angles) 174 res=[] 175 yx = [] 176 for r,angle in combinations: 177 x = r*np.cos(angle) 178 y = r*np.sin(angle) 179 res.append(np.arctan2(y,x)) 180 yx.append(y) 181 yx.append(x) 182 183 184 config.writeInput(1, np.array(yx).flatten(),"Atan2Input") 185 186 # Q2.29 or Q2.13 to represent PI in the output 187 if format == Tools.Q31 or format == Tools.Q15: 188 config.writeReference(1, np.array(res)/4.0,"Atan2Ref") 189 else: 190 config.writeReference(1, np.array(res),"Atan2Ref") 191 192 config.setOverwrite(False) 193 194 if format == Tools.Q31 or format == Tools.Q15: 195 196 if format == Tools.Q31: 197 theInput=np.array([1.0-1e-6,0.6,0.5,0.3,0.25,0.1,1.0/(1<<31)]) 198 199 if format == Tools.Q15: 200 theInput=np.array([1.0-1e-6,0.6,0.5,0.3,0.25,0.1,1.0/(1<<15)]) 201 202 ref=1.0 / theInput 203 shiftAndScaled=np.array([normalizeToOne(x) for x in ref]).transpose() 204 shiftValues=shiftAndScaled[0].astype(np.int16) 205 scaledValues=shiftAndScaled[1] 206 #print(shiftAndScaled) 207 208 209 config.writeInput(1, np.array(theInput),"RecipInput") 210 config.writeReference(1, scaledValues,"RecipRef") 211 config.writeReferenceS16(1, shiftValues,"RecipShift") 212 213 214 215def tocint32(x): 216 if x < 0: 217 return((0x10000000000000000 + x) & 0xFFFFFFFF) 218 else: 219 return(x & 0xFFFFFFFF) 220 221# C and Python are not rounding the integer division 222# in the same way 223def cdiv(a,b): 224 sign = 1 225 if ((a<0) and (b>0)) or ((a>0) and (b<0)): 226 sign = -1 227 228 a= abs(a) 229 b = abs(b) 230 231 d = sign*(a // b) 232 233 return(d) 234 235def testInt64(config): 236 theInput=[0x1000000080000000, 237 0x0000000080000000, 238 0x0000000020000000, 239 0x0000000000000000] 240 241 ref=[0x40000002, 242 0x40000000, 243 0x40000000, 244 0 245 ] 246 norms=[-30,-1,1,0] 247 config.writeInputU64(1,np.array(theInput),"Norm64To32_Input") 248 config.writeReferenceS16(1,norms,"RefNorm64To32_Norms") 249 config.writeReferenceS32(1,ref,"RefNorm64To32_Vals") 250 251 config.setOverwrite(False) 252 253 allCombinations=[(0x7FFFFFFFFFFFFFFF,2), 254 (-0x7FFFFFFFFFFFFFFF-1,2), 255 ( 0x4000000000000000,0x7FFFFFFF), 256 ( -0x4000000000000000,0x7FFFFFFF), 257 ( 0x2000000000000000,0x7FFFFFFF), 258 ( -0x2000000000000000,0x7FFFFFFF), 259 ( 0x1000000000000000,0x7FFFFFFF), 260 ( -0x1000000000000000,0x7FFFFFFF), 261 ( 0x0000000080000000,2), 262 ( -0x0000000080000000,2), 263 ( 0x0000000040000000,2), 264 ( -0x0000000080000000,2) 265 ] 266 267 res = [tocint32(cdiv(x,y)) for (x,y) in allCombinations] 268 269 allCombinations=np.array(allCombinations,dtype=np.int64).flatten() 270 config.writeInputS64(1,allCombinations[0::2],"DivDenInput") 271 config.writeInputS32(1,allCombinations[1::2],"DivNumInput") 272 273 config.writeReferenceU32(1, res,"DivRef") 274 config.setOverwrite(False) 275 276 277def writeTestsFloat(config,format): 278 279 writeTests(config,format) 280 281 data1 = np.random.randn(20) 282 data1 = np.abs(data1) 283 data1 = data1 + 1e-3 # To avoid zero values 284 data1 = Tools.normalize(data1) 285 286 287 samples=np.concatenate((np.array([0.0,1.0]),np.linspace(-0.4,0.4))) 288 config.writeInput(1, samples,"ExpInput") 289 v = np.exp(samples) 290 config.writeReference(1, v,"Exp") 291 292 # For benchmarks and other tests 293 samples=np.random.randn(NBSAMPLES) 294 samples = np.abs(Tools.normalize(samples)) 295 config.writeInput(1, samples,"Samples") 296 297 v = 1.0 / samples 298 config.writeReference(1, v,"Inverse") 299 300 301 302 303 304def generatePatterns(): 305 PATTERNDIR = os.path.join("Patterns","DSP","FastMath","FastMath") 306 PARAMDIR = os.path.join("Parameters","DSP","FastMath","FastMath") 307 308 configf64=Tools.Config(PATTERNDIR,PARAMDIR,"f64") 309 configf32=Tools.Config(PATTERNDIR,PARAMDIR,"f32") 310 configf16=Tools.Config(PATTERNDIR,PARAMDIR,"f16") 311 configq31=Tools.Config(PATTERNDIR,PARAMDIR,"q31") 312 configq15=Tools.Config(PATTERNDIR,PARAMDIR,"q15") 313 314 configq64=Tools.Config(PATTERNDIR,PARAMDIR,"q63") 315 316 317 318 configf64.setOverwrite(False) 319 configf32.setOverwrite(False) 320 configf16.setOverwrite(False) 321 configq31.setOverwrite(False) 322 configq15.setOverwrite(False) 323 configq64.setOverwrite(False) 324 325 writeTestsFloat(configf64,Tools.F64) 326 writeTestsFloat(configf32,0) 327 writeTestsFloat(configf16,16) 328 writeTests(configq31,31) 329 writeTests(configq15,15) 330 331 testInt64(configq64) 332 333 334if __name__ == '__main__': 335 generatePatterns() 336 337