annotate constant-q-cpp/src/ext/kissfft/tools/kiss_fftnd.c @ 372:af71cbdab621 tip

Update bqvec code
author Chris Cannam
date Tue, 19 Nov 2019 10:13:32 +0000
parents 5d0a2ebb4d17
children
rev   line source
Chris@366 1
Chris@366 2
Chris@366 3 /*
Chris@366 4 Copyright (c) 2003-2004, Mark Borgerding
Chris@366 5
Chris@366 6 All rights reserved.
Chris@366 7
Chris@366 8 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Chris@366 9
Chris@366 10 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Chris@366 11 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Chris@366 12 * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
Chris@366 13
Chris@366 14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Chris@366 15 */
Chris@366 16
Chris@366 17 #include "kiss_fftnd.h"
Chris@366 18 #include "_kiss_fft_guts.h"
Chris@366 19
Chris@366 20 struct kiss_fftnd_state{
Chris@366 21 int dimprod; /* dimsum would be mighty tasty right now */
Chris@366 22 int ndims;
Chris@366 23 int *dims;
Chris@366 24 kiss_fft_cfg *states; /* cfg states for each dimension */
Chris@366 25 kiss_fft_cpx * tmpbuf; /*buffer capable of hold the entire input */
Chris@366 26 };
Chris@366 27
Chris@366 28 kiss_fftnd_cfg kiss_fftnd_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
Chris@366 29 {
Chris@366 30 kiss_fftnd_cfg st = NULL;
Chris@366 31 int i;
Chris@366 32 int dimprod=1;
Chris@366 33 size_t memneeded = sizeof(struct kiss_fftnd_state);
Chris@366 34 char * ptr;
Chris@366 35
Chris@366 36 for (i=0;i<ndims;++i) {
Chris@366 37 size_t sublen=0;
Chris@366 38 kiss_fft_alloc (dims[i], inverse_fft, NULL, &sublen);
Chris@366 39 memneeded += sublen; /* st->states[i] */
Chris@366 40 dimprod *= dims[i];
Chris@366 41 }
Chris@366 42 memneeded += sizeof(int) * ndims;/* st->dims */
Chris@366 43 memneeded += sizeof(void*) * ndims;/* st->states */
Chris@366 44 memneeded += sizeof(kiss_fft_cpx) * dimprod; /* st->tmpbuf */
Chris@366 45
Chris@366 46 if (lenmem == NULL) {/* allocate for the caller*/
Chris@366 47 st = (kiss_fftnd_cfg) malloc (memneeded);
Chris@366 48 } else { /* initialize supplied buffer if big enough */
Chris@366 49 if (*lenmem >= memneeded)
Chris@366 50 st = (kiss_fftnd_cfg) mem;
Chris@366 51 *lenmem = memneeded; /*tell caller how big struct is (or would be) */
Chris@366 52 }
Chris@366 53 if (!st)
Chris@366 54 return NULL; /*malloc failed or buffer too small */
Chris@366 55
Chris@366 56 st->dimprod = dimprod;
Chris@366 57 st->ndims = ndims;
Chris@366 58 ptr=(char*)(st+1);
Chris@366 59
Chris@366 60 st->states = (kiss_fft_cfg *)ptr;
Chris@366 61 ptr += sizeof(void*) * ndims;
Chris@366 62
Chris@366 63 st->dims = (int*)ptr;
Chris@366 64 ptr += sizeof(int) * ndims;
Chris@366 65
Chris@366 66 st->tmpbuf = (kiss_fft_cpx*)ptr;
Chris@366 67 ptr += sizeof(kiss_fft_cpx) * dimprod;
Chris@366 68
Chris@366 69 for (i=0;i<ndims;++i) {
Chris@366 70 size_t len;
Chris@366 71 st->dims[i] = dims[i];
Chris@366 72 kiss_fft_alloc (st->dims[i], inverse_fft, NULL, &len);
Chris@366 73 st->states[i] = kiss_fft_alloc (st->dims[i], inverse_fft, ptr,&len);
Chris@366 74 ptr += len;
Chris@366 75 }
Chris@366 76 /*
Chris@366 77 Hi there!
Chris@366 78
Chris@366 79 If you're looking at this particular code, it probably means you've got a brain-dead bounds checker
Chris@366 80 that thinks the above code overwrites the end of the array.
Chris@366 81
Chris@366 82 It doesn't.
Chris@366 83
Chris@366 84 -- Mark
Chris@366 85
Chris@366 86 P.S.
Chris@366 87 The below code might give you some warm fuzzies and help convince you.
Chris@366 88 */
Chris@366 89 if ( ptr - (char*)st != (int)memneeded ) {
Chris@366 90 fprintf(stderr,
Chris@366 91 "################################################################################\n"
Chris@366 92 "Internal error! Memory allocation miscalculation\n"
Chris@366 93 "################################################################################\n"
Chris@366 94 );
Chris@366 95 }
Chris@366 96 return st;
Chris@366 97 }
Chris@366 98
Chris@366 99 /*
Chris@366 100 This works by tackling one dimension at a time.
Chris@366 101
Chris@366 102 In effect,
Chris@366 103 Each stage starts out by reshaping the matrix into a DixSi 2d matrix.
Chris@366 104 A Di-sized fft is taken of each column, transposing the matrix as it goes.
Chris@366 105
Chris@366 106 Here's a 3-d example:
Chris@366 107 Take a 2x3x4 matrix, laid out in memory as a contiguous buffer
Chris@366 108 [ [ [ a b c d ] [ e f g h ] [ i j k l ] ]
Chris@366 109 [ [ m n o p ] [ q r s t ] [ u v w x ] ] ]
Chris@366 110
Chris@366 111 Stage 0 ( D=2): treat the buffer as a 2x12 matrix
Chris@366 112 [ [a b ... k l]
Chris@366 113 [m n ... w x] ]
Chris@366 114
Chris@366 115 FFT each column with size 2.
Chris@366 116 Transpose the matrix at the same time using kiss_fft_stride.
Chris@366 117
Chris@366 118 [ [ a+m a-m ]
Chris@366 119 [ b+n b-n]
Chris@366 120 ...
Chris@366 121 [ k+w k-w ]
Chris@366 122 [ l+x l-x ] ]
Chris@366 123
Chris@366 124 Note fft([x y]) == [x+y x-y]
Chris@366 125
Chris@366 126 Stage 1 ( D=3) treats the buffer (the output of stage D=2) as an 3x8 matrix,
Chris@366 127 [ [ a+m a-m b+n b-n c+o c-o d+p d-p ]
Chris@366 128 [ e+q e-q f+r f-r g+s g-s h+t h-t ]
Chris@366 129 [ i+u i-u j+v j-v k+w k-w l+x l-x ] ]
Chris@366 130
Chris@366 131 And perform FFTs (size=3) on each of the columns as above, transposing
Chris@366 132 the matrix as it goes. The output of stage 1 is
Chris@366 133 (Legend: ap = [ a+m e+q i+u ]
Chris@366 134 am = [ a-m e-q i-u ] )
Chris@366 135
Chris@366 136 [ [ sum(ap) fft(ap)[0] fft(ap)[1] ]
Chris@366 137 [ sum(am) fft(am)[0] fft(am)[1] ]
Chris@366 138 [ sum(bp) fft(bp)[0] fft(bp)[1] ]
Chris@366 139 [ sum(bm) fft(bm)[0] fft(bm)[1] ]
Chris@366 140 [ sum(cp) fft(cp)[0] fft(cp)[1] ]
Chris@366 141 [ sum(cm) fft(cm)[0] fft(cm)[1] ]
Chris@366 142 [ sum(dp) fft(dp)[0] fft(dp)[1] ]
Chris@366 143 [ sum(dm) fft(dm)[0] fft(dm)[1] ] ]
Chris@366 144
Chris@366 145 Stage 2 ( D=4) treats this buffer as a 4*6 matrix,
Chris@366 146 [ [ sum(ap) fft(ap)[0] fft(ap)[1] sum(am) fft(am)[0] fft(am)[1] ]
Chris@366 147 [ sum(bp) fft(bp)[0] fft(bp)[1] sum(bm) fft(bm)[0] fft(bm)[1] ]
Chris@366 148 [ sum(cp) fft(cp)[0] fft(cp)[1] sum(cm) fft(cm)[0] fft(cm)[1] ]
Chris@366 149 [ sum(dp) fft(dp)[0] fft(dp)[1] sum(dm) fft(dm)[0] fft(dm)[1] ] ]
Chris@366 150
Chris@366 151 Then FFTs each column, transposing as it goes.
Chris@366 152
Chris@366 153 The resulting matrix is the 3d FFT of the 2x3x4 input matrix.
Chris@366 154
Chris@366 155 Note as a sanity check that the first element of the final
Chris@366 156 stage's output (DC term) is
Chris@366 157 sum( [ sum(ap) sum(bp) sum(cp) sum(dp) ] )
Chris@366 158 , i.e. the summation of all 24 input elements.
Chris@366 159
Chris@366 160 */
Chris@366 161 void kiss_fftnd(kiss_fftnd_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
Chris@366 162 {
Chris@366 163 int i,k;
Chris@366 164 const kiss_fft_cpx * bufin=fin;
Chris@366 165 kiss_fft_cpx * bufout;
Chris@366 166
Chris@366 167 /*arrange it so the last bufout == fout*/
Chris@366 168 if ( st->ndims & 1 ) {
Chris@366 169 bufout = fout;
Chris@366 170 if (fin==fout) {
Chris@366 171 memcpy( st->tmpbuf, fin, sizeof(kiss_fft_cpx) * st->dimprod );
Chris@366 172 bufin = st->tmpbuf;
Chris@366 173 }
Chris@366 174 }else
Chris@366 175 bufout = st->tmpbuf;
Chris@366 176
Chris@366 177 for ( k=0; k < st->ndims; ++k) {
Chris@366 178 int curdim = st->dims[k];
Chris@366 179 int stride = st->dimprod / curdim;
Chris@366 180
Chris@366 181 for ( i=0 ; i<stride ; ++i )
Chris@366 182 kiss_fft_stride( st->states[k], bufin+i , bufout+i*curdim, stride );
Chris@366 183
Chris@366 184 /*toggle back and forth between the two buffers*/
Chris@366 185 if (bufout == st->tmpbuf){
Chris@366 186 bufout = fout;
Chris@366 187 bufin = st->tmpbuf;
Chris@366 188 }else{
Chris@366 189 bufout = st->tmpbuf;
Chris@366 190 bufin = fout;
Chris@366 191 }
Chris@366 192 }
Chris@366 193 }