Reply by BobM August 30, 20052005-08-30
Michel Rouzic wrote:
> Now I dont have the problems I had before, and convolving the shifted > delta function gives the expected result.
Good to hear it's working now.
> As for the windowed-sinc function, forget anything I could say about > it, the code looks right, but all it outputs is a shifted delta > function...
Read up on group delay. It's expected that there will be a time shift (delay) with any FIR filter. If it doesn't seem filtered from the frequency domain point of view, it seems like there may be a problem with the filter coefficients.
Reply by Michel Rouzic August 30, 20052005-08-30
BobM wrote:

OK, i turned this part into this :

	for (i=0; i<*n3-(blocksize/2); i++)	//filling of s3 from the content
of the blocks
		s3[i]=block[i/(blocksize/2)][i%(blocksize/2)];	//first half of each
block
	for (i=blocksize/2; i<*n3; i++)
		s3[i]+=block[i/(blocksize/2) - 1][i%(blocksize/2) +
(blocksize/2)];	//second half of each block

Now I dont have the problems I had before, and convolving the shifted
delta function gives the expected result.

As for the windowed-sinc function, forget anything I could say about
it, the code looks right, but all it outputs is a shifted delta
function... I tried a convolution with a little kernel (2 bins,
first=1, second = -1) and the result sounds right, so I can say my
convolution works right.

thank you for help

