1 | function [Q,err] = quadgr(fun,a,b,tol) |
---|
2 | %QUADGR Gauss-Legendre quadrature with Richardson extrapolation. |
---|
3 | % [Q,ERR] = QUADGR(FUN,A,B,TOL) approximates the integral of a function |
---|
4 | % FUN from A to B with an absolute error tolerance TOL. FUN is a function |
---|
5 | % handle and must accept vector arguments. TOL is 1e-6 by default. Q is |
---|
6 | % the integral approximation and ERR is an estimate of the absolute error. |
---|
7 | % |
---|
8 | % QUADGR uses a 12-point Gauss-Legendre quadrature. The error estimate is |
---|
9 | % based on successive interval bisection. Richardson extrapolation |
---|
10 | % accelerates the convergence for some integrals, especially integrals |
---|
11 | % with endpoint singularities. |
---|
12 | % |
---|
13 | % Examples: |
---|
14 | % Q = quadgr(@(x) log(x),0,1) |
---|
15 | % [Q,err] = quadgr(@(x) exp(x),0,9999i*pi) |
---|
16 | % [Q,err] = quadgr(@(x) sqrt(4-x.^2),0,2,1e-12) |
---|
17 | % [Q,err] = quadgr(@(x) x.^-0.75,0,1) |
---|
18 | % [Q,err] = quadgr(@(x) 1./sqrt(1-x.^2),-1,1) |
---|
19 | % [Q,err] = quadgr(@(x) exp(-x.^2),-inf,inf,1e-9) % sqrt(pi) |
---|
20 | % [Q,err] = quadgr(@(x) cos(x).*exp(-x),0,inf,1e-9) |
---|
21 | % |
---|
22 | % See also QUAD, QUADGK |
---|
23 | |
---|
24 | % Author: jonas.lundgren@saabgroup.com, 2009. |
---|
25 | |
---|
26 | if nargin < 3, help quadgr, return, end |
---|
27 | if nargin < 4, tol = 1e-6; end |
---|
28 | |
---|
29 | % Order limits (required if infinite limits) |
---|
30 | if a == b |
---|
31 | Q = b - a; |
---|
32 | err = b - a; |
---|
33 | return |
---|
34 | elseif a > b |
---|
35 | reverse = true; |
---|
36 | atmp = a; |
---|
37 | a = b; |
---|
38 | b = atmp; |
---|
39 | else |
---|
40 | reverse = false; |
---|
41 | end |
---|
42 | |
---|
43 | % Infinite limits |
---|
44 | if isinf(a) || isinf(b) |
---|
45 | % Check real limits |
---|
46 | if ~isreal(a) || ~isreal(b) || isnan(a) || isnan(b) |
---|
47 | error('quadgr:inflim','Infinite intervals must be real.') |
---|
48 | end |
---|
49 | % Change of variable |
---|
50 | if isfinite(a) && isinf(b) |
---|
51 | % a to inf |
---|
52 | fun1 = @(t) fun(a + t./(1-t))./(1-t).^2; |
---|
53 | [Q,err] = quadgr(fun1,0,1,tol); |
---|
54 | elseif isinf(a) && isfinite(b) |
---|
55 | % -inf to b |
---|
56 | fun2 = @(t) fun(b + t./(1+t))./(1+t).^2; |
---|
57 | [Q,err] = quadgr(fun2,-1,0,tol); |
---|
58 | else % -inf to inf |
---|
59 | fun1 = @(t) fun(t./(1-t))./(1-t).^2; |
---|
60 | fun2 = @(t) fun(t./(1+t))./(1+t).^2; |
---|
61 | [Q1,err1] = quadgr(fun1,0,1,tol/2); |
---|
62 | [Q2,err2] = quadgr(fun2,-1,0,tol/2); |
---|
63 | Q = Q1 + Q2; |
---|
64 | err = err1 + err2; |
---|
65 | end |
---|
66 | % Reverse direction |
---|
67 | if reverse |
---|
68 | Q = -Q; |
---|
69 | end |
---|
70 | return |
---|
71 | end |
---|
72 | |
---|
73 | % Gauss-Legendre quadrature (12-point) |
---|
74 | xq = [0.12523340851146894; 0.36783149899818018; 0.58731795428661748; ... |
---|
75 | 0.76990267419430469; 0.9041172563704748; 0.98156063424671924]; |
---|
76 | wq = [0.24914704581340288, 0.23349253653835478, 0.20316742672306584, ... |
---|
77 | 0.16007832854334636, 0.10693932599531818, 0.047175336386511842]; |
---|
78 | xq = [xq; -xq]; |
---|
79 | wq = [wq, wq]; |
---|
80 | nq = length(xq); |
---|
81 | |
---|
82 | % Initiate vectors |
---|
83 | maxit = 17; % Max number of iterations |
---|
84 | Q0 = zeros(maxit,1); % Quadrature |
---|
85 | Q1 = zeros(maxit,1); % First Richardson extrapolation |
---|
86 | Q2 = zeros(maxit,1); % Second Richardson extrapolation |
---|
87 | |
---|
88 | % One interval |
---|
89 | hh = (b - a)/2; % Half interval length |
---|
90 | x = (a + b)/2 + hh*xq; % Nodes |
---|
91 | % Quadrature |
---|
92 | Q0(1) = hh*wq*fun(x); |
---|
93 | |
---|
94 | % Successive bisection of intervals |
---|
95 | for k = 2:maxit |
---|
96 | |
---|
97 | % Interval bisection |
---|
98 | hh = hh/2; |
---|
99 | x = [x + a; x + b]/2; |
---|
100 | % Quadrature |
---|
101 | Q0(k) = hh*wq*sum(reshape(fun(x),nq,[]),2); |
---|
102 | |
---|
103 | % Richardson extrapolation |
---|
104 | if k >= 5 |
---|
105 | Q1(k) = richardson(Q0,k); |
---|
106 | Q2(k) = richardson(Q1,k); |
---|
107 | elseif k >= 3 |
---|
108 | Q1(k) = richardson(Q0,k); |
---|
109 | end |
---|
110 | |
---|
111 | % Estimate absolute error |
---|
112 | if k >= 6 |
---|
113 | Qv = [Q0(k), Q1(k), Q2(k)]; |
---|
114 | Qw = [Q0(k-1), Q1(k-1), Q2(k-1)]; |
---|
115 | elseif k >= 4 |
---|
116 | Qv = [Q0(k), Q1(k)]; |
---|
117 | Qw = [Q0(k-1), Q1(k-1)]; |
---|
118 | else |
---|
119 | Qv = Q0(k); |
---|
120 | Qw = Q0(k-1); |
---|
121 | end |
---|
122 | [err,j] = min(abs(Qv - Qw)); |
---|
123 | Q = Qv(j); |
---|
124 | |
---|
125 | % Convergence |
---|
126 | if err < tol || ~isfinite(Q) |
---|
127 | break; |
---|
128 | end |
---|
129 | |
---|
130 | end |
---|
131 | |
---|
132 | % Convergence check |
---|
133 | if ~isfinite(Q) |
---|
134 | warning('quadgr:infnan','Integral approximation is Infinite or NaN.') |
---|
135 | elseif err > tol |
---|
136 | warning('quadgr:maxiter','Max number of iterations reached without convergence.') |
---|
137 | end |
---|
138 | |
---|
139 | % The error estimate should not be zero |
---|
140 | err = err + 2*eps(Q); |
---|
141 | % Reverse direction |
---|
142 | if reverse |
---|
143 | Q = -Q; |
---|
144 | end |
---|
145 | |
---|
146 | % disp([Q0 Q1 Q2]) |
---|
147 | |
---|
148 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
149 | function R = richardson(Q,k) |
---|
150 | % Richardson extrapolation with parameter estimation |
---|
151 | c = real((Q(k-1)-Q(k-2))/(Q(k)-Q(k-1))) - 1; |
---|
152 | % The lower bound 0.07 admits the singularity x.^-0.9 |
---|
153 | c = max(c,0.07); |
---|
154 | R = Q(k) + (Q(k) - Q(k-1))/c; |
---|