annotate ext/kissfft/test/testkiss.py @ 184:76ec2365b250

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