API
kissfft有两套API,
一个是在kiss_fftr.h中
另一个在kiss_fft.h中
区别
Basic API还是kiss_fft.h里的,kiss_fftr.h是在kiss_fft.h的基础上封装了一层。
Basic API只有fft没有见到ifft??
利用频域数据的共轭对称性可以使用一个接口完成fft和ifft,这里的逻辑也即是kiss_fftr.h里封装的两个接口
Demo编码数据类型都采用FIXED_POINT, 即int16
Demo
下面的代码是在源码中test_real.c中改的,部分函数可参见源码,这里不再列出
int i = 0;int nfft = 8;kiss_fft_cpx cin[nfft];kiss_fft_cpx cout[nfft];kiss_fft_cpx sout[nfft];kiss_fft_cfg kiss_fft_state;kiss_fftr_cfg kiss_fftr_state;kiss_fft_scalar rin[nfft * 2];kiss_fft_scalar rout[nfft * 2];memset(rin, 0, sizeof(short) * nfft * 2);memset(rout, 0, sizeof(short) * nfft * 2);kiss_fft_scalar zero;memset(&zero, 0, sizeof(zero));for (i = 0; i < nfft; ++i) {rin[i] = rand_scalar();cin[i].r = rin[i];cin[i].i = zero;}for (; i < nfft * 2; ++i) {rin[i] = rand_scalar();}printf(" init data for kiss_fft (rin): ");for (i = 0; i < nfft * 2; i++) {printf("%d, ", rin[i]);}printf("\n");printf(" init data for kiss_fft (cin): ");for (i = 0; i < nfft; i++) {printf("(%d+%di), ", cin[i].r, cin[i].i);}printf("\n");memset(cout, 0, sizeof(short) * nfft);memset(sout, 0, sizeof(short) * nfft);kiss_fft_state = kiss_fft_alloc(nfft, 0, 0, 0);kiss_fftr_state = kiss_fftr_alloc(nfft, 0, 0, 0);kiss_fft(kiss_fft_state, cin, cout);kiss_fftr(kiss_fftr_state, rin, sout);free(kiss_fft_state);free(kiss_fftr_state);printf(" results from kiss_fft (cout): ");for (i = 0; i < nfft; i++) {printf("(%d+%di), ", cout[i].r, cout[i].i);}printf("\n");printf(" results from kiss_fftr (sout): ");for (i = 0; i < nfft; i++) {printf("(%d+%di), ", sout[i].r, sout[i].i);}printf("\n");printf("##### nfft=%d, inverse=%d, snr=%g\n", nfft, 0, snr_compare(cout, sout, (nfft / 2) + 1));kiss_fft_state = kiss_fft_alloc(nfft, 1, 0, 0);kiss_fftr_state = kiss_fftr_alloc(nfft, 1, 0, 0);// 我们在这里分别使用cout(fft API)结果和sout(fftrAPI)结果来比较ifft的准确性// case A. kiss_fft(kiss_fft_state, cout, cin);kiss_fftri(kiss_fftr_state, cout, rin);// case B. // kiss_fft(kiss_fft_state, sout, cin);// kiss_fftri(kiss_fftr_state, sout, rin);// end casefree(kiss_fft_state);free(kiss_fftr_state);printf(" results from kiss_ifft (cin): ");for (i = 0; i < nfft; i++) {cin[i].r *= nfft;cin[i].i *= nfft;printf("(%d+%di), ", cin[i].r, cin[i].i);}printf("\n");printf(" results from kiss_fftri (rin): ");for (i = 0; i < nfft * 2; i++) {rin[i] *= nfft;printf("%d, ", rin[i]);}printf("\n");
结果
实数数组是复数数据长度的两倍,但是从源码可以看到int16的数组会被强转为kiss_fft_cpx结构体,每两个数据会被拼成一个kiss_fft_cpx结构体。所以总数据量长度是一致的。
但是从结果来看,basic fft API比fftr API做出来的结果更可靠一些。(result的三四行对比)
inverse FFT
case A (使用fft API结果做ifft)
- 如果处理正确,得到的结果是nfft长度的复数数组,image均为0,real部分是ifft数据。
- fftr的结果在大于nfft长度时就开始偏离了
case B (使用fftr API结果做ifft)
- fftr API结果不可用于fft的ifft处理。
- fftr的结果在大于nfft长度时就开始偏离了
结论
- fftAPI和fftrAPI不要混用
- ifft后的实数结果只能使用nfft长度,而不能使用2*nfft长度。因为数据实际上是来自kiss_fft_cpx的,数据image部分占用了nfft长度,而且都为0.
其他注意
- 数据越长,ifft还原越存在偏离
- 数据值偏小,如均值小于20,可能ifft还原后的数据大量为0. 解决方案是可以先将原始数据乘nfft,ifft后不要再乘nfft了,就是这个动作前置。