Matlab AR digital fiter computation w/o loops - matlab

I'm given the a(k) matrix and e(n) and I need to compute y(n) from the following eq:
y(n) = sum(k = 1 to 10 )( a(k)*y(n-k) ) + e(n).
I have the a matrix(filter coefficients) and the e matrix (the residual), therefore there is only 1 unknown: y, which is built by the previous 10 samples of y.
An example to this equation:
say e(0) (my first residual sample) = 3
and y(-10) to y(-1) = 0
then y(0), my first sample in the signal y, would just be e(0) = 3:
y(0) = a(1)*y(-1) + a(2)*y(-2) + .... + a(10)*y(-10) + e(0) = e(0) = 3
and if e(1) = 4, and a(1) = 5, then
y(1) = a(1)*y(0) + a(2)*y(-1) + a(3)&y(-2) + ... + a(10)*y(-9) + e(1) = 19
The problem is
I don't know how to do this without loops because, say, y(n) needs y(n-1), so I need to immediately append y(n-1) into my matrix in order to get y(n).
If n (the number of samples) = say, 10,000,000, then using a loop is not ideal.
What I've done so far
I have not implemented anything. The only thing I've done for this particular problem is research on what kind of Matlab functions I could use.
What I need
A Matlab function that, given an equation and or input matrix, computes the next y(n) and automatically appends that to the input matrix, and then computes the next y(n+1), and automatically append that to the input matrix and so on.
If there is anything regarding my approach
That seems like it's on the wrong track, or my question isn't clear enough, of if there is no such matlab function that exists, then I apologize in advance. Thank you for your time.

Related

Using MATLAB plots to find linear equation constants

Finding m and c for an equation y = mx + c, with the help of math and plots.
y is data_model_1, x is time.
Avoid other MATLAB functions like fitlm as it defeats the purpose.
I am having trouble finding the constants m and c. I am trying to find both m and c by limiting them to a range (based on smart guess) and I need to deduce the m and c values based on the mean error range. The point where mean error range is closest to 0 should be my m and c values.
load(file)
figure
plot(time,data_model_1,'bo')
hold on
for a = 0.11:0.01:0.13
c = -13:0.1:-10
data_a = a * time + c ;
plot(time,data_a,'r');
end
figure
hold on
for a = 0.11:0.01:0.13
c = -13:0.1:-10
data_a = a * time + c ;
mean_range = mean(abs(data_a - data_model_1));
plot(a,mean_range,'b.')
end
A quick & dirty approach
You can quickly get m and c using fminsearch(). In the first example below, the error function is the sum of squared error (SSE). The second example uses the sum of absolute error. The key here is ensuring the error function is convex.
Note that c = Beta(1) and m = Beta(2).
Reproducible example (MATLAB code[1]):
% Generate some example data
N = 50;
X = 2 + 13*random(makedist('Beta',.7,.8),N,1);
Y = 5 + 1.5.*X + randn(N,1);
% Example 1
SSEh =#(Beta) sum((Y - (Beta(1) + (Beta(2).*X))).^2);
Beta0 = [0.5 0.5]; % Initial Guess
[Beta SSE] = fminsearch(SSEh,Beta0)
% Example 2
SAEh =#(Beta) sum(abs(Y-(Beta(1) + Beta(2).*X)));
[Beta SumAbsErr] = fminsearch(SAEh,Beta0)
This is a quick & dirty approach that can work for many applications.
#Wolfie's comment directs you to the analytical approach to solve a system of linear equations with the \ operator or mldivide(). This is the more correct approach (though it will get a similar answer). One caveat is this approach gets the SSE answer.
[1] Tested with MATLAB R2018a

Calculate roots of characteristic equation of symbolic matrix

