DSPRelated.com
Forums

FFT and time domain amplitude after FFT convolution

Started by Michel Rouzic March 16, 2006
I got a little problem when performing a FFT convolution. I try to have
the output to have the same amplitude as it would with a time-domain
convolution.

To do so, I set the sum of the values of the samples of my kernel to
1.0, and after I FFT the kernel and the signal to convolve, I divide
the values of both signals by the square root of the number of samples
(which is the same since they are both zero-padded so their length
equals both of their original length added together minus 1), I perform
the complex multiplication, IFFT the result and then divide the values
by the quare root of the number of samples again.

However, the result is much quieter than what i expected, I'm pretty
sure I got something wrong, so what's the right way to get to the right
amplitudes? (btw, i'm looking forward being as computationally
efficient as possible, so if the solution could consist of a minimal
number of multiplications, that would be cool)

"Michel Rouzic" <Michel0528@yahoo.fr> wrote in message 
news:1142536511.114291.297400@j52g2000cwj.googlegroups.com...
>I got a little problem when performing a FFT convolution. I try to have > the output to have the same amplitude as it would with a time-domain > convolution. > > To do so, I set the sum of the values of the samples of my kernel to > 1.0, and after I FFT the kernel and the signal to convolve, I divide > the values of both signals by the square root of the number of samples > (which is the same since they are both zero-padded so their length > equals both of their original length added together minus 1), I perform > the complex multiplication, IFFT the result and then divide the values > by the quare root of the number of samples again. > > However, the result is much quieter than what i expected, I'm pretty > sure I got something wrong, so what's the right way to get to the right > amplitudes? (btw, i'm looking forward being as computationally > efficient as possible, so if the solution could consist of a minimal > number of multiplications, that would be cool) >
Michael, I usually do it empirically with a couple of "sanity checks": Take a simple kernel like a unit sample in time. You know that the result of convolution should be and set the IFFT scaling accordingly. The array lengths should be what you're using/doing. Your scaling with sqrt(1/N) is that of a physicist and implies 2x the multiplies of a "normal" DSP scaling approach. Most DSP approaches, subject to numeric scaling needs perhaps, use no scaling on FFT and 1/N on IFFT. If you change the length of the arrays in frequency, then that makes a difference. It's easy to experiment - as above. Fred
Fred Marshall wrote:
> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message > news:1142536511.114291.297400@j52g2000cwj.googlegroups.com... > >I got a little problem when performing a FFT convolution. I try to have > > the output to have the same amplitude as it would with a time-domain > > convolution. > > > > To do so, I set the sum of the values of the samples of my kernel to > > 1.0, and after I FFT the kernel and the signal to convolve, I divide > > the values of both signals by the square root of the number of samples > > (which is the same since they are both zero-padded so their length > > equals both of their original length added together minus 1), I perform > > the complex multiplication, IFFT the result and then divide the values > > by the quare root of the number of samples again. > > > > However, the result is much quieter than what i expected, I'm pretty > > sure I got something wrong, so what's the right way to get to the right > > amplitudes? (btw, i'm looking forward being as computationally > > efficient as possible, so if the solution could consist of a minimal > > number of multiplications, that would be cool) > > > > Michael, > > I usually do it empirically with a couple of "sanity checks": > > Take a simple kernel like a unit sample in time. > You know that the result of convolution should be and set the IFFT scaling > accordingly. > The array lengths should be what you're using/doing.
But wait, does it mean that you gotta try convolving a unique sample with signals of different length, then compare their length and their amplitude and deduce how you should manage that? I thought about doing that, but I thought i'd ask people who already know, rather tha trying with signals of different sizes, kernels of different sizes (like a 1.0 sample and N zeroes) and different buffer size (i'm using what I think is called overlap-add). Isn't there a general solution?
> Your scaling with sqrt(1/N) is that of a physicist and implies 2x the > multiplies of a "normal" DSP scaling approach. Most DSP approaches, subject > to numeric scaling needs perhaps, use no scaling on FFT and 1/N on IFFT. If > you change the length of the arrays in frequency, then that makes a > difference. > It's easy to experiment - as above.
Well yeah, actually I did that too, no scaling on both FFT's, and after the IFFT, division by the number of samples. But that gives a result that's too loud, a few times too loud, but I thought that it would work no matter what, so why doesn't it just work? why am I even supposed to experiment since everybody goes through this when trying to implement FFT convolution? I'm a bit confused, it works good with a kernel made of only one sample which value is 1.0 and the rest are zeroes, but whenever it's something different, although the sum of all it's samples equal one, it doesn't work (i mean its way to loud)
"Michel Rouzic" <Michel0528@yahoo.fr> wrote in message 
news:1142556392.986353.61230@e56g2000cwe.googlegroups.com...
> > Fred Marshall wrote: >> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message >> news:1142536511.114291.297400@j52g2000cwj.googlegroups.com... >> >I got a little problem when performing a FFT convolution. I try to have >> > the output to have the same amplitude as it would with a time-domain >> > convolution. >> > >> > To do so, I set the sum of the values of the samples of my kernel to >> > 1.0, and after I FFT the kernel and the signal to convolve, I divide >> > the values of both signals by the square root of the number of samples >> > (which is the same since they are both zero-padded so their length >> > equals both of their original length added together minus 1), I perform >> > the complex multiplication, IFFT the result and then divide the values >> > by the quare root of the number of samples again. >> > >> > However, the result is much quieter than what i expected, I'm pretty >> > sure I got something wrong, so what's the right way to get to the right >> > amplitudes? (btw, i'm looking forward being as computationally >> > efficient as possible, so if the solution could consist of a minimal >> > number of multiplications, that would be cool) >> > >> >> Michael, >> >> I usually do it empirically with a couple of "sanity checks": >> >> Take a simple kernel like a unit sample in time. >> You know that the result of convolution should be and set the IFFT >> scaling >> accordingly. >> The array lengths should be what you're using/doing. > > But wait, does it mean that you gotta try convolving a unique sample > with signals of different length, then compare their length and their > amplitude and deduce how you should manage that? I thought about doing > that, but I thought i'd ask people who already know, rather tha trying > with signals of different sizes, kernels of different sizes (like a 1.0 > sample and N zeroes) and different buffer size (i'm using what I think > is called overlap-add). Isn't there a general solution? > >> Your scaling with sqrt(1/N) is that of a physicist and implies 2x the >> multiplies of a "normal" DSP scaling approach. Most DSP approaches, >> subject >> to numeric scaling needs perhaps, use no scaling on FFT and 1/N on IFFT. >> If >> you change the length of the arrays in frequency, then that makes a >> difference. >> It's easy to experiment - as above. > > Well yeah, actually I did that too, no scaling on both FFT's, and after > the IFFT, division by the number of samples. But that gives a result > that's too loud, a few times too loud, but I thought that it would work > no matter what, so why doesn't it just work? why am I even supposed to > experiment since everybody goes through this when trying to implement > FFT convolution? I'm a bit confused, it works good with a kernel made > of only one sample which value is 1.0 and the rest are zeroes, but > whenever it's something different, although the sum of all it's samples > equal one, it doesn't work (i mean its way to loud)
OK - I'll try to use some numbers then: I should probably refer you to any number of discussions on comp.dsp that deal with how processes might be scaled. This is different, if related, to how the FFT/IFFT processes might be scaled. For example: I have a sum of sinusoids at different frequencies all with peak amplitude 1.0 and I want to look at the spectral content after passing the signal through a lowpass filter. The lowpass filter has gain 1.0 in the passband - so all the low frequency sinusoids should pass relatively unaltered in magnitude. Now we'll take an FFT of the filtered signal. - some will want each sinusoid to have peaks in frequency with amplitude 0.5. - some will want each sinusoid to have peaks in frequency with amplitude 1.0. (I am not going to talk about scalloping losses so each frequency is dead on a frequency sample point, OK?) - some will want each sinusoid to have peaks in frequency with amplitude N/2 because that's what an unscaled FFT will generate. If N=100, the peaks will be 50. This is mentioned below. Now let's talk about the filter: You said: the sum of the coefficients of the filter is set to 1.0. I sure hope it's a lowpass filter or the filter is going to have a lot of gain! Why? Because the sum of the coefficients of the filter is the gain at f=0 and if it's a bandpass filter then the in-band gain will be the reciprocal of the intended gain at f=0. If the intended gain at f=0 is 0.001 then the passband gain will be scaled by 1/0.001 = 1000 and, yes the output will be "loud". So, maybe that normalization isn't the best idea except in the case of a lowpass. A better normalization will make the filter response 1.0 in the passband. That's generally what the filter design programs do in the first place. Presumably what one normally wants to do is to not change the input/output energy in the passband ("loudness"). That's your objective, right? Now, if you zero pad the filter unit sample response, the passband response doesn't change. That should be obvious for a lowpass filter because the sum has to be 1.0 at f=0 no matter how many zeros are added at the end. Zero padding in time doesn't scale it only interpolates in frequency. Why? Because zero padding the filter doesn't do anything to the filter whatsoever and the interpolation is only a higher resolution version of a frequency response plot of the filter's (atually continuous) frequency response. Now, take that sinusoid above and double its length. The FFT output will have peaks of amplitude N/2 as before except now N->2N. If there are 200 samples then the peaks are 100. Why? Because the signal is twice as long and has twice the energy compared to the case above. If the sinusoid from the case above were to be zero padded by a factor of 2 then the amplitude peaks in frequency would remain at 50 because the energy doesn't change. Summary: For an enduring signal like a sinusoid, the window duration for the FFT will affect the energy being processed. And, it will also affect the number of samples. Accordingly, the frequency peaks will remain at K*N/2 no matter the width of the window (where K is the amplitude of the signal). For a time-limited "signal" like the unit sample response of a filter, or a fixed-length but zero padded version of an enduring signal like a sinusoid, the number of zeros added will have no affect on the frequency domain peak amplitudes. If you're doing filtering by frequency domain multiplication, there should be no scaling problem. You can zero pad the filter as much as you need to with no scaling impact. You can zero pad the signal as much as you need with no scaling impact - *except* the result will be the same, or nearly the same, as if you had not zero padded ... from a scaling point of view. The most straightforward and most often used method I believe is to do this: - Decide on the time duration N of the signal chunks to be filtered. - Design the (FIR) filter of length L. - Zero pad it out by (not "to") the length of the signal time duration less one; N-1 zeros getting N+L-1 - FFT the zero-padded filter with *no* scaling and save it. - Grab each chunk of the signal of length N or, alternately and probably more commonly, N+L-1 - If length N, zero pad out to length N+L-1. - FFT the signal array with *no* scaling. - Multiply the N+L-1 length filter and signal arrays in frequency. - IFFT the product scaling by 1/(N+L-1) Fred
Fred Marshall wrote:
> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message > news:1142556392.986353.61230@e56g2000cwe.googlegroups.com... > > > > Fred Marshall wrote: > >> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message > >> news:1142536511.114291.297400@j52g2000cwj.googlegroups.com... > >> >I got a little problem when performing a FFT convolution. I try to have > >> > the output to have the same amplitude as it would with a time-domain > >> > convolution. > >> > > >> > To do so, I set the sum of the values of the samples of my kernel to > >> > 1.0, and after I FFT the kernel and the signal to convolve, I divide > >> > the values of both signals by the square root of the number of samples > >> > (which is the same since they are both zero-padded so their length > >> > equals both of their original length added together minus 1), I perform > >> > the complex multiplication, IFFT the result and then divide the values > >> > by the quare root of the number of samples again. > >> > > >> > However, the result is much quieter than what i expected, I'm pretty > >> > sure I got something wrong, so what's the right way to get to the right > >> > amplitudes? (btw, i'm looking forward being as computationally > >> > efficient as possible, so if the solution could consist of a minimal > >> > number of multiplications, that would be cool) > >> > > >> > >> Michael, > >> > >> I usually do it empirically with a couple of "sanity checks": > >> > >> Take a simple kernel like a unit sample in time. > >> You know that the result of convolution should be and set the IFFT > >> scaling > >> accordingly. > >> The array lengths should be what you're using/doing. > > > > But wait, does it mean that you gotta try convolving a unique sample > > with signals of different length, then compare their length and their > > amplitude and deduce how you should manage that? I thought about doing > > that, but I thought i'd ask people who already know, rather tha trying > > with signals of different sizes, kernels of different sizes (like a 1.0 > > sample and N zeroes) and different buffer size (i'm using what I think > > is called overlap-add). Isn't there a general solution? > > > >> Your scaling with sqrt(1/N) is that of a physicist and implies 2x the > >> multiplies of a "normal" DSP scaling approach. Most DSP approaches, > >> subject > >> to numeric scaling needs perhaps, use no scaling on FFT and 1/N on IFFT. > >> If > >> you change the length of the arrays in frequency, then that makes a > >> difference. > >> It's easy to experiment - as above. > > > > Well yeah, actually I did that too, no scaling on both FFT's, and after > > the IFFT, division by the number of samples. But that gives a result > > that's too loud, a few times too loud, but I thought that it would work > > no matter what, so why doesn't it just work? why am I even supposed to > > experiment since everybody goes through this when trying to implement > > FFT convolution? I'm a bit confused, it works good with a kernel made > > of only one sample which value is 1.0 and the rest are zeroes, but > > whenever it's something different, although the sum of all it's samples > > equal one, it doesn't work (i mean its way to loud) > > OK - I'll try to use some numbers then: > > I should probably refer you to any number of discussions on comp.dsp that > deal with how processes might be scaled. This is different, if related, to > how the FFT/IFFT processes might be scaled. > For example: > I have a sum of sinusoids at different frequencies all with peak amplitude > 1.0 and I want to look at the spectral content after passing the signal > through a lowpass filter. > The lowpass filter has gain 1.0 in the passband - so all the low frequency > sinusoids should pass relatively unaltered in magnitude. > Now we'll take an FFT of the filtered signal. > - some will want each sinusoid to have peaks in frequency with amplitude > 0.5. > - some will want each sinusoid to have peaks in frequency with amplitude > 1.0. > (I am not going to talk about scalloping losses so each frequency is dead on > a frequency sample point, OK?) > - some will want each sinusoid to have peaks in frequency with amplitude N/2 > because that's what an unscaled FFT will generate. If N=100, the peaks will > be 50. This is mentioned below. > > Now let's talk about the filter: > You said: the sum of the coefficients of the filter is set to 1.0. > I sure hope it's a lowpass filter or the filter is going to have a lot of > gain! > Why? Because the sum of the coefficients of the filter is the gain at f=0 > and if it's a bandpass filter then the in-band gain will be the reciprocal > of the intended gain at f=0. > If the intended gain at f=0 is 0.001 then the passband gain will be scaled > by 1/0.001 = 1000 and, yes the output will be "loud".
oh, i got it. hadn't fully thought about what I was doing by calculating the sum of samples of my kernel. it's calculating the DC component, and since it's not necessarly a lowpass FIR (it's more like a speaker's impulse response)
> So, maybe that normalization isn't the best idea except in the case of a > lowpass. > A better normalization will make the filter response 1.0 in the passband. > That's generally what the filter design programs do in the first place. > Presumably what one normally wants to do is to not change the input/output > energy in the passband ("loudness"). That's your objective, right?
Yeah that's pretty much it. The kernel has about all frequencies well represented (with differences from the max magnitude to the min of about 30 or 40 dB) and the goal is to have the output sound sounding as loud as the input.
> Now, if you zero pad the filter unit sample response, the passband response > doesn't change. That should be obvious for a lowpass filter because the sum > has to be 1.0 at f=0 no matter how many zeros are added at the end. Zero > padding in time doesn't scale it only interpolates in frequency. Why? > Because zero padding the filter doesn't do anything to the filter whatsoever > and the interpolation is only a higher resolution version of a frequency > response plot of the filter's (atually continuous) frequency response. > > Now, take that sinusoid above and double its length. The FFT output will > have peaks of amplitude N/2 as before except now N->2N. If there are 200 > samples then the peaks are 100. Why? Because the signal is twice as long > and has twice the energy compared to the case above. > If the sinusoid from the case above were to be zero padded by a factor of 2 > then the amplitude peaks in frequency would remain at 50 because the energy > doesn't change. > > Summary: > For an enduring signal like a sinusoid, the window duration for the FFT will > affect the energy being processed. And, it will also affect the number of > samples. Accordingly, the frequency peaks will remain at K*N/2 no matter > the width of the window (where K is the amplitude of the signal). > For a time-limited "signal" like the unit sample response of a filter, or a > fixed-length but zero padded version of an enduring signal like a sinusoid, > the number of zeros added will have no affect on the frequency domain peak > amplitudes. > > If you're doing filtering by frequency domain multiplication, there should > be no scaling problem. > You can zero pad the filter as much as you need to with no scaling impact. > You can zero pad the signal as much as you need with no scaling impact - > *except* the result will be the same, or nearly the same, as if you had not > zero padded ... from a scaling point of view. > > The most straightforward and most often used method I believe is to do this: > - Decide on the time duration N of the signal chunks to be filtered. > - Design the (FIR) filter of length L.
Here is the problem. I got my kernel, but the big question is, to what do I amplify it. Because as I understand it, my problem is not in what I do in the process of FFT convolution, but rather how I "amplify" my kernel (since so far I was basing myself on having the sum of it's values set to 1.0, which isn't a good idea in my case when the DC element must be about 30 dB under the peak in the frequency domain) So, how do I set my kernel to the right amplitude? By setting the sum of the magnitude bins in the frequency domain to some value based on its length? The way I see it, if I set the sum of the magnitude bins to be equal to the sum of the magnitude bins of a delta function of the exact same length, I should get it right, right? (btw, I have no idea on how to calculate the one value the magnitude bins for a delta function based on its length)
> - Zero pad it out by (not "to") the length of the signal time duration less > one; > N-1 zeros getting N+L-1 > - FFT the zero-padded filter with *no* scaling and save it. > - Grab each chunk of the signal of length N or, alternately and probably > more commonly, N+L-1 > - If length N, zero pad out to length N+L-1. > - FFT the signal array with *no* scaling. > - Multiply the N+L-1 length filter and signal arrays in frequency. > - IFFT the product scaling by 1/(N+L-1)
No problem about that. I'm thinking by the way that since I'll calculate my kernel only once and use it indefinitly (it's about real-time convolution, so once i have calculated everything for my kernel I just gotta save it and use it forever if I want), I'm better of doing the 1/(N+L-1) scaling directly on the kernel (so I wouldn't have to do it everytime on each buffer)
"Michel Rouzic" <Michel0528@yahoo.fr> wrote in message 
news:1142570053.519282.56790@e56g2000cwe.googlegroups.com...

> Here is the problem. I got my kernel, but the big question is, to what > do I amplify it. Because as I understand it, my problem is not in what > I do in the process of FFT convolution, but rather how I "amplify" my > kernel (since so far I was basing myself on having the sum of it's > values set to 1.0, which isn't a good idea in my case when the DC > element must be about 30 dB under the peak in the frequency domain) > > So, how do I set my kernel to the right amplitude? By setting the sum > of the magnitude bins in the frequency domain to some value based on > its length? The way I see it, if I set the sum of the magnitude bins to > be equal to the sum of the magnitude bins of a delta function of the > exact same length, I should get it right, right? (btw, I have no idea > on how to calculate the one value the magnitude bins for a delta > function based on its length)
You got the filter by specifying the gain you wanted at each frequency or in each band, right? Then leave it alone... That is all you need to do. Nothing more. Then, if you decide you need 10dB more gain or less gain, adjust accordingly. Otherwise, you already have what you need.
> >> - Zero pad it out by (not "to") the length of the signal time duration >> less >> one; >> N-1 zeros getting N+L-1 >> - FFT the zero-padded filter with *no* scaling and save it. >> - Grab each chunk of the signal of length N or, alternately and probably >> more commonly, N+L-1 >> - If length N, zero pad out to length N+L-1. >> - FFT the signal array with *no* scaling. >> - Multiply the N+L-1 length filter and signal arrays in frequency. >> - IFFT the product scaling by 1/(N+L-1) > > No problem about that. I'm thinking by the way that since I'll > calculate my kernel only once and use it indefinitly (it's about > real-time convolution, so once i have calculated everything for my > kernel I just gotta save it and use it forever if I want), I'm better > of doing the 1/(N+L-1) scaling directly on the kernel (so I wouldn't > have to do it everytime on each buffer) >
That sounds like a good idea. Fred
Fred Marshall wrote:
> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message > news:1142570053.519282.56790@e56g2000cwe.googlegroups.com... > > > Here is the problem. I got my kernel, but the big question is, to what > > do I amplify it. Because as I understand it, my problem is not in what > > I do in the process of FFT convolution, but rather how I "amplify" my > > kernel (since so far I was basing myself on having the sum of it's > > values set to 1.0, which isn't a good idea in my case when the DC > > element must be about 30 dB under the peak in the frequency domain) > > > > So, how do I set my kernel to the right amplitude? By setting the sum > > of the magnitude bins in the frequency domain to some value based on > > its length? The way I see it, if I set the sum of the magnitude bins to > > be equal to the sum of the magnitude bins of a delta function of the > > exact same length, I should get it right, right? (btw, I have no idea > > on how to calculate the one value the magnitude bins for a delta > > function based on its length) > > You got the filter by specifying the gain you wanted at each frequency or in > each band, right? Then leave it alone... That is all you need to do. > Nothing more. > Then, if you decide you need 10dB more gain or less gain, adjust > accordingly. > Otherwise, you already have what you need.
Well no. I got my filter by performing measurements, cross-coreelations etc.. The original gain if ever I could get it by doing that got lost in the mix. Plus, its pretty much a general purpose convolution program, although most kernels used should have to be of the same kind as the one i'm using right now, I could leave it up to myself/the user to mess around with the kernel's scaling but honnestly i'd prefer some automated thing, since a manual thing would result in a process of trial in order to find what's the highest scaling possible without reaching over 1.0 or -1.0. I guess I could convolve the kernel with a white noise or MLS (or even a log sweep) that would be at first normalized to 1.0 and I'd look forward making the result normalized to 1.0 as well, but honnestly I wouldn't spit on an alternative solution.
"Michel Rouzic" <Michel0528@yahoo.fr> wrote in message 
news:1142601336.925968.203810@i39g2000cwa.googlegroups.com...
> > Fred Marshall wrote: >> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message >> news:1142570053.519282.56790@e56g2000cwe.googlegroups.com... >> >> > Here is the problem. I got my kernel, but the big question is, to what >> > do I amplify it. Because as I understand it, my problem is not in what >> > I do in the process of FFT convolution, but rather how I "amplify" my >> > kernel (since so far I was basing myself on having the sum of it's >> > values set to 1.0, which isn't a good idea in my case when the DC >> > element must be about 30 dB under the peak in the frequency domain) >> > >> > So, how do I set my kernel to the right amplitude? By setting the sum >> > of the magnitude bins in the frequency domain to some value based on >> > its length? The way I see it, if I set the sum of the magnitude bins to >> > be equal to the sum of the magnitude bins of a delta function of the >> > exact same length, I should get it right, right? (btw, I have no idea >> > on how to calculate the one value the magnitude bins for a delta >> > function based on its length) >> >> You got the filter by specifying the gain you wanted at each frequency or >> in >> each band, right? Then leave it alone... That is all you need to do. >> Nothing more. >> Then, if you decide you need 10dB more gain or less gain, adjust >> accordingly. >> Otherwise, you already have what you need. > > Well no. I got my filter by performing measurements, cross-coreelations > etc.. The original gain if ever I could get it by doing that got lost > in the mix. Plus, its pretty much a general purpose convolution > program, although most kernels used should have to be of the same kind > as the one i'm using right now, I could leave it up to myself/the user > to mess around with the kernel's scaling but honnestly i'd prefer some > automated thing, since a manual thing would result in a process of > trial in order to find what's the highest scaling possible without > reaching over 1.0 or -1.0. > > I guess I could convolve the kernel with a white noise or MLS (or even > a log sweep) that would be at first normalized to 1.0 and I'd look > forward making the result normalized to 1.0 as well, but honnestly I > wouldn't spit on an alternative solution.
Mike, What you want may be what's commonly referred to as "unobtanium". That's because only you know what you want / need. (I was going to ask earlier what you really meant by "loud" because that's not well defined except as a matter of your own perception - psychoacoustics and all that). I think that's why equalizers have those little slide handles and radios have volume controls. There's no good way to "can" the settings in an algorithm. I really don't understand your description of how you arrive at the filter. "performing measurements" "cross correlations" <<<< this one puzzles me a bit "etc." I don't know what a tool being general purpose has to do with anything we're discussing. "original gain" referring to what? Presumably you have signal that has a level or levels but I don't understand "gain" in this context. If you convolve the kernel (of the filter) with white noise then you'll pretty much get a spectrum out that is indicative of the filter response which you already know or can know from the filter coefficients. If you use a sweep (if I understand you there and taking a leap) you get the same thing. Now ... you say you want to "normalize the result" (at the output) using a "normalized" input. OK. So, now you're right back to saying this: "I want a filter that has unity gain at some frequencies" So, you must know what those frequencies are - or similarly know what the filter spectral shaping countour is - which suggests that normalization to unity only happens at one or a few points. - If you know what those frequencies are, or what the countour is, then you have the specifications for a filter design. (More on this below**). Problem solved. - If you don't know what those frequencies are then you're stuck unless you resort to an adaptive filter method which will probably emphasize signals of longer duration and deemphasize noise. There are too many approaches and structures to mention here and now. Anyway, in this situation you end up with a set of filter coefficients and have the same situation as above. Gain remains subjective though... although line cancellers have to have exact gain to do their job and line enhancers operate on the same principles. But, is that "exact gain" the gain you want? **If you have a known countour (as might be from an equalizer) then there are filter design programs that will design any frequency shape you like. Not just stopbands of zero and passbands of 1.0. Or, you might use the Parks McClellan program and just specify lots of bands with their own gains. Gain remains subjective though... Maybe a bit more about the real application? Fred
Fred Marshall wrote:
> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message > news:1142601336.925968.203810@i39g2000cwa.googlegroups.com... > > > > Fred Marshall wrote: > >> "Michel Rouzic" <Michel0528@yahoo.fr> wrote in message > >> news:1142570053.519282.56790@e56g2000cwe.googlegroups.com... > >> > >> > Here is the problem. I got my kernel, but the big question is, to what > >> > do I amplify it. Because as I understand it, my problem is not in what > >> > I do in the process of FFT convolution, but rather how I "amplify" my > >> > kernel (since so far I was basing myself on having the sum of it's > >> > values set to 1.0, which isn't a good idea in my case when the DC > >> > element must be about 30 dB under the peak in the frequency domain) > >> > > >> > So, how do I set my kernel to the right amplitude? By setting the sum > >> > of the magnitude bins in the frequency domain to some value based on > >> > its length? The way I see it, if I set the sum of the magnitude bins to > >> > be equal to the sum of the magnitude bins of a delta function of the > >> > exact same length, I should get it right, right? (btw, I have no idea > >> > on how to calculate the one value the magnitude bins for a delta > >> > function based on its length) > >> > >> You got the filter by specifying the gain you wanted at each frequency or > >> in > >> each band, right? Then leave it alone... That is all you need to do. > >> Nothing more. > >> Then, if you decide you need 10dB more gain or less gain, adjust > >> accordingly. > >> Otherwise, you already have what you need. > > > > Well no. I got my filter by performing measurements, cross-coreelations > > etc.. The original gain if ever I could get it by doing that got lost > > in the mix. Plus, its pretty much a general purpose convolution > > program, although most kernels used should have to be of the same kind > > as the one i'm using right now, I could leave it up to myself/the user > > to mess around with the kernel's scaling but honnestly i'd prefer some > > automated thing, since a manual thing would result in a process of > > trial in order to find what's the highest scaling possible without > > reaching over 1.0 or -1.0. > > > > I guess I could convolve the kernel with a white noise or MLS (or even > > a log sweep) that would be at first normalized to 1.0 and I'd look > > forward making the result normalized to 1.0 as well, but honnestly I > > wouldn't spit on an alternative solution. > > Mike, > > What you want may be what's commonly referred to as "unobtanium". > That's because only you know what you want / need. > (I was going to ask earlier what you really meant by "loud" because that's > not well defined except as a matter of your own perception - psychoacoustics > and all that).
by loud I meant well over 1.0 and -1.0. my purpose is to make the resulting signal hold well between those two boundaries without crossing, provided that the original sounds repects those too.
> I think that's why equalizers have those little slide handles and radios > have volume controls. There's no good way to "can" the settings in an > algorithm. > > I really don't understand your description of how you arrive at the filter. > "performing measurements" > "cross correlations" <<<< this one puzzles me a bit > "etc." > I don't know what a tool being general purpose has to do with anything we're > discussing.
OK, but I don't wanna get too deep in the details. I obtained the filter mainly by playing a signal (a log sweep, but it could have been a MLS or any other signal trhat's well represented in the frequency range i'm interested in) and recording it, then cross correlating the two signals (basically, because i did much more than that and also compensated the bias induced by the non linearity of the orignal signal's magnitude in the frequency domain), and also "inverting it" so it can be used as a deconvolution kernel, but I really don't wanna get in those details.
> "original gain" referring to what? Presumably you have signal that has a > level or levels but I don't understand "gain" in this context.
Well, idk, actually, from the start I don't think I could even have quantified the gain really, since the recorded signal of the signal played by the speaker doesn't reflect any gain.
> If you convolve the kernel (of the filter) with white noise then you'll > pretty much get a spectrum out that is indicative of the filter response > which you already know or can know from the filter coefficients. > If you use a sweep (if I understand you there and taking a leap) you get the > same thing. > Now ... you say you want to "normalize the result" (at the output) using a > "normalized" input. > OK. > So, now you're right back to saying this: > "I want a filter that has unity gain at some frequencies" > So, you must know what those frequencies are - or similarly know what the > filter spectral shaping countour is - which suggests that normalization to > unity only happens at one or a few points.
I'm not sure I got that one. I'm starting to think that there's no automated solution to that and that i'd just have to try changing my kernel's gain until I obtain satisfaction with the result's amplitude.
> - If you know what those frequencies are, or what the countour is, then you > have the specifications for a filter design. (More on this below**). > Problem solved. > > - If you don't know what those frequencies are then you're stuck unless you > resort to an adaptive filter method which will probably emphasize signals of > longer duration and deemphasize noise. There are too many approaches and > structures to mention here and now. > Anyway, in this situation you end up with a set of filter coefficients and > have the same situation as above. > Gain remains subjective though... although line cancellers have to have > exact gain to do their job and line enhancers operate on the same > principles. But, is that "exact gain" the gain you want?
Idk if it's cuz i'm tired, but i'm having a though time trying to understand it all. However, I'm starting to agree with you, I think that my whole gain thing that I thought at the beginning of this thread could be treated objectively is really something subjective, although the result can be verified, it all depends on the type of signal i convolve it with.
> **If you have a known countour (as might be from an equalizer) then there > are filter design programs that will design any frequency shape you like. > Not just stopbands of zero and passbands of 1.0. Or, you might use the > Parks McClellan program and just specify lots of bands with their own gains. > Gain remains subjective though... > > Maybe a bit more about the real application?
I described shortly above what I did to obtain my filter, the real application of this is to obtain a real-time sound convolver "compensating" (understand deconvolving) the frequency response of a set of speakers (as measured by a calibrated microphone). The reason for this topic is that, since it'll be outputting integers, I have to make sure that a signal normalized to +/-1.0 in the input will otuput as a signal normalized to +/-1.0 or something close. however, since it's supposed to be real time, you can't just normalize the output, since if you normalize a buffer with a certain value, another buffer with higher peaks will be normalized with a certain value, and it wouldn't sound right (a buffer would suddenyl sound lower than another). Although after awhile, provided that the value for the highest peak ever encountered is kept, i don't like this solution too much, since it might take some time till the max value of the normalization is reached. So I guessed that maybe convolving it with a white noise could give a representative idea of the output's amplitude, and what to do to keep it close to the input's, although at the peak frequencies in the kernel, if only those peak frequencies are in the input signal, the output signal might go over +/-1.0. So the next idea is too convolve with a sweep : thus, let's say for example the peak frequency in my kernel is 300 Hz, in the output, the sweep will have the highest amplitude at the part it reaches 300 Hz, thus, normalizing according to the max amplitude reachable with the kernel's peak woudl garantee not getting over +/-1.0 in the output signal but potential close. I guess this isn't too bad, although it might make it sound most of the time less "loud" than the original signal, I also thought that this could be achived by making the frequency peak in the kernel's magnitude equal the value all magnitudes in the frequency would have if it was a delta function of the same length, although i'm not sure, plus idk how to calculate that value without actually creating a delta function zero-padded to the lengtrh of the signal i'm trying to normalize and then FFT it and turn it to polar form. So maybe the best is to try messing with the kernel until the user/me decides it sounds loud enough/not too loud, but I wanna hear your opinion :)