In The Web Audio Api, How to set correctly the Q value of a BiquadFilter for 1/3 of Octave - web-audio-api

I want to emulate a clasic 1/3 band analog eq and 1 octave eq. I am using BiquadFilter (Peaking) but I am not able to find out how to correctly set up the Q value for this.
In the WAA documentation are no examples of equivalences or example values. Does anybody know how can I achieve this?
Thanks.
Edit
I have found this answer that points to The Audio EQ Cookbook and says:
As mentioned in https://webaudio.github.io/web-audio-api/#filters-characteristics, the formulas for the biquad filters are based on notes at http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
This says the Q and bandwidth are related by the formula
1/Q = 2*sinh(ln(2)/2*BW*w0/sin(w0))
where w0 = = 2*pi*f0/Fs and f0 is the center frequency and Fs is the sample rate.
In that equation I am not sure how to get correctly the Bandwidth, for example in this page http://www.sengpielaudio.com/calculator-bandwidth.htm we can see a formula that states BW = f2 − f1 where f2 is the next frequency on the Eq and f1 the previous freq?
For example if the EQ is 1/3 Octave, the center frequency is 1Khz and the Sample Rate 44100hz,
f2 = 1250Hz
f0 = 1000Hz
f1 = 800hz
w0 = 2*pi*1000 / 44100 = 0.14247585730565954
BW = 1250hz - 800hz = 450
But that gives a Q of 1.09283639196669×10^-68 that is too little. But if I asume the BW as 1/3 (like one third of octave) it gives 4.30381250657881 that is almost the same as the BW to Q calculator in the same Sengpiel Audio website.
So Why BW = f2 − f1 ? Should I use BW = 1 for One octave or BW = 1/3 for One third for in Q equation?
Also, is this Q value compatible with BiquadFilter.Q values or do I have to normalize it?

Peaking Equalizers gives a nice description and a simple relationship between Q and the BW. Combining this with the audio cookbook should give you the information you need to create the desired peaking filters.

Related

Matlab: How to find frequency, amplitude and phase of a sinusoidal function with linerary increasing frequency and phase?

I am trying to calculate amplitude and frequency modulation, as well as phase, of a sinusoidal function.
The function is decribed as follows:
fs = 128;
x1 = 1/fs:1/fs:1;
A1 = 50*x1;
B1 = 10*x1;
C1 = 1;
D1 = 1;
y1 = D1 + A1.*sin(C1 + B1.*x1);
As a result I have obtained a sinusoidal function. It's amplitude and frequency increase over time, and are dependant on time. I need to use only 128 samples, so sampling frequency was changed to 128Hz.
Now, assuming I do NOT know A1, B1, C1 or D1 parameters, and only know the sampling frequency and result of "y1", is it possible to calculate all of those parameters?
What I would like, is to be able to determine frequency, amplitude and shift of the function at any given point in time.
I know that it's possible to calculate all of those for a function with stable parameters in few ways, I personally have tried this:
zastep2 = 1 + 40.*sin(1 + 10.*x1);
x = x1';
y = zastep2';
calc = #(d) [ones(size(x)),sin(d*x),cos(d*x)]\y;
calc2 = #(d) sum((y-[ones(size(x)),sin(d*x),cos(d*x)]*calc(d)).^2);
Bw = fminbnd(calc2,1,50)
abb = calc(Bw);
Dw = abb(1)
Aw = norm(abb([2 3]))
Cw = acos(abb(2)/Aw)
"zastep2" is used to simulate a function with unchanging parameters. As a result, I get the values of Dw = 1, Cw = 1, Aw = 40 and Bw = 10, so everything is okay.
Problem is, my function's amplitude and frequency linerary increase in every step, so using this kind of solution is impossible.
Is there any way to calculate those if both frequency and amplitude increase in every step? I am of course not asking for an instant solution or complete code, but I am really stuck on this, and after searching in the Internet for quite a while, decided to ask my own question.
Instead of calculating the actual parameters A1, B1, C1 or D1 you could estimate them if you have y1 and the sampling frequency.
You could use the Cramer Rao lower bound or Maximum likelihood to find a pretty good estimate for these parameters since you already know the sampling frequency and the output y1 the estimation turns out pretty close to the original values.
https://en.wikipedia.org/wiki/Estimation_theory