I have 3 data matrices A,B,C (all 3x3), with which I use the following code to calculate roots of D(p)X = 0
syms p
D = A + B*p + C*(p^2)
solP = double(solve(det(D)))
From this, I get 6 values for solP. But when I try substituting it back into the symbolic matrix D, as follows, I get non-zero values of det(D) sometimes
for i = 1:6
p = solP(i)
det(double(subs(D)) % Should be zero always as we are substituting roots
end
Please help me understand this behaviour.
EDIT ::
Example :
A =
1.0e+11 *
4.8976 7.0936 6.7970
4.4559 7.5469 6.5510
6.4631 2.7603 1.6261
B =
1.0e+11 *
3.9223 7.0605 0.4617
6.5548 0.3183 0.9713
1.7119 2.7692 8.2346
C =
1.0e+11 *
6.9483 0.3445 7.6552
3.1710 4.3874 7.9520
9.5022 3.8156 1.8687
solP =
0.1061 + 0.0000i
1.5311 + 0.0000i
-0.3432 + 0.9356i
-0.3432 - 0.9356i
0.4228 - 0.5465i
0.4228 + 0.5465i
det(D) =
2.2143e+19
-5.4911e+20
-8.6415e+19 + 4.5024e+19i
-8.6415e+19 - 4.5024e+19i
-1.4547e+19 + 9.1135e+19i
-1.4547e+19 - 9.1135e+19i
The problem is related to the relative accuracy of floating point values, typically 1e-16.
The input matrices are of the order 1e+11 - 1e+12, the solution is of the order 1e+0, so the elements of D are also of the order 1e+11 - 1e+12. To calculate a determinant of a 3x3 matrix, one should take products of three matrix elements and add/subtract them. So, each term is of the order of 1e+33 - 1e+36. If you subtract such a values to obtain the determinant, the expected accuracy is in the order of 1e+17 - 1e+20. Indeed, this corresponds with the values you get. Given the relative accuracy, you are not able to reach further to zero.
Note that if you scale your input matrices, i.e. divide it by 1e+11, the solutions are indeed the same, but the determinants are probably more what you would expect.

How can a loop involving recursive multiplication and accumulation be vectorized?

In matlab, I have a loop of the form:
a=1;
for (i = 1:N)
a = a * b(i) + c(i);
end
Can this loop be vectorized, or partially unrolled?
For b and c of length 4 each, when the loop is unrolled, you would have -
output = b1b2b3b4 + c1b2b3b4 + c2b3b4 + c3b4 + c4
So, the generic formula would be :
output = b1b2b3...bN + c1b2b3..bN + c2b3..bN + c3b4..bN + ... cN-1bN + cN
The cummulative product of b could be calculated with cumprod with elements being flipped or "reversed". Rest is all about elementwise multiplication with c elements that are 1 place shifted and then including the remaining scalar elements from the cummulative product and c and finally summing all those up to get us the final scalar output.
So, the coded version would look something like this -
cumb = cumprod(b,'reverse');
a = sum(cumb(2:end).*c(1:end-1)) + cumb(1) + c(end);
Benchmarking
Let's compare the loopy approach from the question against the vectorized one as proposed earlier in this post.
Here are the approaches as functions -
function a = loopy(b,c)
N = numel(b);
a = 1;
for i = 1:N
a = a * b(i) + c(i);
end
return;
function a = vectorized(b,c)
cumb = cumprod(b,'reverse');
a = sum(cumb(2:end).*c(1:end-1)) + cumb(1) + c(end);
return;
Here's the code to benchmark those two approaches -
datasizes = 10.^(1:8);
Nd = numel(datasizes);
time_loopy = zeros(1,Nd);
time_vectorized = zeros(1,Nd);
for k1 = 1:numel(datasizes)
N = datasizes(k1);
b = rand(1,N);
c = rand(1,N);
func1 = #() loopy(b,c);
func2 = #() vectorized(b,c);
time_loopy(k1) = timeit(func1);
time_vectorized(k1) = timeit(func2);
end
figure,
loglog(datasizes,time_loopy,'-rx'), hold on
loglog(datasizes,time_vectorized,'-b+'),
set(gca,'xgrid','on'),set(gca,'ygrid','on'),
xlabel('Datasize (# elements)'), ylabel('Runtime (s)')
legend({'Loop','Vectorized'}),title('Runtime Plot')
figure,
semilogx(datasizes,time_loopy./time_vectorized,'-k.')
set(gca,'xgrid','on'),set(gca,'ygrid','on'),
xlabel('Datasize (# elements)'), ylabel('Speedup (x)')
legend({'Speedup with vectorized method over loopy one'}),title('Speedup Plot')
Here's the runtime and speedup plots -
Few observations
Stage #1: From starting datasize until 1000 elements, loopy approach has the upper hand, as the vectorized approach isn't getting enough elements to benefit from everything-in-one-go approach.
Stage #2: From 1000 elements until 1000,0000 elements, vectorized method seems to be the better one, as its getting enough elements to work with.
Stage #3: For the bigger datasize cases, it seems the memory bandwidth requirement of storing and working with millions of elements with vectorized approach as opposed to using just a scalar value with the loopy approach
might be pegging back the vectorized approach.
Conclusions: If performance is the most important criteria, one can go with vectorized method or stay with the original loopy code based on the datasizes.

Matlab Vectorize

I have a probability matrix(glcm) of size 256x256x20. I have reshaped the matrix to
65536x20, so that I can eliminate one loop (along the 3rd dimension).
I want to do the following calculation.
for y = 1:256
for x = 1:256
if (ismember((x + y),(2:2*256)))
p_xplusy((x+y),:) = p_xplusy((x+y),:) + glcm(((y-1)*256+x),:);
end
end
end
So the p_xplusy will be a 511x20 matrix which each element is the sum of the diagonal of nxn sub matrix (where n belongs to 1:256) of the original 256x256x20 matrix.
This code block is making my program inefficient and I want to vectorize this loop. Any help would be appreciated.
Since your if statement is just checking whether x+y is less than or equal to 256, just force it to always be, and remove excess loops:
for y = 1:256
for x = 1:256-y
p_xplusy((x+y),:) = p_xplusy((x+y),:) + glcm(((y-1)*256+x),:);
end
end
This should provide a noticeable speed-up to your code.
You can reduce the complexity from O(n^2) to O(2*n) and thus improve runtime efficiency -
N = 256;
for k1 = 1:N
idx_glcm = k1:N-1:N*(k1-1)+1;
p_xplusy(k1+1,:) = p_xplusy(k1+1,:) + sum(glcm(idx_glcm,:),1);
end
for k1 = 2:N
idx_glcm = k1*N:N-1:N*(N-1)+k1;
p_xplusy(N+k1,:) = p_xplusy(N+k1,:) + sum(glcm(idx_glcm,:),1);
end
Some quick runtime tests seem to confirm our efficiency theory too.

Integration via trapezoidal sums in MATLAB

I need help finding an integral of a function using trapezoidal sums.
The program should take successive trapezoidal sums with n = 1, 2, 3, ...
subintervals until there are two neighouring values of n that differ by less than a given tolerance. I want at least one FOR loop within a WHILE loop and I don't want to use the trapz function. The program takes four inputs:
f: A function handle for a function of x.
a: A real number.
b: A real number larger than a.
tolerance: A real number that is positive and very small
The problem I have is trying to implement the formula for trapezoidal sums which is
Δx/2[y0 + 2y1 + 2y2 + … + 2yn-1 + yn]
Here is my code, and the area I'm stuck in is the "sum" part within the FOR loop. I'm trying to sum up 2y2 + 2y3....2yn-1 since I already accounted for 2y1. I get an answer, but it isn't as accurate as it should be. For example, I get 6.071717974723753 instead of 6.101605982576467.
Thanks for any help!
function t=trapintegral(f,a,b,tol)
format compact; format long;
syms x;
oldtrap = ((b-a)/2)*(f(a)+f(b));
n = 2;
h = (b-a)/n;
newtrap = (h/2)*(f(a)+(2*f(a+h))+f(b));
while (abs(newtrap-oldtrap)>=tol)
oldtrap = newtrap;
for i=[3:n]
dx = (b-a)/n;
trapezoidsum = (dx/2)*(f(x) + (2*sum(f(a+(3:n-1))))+f(b));
newtrap = trapezoidsum;
end
end
t = newtrap;
end
The reason why this code isn't working is because there are two slight errors in your summation for the trapezoidal rule. What I am precisely referring to is this statement:
trapezoidsum = (dx/2)*(f(x) + (2*sum(f(a+(3:n-1))))+f(b));
Recall the equation for the trapezoidal integration rule:
Source: Wikipedia
For the first error, f(x) should be f(a) as you are including the starting point, and shouldn't be left as symbolic. In fact, you should simply get rid of the syms x statement as it is not useful in your script. a corresponds to x1 by consulting the above equation.
The next error is the second term. You actually need to multiply your index values (3:n-1) by dx. Also, this should actually go from (1:n-1) and I'll explain later. The equation above goes from 2 to N, but for our purposes, we are going to go from 1 to N-1 as you have your code set up like that.
Remember, in the trapezoidal rule, you are subdividing the finite interval into n pieces. The ith piece is defined as:
x_i = a + dx*i; ,
where i goes from 1 up to N-1. Note that this starts at 1 and not 3. The reason why is because the first piece is already taken into account by f(a), and we only count up to N-1 as piece N is accounted by f(b). For the equation, this goes from 2 to N and by modifying the code this way, this is precisely what we are doing in the end.
Therefore, your statement actually needs to be:
trapezoidsum = (dx/2)*(f(a) + (2*sum(f(a+dx*(1:n-1))))+f(b));
Try this and let me know if you get the right answer. FWIW, MATLAB already implements trapezoidal integration by doing trapz as #ADonda already pointed out. However, you need to properly structure what your x and y values are before you set this up. In other words, you would need to set up your dx before hand, then calculate your x points using the x_i equation that I specified above, then use these to generate your y values. You then use trapz to calculate the area. In other words:
dx = (b-a) / n;
x = a + dx*(0:n);
y = f(x);
trapezoidsum = trapz(x,y);
You can use the above code as a reference to see if you are implementing the trapezoidal rule correctly. Your implementation and using the above code should generate the same results. All you have to do is change the value of n, then run this code to generate the approximation of the area for different subdivisions underneath your curve.
Edit - August 17th, 2014
I figured out why your code isn't working. Here are the reasons why:
The for loop is unnecessary. Take a look at the for loop iteration. You have a loop going from i = [3:n] yet you don't reference the i variable at all in your loop. As such, you don't need this at all.
You are not computing successive intervals properly. What you need to do is when you compute the trapezoidal sum for the nth subinterval, you then increment this value of n, then compute the trapezoidal rule again. This value is not being incremented properly in your while loop, which is why your area is never improving.
You need to save the previous area inside the while loop, then when you compute the next area, that's when you determine whether or not the difference between the areas is less than the tolerance. We can also get rid of that code at the beginning that tries and compute the area for n = 2. That's not needed, as we can place this inside your while loop. As such, this is what your code should look like:
function t=trapintegral(f,a,b,tol)
format long; %// Got rid of format compact. Useless
%// n starts at 2 - Also removed syms x - Useless statement
n = 2;
newtrap = ((b-a)/2)*(f(a) + f(b)); %// Initialize
oldtrap = 0; %// Initialize to 0
while (abs(newtrap-oldtrap)>=tol)
oldtrap = newtrap; %//Save the old area from the previous iteration
dx = (b-a)/n; %//Compute width
%//Determine sum
trapezoidsum = (dx/2)*(f(a) + (2*sum(f(a+dx*(1:n-1))))+f(b));
newtrap = trapezoidsum; % //This is the new sum
n = n + 1; % //Go to the next value of n
end
t = newtrap;
end
By running your code, this is what I get:
trapezoidsum = trapintegral(#(x) (x+x.^2).^(1/3),1,4,0.00001)
trapezoidsum =
6.111776299189033
Caveat
Look at the way I defined your function. You must use element-by-element operations as the sum command inside the loop will be vectorized. Take a look at the ^ operations specifically. You need to prepend a dot to the operations. Once you do this, I get the right answer.
Edit #2 - August 18th, 2014
You said you want at least one for loop. This is highly inefficient, and whoever specified having one for loop in the code really doesn't know how MATLAB works. Nevertheless, you can use the for loop to accumulate the sum term. As such:
function t=trapintegral(f,a,b,tol)
format long; %// Got rid of format compact. Useless
%// n starts at 3 - Also removed syms x - Useless statement
n = 3;
%// Compute for n = 2 first, then proceed if we don't get a better
%// difference tolerance
newtrap = ((b-a)/2)*(f(a) + f(b)); %// Initialize
oldtrap = 0; %// Initialize to 0
while (abs(newtrap-oldtrap)>=tol)
oldtrap = newtrap; %//Save the old area from the previous iteration
dx = (b-a)/n; %//Compute width
%//Determine sum
%// Initialize
trapezoidsum = (dx/2)*(f(a) + f(b));
%// Accumulate sum terms
%// Note that we multiply each term by (dx/2), but because of the
%// factor of 2 for each of these terms, these cancel and we thus have dx
for n2 = 1 : n-1
trapezoidsum = trapezoidsum + dx*f(a + dx*n2);
end
newtrap = trapezoidsum; % //This is the new sum
n = n + 1; % //Go to the next value of n
end
t = newtrap;
end
Good luck!