MATLAB: Converting these 5 lines of MATLAB code to C++

arrayfilterMATLABvector

I am trying to convert the MATLAB code here to C++.
The code outputs BiQuad a1/a2 filter coefficients for a series of cascaded all-pass filters to help simulate inharmonicity of a synthesized string (eg. guitar/piano). It comes from this article.
Most of the code is pretty obvious and nearly identical to C++, but there are some lines I don't understand because I'm not trained in MATLAB. I'm hoping for a bit of help so I can get this done. The main points I don't get are:
1) What are the square brackets and colons for?
I'm stuck on these two lines:
phik = pi*[1:2:2*nap-1];
etan = [0:nap-1]/(1.2*nap) * df;
I understand the square brackets have to do with arrays and the colons have to do with vectors. But what specifically is each of those doing? The manual here gives an example of:
x = 1:3:19
As creating a vector that increments by 3. So is the first line creating an array of values that starts at one, increments by 2, and goes up to (2*nap – 1)? And all values in the array are then multiplied by pi?
In the second line, is it creating an array of etan values that go from 0 to nap-1 and then dividing each by 1.2*nap and multiplying by df? If so, what is the increment? Is an increment of 1 assumed when it's not specified?
2) What is the meaning of this line:
delta = diff([-theta(1) theta])/2;
I understand diff means it takes the difference of the two values. Is it right term minus left term in this case?
Next what is "theta(1)"? Theta was defined as follows:
theta = fs/(2*pi) * (phik - phin + (2*pi/fs)*etan.*taun) ./ (taun - mu0);
I understand parentheses are supposed to be for function input operations, same as C++. But I don't see any place for a "1" input to apply here for theta. What does that do? Is it referencing the first theta in an array of thetas perhaps? ie. The theta of the first all pass filter? I'm not sure.
3) How do these lines output the array of BiQuad coefficients?
temp = [ones(nap,1) 2*alpha'.*cc' alpha'.^2];
sos = [fliplr(temp) temp];
I think temp creates a vector of 3 values. "ones(nap,1)" returns a nap-by-one matrix of one values. The second part I'm confused on. What are the apostrophes here? What is this doing with "alpha" and "cc"?
Lastly the sos function obviously just reverses the elements contained by sos. But what do we even have at that point? A matrix of ones, and two functions multiplying out alphas? Which one of these elements is a1 and a2 of the Biquad?
4) How do you implement these outputs into a Biquad All Pass? (Minor question since I'm pretty sure I have this…)
My understand from this article is that to obtain an all pass biquad, you set g = a2, B1 = a1/a2, and B2 = 1/a2. Thus you only need a1 and a2 which the above code should provide for the series of all passes. Lastly, the format of a biquad for sample by sample processing is given here as:
So I am presuming a correct C++ implementation per all pass would be:
double g = a2;
double B1 = a1/a2;
double B2 = 1/a2;
inputGained_2 = inputGained_1;
inputGained_1 = inputGained;
inputGained = input * g;
output_2 = output_1;
output_1 = output;
output = inputGained + (B1 * inputGained_1) + (B2 * inputGained_2) - (a1 * output_1) - (a2 * output_2);
I'm pretty sure that's straight forward and I've gotten that part right. But with questions 1-3 for how to get my a1 and a2 for each all pass so I can process them in series I'm stuck on those 5 lines above.
Any help?
Thanks.

Best Answer

  • As creating a vector that increments by 3. So is the first line creating an array of values that starts at one, increments by 2, and goes up to (2*nap - 1)? And all values in the array are then multiplied by pi? YES
    In the second line, is it creating an array of etan values that go from 0 to nap-1 and then dividing each by 1.2*nap and multiplying by df? If so, what is the increment? Is an increment of 1 assumed when it's not specified? YES and the increment is 1 if not explicitly given.
    I understand diff means it takes the difference of the two values. Is it right term minus left term in this case?
    Next what is "theta(1)"?
    I understand parentheses are supposed to be for function input operations, same as C++. But I don't see any place for a "1" input to apply here for theta. What does that do? Is it referencing the first theta in an array of thetas perhaps? ie. The theta of the first all pass filter? I'm not sure.
    diff performs first order difference. Given a vector, x(i), i = 1:n, diff gives another vector of length n-1, with each element being x(i+1)-x(i).
    A extra theta(1) was added to make sure that the output has a length being the same to theta.
    and yes theta(1) is indexing the first element of theta. In C++, it's theta[0] i think.
    I think temp creates a vector of 3 values. "ones(nap,1)" returns a nap-by-one matrix of one values. The second part I'm confused on. What are the apostrophes here? What is this doing with "alpha" and "cc"? .* does element wise multiplication, and .^ does element wise power. E.g., [1, 2, 3].*[1, 2, 3] = [1, 4, 9] (and in this case you couldn't use * directly as it doesn't meet the criterion to perform a vector/matrix multiplication. [1, 2, 3].^2 = [1, 4, 9] as well, and you couldn't use [1, 2, 3]^2.
    Lastly the sos function obviously just reverses the elements contained by sos. But what do we even have at that point? A matrix of ones, and two functions multiplying out alphas? Which one of these elements is a1 and a2 of the Biquad? Yes i think it is required by the algorithm. Didn't dig deeper but you are right that it creates a symmetrical vector by first flip the vector and concatanent them.
    I didn't check that article you referred, but I think your implementation of CPP only accepts a1/a2 as a scalar (single value). It that would be the outcome from those code you mentioned, they are vectors. So in CPP i believe you would need to implement a for/while loop.