Shifting in FFT

Input image
Listing-1
i = imread('Untitled.png');
i = rgb2gray(i);
F = fft2(i);
%%%F = fftshift(F);
F = abs(F);
F = log(F+1);
F = mat2gray(F);
imshow(F);
Output
.
Listing-2
i = imread('Untitled.png');
i = rgb2gray(i);
F = fft2(i);
F = fftshift(F);
F = abs(F);
F = log(F+1);
F = mat2gray(F);
imshow(F);
Output
Seeing the the above two outputs, can you answer the following questions,
Why does the FFT of an image produce such an spectrum where zero frequencies are at the corner of the image?
Why is that a problem (or, is that)?
Why does the shifting operation fixes that phenomenon?
Here are some answers:
Why does the FFT of an image produce such an spectrum where zero
frequencies are at the corner of the image?
The fft is a fast implementation of the Discrete Fourier Transform (DFT). In 1-D, the DFT is defined as X[m] = \sum_n x[n] exp(j 2 pi (m-1)(n-1)/N). Therefore, clearly, the first element of the transform corresponds to the frequency zero. This is similar in 2-D, where the first row/column carries the zero frequency.
Why is that a problem (or, is that)?
It isn't, not at all. It works as intended. It is maybe only a "problem" that we are more used to seeing the zero frequency in the middle since spectrum has some symmetries so we like to look at it in [-Nyquist,Nyquist] instead of [0,2*Nyquist]. Though technically this is no different since it is anyways periodic.
Why does the shifting operation fixes that phenomenon?
Since shifting the zero frequency to the middle produces images that are somewhat visually more pleasing, a function to do this job has been made available. It is only intended to be used for display. The documentation of fftshift shows in detail how it works, also in 2-D.

Matlab Average Two Fourier transforms with different frequency vectors

Suppose I have two power spectrum vectors PS1 and PS2 which were created using fft and then taking only the positive frequency values and squaring the fft values (complex conjugate really).
Suppose also that the corresponding frequency values for PS1 and PS2 are different. E.g. PS1(10) might correspond to 10 Hz and PS2(10) might correspond to 10.5 Hz.
I want to have an average of these two (and more) power spectra. How would I best create such an average? It is fine if the PS_ave is a longer vector than any of the original power spectra, so long as there is a corresponding frequency vector. So, it might be that PS_ave(11) corresponds to 10.25 Hz, and this value should probably be the average of PS1(10) and PS2(10). All ideas are welcome!
Thanks!
You might try using interp1, which can interpolate within one signal to match frequencies for another spectrum. The following example illustrates this:
v1 =1;
t1 = [0:0.1:10];
sig1 = sin(2*pi*t1*v1).*exp(-0.5*t1)/length(t1);
v2 = 0.5;
t2 = [0:0.2:10];
sig2 = cos(2*pi*t2*v2).*exp(-0.5*t2)/length(t2);
s1= fft(sig1);
s1 = s1(1:end/2);
f1 = [0:length(s1)-1]*(1/max(t1));
s2= fft(sig2);
s2 = s2(1:end/2);
f2 = [0:length(s2)-1]*(1/max(t2));
p1 = abs(s1);
p2 = abs(s2);
% Now average using interpolation to find points in the longer vector matching the shorter
p1_interp = interp1(f1,p1,f2);
power_avg = mean([p2; p1_interp],1)
hold on, plot(f2,power_avg,'r')
Here's the result (red = avg power):

I want to use MATLAB fft2 function for electromagnetic wave propagation

