MATLAB: Finding inflection points of a noisy signal

inflectionsignal

Hi, I'd like to find the inflection points of this noisy signal. Do you have any suggestions on how to do this?
fs = 100; %Hz
dt = 1 / fs;
t = 0:dt:2;
x = sin(3 * pi * t) - (3 * cos(11 * pi * t));
x_noise = x + (1.5 * rand(size(x)));

Best Answer

Differentiation is a noise amplification process. Why does that matter here? And what do I mean by that claim, anyway?
First, the claim. Computing a derivative goes back to a finite difference, thus deltay/deltax, taken as a limit as deltax goes to zero. If your data is noisy, then the noise in y is divided by a tiny number, thus amplifying the noise.
Another way to look at it if you prefer, you can view estimation of the derivative from data as trying to solve a first kind integral equation, something known to be ill-posed. ill-posed means here that the solution amplifies any noise in the data heavily.
Worse, higher order derivatives are larger amplifiers of noise in the data. So computing the second derivative (in the presence of noise) is a more difficult problem than computing the first derivative.
Why is any of this relevant to the question at hand? Because an inflection point is a point where the second derivative changes sign! So, you want to infer where that second derivative changes sign, therefore you need to estimate that second derivative function in the presence of significant noise.
Don't expect magic to happen here. It won't. That noise will cause all sorts of nasty stuff to happen to you.
x = linspace(0,2*pi,100);
y = sin(x) + randn(size(x))/5;
plot(x,y,'o')
grid on
Yes. We all know the inflection point happens at x == pi. But this noise is pretty nasty. Any kind of local smoothing you do will be overwhelmed by that noise. Even visually, I can conclude the inflection point is somewhere between 2.5 and 3.5, but I'm not sure I would have much more confidence than that.
The simplest trick may be to use some sort of smoothing spline. I'll use my SLM toolbox here.
slm = slmengine(x,y,'knots',10,'reg','cross','plot','on');
A credibly decent curve fit there, given the amount of noise. Less data or more noise might have been problematic though.
Look at the second derivative function. (This is available as a menu choice form the plot from my SLM toolbox .)
So it appears the inflection point happens just a bit beyond x==3. Although we should also find zero crossings near 0 and 2*pi.
We can find those second derivative crossings using slmsolve, another tool from that toolbox.
slmsolve(slm,0,2)
ans =
0.099671 3.0826 6.2232
As expected, there were three of them.
While it might seem pretty decent as an estimate. I'll bet if you tried to compute confidence intervals on that estimate based on tools such as a jackknife or bootstrap, they might be moderately wide. Again, fewer data points or more noise would result in a great deal more uncertainty.
Note that I added some capability to slmsolve just to enable this computation. I've posted a new version on the FEX. You should find it there now.