WebGL 逆 FFT 实现
WebGL inverse FFT implementation
我正在尝试使用片段着色器在 WebGL 中实现 FFT 和相关的逆 FFT。我正在使用来自 this github site 的着色器代码。我相信我正在正确地进行 FFT,因为我得到的结果看起来是正确的,但是我对逆 FFT 的实现并没有像它应该的那样给我返回初始结果。我对逆FFT的理解只是改变旋转因子参数上的符号:
FFT twiddleArgument = -2.0 * PI * (index / u_subtransformSize)
iFFT twiddleArgument = 2.0 * PI * (index / u_subtransformSize)
我在概念上有什么地方做错了吗?
FFT 着色器代码:
//GPU FFT using a Stockham formulation
#define HORIZONTAL
precision mediump float;
const float PI = 3.14159265359;
uniform sampler2D u_input_complex;
uniform float u_transformSize;
uniform float u_subtransformSize;
varying vec2 vUV;
vec2 multiplyComplex (vec2 a, vec2 b) {
return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);
}
void main(void){
#ifdef HORIZONTAL
float index = vUV.x * u_transformSize - 0.5;
#else
float index = vUV.y * u_transformSize - 0.5;
#endif
float evenIndex = floor(index / u_subtransformSize) * (u_subtransformSize * 0.5) + mod(index, u_subtransformSize * 0.5);
//transform two complex sequences simultaneously
#ifdef HORIZONTAL
vec4 even = texture2D(u_input_complex, vec2(evenIndex + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
vec4 odd = texture2D(u_input_complex, vec2(evenIndex + u_transformSize * 0.5 + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
#else
vec4 even = texture2D(u_input_complex, vec2(gl_FragCoord.x, evenIndex + 0.5) / u_transformSize).rgba;
vec4 odd = texture2D(u_input_complex, vec2(gl_FragCoord.x, evenIndex + u_transformSize * 0.5 + 0.5) / u_transformSize).rgba;
#endif
float twiddleArgument1D = -2.0 * PI * (index / u_subtransformSize);
vec2 twiddle1D = vec2(cos(twiddleArgument1D), sin(twiddleArgument1D));
vec2 outputA = even.xy + multiplyComplex(twiddle1D, odd.xy); //even.xy
vec2 outputB = even.zw + multiplyComplex(twiddle1D, odd.zw); //even.zw
gl_FragColor = vec4(outputA,outputB);
}
反向 FFT 着色器代码:
precision mediump float;
const float PI = 3.14159265359;
uniform sampler2D u_input;
uniform float u_transformSize;
uniform float u_subtransformSize;
varying vec2 vUV;
vec2 multiplyComplex (vec2 a, vec2 b) {
return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);
}
void main(void){
#ifdef HORIZONTAL
float index = vUV.x * u_transformSize - 0.5;
#else
float index = vUV.y * u_transformSize - 0.5;
#endif
float evenIndex = floor(index / u_subtransformSize) * (u_subtransformSize * 0.5) + mod(index, u_subtransformSize * 0.5);
//transform two complex sequences simultaneously
#ifdef HORIZONTAL
vec4 even = texture2D(u_input, vec2(evenIndex + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
vec4 odd = texture2D(u_input, vec2(evenIndex + u_transformSize * 0.5 + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
#else
vec4 even = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + 0.5) / u_transformSize).rgba;
vec4 odd = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + u_transformSize * 0.5 + 0.5) / u_transformSize).rgba;
#endif
float twiddleArgument1D = 2.0 * PI * (index / u_subtransformSize);
vec2 twiddle1D = vec2(cos(twiddleArgument1D), sin(twiddleArgument1D));
vec2 outputA = even.xy + multiplyComplex(twiddle1D, odd.xy);
vec2 outputB = even.zw + multiplyComplex(twiddle1D, odd.zw); //even.zw
gl_FragColor = vec4(outputA, outputB);
}
我看到的错误与我 运行 的另一个着色器程序中的拼写错误有关(不是问题中发布的着色器程序)。我现在开始工作了。问题中的着色器适用于 FFT 和 iFFT。
当你有FFT函数时,你可以使用它创建IFFT函数。
r
:实数。
i
:虚数。
c
:r
和i
集合的复数。
carr
: c
.
数组
cswap(carr)
:交换 carr
中每个 c
的 r
和 i
。
cnorm(carr)
:将carr
中的每个c
s归一化为carr
的长度。
fft(carr)
: carr
.
的快速傅立叶变换
然后
ifft(carr)
: cnorm(cswap(fft(cswap(carr))))
.
我正在尝试使用片段着色器在 WebGL 中实现 FFT 和相关的逆 FFT。我正在使用来自 this github site 的着色器代码。我相信我正在正确地进行 FFT,因为我得到的结果看起来是正确的,但是我对逆 FFT 的实现并没有像它应该的那样给我返回初始结果。我对逆FFT的理解只是改变旋转因子参数上的符号:
FFT twiddleArgument = -2.0 * PI * (index / u_subtransformSize)
iFFT twiddleArgument = 2.0 * PI * (index / u_subtransformSize)
我在概念上有什么地方做错了吗?
FFT 着色器代码:
//GPU FFT using a Stockham formulation
#define HORIZONTAL
precision mediump float;
const float PI = 3.14159265359;
uniform sampler2D u_input_complex;
uniform float u_transformSize;
uniform float u_subtransformSize;
varying vec2 vUV;
vec2 multiplyComplex (vec2 a, vec2 b) {
return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);
}
void main(void){
#ifdef HORIZONTAL
float index = vUV.x * u_transformSize - 0.5;
#else
float index = vUV.y * u_transformSize - 0.5;
#endif
float evenIndex = floor(index / u_subtransformSize) * (u_subtransformSize * 0.5) + mod(index, u_subtransformSize * 0.5);
//transform two complex sequences simultaneously
#ifdef HORIZONTAL
vec4 even = texture2D(u_input_complex, vec2(evenIndex + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
vec4 odd = texture2D(u_input_complex, vec2(evenIndex + u_transformSize * 0.5 + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
#else
vec4 even = texture2D(u_input_complex, vec2(gl_FragCoord.x, evenIndex + 0.5) / u_transformSize).rgba;
vec4 odd = texture2D(u_input_complex, vec2(gl_FragCoord.x, evenIndex + u_transformSize * 0.5 + 0.5) / u_transformSize).rgba;
#endif
float twiddleArgument1D = -2.0 * PI * (index / u_subtransformSize);
vec2 twiddle1D = vec2(cos(twiddleArgument1D), sin(twiddleArgument1D));
vec2 outputA = even.xy + multiplyComplex(twiddle1D, odd.xy); //even.xy
vec2 outputB = even.zw + multiplyComplex(twiddle1D, odd.zw); //even.zw
gl_FragColor = vec4(outputA,outputB);
}
反向 FFT 着色器代码:
precision mediump float;
const float PI = 3.14159265359;
uniform sampler2D u_input;
uniform float u_transformSize;
uniform float u_subtransformSize;
varying vec2 vUV;
vec2 multiplyComplex (vec2 a, vec2 b) {
return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);
}
void main(void){
#ifdef HORIZONTAL
float index = vUV.x * u_transformSize - 0.5;
#else
float index = vUV.y * u_transformSize - 0.5;
#endif
float evenIndex = floor(index / u_subtransformSize) * (u_subtransformSize * 0.5) + mod(index, u_subtransformSize * 0.5);
//transform two complex sequences simultaneously
#ifdef HORIZONTAL
vec4 even = texture2D(u_input, vec2(evenIndex + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
vec4 odd = texture2D(u_input, vec2(evenIndex + u_transformSize * 0.5 + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
#else
vec4 even = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + 0.5) / u_transformSize).rgba;
vec4 odd = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + u_transformSize * 0.5 + 0.5) / u_transformSize).rgba;
#endif
float twiddleArgument1D = 2.0 * PI * (index / u_subtransformSize);
vec2 twiddle1D = vec2(cos(twiddleArgument1D), sin(twiddleArgument1D));
vec2 outputA = even.xy + multiplyComplex(twiddle1D, odd.xy);
vec2 outputB = even.zw + multiplyComplex(twiddle1D, odd.zw); //even.zw
gl_FragColor = vec4(outputA, outputB);
}
我看到的错误与我 运行 的另一个着色器程序中的拼写错误有关(不是问题中发布的着色器程序)。我现在开始工作了。问题中的着色器适用于 FFT 和 iFFT。
当你有FFT函数时,你可以使用它创建IFFT函数。
r
:实数。
i
:虚数。
c
:r
和i
集合的复数。
carr
: c
.
cswap(carr)
:交换 carr
中每个 c
的 r
和 i
。
cnorm(carr)
:将carr
中的每个c
s归一化为carr
的长度。
fft(carr)
: carr
.
然后
ifft(carr)
: cnorm(cswap(fft(cswap(carr))))
.