Integration via trapezoidal sums in MATLAB

浪尽此生 提交于 2020-02-05 08:23:49

问题


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

回答1:


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:

  1. 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.

  2. 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.

  3. 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!



来源:https://stackoverflow.com/questions/25342462/integration-via-trapezoidal-sums-in-matlab

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!