Reply by BobM August 29, 20052005-08-29
Michel Rouzic wrote:
> for (i=0; i<nblocks; i++) //filling of s3 from the content of the > blocks > for (j=0; j<blocksize/2; j++) > s3[i*(blocksize/2) + j]=s3[i*(blocksize/2) + j]+block[i][j];
The problem looks to be here. It looks like only the first half of each block is being sent to output, and that there's no overlap. Be sure you are overlapping each block and adding the overlapped parts. If your input block size (the amount of input samples you filter each time) is always blocksize/2, then an overlap size of blocksize/2 samples is ok. However, while it looks like you intend to overlap and add the blocks, the above code doesn't do that. You'll need to output the entire block, overlapped by blocksize/2 samples (assuming the input block size is blocksize/2). I still recommend getting familiar with the time-domain implementation of an FIR. It's more intuitive for understanding time-domain effects like group delay.
Reply by Michel Rouzic August 29, 20052005-08-29
BobM wrote:
> It's difficult what to say what is wrong without knowing more > information about how your function works. What is the total input size > in samples? The filter size? The input block size?
I used two test input signals, one 2,103,154 samples long, the other, 972 samples long. as for the filter, it's 20,000 samples long in the case of the shifted delta function. I'm not sure to know what you mean by input block size
> I'm assuming your filter size is 20,000 taps. If my math is correct, > the max your input block size can be is 12,769 samples (32768-20000+1).
huh? ok, we maybe got the finger on something wrong... what I do is, in the case of the convolution by the shifted delta function, take the 20,000 samples long signal, and provided that the other input signal is longer than that, zero-pad that signal to the power of two above twice the length of the signal (I guess that is 65,536 here), then, I cut the 2,103,154 samples long signal into blocks of 32,768 samples and I zero-pad each block to 65,536 (i think i made no mistake)
> Anyway, the result you're getting seems correct to me. As long as your > input signal is shifted in time by 4000 samples, which it sounds like > it is, then this is the correct behavior.
No, it's not getting shifted, but muted, I mean, some regions of 4000 samples are getting, each 32,768 samples, set to zero, as the other 28,768 samples are unchanged, even when using a windowed-sinc function. This is indeed quite far from a normal behavior
> Also, it seems your input > block isn't too big, because I'd expect to see some non-zero samples > folding back into the first 4000 samples if it was too big. Sounds like > the convolution itself is working. > > > I also tried with a windowed-sinc function, i used 88.2 Hz as a cutoff > > frequency, 8.82 Hz as the bandwidth of the rolloff, and when convolving > > with the input signal, not only the output signal has regions regularly > > set to zero, but the output signal doesnt look/sound at all like it's > > been low-passed filtered > > How many taps is this filter?
20,001. I calculate the length of the filter by 4/BW (BW=the bandwidth of the roll off) and make sure the number is odd.
> If it's not many taps, then this may be > such a shallow filter that it there's almost no effect. > What kind of > window is being used to generate the filter?
Blackman. I made sure it's working right. I even made sure that the first and last bins were always non-zero.
> According to the first > result you mentioned it sounds like your convolution is working, so > this may be related to the filter you're using. Does this same filter > work with a time-domain implementation of convolution?
Haven't made a time-domain convolution. i thought i'd go straight to the goal... anyways, it looks perfectly right.
> > > any ideas on what can be wrong? > > Again, please provide some more information. However, my hunch is that > the convolution itself is working. But confirm that your input block > isn't too big. Also check the way you're piecing the output blocks back > together. Whether you're doing overlap-add or overlap-save, check that > the overlapped portions are being added together before sending them > off to output.
Maybe it's not very appropriate to paste such a long code, but I have the feeling that it'll go much faster if you can get to see a stripped-down-to-the-essential version of my function, so here it is (the first functions are here because they are used in the fftconv function) #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <math.h> #include <fftw3.h> double log_2(double x) //log base 2 performing function { double y; y=log(x)/log(2); return y; } double modfloat(double a, double b) //modulo returning function { double c, d, x; c=(uint32_t) a/b; d=a/b; x=d-c; return x; } double roundup(double in) //function rounding the input to the upper integer (unless the input already is an integer) { double out; if (modfloat(in,1) == 0) out=in; else out=in - (modfloat(in,1)) + 1; return out; } double *zeropad(double *s, uint32_t nin, uint32_t nout) { uint32_t i; double *h; h=malloc (sizeof(double) * nout); for (i=0; i<nin; i++) h[i]=s[i]; for (i=nin; i<nout; i++) h[i]=0; return h; } void dftfunction(double *in, uint32_t N, uint8_t method, uint8_t root) { uint32_t i; fftw_plan p; p = fftw_plan_r2r_1d(N, in, in, method, FFTW_ESTIMATE); fftw_execute(p); fftw_destroy_plan(p); if (root==1) for (i=0;i<N;i++) in[i]=in[i]/sqrt(N); } double *fftconv(double *s1, uint32_t n1, double *s2, uint32_t n2, uint32_t *n3) //s1 and s2 the two input signals, n1 and n2 their respective length { uint32_t i, j, nmin, nmax, blocksize, nblocks; double *s3, *smin, *smax, **block, a, b, c, d; printf("fftconv...\n"); *n3=n1+n2-1; //output signal length s3=malloc (*n3 * sizeof(double)); if (n1<n2) { smin=s1; smax=s2; nmin=n1; nmax=n2; } else { smin=s2; smax=s1; nmin=n2; nmax=n1; } blocksize=pow(2, (uint32_t) roundup(log_2((double) (nmin)*2))); //size of blocks for the overlap-add of the long signal, size of the zeropadded short signal smin=zeropad(smin, nmin, blocksize); dftfunction(smin, blocksize, 0, 0); //FFT of the shortest signal nblocks=*n3/(blocksize/2); //number of blocks for the o-a of the long signal block=malloc (nblocks * sizeof(double *)); for (i=0; i<nblocks; i++) //loop filling the contents of the long signal in an array of blocks { block[i]=malloc (blocksize * sizeof(double)); for (j=0; j<blocksize/2; j++) block[i][j]=smax[i*(blocksize/2) + j]; for (j=blocksize/2; j<blocksize; j++) block[i][j]=0; dftfunction(block[i], blocksize, 0, 1); //FFT of each block } for (i=0; i<nblocks; i++) { a=block[i][0]; // DC c=smin[0]; block[i][0]=a*c; // no need for imaginary parts for (j=1; j<blocksize/2; j++) { a=block[i][j]; b=block[i][blocksize-j]; c=smin[j]; d=smin[blocksize-j]; block[i][j]=a*c - b*d; block[i][blocksize-j]=b*c + a*d; } a=block[i][blocksize/2]; // Nyquist c=smin[blocksize/2]; block[i][blocksize/2]=a*c; dftfunction(block[i], blocksize, 1, 1); //IFFT of the result of the multiplication in each block } for (i=0; i<*n3; i++) //initialisation of the output signal s3 s3[i]=0; for (i=0; i<nblocks; i++) //filling of s3 from the content of the blocks for (j=0; j<blocksize/2; j++) s3[i*(blocksize/2) + j]=s3[i*(blocksize/2) + j]+block[i][j]; return s3; free(block); }
Reply by BobM August 28, 20052005-08-28
It's difficult what to say what is wrong without knowing more
information about how your function works. What is the total input size
in samples? The filter size? The input block size?

