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