comparison ext/kissfft/test/testkiss.py @ 409:1f1999b0f577

Bring in kissfft into this repo (formerly a subrepo, but the remote is not responding)
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 21 Jul 2015 07:34:15 +0100
parents
children
comparison
equal deleted inserted replaced
408:5316fa4b0f33 409:1f1999b0f577
1 #!/usr/bin/env python
2
3 import math
4 import sys
5 import os
6 import random
7 import struct
8 import popen2
9 import getopt
10 import numpy
11
12 pi=math.pi
13 e=math.e
14 j=complex(0,1)
15
16 doreal=0
17
18 datatype = os.environ.get('DATATYPE','float')
19
20 util = '../tools/fft_' + datatype
21 minsnr=90
22 if datatype == 'double':
23 fmt='d'
24 elif datatype=='int16_t':
25 fmt='h'
26 minsnr=10
27 elif datatype=='int32_t':
28 fmt='i'
29 elif datatype=='simd':
30 fmt='4f'
31 sys.stderr.write('testkiss.py does not yet test simd')
32 sys.exit(0)
33 elif datatype=='float':
34 fmt='f'
35 else:
36 sys.stderr.write('unrecognized datatype %s\n' % datatype)
37 sys.exit(1)
38
39
40 def dopack(x,cpx=1):
41 x = numpy.reshape( x, ( numpy.size(x),) )
42
43 if cpx:
44 s = ''.join( [ struct.pack(fmt*2,c.real,c.imag) for c in x ] )
45 else:
46 s = ''.join( [ struct.pack(fmt,c.real) for c in x ] )
47 return s
48
49 def dounpack(x,cpx):
50 uf = fmt * ( len(x) / struct.calcsize(fmt) )
51 s = struct.unpack(uf,x)
52 if cpx:
53 return numpy.array(s[::2]) + numpy.array( s[1::2] )*j
54 else:
55 return numpy.array(s )
56
57 def make_random(dims=[1]):
58 res = []
59 for i in range(dims[0]):
60 if len(dims)==1:
61 r=random.uniform(-1,1)
62 if doreal:
63 res.append( r )
64 else:
65 i=random.uniform(-1,1)
66 res.append( complex(r,i) )
67 else:
68 res.append( make_random( dims[1:] ) )
69 return numpy.array(res)
70
71 def flatten(x):
72 ntotal = numpy.size(x)
73 return numpy.reshape(x,(ntotal,))
74
75 def randmat( ndims ):
76 dims=[]
77 for i in range( ndims ):
78 curdim = int( random.uniform(2,5) )
79 if doreal and i==(ndims-1):
80 curdim = int(curdim/2)*2 # force even last dimension if real
81 dims.append( curdim )
82 return make_random(dims )
83
84 def test_fft(ndims):
85 x=randmat( ndims )
86
87
88 if doreal:
89 xver = numpy.fft.rfftn(x)
90 else:
91 xver = numpy.fft.fftn(x)
92
93 open('/tmp/fftexp.dat','w').write(dopack( flatten(xver) , True ) )
94
95 x2=dofft(x,doreal)
96 err = xver - x2
97 errf = flatten(err)
98 xverf = flatten(xver)
99 errpow = numpy.vdot(errf,errf)+1e-10
100 sigpow = numpy.vdot(xverf,xverf)+1e-10
101 snr = 10*math.log10(abs(sigpow/errpow) )
102 print 'SNR (compared to NumPy) : %.1fdB' % float(snr)
103
104 if snr<minsnr:
105 print 'xver=',xver
106 print 'x2=',x2
107 print 'err',err
108 sys.exit(1)
109
110 def dofft(x,isreal):
111 dims=list( numpy.shape(x) )
112 x = flatten(x)
113
114 scale=1
115 if datatype=='int16_t':
116 x = 32767 * x
117 scale = len(x) / 32767.0
118 elif datatype=='int32_t':
119 x = 2147483647.0 * x
120 scale = len(x) / 2147483647.0
121
122 cmd='%s -n ' % util
123 cmd += ','.join([str(d) for d in dims])
124 if doreal:
125 cmd += ' -R '
126
127 print cmd
128 p = popen2.Popen3(cmd )
129
130 open('/tmp/fftin.dat','w').write(dopack( x , isreal==False ) )
131
132 p.tochild.write( dopack( x , isreal==False ) )
133 p.tochild.close()
134
135 res = dounpack( p.fromchild.read() , 1 )
136 open('/tmp/fftout.dat','w').write(dopack( flatten(res) , True ) )
137 if doreal:
138 dims[-1] = int( dims[-1]/2 ) + 1
139
140 res = scale * res
141
142 p.wait()
143 return numpy.reshape(res,dims)
144
145 def main():
146 opts,args = getopt.getopt(sys.argv[1:],'r')
147 opts=dict(opts)
148
149 global doreal
150 doreal = opts.has_key('-r')
151
152 if doreal:
153 print 'Testing multi-dimensional real FFTs'
154 else:
155 print 'Testing multi-dimensional FFTs'
156
157 for dim in range(1,4):
158 test_fft( dim )
159
160 if __name__ == "__main__":
161 main()
162