2.查表法
在实时DSP应用中实现非线性运算,一般都采取适当降低运算精度来提高程序的运算速度。查表法是快速实现非线性运算最常用的方法。采用这种方法必须根据自变量的范围和精度要求制作一张表格。显然输入的范围越大,精度要求越高,则所需的表格就越大,即存储量也越大。查表法求值所需的计算就是根据输入值确定表的地址,根据地址就可得到相应的值,因而运算量较小。查表法比较适合于非线性函数是周期函数或已知非线性函数输入值范围这两种情况,例3.12和例3.13分别说明这两种情况。
例3.12 已知正弦函数y=cos(x),制作一个512点表格,并说明查表方法。
由于正弦函数是周期函数,函数值在-1至+1之间,用查表法比较合适。
由于Q15的表示范围为-1至32767/32768之间,原则上讲-1至+1的范围必须用Q14表示。但一般从方便和总体精度考虑,类似情况仍用Q15表示,此时+1用32767来表示。
(1) 产生512点值的C语言程序如下所示:
#define N 512
#define pi 3.14159
int sin_tab[512];
void main( )
{
int i;
for(i=0;i<N;i++) sin_tab[i]=(int)(32767*sin(2*pi*i/N)); //32767为2的15次方
}
(2) 查表
查表实际上就是根据输入值确定表的地址。设输入x在0~2p之间,则x对应于512点表的地址为:index = (int)(512*x/2p),则 y = sin(x) = sin_tab[index]。
如果x用Q12定点数表示,将512/2p用Q8表示为 20861,则计算正弦表的地址的公式为:index = (x*20861L)>>20
例3.13 用查表法求以2为底的对数,已知自变量取值范围为0.5~1,要求将自变量范围均匀划分为10等分。试制作这个表格并说明查表方法。
(1) 做表:
y = log2(x),由于x在0.5到1之间,因此y在-1到0之间,x和y均可用Q15表示。由于对x均匀划分为10段,因此,10段对应于输入x的范围如表3.2所示。若每一段的对数值都取第1点的对数值,则表中第1段的对数值为y0(Q15) = (int)(log2(0.5)×32768),第2段的对数值为y1(Q15) = (int)(log2(0.55)×32768),依次类推。
表3.2 logtab0 10点对数表(输入0.5~1)
地址
输入值
对数值(Q15)
0
0.50~0.55
-32768
1
0.55~0.60
-28262
2
0.60~0.65
-24149
3
0.65~0.70
-20365
4
0.70~0.75
-16862
5
0.75~0.80
-13600
6
0.80~0.85
-10549
7
0.85~0.90
-7683
8
0.90~0.95
-4981
9
0.95~1.00
-2425
(2) 查表:查表时,先根据输入值计算表的地址,计算方法为:index=( (x-16384)×20)>>15。式中,index就是查表用的地址。例如,已知输入x= 26869,则index=6,因此y= -10549。
3.混合法
(1) 提高查表法的精度
上述方法查表所得结果的精度随表的大小而变化,表越大,则精度越高,但存储量也越大。当系统的存储量有限而精度要求也较高时,查表法就不太适合。那么能否在适当增加运算量的情况下提高非线性运算的精度呢?下面介绍一种查表结合少量运算来计算非线性函数的混合法,这种方法适用于在输入变量的范围内函数呈单调变化的情形。
混合法是在查表的基础上采用计算的方法以提高当输入值处于表格两点之间时的精度。提高精度的一个简便方法是采用折线近似法,如图3.1所示。
仍以求以2为底的对数为例(例3.13)。设输入值为x,则精确的对数值为y,在表格值的两点之间作一直线,用y'作为y的近似值,则有:
y'=y0+ y
如
图3.1 提高精度的折线近似法
其中y0由查表求得。现在只需在查表求得y0的基础上增加 y即可。 y的计算方法如下:
y=( x/ x0) y= x( y0/ x0)
式中 y0/ x0对每一段来说是一个恒定值,可作一个表格直接查得。此外计算 x时需用到每段横坐标的起始值,这个值也可作一个表格。这样共有三个大小均为10的表格,分别为存储每段起点对数值的表logtab0、存储每段 y0/ x0 值的表logtab1和存储每段输入起始值x0的表logtab2,表logtab1和表logtab2可用下列两个数组表示:
int logtab1[10]={22529,20567,18920,17517,16308,15255,14330,13511,12780,12124};
int logtab2[10]={16384,18022,19660,21299,22938,24576,26214,27853,29491,31130};
综上所述,采用混合法计算对数值的方法可归纳为:
①根据输入值,计算查表地址:index=((x-16384)×20)>>15;
②查表得y0=logtab0[index];
③计算 x=x-logtab2[index];
④计算 y=( x×logtab1[index])>>13;
⑤计算得结果y=y0+ y。
例3.15 实现以2为底的对数的C定点模拟程序
int logtab0[10]={-32768,-28262,-24149,-20365,-16862,
-13600,-10549,-7683,-4981,-2425};
int logtab1[10]={22529,20567,18920,17517,16308,
15255,14330,13511,12780,12124};
int logtab2[10]={16384,18022,19660,21299,22938,
24576,26214,27853,29491,31130};
int log2_fast(int Am)
{
int point,point1;
int index,x0,dx,dy,y;
point=0;
while(Am<16384) {point++;Am=Am<<1;}
point1=(15-point-4)*512;
index=((Am-16384)*20L)>>15;
dx=Am-logtab2[index];
dy=((long)dx*logtab1[index])>>13;
y=(dy+logtab0[index])>>6;
y=point1+y;
return (y);
}
上述程序中,输入值Am采用Q4表示,输出采用Q9表示,果输入输出的Q值与上面程序中的不同,则应做相应的修改。 |