经常遇到的 FFT 的两个应用(尤其是在信号处理区域中)是离散卷积和离散相关运算。
假设有两个函数 x(t) 和 y(t),x(t) 和 y(t) 的卷积的傅里叶变换(表示为 x * y)是各个傅里叶变换的积:DFT (x * y)=X (·) Y,其中 * 表示卷积运算,(·) 表示逐点乘法。
通常,x(t) 是由一组 N 个数据点 xj, j = 0, …, N -1 以离散方式表示的连续和周期性信号,这些数据点是在有限持续时间内取样的,通常是以等间隔在 x(t) 的一个周期内取样。y(t) 通常是以零开始的响应,峰值达到最大值,然后返回到零。在相等间隔对 y(t) 进行离散化处理将生成一组 N 个数据点,yk, k = 0, …, N -1。如果 yk 中的实际取样数量小于 N,则使用零填充数据。然后可将离散卷积定义为
的值与 k = 0, …, N -1 的值相同,但使用环绕顺序。
Oracle Developer Studio 性能库例程允许使用上述定义通过 k = 0, …, N -1 或使用 FFT 来计算卷积。如果使用 FFT 计算两个序列的卷积,请执行以下步骤:
计算 X = x 的正向 FFT
计算 Y = y 的正向 FFT
计算 Z = X (·) Y <=> DFT (x * y)
计算 z = Z 的逆向 FFT;z = (x * y)
卷积的一个有趣的特性是两个多项式的积实际上是一个卷积。m 项多项式
和 n 项多项式
的积具有 m+n-1 系数,可通过以下方程获得该系数:
其中 k = 0, …, m + n - 2。
与卷积密切相关的是相关运算。 它计算直接叠加的两个序列的相关,或一个序列相对于另一个序列发生移位时的相关。与卷积相同,可以使用 FFT 有效地计算两个序列的相关,如下所述:
计算两个输入序列的 FFT。
计算一个序列所产生的变换和另一个序列的变换的共轭复数的逐点积。
计算积的逆向 FFT。
性能库中的例程还允许按以下定义计算相关:
有许多方法可以解释卷积和相关运算的取样输入数据。卷积和相关例程的参数列表包含可处理以下情况的参数:
信号和/或响应函数可能从不同取样时间开始。
您可能只需要部分信号来生成输出。
信号和/或响应函数可能从未显式存储的一个或多个零开始。
Oracle Developer Studio 性能库包含如表 19所示的卷积例程。
|
[S,D,C,Z]CNVCOR 例程用于计算包含一个或多个输入向量的过滤器的卷积或相关。[S,D,C,Z]CNVCOR2 例程用于计算两个矩阵的二维卷积或相关。
一维卷积和相关例程使用表 20中显示的参数。
|
二维卷积和相关例程使用表 21中显示的参数。
|
表 24中显示了与一维和二维卷积和相关例程一起使用的 WORK 工作数组的最小维数。一维卷积和相关例程的最小维数取决于参数 NPRE、NX、NY 和 NZ 的值。
二维卷积和相关例程的最小维数取决于表 22中显示的参数的值。
|
MYC_INIT 和 NYC_INIT 取决于以下矩阵,其中 X 是过滤器矩阵,Y 是输入矩阵。
|
表 24中显示了分配给最小工作数组大小的值。
|
如果由 LWORK 指定的工作区大小不够大,则在例程中分配内存。
以下示例使用 CCNVCOR 执行两个复数向量的 FFT 卷积。
示例 19 使用傅里叶变换方法和复数数据的一维卷积my_system% cat con_ex20.f PROGRAM TEST C INTEGER LWORK INTEGER N PARAMETER (N = 3) PARAMETER (LWORK = 4 * N + 15) COMPLEX P1(N), P2(N), P3(2*N-1), WORK(LWORK) DATA P1 / 1, 2, 3 /, P2 / 4, 5, 6 / C EXTERNAL CCNVCOR C PRINT *, 'P1:' PRINT 1000, P1 PRINT *, 'P2:' PRINT 1000, P2 CALL CCNVCOR ('V', 'T', N, P1, 1, 1, N, 0, 1, P2, 1, 1, 1, $ 2 * N - 1, 1, P3, 1, 1, 1, WORK, LWORK) C PRINT *, 'P3:' PRINT 1000, P3 C 1000 FORMAT (1X, 100(F4.1,' +',F4.1,'i ')) C END my_system% f95 -dalign con_ex20.f -xlibrary=sunperf my_system% a.out P1: 1.0 + 0.0i 2.0 + 0.0i 3.0 + 0.0i P2: 4.0 + 0.0i 5.0 + 0.0i 6.0 + 0.0i P3: 4.0 + 0.0i 13.0 + 0.0i 28.0 + 0.0i 27.0 + 0.0i 18.0 + 0.0i
如果任何向量与可写向量发生重叠(由于使用了参数别名,或者由于为各个 INC 参数选择了不恰当的值),则结果都将为未定义,并且每次运行时都不同。
最常用的计算形式以及执行最快的情况是将过滤器向量 X 应用于存储在 Y 的列中的一系列向量,并将结果放在 Z 的列中。在这种情况下,INCX = 1,INC1Y = 1,INC2Y ≥ NY,INC1Z = 1,INC2Z ≥ NZ。另一种常用形式是将过滤器向量 X 应用于存储在 Y 的行中的一系列向量,并将结果存储在 Z 的行中,在这种情况下,INCX = 1,INC1Y ≥ NY,INC2Y = 1,INC1Z ≥ NZ,以及 INC2Z = 1。
可使用卷积来计算多项式的积。以下示例示例 20使用 SCNVCOR 计算 1 + 2x + 3x2 和 4 + 5x + 6x2 的积。
示例 20 使用傅里叶变换方法和实数数据的一维卷积my_system% cat con_ex21.f PROGRAM TEST INTEGER LWORK, NX, NY, NZ PARAMETER (NX = 3) PARAMETER (NY = NX) PARAMETER (NZ = 2*NY-1) PARAMETER (LWORK = 4*NZ+32) REAL X(NX), Y(NY), Z(NZ), WORK(LWORK) C DATA X / 1, 2, 3 /, Y / 4, 5, 6 /, WORK / LWORK*0 / C PRINT 1000, 'X' PRINT 1010, X PRINT 1000, 'Y' PRINT 1010, Y CALL SCNVCOR ('V', 'T', NX, X, 1, 1, $NY, 0, 1, Y, 1, 1, 1, NZ, 1, Z, 1, 1, 1, WORK, LWORK) PRINT 1020, 'Z' PRINT 1010, Z 1000 FORMAT (1X, 'Input vector ', A1) 1010 FORMAT (1X, 300F5.0) 1020 FORMAT (1X, 'Output vector ', A1) END my_system% f95 -dalign con_ex21.f -library=sunperf my_system% a.out Input vector X 1. 2. 3. Input vector Y 4. 5. 6. Output vector Z 4. 13. 28. 27. 18.
使输出向量比输入向量长,如上例所示,可将零隐式添加到输入末尾。实际上,零不是在任何向量中都是必需的,在示例中也未使用零,但使用隐式零进行填充会产生输入向量的舍入移位的效果,而不是循环移位效果。
以下示例示例 21将计算向量 [ 1, 2, 3 ] 和初始列向量 [ 4, 5, 6 ] 定义的循环矩阵之间的积。
示例 21 用于计算向量和循环矩阵的积的卷积my_system% cat con_ex22.f PROGRAM TEST C INTEGER LWORK, NX, NY, NZ PARAMETER (NX = 3) PARAMETER (NY = NX) PARAMETER (NZ = NY) PARAMETER (LWORK = 4*NZ+32) REAL X(NX), Y(NY), Z(NZ), WORK(LWORK) C DATA X / 1, 2, 3 /, Y / 4, 5, 6 /, WORK / LWORK*0 / C PRINT 1000, 'X' PRINT 1010, X PRINT 1000, 'Y' PRINT 1010, Y CALL SCNVCOR ('V', 'T', NX, X, 1, 1, $NY, 0, 1, Y, 1, 1, 1, NZ, 1, Z, 1, 1, 1, $WORK, LWORK) PRINT 1020, 'Z' PRINT 1010, Z C 1000 FORMAT (1X, 'Input vector ', A1) 1010 FORMAT (1X, 300F5.0) 1020 FORMAT (1X, 'Output vector ', A1) END my_system% f95 -dalign con_ex22.f -library=sunperf my_system% a.out Input vector X 1. 2. 3. Input vector Y 4. 5. 6. Output vector Z 31. 31. 28.
下面的示例和前面的示例之间的区别在于,输出向量的长度与输入向量的长度相同,所以在输入向量的末尾没有隐式零。由于没有可以移位到其中的隐式零,因此不会产生前面示例中的舍入移位的效果,而循环移位将产生循环矩阵积。
示例 22 使用直接方法的二维卷积my_system% cat con_ex23.f PROGRAM TEST C INTEGER M, N PARAMETER (M = 2) PARAMETER (N = 3) C INTEGER I, J COMPLEX P1(M,N), P2(M,N), P3(M,N) DATA P1 / 1, -2, 3, -4, 5, -6 /, P2 / -1, 2, -3, 4, -5, 6 / EXTERNAL CCNVCOR2 C PRINT *, 'P1:' PRINT 1000, ((P1(I,J), J = 1, N), I = 1, M) PRINT *, 'P2:' PRINT 1000, ((P2(I,J), J = 1, N), I = 1, M) C CALL CCNVCOR2 ('V', 'Direct', 'No Transpose X', 'No Overwrite X', $ 'No Transpose Y', 'No Overwrite Y', M, N, P1, M, $ M, N, 0, 0, P2, M, M, N, P3, M, 0, 0) C PRINT *, 'P3:' PRINT 1000, ((P3(I,J), J = 1, N), I = 1, M) C 1000 FORMAT (3(F5.1,' +',F5.1,'i ')) C END my_system% f95 -dalign con_ex23.f -library=sunperf my_system% a.out P1: 1.0 + 0.0i 3.0 + 0.0i 5.0 + 0.0i -2.0 + 0.0i -4.0 + 0.0i -6.0 + 0.0i P2: -1.0 + 0.0i -3.0 + 0.0i -5.0 + 0.0i 2.0 + 0.0i 4.0 + 0.0i 6.0 + 0.0i P3: -83.0 + 0.0i -83.0 + 0.0i -59.0 + 0.0i 80.0 + 0.0i 80.0 + 0.0i 56.0 + 0.0i