Suppose a function has some noise. What's the best way to make a chebfun of it?
For example, consider $$ f(x) = \tanh(8(x-{\textstyle{1\over 2}})) + 10^{-6} \times \hbox{noise}. $$ We can manufacture such a function in a convenient deterministic way like this:
ff = @(x) tanh(8*(x-.5)) + 1e-6*sin((1:length(x))'.^2);
If you try to make a chebfun of ff
, there is no convergence:
f = chebfun(ff);
Warning: Function not resolved using 65537 pts. Have you tried 'splitting on'?
However, since we know the scale of the noise, it is easy enough to get the right effect by adjusting the Chebfun eps
parameter:
f = chebfun(ff,'eps',1e-6)
f = chebfun column (1 smooth piece) interval length endpoint values [ -1, 1] 65 -1 1 vertical scale = 1
How did we do? Well, one way to see is to construct a chebfun f2
of twice this degree. Here are the Chebyshev coefficients of that function (black dots) superimposed on the those of f
(blue circles). The match is very satisfactory.
MS = 'markersize'; plotcoeffs(f,'ob',MS,7), ylim([1e-10 10]), hold on f2 = chebfun(ff,'eps',1e-6,'doublelength'); plotcoeffs(f2,'.k',MS,10), hold off
Now, how important was it that we got the amplitude of the noise just right? Let's repeat the experiment, but with eps
increased to $10^{-3}$. As you'd expect, there is a loss of accuracy.
f = chebfun(ff,'eps',1e-3) plotcoeffs(f,'ob',MS,7), ylim([1e-10 10]), hold on plotcoeffs(f2,'.k',MS,10), hold off
f = chebfun column (1 smooth piece) interval length endpoint values [ -1, 1] 32 -1 1 vertical scale = 1
And here we are with eps
tightened to $10^{-9}$:
f = chebfun(ff,'eps',1e-9) plotcoeffs(f,'ob',MS,7), ylim([1e-10 10]), hold on plotcoeffs(f2,'.k',MS,10), hold off
f = chebfun column (1 smooth piece) interval length endpoint values [ -1, 1] 65 -1 1 vertical scale = 1
This shows that the Chebfun constructor (the code standardChop
) is pretty flexible about settling for a bit less accuracy than you hoped for. It's not completely flexible, though, and if we tighten eps
by a further factor of 1000, there is nonconvergence again:
f = chebfun(ff,'eps',1e-12);
Warning: Function not resolved using 65537 pts. Have you tried 'splitting on'?
Just for fun let's illustrate what Chebfun achieves by being not completely flexible. Here is a function that is not random, but again has a plateau in its Chebyshev series down at the level of $10^{-6}$: $$ g(x) = \tanh(8(x-{\textstyle{1\over 2}})) + 10^{-6} \sin(200\exp(x)). $$
gg = @(x) tanh(8*(x-.5)) + 1e-6*sin(200*exp(x)); g = chebfun(gg); plotcoeffs(g,'ob',MS,4), ylim([1e-18 1e2])
If we construct a chebfun with eps
equal to $10^{-6}$, the plateau is treated as noise and chopped off:
g = chebfun(gg,'eps',1e-6); plotcoeffs(g,'ob',MS,4), ylim([1e-18 1e2])
With eps
equal to $10^{-9}$, the plateau is still treated as noise:
g = chebfun(gg,'eps',1e-9); plotcoeffs(g,'ob',MS,4), ylim([1e-18 1e2])
With eps
set to $10^{-12}$, however, Chebfun is unsatisfied with the series of length 70, looks further, and correctly captures the low-amplitude component.
g = chebfun(gg,'eps',1e-12); plotcoeffs(g,'ob',MS,4), ylim([1e-18 1e2])
Reference:
J. L. Aurentz and L. N. Trefethen, "Chopping a Chebyshev series", http://arxiv.org/abs/1512.01803, December 2015.