···11-#!/usr/bin/env python
22-# Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
33-# This file is part of KISS FFT - https://github.com/mborgerding/kissfft
44-#
55-# SPDX-License-Identifier: BSD-3-Clause
66-# See COPYING file for more information.
77-88-# use FFTPACK as a baseline
99-import FFT
1010-from Numeric import *
1111-import math
1212-import random
1313-import sys
1414-import struct
1515-import fft
1616-1717-pi=math.pi
1818-e=math.e
1919-j=complex(0,1)
2020-lims=(-32768,32767)
2121-2222-def randbuf(n,cpx=1):
2323- res = array( [ random.uniform( lims[0],lims[1] ) for i in range(n) ] )
2424- if cpx:
2525- res = res + j*randbuf(n,0)
2626- return res
2727-2828-def main():
2929- from getopt import getopt
3030- import popen2
3131- opts,args = getopt( sys.argv[1:],'u:n:Rt:' )
3232- opts=dict(opts)
3333- exitcode=0
3434-3535- util = opts.get('-u','./kf_float')
3636-3737- try:
3838- dims = [ int(d) for d in opts['-n'].split(',')]
3939- cpx = opts.get('-R') is None
4040- fmt=opts.get('-t','f')
4141- except KeyError:
4242- sys.stderr.write("""
4343- usage: compfft.py
4444- -n d1[,d2,d3...] : FFT dimension(s)
4545- -u utilname : see sample_code/fftutil.c, default = ./kf_float
4646- -R : real-optimized version\n""")
4747- sys.exit(1)
4848-4949- x = fft.make_random( dims )
5050-5151- cmd = '%s -n %s ' % ( util, ','.join([ str(d) for d in dims]) )
5252- if cpx:
5353- xout = FFT.fftnd(x)
5454- xout = reshape(xout,(size(xout),))
5555- else:
5656- cmd += '-R '
5757- xout = FFT.real_fft(x)
5858-5959- proc = popen2.Popen3( cmd , bufsize=len(x) )
6060-6161- proc.tochild.write( dopack( x , fmt ,cpx ) )
6262- proc.tochild.close()
6363- xoutcomp = dounpack( proc.fromchild.read( ) , fmt ,1 )
6464- #xoutcomp = reshape( xoutcomp , dims )
6565-6666- sig = xout * conjugate(xout)
6767- sigpow = sum( sig )
6868-6969- diff = xout-xoutcomp
7070- noisepow = sum( diff * conjugate(diff) )
7171-7272- snr = 10 * math.log10(abs( sigpow / noisepow ) )
7373- if snr<100:
7474- print xout
7575- print xoutcomp
7676- exitcode=1
7777- print 'NFFT=%s,SNR = %f dB' % (str(dims),snr)
7878- sys.exit(exitcode)
7979-8080-def dopack(x,fmt,cpx):
8181- x = reshape( x, ( size(x),) )
8282- if cpx:
8383- s = ''.join( [ struct.pack('ff',c.real,c.imag) for c in x ] )
8484- else:
8585- s = ''.join( [ struct.pack('f',c) for c in x ] )
8686- return s
8787-8888-def dounpack(x,fmt,cpx):
8989- uf = fmt * ( len(x) / 4 )
9090- s = struct.unpack(uf,x)
9191- if cpx:
9292- return array(s[::2]) + array( s[1::2] )*j
9393- else:
9494- return array(s )
9595-9696-if __name__ == "__main__":
9797- main()
-107
test/fastfir.py
···11-#!/usr/bin/env python
22-# Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
33-# This file is part of KISS FFT - https://github.com/mborgerding/kissfft
44-#
55-# SPDX-License-Identifier: BSD-3-Clause
66-# See COPYING file for more information.
77-88-from Numeric import *
99-from FFT import *
1010-1111-def make_random(len):
1212- import random
1313- res=[]
1414- for i in range(int(len)):
1515- r=random.uniform(-1,1)
1616- i=random.uniform(-1,1)
1717- res.append( complex(r,i) )
1818- return res
1919-2020-def slowfilter(sig,h):
2121- translen = len(h)-1
2222- return convolve(sig,h)[translen:-translen]
2323-2424-def nextpow2(x):
2525- return 2 ** math.ceil(math.log(x)/math.log(2))
2626-2727-def fastfilter(sig,h,nfft=None):
2828- if nfft is None:
2929- nfft = int( nextpow2( 2*len(h) ) )
3030- H = fft( h , nfft )
3131- scraplen = len(h)-1
3232- keeplen = nfft-scraplen
3333- res=[]
3434- isdone = 0
3535- lastidx = nfft
3636- idx0 = 0
3737- while not isdone:
3838- idx1 = idx0 + nfft
3939- if idx1 >= len(sig):
4040- idx1 = len(sig)
4141- lastidx = idx1-idx0
4242- if lastidx <= scraplen:
4343- break
4444- isdone = 1
4545- Fss = fft(sig[idx0:idx1],nfft)
4646- fm = Fss * H
4747- m = inverse_fft(fm)
4848- res.append( m[scraplen:lastidx] )
4949- idx0 += keeplen
5050- return concatenate( res )
5151-5252-def main():
5353- import sys
5454- from getopt import getopt
5555- opts,args = getopt(sys.argv[1:],'rn:l:')
5656- opts=dict(opts)
5757-5858- siglen = int(opts.get('-l',1e4 ) )
5959- hlen =50
6060-6161- nfft = int(opts.get('-n',128) )
6262- usereal = opts.has_key('-r')
6363-6464- print 'nfft=%d'%nfft
6565- # make a signal
6666- sig = make_random( siglen )
6767- # make an impulse response
6868- h = make_random( hlen )
6969- #h=[1]*2+[0]*3
7070- if usereal:
7171- sig=[c.real for c in sig]
7272- h=[c.real for c in h]
7373-7474- # perform MAC filtering
7575- yslow = slowfilter(sig,h)
7676- #print '<YSLOW>',yslow,'</YSLOW>'
7777- #yfast = fastfilter(sig,h,nfft)
7878- yfast = utilfastfilter(sig,h,nfft,usereal)
7979- #print yfast
8080- print 'len(yslow)=%d'%len(yslow)
8181- print 'len(yfast)=%d'%len(yfast)
8282- diff = yslow-yfast
8383- snr = 10*log10( abs( vdot(yslow,yslow) / vdot(diff,diff) ) )
8484- print 'snr=%s' % snr
8585- if snr < 10.0:
8686- print 'h=',h
8787- print 'sig=',sig[:5],'...'
8888- print 'yslow=',yslow[:5],'...'
8989- print 'yfast=',yfast[:5],'...'
9090-9191-def utilfastfilter(sig,h,nfft,usereal):
9292- import compfft
9393- import os
9494- open( 'sig.dat','w').write( compfft.dopack(sig,'f',not usereal) )
9595- open( 'h.dat','w').write( compfft.dopack(h,'f',not usereal) )
9696- if usereal:
9797- util = './fastconvr'
9898- else:
9999- util = './fastconv'
100100- cmd = 'time %s -n %d -i sig.dat -h h.dat -o out.dat' % (util, nfft)
101101- print cmd
102102- ec = os.system(cmd)
103103- print 'exited->',ec
104104- return compfft.dounpack(open('out.dat').read(),'f',not usereal)
105105-106106-if __name__ == "__main__":
107107- main()
-201
test/fft.py
···11-#!/usr/bin/env python
22-# Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
33-# This file is part of KISS FFT - https://github.com/mborgerding/kissfft
44-#
55-# SPDX-License-Identifier: BSD-3-Clause
66-# See COPYING file for more information.
77-88-import math
99-import sys
1010-import random
1111-1212-pi=math.pi
1313-e=math.e
1414-j=complex(0,1)
1515-1616-def fft(f,inv):
1717- n=len(f)
1818- if n==1:
1919- return f
2020-2121- for p in 2,3,5:
2222- if n%p==0:
2323- break
2424- else:
2525- raise Exception('%s not factorable ' % n)
2626-2727- m = n/p
2828- Fout=[]
2929- for q in range(p): # 0,1
3030- fp = f[q::p] # every p'th time sample
3131- Fp = fft( fp ,inv)
3232- Fout.extend( Fp )
3333-3434- for u in range(m):
3535- scratch = Fout[u::m] # u to end in strides of m
3636- for q1 in range(p):
3737- k = q1*m + u # indices to Fout above that became scratch
3838- Fout[ k ] = scratch[0] # cuz e**0==1 in loop below
3939- for q in range(1,p):
4040- if inv:
4141- t = e ** ( j*2*pi*k*q/n )
4242- else:
4343- t = e ** ( -j*2*pi*k*q/n )
4444- Fout[ k ] += scratch[q] * t
4545-4646- return Fout
4747-4848-def rifft(F):
4949- N = len(F) - 1
5050- Z = [0] * (N)
5151- for k in range(N):
5252- Fek = ( F[k] + F[-k-1].conjugate() )
5353- Fok = ( F[k] - F[-k-1].conjugate() ) * e ** (j*pi*k/N)
5454- Z[k] = Fek + j*Fok
5555-5656- fp = fft(Z , 1)
5757-5858- f = []
5959- for c in fp:
6060- f.append(c.real)
6161- f.append(c.imag)
6262- return f
6363-6464-def real_fft( f,inv ):
6565- if inv:
6666- return rifft(f)
6767-6868- N = len(f) / 2
6969-7070- res = f[::2]
7171- ims = f[1::2]
7272-7373- fp = [ complex(r,i) for r,i in zip(res,ims) ]
7474- print 'fft input ', fp
7575- Fp = fft( fp ,0 )
7676- print 'fft output ', Fp
7777-7878- F = [ complex(0,0) ] * ( N+1 )
7979-8080- F[0] = complex( Fp[0].real + Fp[0].imag , 0 )
8181-8282- for k in range(1,N/2+1):
8383- tw = e ** ( -j*pi*(.5+float(k)/N ) )
8484-8585- F1k = Fp[k] + Fp[N-k].conjugate()
8686- F2k = Fp[k] - Fp[N-k].conjugate()
8787- F2k *= tw
8888- F[k] = ( F1k + F2k ) * .5
8989- F[N-k] = ( F1k - F2k ).conjugate() * .5
9090- #F[N-k] = ( F1kp + e ** ( -j*pi*(.5+float(N-k)/N ) ) * F2kp ) * .5
9191- #F[N-k] = ( F1k.conjugate() - tw.conjugate() * F2k.conjugate() ) * .5
9292-9393- F[N] = complex( Fp[0].real - Fp[0].imag , 0 )
9494- return F
9595-9696-def main():
9797- #fft_func = fft
9898- fft_func = real_fft
9999-100100- tvec = [0.309655,0.815653,0.768570,0.591841,0.404767,0.637617,0.007803,0.012665]
101101- Ftvec = [ complex(r,i) for r,i in zip(
102102- [3.548571,-0.378761,-0.061950,0.188537,-0.566981,0.188537,-0.061950,-0.378761],
103103- [0.000000,-1.296198,-0.848764,0.225337,0.000000,-0.225337,0.848764,1.296198] ) ]
104104-105105- F = fft_func( tvec,0 )
106106-107107- nerrs= 0
108108- for i in range(len(Ftvec)/2 + 1):
109109- if abs( F[i] - Ftvec[i] )> 1e-5:
110110- print 'F[%d]: %s != %s' % (i,F[i],Ftvec[i])
111111- nerrs += 1
112112-113113- print '%d errors in forward fft' % nerrs
114114- if nerrs:
115115- return
116116-117117- trec = fft_func( F , 1 )
118118-119119- for i in range(len(trec) ):
120120- trec[i] /= len(trec)
121121-122122- for i in range(len(tvec) ):
123123- if abs( trec[i] - tvec[i] )> 1e-5:
124124- print 't[%d]: %s != %s' % (i,tvec[i],trec[i])
125125- nerrs += 1
126126-127127- print '%d errors in reverse fft' % nerrs
128128-129129-130130-def make_random(dims=[1]):
131131- import Numeric
132132- res = []
133133- for i in range(dims[0]):
134134- if len(dims)==1:
135135- r=random.uniform(-1,1)
136136- i=random.uniform(-1,1)
137137- res.append( complex(r,i) )
138138- else:
139139- res.append( make_random( dims[1:] ) )
140140- return Numeric.array(res)
141141-142142-def flatten(x):
143143- import Numeric
144144- ntotal = Numeric.product(Numeric.shape(x))
145145- return Numeric.reshape(x,(ntotal,))
146146-147147-def randmat( ndims ):
148148- dims=[]
149149- for i in range( ndims ):
150150- curdim = int( random.uniform(2,4) )
151151- dims.append( curdim )
152152- return make_random(dims )
153153-154154-def test_fftnd(ndims=3):
155155- import FFT
156156- import Numeric
157157-158158- x=randmat( ndims )
159159- print 'dimensions=%s' % str( Numeric.shape(x) )
160160- #print 'x=%s' %str(x)
161161- xver = FFT.fftnd(x)
162162- x2=myfftnd(x)
163163- err = xver - x2
164164- errf = flatten(err)
165165- xverf = flatten(xver)
166166- errpow = Numeric.vdot(errf,errf)+1e-10
167167- sigpow = Numeric.vdot(xverf,xverf)+1e-10
168168- snr = 10*math.log10(abs(sigpow/errpow) )
169169- if snr<80:
170170- print xver
171171- print x2
172172- print 'SNR=%sdB' % str( snr )
173173-174174-def myfftnd(x):
175175- import Numeric
176176- xf = flatten(x)
177177- Xf = fftndwork( xf , Numeric.shape(x) )
178178- return Numeric.reshape(Xf,Numeric.shape(x) )
179179-180180-def fftndwork(x,dims):
181181- import Numeric
182182- dimprod=Numeric.product( dims )
183183-184184- for k in range( len(dims) ):
185185- cur_dim=dims[ k ]
186186- stride=dimprod/cur_dim
187187- next_x = [complex(0,0)]*len(x)
188188- for i in range(stride):
189189- next_x[i*cur_dim:(i+1)*cur_dim] = fft(x[i:(i+cur_dim)*stride:stride],0)
190190- x = next_x
191191- return x
192192-193193-if __name__ == "__main__":
194194- try:
195195- nd = int(sys.argv[1])
196196- except:
197197- nd=None
198198- if nd:
199199- test_fftnd( nd )
200200- else:
201201- sys.exit(0)
-26
test/tailscrap.m
···11-function maxabsdiff=tailscrap()
22-% test code for circular convolution with the scrapped portion
33-% at the tail of the buffer, rather than the front
44-%
55-% The idea is to rotate the zero-padded h (impulse response) buffer
66-% to the left nh-1 samples, rotating the junk samples as well.
77-% This could be very handy in avoiding buffer copies during fast filtering.
88-nh=10;
99-nfft=256;
1010-1111-h=rand(1,nh);
1212-x=rand(1,nfft);
1313-1414-hpad=[ h(nh) zeros(1,nfft-nh) h(1:nh-1) ];
1515-1616-% baseline comparison
1717-y1 = filter(h,1,x);
1818-y1_notrans = y1(nh:nfft);
1919-2020-% fast convolution
2121-y2 = ifft( fft(hpad) .* fft(x) );
2222-y2_notrans=y2(1:nfft-nh+1);
2323-2424-maxabsdiff = max(abs(y2_notrans - y1_notrans))
2525-2626-end
-81
test/test_vs_dft.c
···11-/*
22- * Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
33- * This file is part of KISS FFT - https://github.com/mborgerding/kissfft
44- *
55- * SPDX-License-Identifier: BSD-3-Clause
66- * See COPYING file for more information.
77- */
88-#include "kiss_fft.h"
99-1010-1111-void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse)
1212-{
1313- int bin,k;
1414- double errpow=0,sigpow=0;
1515-1616- for (bin=0;bin<nfft;++bin) {
1717- double ansr = 0;
1818- double ansi = 0;
1919- double difr;
2020- double difi;
2121-2222- for (k=0;k<nfft;++k) {
2323- double phase = -2*M_PI*bin*k/nfft;
2424- double re = cos(phase);
2525- double im = sin(phase);
2626- if (isinverse)
2727- im = -im;
2828-2929-#ifdef FIXED_POINT
3030- re /= nfft;
3131- im /= nfft;
3232-#endif
3333-3434- ansr += in[k].r * re - in[k].i * im;
3535- ansi += in[k].r * im + in[k].i * re;
3636- }
3737- difr = ansr - out[bin].r;
3838- difi = ansi - out[bin].i;
3939- errpow += difr*difr + difi*difi;
4040- sigpow += ansr*ansr+ansi*ansi;
4141- }
4242- printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,10*log10(sigpow/errpow) );
4343-}
4444-4545-void test1d(int nfft,int isinverse)
4646-{
4747- size_t buflen = sizeof(kiss_fft_cpx)*nfft;
4848-4949- kiss_fft_cpx * in = (kiss_fft_cpx*)malloc(buflen);
5050- kiss_fft_cpx * out= (kiss_fft_cpx*)malloc(buflen);
5151- kiss_fft_cfg cfg = kiss_fft_alloc(nfft,isinverse,0,0);
5252- int k;
5353-5454- for (k=0;k<nfft;++k) {
5555- in[k].r = (rand() % 65536) - 32768;
5656- in[k].i = (rand() % 65536) - 32768;
5757- }
5858-5959- kiss_fft(cfg,in,out);
6060-6161- check(in,out,nfft,isinverse);
6262-6363- free(in);
6464- free(out);
6565- free(cfg);
6666-}
6767-6868-int main(int argc,char ** argv)
6969-{
7070- if (argc>1) {
7171- int k;
7272- for (k=1;k<argc;++k) {
7373- test1d(atoi(argv[k]),0);
7474- test1d(atoi(argv[k]),1);
7575- }
7676- }else{
7777- test1d(32,0);
7878- test1d(32,1);
7979- }
8080- return 0;
8181-}