I want to do EM (ELECTROMAGNETIC) wave propagation by
find the field Fourier transform in plane z==d , A = fft2(F(x,y,d))
PS(phaseshift) kz = k^2 -(kx^2+ky^2) where kx = 2*pi*1/dx ,ky = 2*pi*1/dy
C = IFFT2(A*EXP(i*PS)
but I dont get the expected result and I think I am confusing the FFT output arrangement and the way I define arrangement of kx and ky
any clue appreciated.
the flow chart is like :
1.Calculate field on z==d
2.Take Fourier 2D transform of the field at z ==d =====> F(Kx,Ky,d)
where ,
kx = 2*pi*fx , fx = 1/dx
ky = 2*pi*fy , fy =1/dy
kz = k^2 – (kx^2+ky^2)
3.Take inverse fourier transfom of (F(Kx,Ky,d)*exp(i*kz*(Z-d))) # Z == d1 when d1 >d to find the total field in z == d1
This happens for z = d1,d1,…..,dn
However I am confused about the frequency arrangement for output of fft and the way I am defining the spacial frequency (kx and Ky) are consistent.
It appears you are propagating the wave by Fraunhofer approximation? While I'm not sure what your output looks like, the FFT often 'splits' the desired signal such that half of it is on the right of the window and half of it is on the left.
Try using :
fftshift(fft(yourstuff));
Be sure to read the fftshift help entry in MATLAB.
If the amplitude is a problem, remember to normalize the FFT correctly (divide by largest valued bin).
Did you check if you used the i variable before (in a for loop for instance?) sometimes it gets overwritten... (in the case you either use j or plain sqrt(-1))
Note that kz = sqrt( k^2 – (kx^2+ky^2) )
rather than kz = k^2 – (kx^2+ky^2)

MATLAB FFT xaxis limits messing up and fftshift

This is the first time I'm using the fft function and I'm trying to plot the frequency spectrum of a simple cosine function:
f = cos(2*pi*300*t)
The sampling rate is 220500. I'm plotting one second of the function f.
Here is my attempt:
time = 1;
freq = 220500;
t = 0 : 1/freq : 1 - 1/freq;
N = length(t);
df = freq/(N*time);
F = fftshift(fft(cos(2*pi*300*t))/N);
faxis = -N/2 / time : df : (N/2-1) / time;
plot(faxis, real(F));
grid on;
xlim([-500, 500]);
Why do I get odd results when I increase the frequency to 900Hz? These odd results can be fixed by increasing the x-axis limits from, say, 500Hz to 1000Hz. Also, is this the correct approach? I noticed many other people didn't use fftshift(X) (but I think they only did a single sided spectrum analysis).
Thank you.
Here is my response as promised.
The first or your questions related to why you "get odd results when you increase the frequency to 900 Hz" is related to the Matlab's plot rescaling functionality as described by #Castilho. When you change the range of the x-axis, Matlab will try to be helpful and rescale the y-axis. If the peaks lie outside of your specified range, matlab will zoom in on the small numerical errors generated in the process. You can remedy this with the 'ylim' command if it bothers you.
However, your second, more open question "is this the correct approach?" requires a deeper discussion. Allow me to tell you how I would go about making a more flexible solution to achieve your goal of plotting a cosine wave.
You begin with the following:
time = 1;
freq = 220500;
This raises an alarm in my head immediately. Looking at the rest of the post, you appear to be interested in frequencies in the sub-kHz range. If that is the case, then this sampling rate is excessive as the Nyquist limit (sr/2) for this rate is above 100 kHz. I'm guessing you meant to use the common audio sampling rate of 22050 Hz (but I could be wrong here)?
Either way, your analysis works out numerically OK in the end. However, you are not helping yourself to understand how the FFT can be used most effectively for analysis in real-world situations.
Allow me to post how I would do this. The following script does almost exactly what your script does, but opens some potential on which we can build . .
%// These are the user parameters
durT = 1;
fs = 22050;
NFFT = durT*fs;
sigFreq = 300;
%//Calculate time axis
dt = 1/fs;
tAxis = 0:dt:(durT-dt);
%//Calculate frequency axis
df = fs/NFFT;
fAxis = 0:df:(fs-df);
%//Calculate time domain signal and convert to frequency domain
x = cos( 2*pi*sigFreq*tAxis );
F = abs( fft(x, NFFT) / NFFT );
subplot(2,1,1);
plot( fAxis, 2*F )
xlim([0 2*sigFreq])
title('single sided spectrum')
subplot(2,1,2);
plot( fAxis-fs/2, fftshift(F) )
xlim([-2*sigFreq 2*sigFreq])
title('whole fft-shifted spectrum')
You calculate a time axis and calculate your number of FFT points from the length of the time axis. This is very odd. The problem with this approach, is that the frequency resolution of the fft changes as you change the duration of your input signal, because N is dependent on your "time" variable. The matlab fft command will use an FFT size that matches the size of the input signal.
In my example, I calculate the frequency axis directly from the NFFT. This is somewhat irrelevant in the context of the above example, as I set the NFFT to equal the number of samples in the signal. However, using this format helps to demystify your thinking and it becomes very important in my next example.
** SIDE NOTE: You use real(F) in your example. Unless you have a very good reason to only be extracting the real part of the FFT result, then it is much more common to extract the magnitude of the FFT using abs(F). This is the equivalent of sqrt(real(F).^2 + imag(F).^2).**
Most of the time you will want to use a shorter NFFT. This might be because you are perhaps running the analysis in a real time system, or because you want to average the result of many FFTs together to get an idea of the average spectrum for a time varying signal, or because you want to compare spectra of signals that have different duration without wasting information. Just using the fft command with a value of NFFT < the number of elements in your signal will result in an fft calculated from the last NFFT points of the signal. This is a bit wasteful.
The following example is much more relevant to useful application. It shows how you would split a signal into blocks and then process each block and average the result:
%//These are the user parameters
durT = 1;
fs = 22050;
NFFT = 2048;
sigFreq = 300;
%//Calculate time axis
dt = 1/fs;
tAxis = dt:dt:(durT-dt);
%//Calculate frequency axis
df = fs/NFFT;
fAxis = 0:df:(fs-df);
%//Calculate time domain signal
x = cos( 2*pi*sigFreq*tAxis );
%//Buffer it and window
win = hamming(NFFT);%//chose window type based on your application
x = buffer(x, NFFT, NFFT/2); %// 50% overlap between frames in this instance
x = x(:, 2:end-1); %//optional step to remove zero padded frames
x = ( x' * diag(win) )'; %//efficiently window each frame using matrix algebra
%// Calculate mean FFT
F = abs( fft(x, NFFT) / sum(win) );
F = mean(F,2);
subplot(2,1,1);
plot( fAxis, 2*F )
xlim([0 2*sigFreq])
title('single sided spectrum')
subplot(2,1,2);
plot( fAxis-fs/2, fftshift(F) )
xlim([-2*sigFreq 2*sigFreq])
title('whole fft-shifted spectrum')
I use a hamming window in the above example. The window that you choose should suit the application http://en.wikipedia.org/wiki/Window_function
The overlap amount that you choose will depend somewhat on the type of window you use. In the above example, the Hamming window weights the samples in each buffer towards zero away from the centre of each frame. In order to use all of the information in the input signal, it is important to use some overlap. However, if you just use a plain rectangular window, the overlap becomes pointless as all samples are weighted equally. The more overlap you use, the more processing is required to calculate the mean spectrum.
Hope this helps your understanding.
Your result is perfectly right. Your frequency axis calculation is also right. The problem lies on the y axis scale. When you use the function xlims, matlab automatically recalculates the y scale so that you can see "meaningful" data. When the cosine peaks lie outside the limit you chose (when f>500Hz), there are no peaks to show, so the scale is calculated based on some veeeery small noise (here at my computer, with matlab 2011a, the y scale was 10-16).
Changing the limit is indeed the correct approach, because if you don't change it you can't see the peaks on the frequency spectrum.
One thing I noticed, however. Is there a reason for you to plot the real part of the transform? Usually, it is abs(F) that gets plotted, and not the real part.
edit: Actually, you're frequency axis is only right because df, in this case, is 1. The faxis line is right, but the df calculation isn't.
The FFT calculates N points from -Fs/2 to Fs/2. So N points over a range of Fs yields a df of Fs/N. As N/time = Fs => time = N/Fs. Substituting that on the expression of df you used: your_df = Fs/N*(N/Fs) = (Fs/N)^2. As Fs/N = 1, the final result was right :P