14930cef6SMatthias Ringwald#!/usr/bin/env python3 24930cef6SMatthias Ringwald# 34930cef6SMatthias Ringwald# Copyright 2022 Google LLC 44930cef6SMatthias Ringwald# 54930cef6SMatthias Ringwald# Licensed under the Apache License, Version 2.0 (the "License"); 64930cef6SMatthias Ringwald# you may not use this file except in compliance with the License. 74930cef6SMatthias Ringwald# You may obtain a copy of the License at 84930cef6SMatthias Ringwald# 94930cef6SMatthias Ringwald# http://www.apache.org/licenses/LICENSE-2.0 104930cef6SMatthias Ringwald# 114930cef6SMatthias Ringwald# Unless required by applicable law or agreed to in writing, software 124930cef6SMatthias Ringwald# distributed under the License is distributed on an "AS IS" BASIS, 134930cef6SMatthias Ringwald# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 144930cef6SMatthias Ringwald# See the License for the specific language governing permissions and 154930cef6SMatthias Ringwald# limitations under the License. 164930cef6SMatthias Ringwald# 174930cef6SMatthias Ringwald 184930cef6SMatthias Ringwaldimport numpy as np 194930cef6SMatthias Ringwaldimport matplotlib.pyplot as plt 204930cef6SMatthias Ringwald 214930cef6SMatthias Ringwald 22*6897da5cSDirk Helbigdef fast_exp2(x, t, p): 234930cef6SMatthias Ringwald 244930cef6SMatthias Ringwald p = p.astype(np.float32) 254930cef6SMatthias Ringwald x = x.astype(np.float32) 264930cef6SMatthias Ringwald 27*6897da5cSDirk Helbig m = ((x + 0.5/8) % (1/8)) - (0.5/8) 28*6897da5cSDirk Helbig e = int((x - m) * 8) 294930cef6SMatthias Ringwald 30*6897da5cSDirk Helbig y = ((((p[0]*m) + p[1])*m + p[2])*m + p[3])*m + p[4] 31*6897da5cSDirk Helbig y = y * 2**(e // 8) * t[e % 8] 32*6897da5cSDirk Helbig 33*6897da5cSDirk Helbig return y.astype(np.float32) 344930cef6SMatthias Ringwald 354930cef6SMatthias Ringwalddef approx_exp2(): 364930cef6SMatthias Ringwald 37*6897da5cSDirk Helbig x = np.arange(0, 1/8, step=1e-6) 38*6897da5cSDirk Helbig p = np.polyfit(x, 2 ** x, 4) 39*6897da5cSDirk Helbig t = [ 2**(i/8) for i in range(8) ] 404930cef6SMatthias Ringwald 41*6897da5cSDirk Helbig x = np.arange(-10, 10, step=1e-3) 42*6897da5cSDirk Helbig y = [ fast_exp2(x[i], t, p) for i in range(len(x)) ] 43*6897da5cSDirk Helbig 444930cef6SMatthias Ringwald e = np.abs(y - 2**x) / (2 ** x) 454930cef6SMatthias Ringwald 46*6897da5cSDirk Helbig print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, \n' 47*6897da5cSDirk Helbig ' {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, '.format(*t)) 48*6897da5cSDirk Helbig print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e} }}'.format(*p)) 494930cef6SMatthias Ringwald print('Max relative error: ', np.max(e)) 504930cef6SMatthias Ringwald print('Max RMS error: ', np.sqrt(np.mean(e ** 2))) 514930cef6SMatthias Ringwald 524930cef6SMatthias Ringwald if False: 534930cef6SMatthias Ringwald fig, (ax1, ax2) = plt.subplots(2) 544930cef6SMatthias Ringwald 554930cef6SMatthias Ringwald ax1.plot(x, 2**x, label='Reference') 564930cef6SMatthias Ringwald ax1.plot(x, y, label='Approximation') 574930cef6SMatthias Ringwald ax1.legend() 584930cef6SMatthias Ringwald 594930cef6SMatthias Ringwald ax2.plot(x, e, label='Relative Error') 604930cef6SMatthias Ringwald ax2.legend() 614930cef6SMatthias Ringwald 624930cef6SMatthias Ringwald plt.show() 634930cef6SMatthias Ringwald 644930cef6SMatthias Ringwald 654930cef6SMatthias Ringwalddef fast_log2(x, p): 664930cef6SMatthias Ringwald 674930cef6SMatthias Ringwald p = p.astype(np.float32) 684930cef6SMatthias Ringwald x = x.astype(np.float32) 694930cef6SMatthias Ringwald 704930cef6SMatthias Ringwald (x, e) = np.frexp(x) 714930cef6SMatthias Ringwald 724930cef6SMatthias Ringwald y = ((((p[0]*x) + p[1])*x + p[2])*x + p[3])*x + p[4] 734930cef6SMatthias Ringwald 744930cef6SMatthias Ringwald return (e ) + y.astype(np.float32) 754930cef6SMatthias Ringwald 764930cef6SMatthias Ringwalddef approx_log2(): 774930cef6SMatthias Ringwald 784930cef6SMatthias Ringwald x = np.logspace(-1, 0, base=2, num=100) 794930cef6SMatthias Ringwald p = np.polyfit(x, np.log2(x), 4) 804930cef6SMatthias Ringwald 814930cef6SMatthias Ringwald x = np.logspace(-2, 5, num=10000) 824930cef6SMatthias Ringwald y = [ fast_log2(x[i], p) for i in range(len(x)) ] 834930cef6SMatthias Ringwald e = np.abs(y - np.log2(x)) 844930cef6SMatthias Ringwald 854930cef6SMatthias Ringwald print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e} }}' 864930cef6SMatthias Ringwald .format(p[0], p[1], p[2], p[3], p[4])) 874930cef6SMatthias Ringwald print('Max absolute error: ', np.max(e)) 884930cef6SMatthias Ringwald print('Max RMS error: ', np.sqrt(np.mean(e ** 2))) 894930cef6SMatthias Ringwald 904930cef6SMatthias Ringwald if False: 914930cef6SMatthias Ringwald fig, (ax1, ax2) = plt.subplots(2) 924930cef6SMatthias Ringwald 934930cef6SMatthias Ringwald ax1.plot(x, np.log2(x), label='Reference') 944930cef6SMatthias Ringwald ax1.plot(x, y, label='Approximation') 954930cef6SMatthias Ringwald ax1.legend() 964930cef6SMatthias Ringwald 974930cef6SMatthias Ringwald ax2.plot(x, e, label = 'Absolute error') 984930cef6SMatthias Ringwald ax2.legend() 994930cef6SMatthias Ringwald 1004930cef6SMatthias Ringwald plt.show() 1014930cef6SMatthias Ringwald 1024930cef6SMatthias Ringwald 1034930cef6SMatthias Ringwalddef table_db_q16(): 1044930cef6SMatthias Ringwald 1054930cef6SMatthias Ringwald k = 10 * np.log10(2); 1064930cef6SMatthias Ringwald 1074930cef6SMatthias Ringwald for i in range(32): 1084930cef6SMatthias Ringwald a = k * np.log2(np.ldexp(32 + i , -5)) - (i // 16) * (k/2); 1094930cef6SMatthias Ringwald b = k * np.log2(np.ldexp(32 + i+1, -5)) - (i // 16) * (k/2); 1104930cef6SMatthias Ringwald 1114930cef6SMatthias Ringwald an = np.ldexp(a, 15) + 0.5 1124930cef6SMatthias Ringwald bn = np.ldexp(b - a, 15) + 0.5 1134930cef6SMatthias Ringwald print('{{ {:5d}, {:4d} }},' 1144930cef6SMatthias Ringwald .format(int(np.ldexp(a, 15) + 0.5), 1154930cef6SMatthias Ringwald int(np.ldexp(b - a, 15) + 0.5)), 1164930cef6SMatthias Ringwald end = ' ' if i % 4 < 3 else '\n') 1174930cef6SMatthias Ringwald 1184930cef6SMatthias Ringwald 1194930cef6SMatthias Ringwaldif __name__ == '__main__': 1204930cef6SMatthias Ringwald 1214930cef6SMatthias Ringwald print('\n--- Approximation of 2^n ---') 1224930cef6SMatthias Ringwald approx_exp2() 1234930cef6SMatthias Ringwald 1244930cef6SMatthias Ringwald print('\n--- Approximation of log2(n) ---') 1254930cef6SMatthias Ringwald approx_log2() 1264930cef6SMatthias Ringwald 1274930cef6SMatthias Ringwald print('\n--- Table of fixed Q16 dB ---') 1284930cef6SMatthias Ringwald table_db_q16() 1294930cef6SMatthias Ringwald 1304930cef6SMatthias Ringwald print('') 131