Michel Rouzic wrote:
> When I convolve with a function that is an array of 20,000 samples set > to 0, and the element 4,000 being set to 1, my output signal looks like > the orginal input (with a longer length of course), unmodified, except > that on every section of 32,768 samples, the first 4,000 are set to > zero.
I'm assuming your filter size is 20,000 taps. If my math is correct, the max your input block size can be is 12,769 samples (32768-20000+1). Anyway, the result you're getting seems correct to me. As long as your input signal is shifted in time by 4000 samples, which it sounds like it is, then this is the correct behavior. Also, it seems your input block isn't too big, because I'd expect to see some non-zero samples folding back into the first 4000 samples if it was too big. Sounds like the convolution itself is working.
> I also tried with a windowed-sinc function, i used 88.2 Hz as a cutoff > frequency, 8.82 Hz as the bandwidth of the rolloff, and when convolving > with the input signal, not only the output signal has regions regularly > set to zero, but the output signal doesnt look/sound at all like it's > been low-passed filtered
How many taps is this filter? If it's not many taps, then this may be such a shallow filter that it there's almost no effect. What kind of window is being used to generate the filter? According to the first result you mentioned it sounds like your convolution is working, so this may be related to the filter you're using. Does this same filter work with a time-domain implementation of convolution?
> any ideas on what can be wrong?
Again, please provide some more information. However, my hunch is that the convolution itself is working. But confirm that your input block isn't too big. Also check the way you're piecing the output blocks back together. Whether you're doing overlap-add or overlap-save, check that the overlapped portions are being added together before sending them off to output.
Reply by Michel Rouzic August 26, 20052005-08-26
BobM wrote:

I tested my function further, and found out that it still doesnt work
properly.

When I convolve with a function that is an array of 20,000 samples set
to 0, and the element 4,000 being set to 1, my output signal looks like
the orginal input (with a longer length of course), unmodified, except
that on every section of 32,768 samples, the first 4,000 are set to
zero.

I also tried with a windowed-sinc function, i used 88.2 Hz as a cutoff
frequency, 8.82 Hz as the bandwidth of the rolloff, and when convolving
with the input signal, not only the output signal has regions regularly
set to zero, but the output signal doesnt look/sound at all like it's
been low-passed filtered

I made sure that my sinc function generator works properly and that my
blackman function works properly too.

any ideas on what can be wrong?

Reply by August 19, 20052005-08-19
Michel Rouzic wrote:
> how would be a 7-point or 9-point FFT, I mean, what would disappear or > appear?
There is no Nyquist element for an odd size. (This is, by the way, documented in the FFTW manual.)
Reply by Michel Rouzic August 17, 20052005-08-17
yeah i understand better now. now i think i'll have to review some of
my functions that do things in the frequency domain because I didn't
understand perfectly the storage of the real-to-real FFT.

Now, if a 8-point FFT result is like that :

