#!/usr/bin/env python

import FFT
import sys
import random
import re
j=complex(0,1)

def randvec(n,iscomplex):
    if iscomplex:
        return [
                int(random.uniform(-32768,32767) ) + j*int(random.uniform(-32768,32767) )
                for i in range(n) ]
    else:
        return [ int(random.uniform(-32768,32767) ) for i in range(n) ]

def c_format(v,round=0):
    if round:
        return ','.join( [ '{%d,%d}' %(int(c.real),int(c.imag) ) for c in v ] )
    else:
        s= ','.join( [ '{%.60f ,%.60f }' %(c.real,c.imag) for c in v ] )
        return re.sub(r'\.?0+ ',' ',s)

def test_cpx( n,inverse ,short):
    v = randvec(n,1)
    scale = 1
    if short:
        minsnr=30
    else:
        minsnr=100

    if inverse:
        tvecout = FFT.inverse_fft(v)
        if short:
            scale = 1
        else:
            scale = len(v)
    else:
        tvecout = FFT.fft(v)
        if short:
            scale = 1.0/len(v)

    tvecout = [ c * scale for c in tvecout ]


    s="""#define NFFT %d""" % len(v) + """
    {
        double snr;
        kiss_fft_cpx test_vec_in[NFFT] = { """  + c_format(v) + """};
        kiss_fft_cpx test_vec_out[NFFT] = {"""  + c_format( tvecout ) + """};
        kiss_fft_cpx testbuf[NFFT];
        void * cfg = kiss_fft_alloc(NFFT,%d,0,0);""" % inverse + """

        kiss_fft(cfg,test_vec_in,testbuf);
        snr = snr_compare(test_vec_out,testbuf,NFFT);
        printf("DATATYPE=" xstr(kiss_fft_scalar) ", FFT n=%d, inverse=%d, snr = %g dB\\n",NFFT,""" + str(inverse) + """,snr);
        if (snr<""" + str(minsnr) + """)
            exit_code++;
        free(cfg);
    }
#undef NFFT
"""
    return s

def compare_func():
    s="""
#define xstr(s) str(s)
#define str(s) #s
double snr_compare( kiss_fft_cpx * test_vec_out,kiss_fft_cpx * testbuf, int n)
{
    int k;
    double sigpow,noisepow,err,snr,scale=0;
    kiss_fft_cpx err;
    sigpow = noisepow = .000000000000000000000000000001;

    for (k=0;k<n;++k) {
        sigpow += test_vec_out[k].r * test_vec_out[k].r +
                  test_vec_out[k].i * test_vec_out[k].i;
        C_SUB(err,test_vec_out[k],testbuf[k].r);
        noisepow += err.r * err.r + err.i + err.i;

        if (test_vec_out[k].r)
            scale += testbuf[k].r / test_vec_out[k].r;
    }
    snr = 10*log10( sigpow / noisepow );
    scale /= n;
    if (snr<10)
        printf( "\\npoor snr, try a scaling factor %f\\n" , scale );
    return snr;
}
"""
    return s

def main():

    from getopt import getopt
    opts,args = getopt(sys.argv[1:],'s')
    opts = dict(opts)
    short = int( opts.has_key('-s') )

    fftsizes = args
    if not fftsizes:
        fftsizes = [ 1800 ]
    print '#include "kiss_fft.h"'
    print compare_func()
    print "int main() { int exit_code=0;\n"
    for n in fftsizes:
        n = int(n)
        print test_cpx(n,0,short)
        print test_cpx(n,1,short)
    print """
    return exit_code;
}
"""

if __name__ == "__main__":
    main()