> array[0]: DC (real) > array[1]: bin 1 (real) > array[2]: bin 2 (real) > array[3]: bin 3 (real) > array[4]: Nyquist (real) > array[5]: bin 3 (imaginary) > array[6]: bin 2 (imaginary) > array[7]: bin 1 (imaginary)
how would be a 7-point or 9-point FFT, I mean, what would disappear or appear? BobM wrote:
> Michel Rouzic wrote: > > wow, thank you BobM, it works perfectly with the code you did. I think > > you pointed out something that I didn't understand about the structure > > of real-to-real FFT, it's what matches to the nyquist frequency. on a > > signal that is multiple of 2, if N/2 is the nyquist, what is the sample > > that symetrically matches to it (i guess i mean N/2 - 1)? > > Good to hear it worked! Jerry answered your question much more clearly > than I could have. > > But how about a rundown of how an FFT result is typically stored.. > > Regarding the complex FFT, think of an 8-point FFT result array called > "array[8][2]" which will hold the results. Here is the way this array > might be arranged: > > REAL PARTS > array[0][0]: DC > array[1][0]: bin 1 > array[2][0]: bin 2 > array[3][0]: bin 3 > array[4][0]: Nyquist > array[5][0]: bin 5 (-3) > array[6][0]: bin 6 (-2) > array[7][0]: bin 7 (-1) > > IMAGINARY PARTS > array[0][1]: DC > array[1][1]: bin 1 > array[2][1]: bin 2 > array[3][1]: bin 3 > array[4][1]: Nyquist > array[5][1]: bin 5 (-3) > array[6][1]: bin 6 (-2) > array[7][1]: bin 7 (-1) > > Note that real parts are stored in [0] and imaginary are in [1]. Bins > above Nyquist are the so-called negative frequencies. Note the symmetry > around Nyquist to the respective positive frequencies. If you were to > graph these out, you might considering plotting the bins above Nyquist > below 0 (-3,-2,-1 shown above). > > For a real signal the real bins symmetrical to each other around > Nyquist will be equal to each other. The imaginary bins symmetrical > around Nyquist will be equal to -1 * each other (complex conjugate). DC > and Nyquist will always be real for a real signal. > > The real-to-real FFT you're using takes advantage of these redundancies > and is stored like this: > > array[0]: DC (real) > array[1]: bin 1 (real) > array[2]: bin 2 (real) > array[3]: bin 3 (real) > array[4]: Nyquist (real) > array[5]: bin 3 (imaginary) > array[6]: bin 2 (imaginary) > array[7]: bin 1 (imaginary) > > Hope this helps, > Bob
Reply by BobM August 17, 20052005-08-17
Michel Rouzic wrote:
> wow, thank you BobM, it works perfectly with the code you did. I think > you pointed out something that I didn't understand about the structure > of real-to-real FFT, it's what matches to the nyquist frequency. on a > signal that is multiple of 2, if N/2 is the nyquist, what is the sample > that symetrically matches to it (i guess i mean N/2 - 1)?
Good to hear it worked! Jerry answered your question much more clearly than I could have. But how about a rundown of how an FFT result is typically stored.. Regarding the complex FFT, think of an 8-point FFT result array called "array[8][2]" which will hold the results. Here is the way this array might be arranged: REAL PARTS array[0][0]: DC array[1][0]: bin 1 array[2][0]: bin 2 array[3][0]: bin 3 array[4][0]: Nyquist array[5][0]: bin 5 (-3) array[6][0]: bin 6 (-2) array[7][0]: bin 7 (-1) IMAGINARY PARTS array[0][1]: DC array[1][1]: bin 1 array[2][1]: bin 2 array[3][1]: bin 3 array[4][1]: Nyquist array[5][1]: bin 5 (-3) array[6][1]: bin 6 (-2) array[7][1]: bin 7 (-1) Note that real parts are stored in [0] and imaginary are in [1]. Bins above Nyquist are the so-called negative frequencies. Note the symmetry around Nyquist to the respective positive frequencies. If you were to graph these out, you might considering plotting the bins above Nyquist below 0 (-3,-2,-1 shown above). For a real signal the real bins symmetrical to each other around Nyquist will be equal to each other. The imaginary bins symmetrical around Nyquist will be equal to -1 * each other (complex conjugate). DC and Nyquist will always be real for a real signal. The real-to-real FFT you're using takes advantage of these redundancies and is stored like this: array[0]: DC (real) array[1]: bin 1 (real) array[2]: bin 2 (real) array[3]: bin 3 (real) array[4]: Nyquist (real) array[5]: bin 3 (imaginary) array[6]: bin 2 (imaginary) array[7]: bin 1 (imaginary) Hope this helps, Bob
Reply by Jerry Avins August 17, 20052005-08-17
Michel Rouzic wrote:
> BobM wrote: > >>>>Michel Rouzic wrote: >>>> >>>>>I think it should be alright like that : >>>>> >>>>> for (i=0; i<nblocks; i++) >>>>> for (j=0; j<blocksize/2; j++) >>>>> { >>>>> a=block[i][j]; >>>>> b=block[i][blocksize-j-1]; >>>>> c=smin[j]; >>>>> d=smin[blocksize-j-1]; >>>>> >>>>> block[i][j]=a*c - b*d; >>>>> block[i][blocksize-j-1]=b*c + a*d; >>>>> } >>>>> >>>>>but it's still giving me weird results, so there must be something >>>>>wrong still, do you see it? >>> >>>well i never even dealt with real-to-complex FFT, only with >>>real-to-real, and well i thought that with the two corrections I did it >>>would be ok (i dont see anything wrong in what i have corrected now). >>>if you want i can post a version of the function that i reduced to the >>>strict necessary, but that's still about 120 lines long.. >> >>I do see something else that may be wrong here. It seems you have set >>up a symmetry between items in the array ({0,blocksize-1}, >>{1,blocksize-2}, etc.) in order to reference {real,imaginary} pairs. My >>assumption is that the item at index [0] should be DC and at >>[blocksize/2] should be Nyquist. This suggests that the symmetry should >>actually be like this: >> >>0: DC >>{1,blocksize-1}: element 1 {real,imaginary} >>{2,blocksize-2}: element 2 {real,imaginary} >>. >>. >>. >>blocksize/2: Nyquist >> >>In other words, element [1] is paired with element [blocksize-1]. Right >>now you have element [0] paired with element [blocksize-1]. >> >>With this in mind I'd try substituting with this code: >> >>for (i=0; i<nblocks; i++) >>{ >> a=block[i][0]; // DC >> c=smin[0]; >> block[i][0]=a*c; // no need for imaginary parts >> for (j=1; j<blocksize/2; j++) >> { >> a=block[i][j]; >> b=block[i][blocksize-j]; >> c=smin[j]; >> d=smin[blocksize-j]; >> >> block[i][j]=a*c - b*d; >> block[i][blocksize-j]=b*c + a*d; >> } >> a=block[i][blocksize/2]; // Nyquist >> c=smin[blocksize/2]; >> block[i][blocksize/2]=a*c; >>} >> >>But otherwise I recommend going with the complex FFT. There may be some >>dimensional issues going on in other parts of your code that you >>haven't shown. In my understanding you need to account for a size >>difference in the FFT array when using the real-to-real FFT. If you use >>the complex FFT, then you won't have to worry about that. > > > wow, thank you BobM, it works perfectly with the code you did. I think > you pointed out something that I didn't understand about the structure > of real-to-real FFT, it's what matches to the nyquist frequency. on a > signal that is multiple of 2, if N/2 is the nyquist, what is the sample > that symetrically matches to it (i guess i mean N/2 - 1)?
DC and Fs/2 are cosine-only terms. The sine component of FS/2 disappears because it's sampled at its zero crossings. At DC sin(2*pi*0*t) is zero. Sometimes, to save space, the terms for DC and Fs/2 are stored together as if they were an imaginary pair. Jerry -- Engineering is the art of making what you want from things you can get. &#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;