{"id":2214,"date":"2008-05-09T08:32:01","date_gmt":"2008-05-09T13:32:01","guid":{"rendered":"https:\/\/blogs.mathworks.com\/pick\/2008\/05\/09\/finding-local-extrema\/"},"modified":"2016-05-11T10:02:50","modified_gmt":"2016-05-11T14:02:50","slug":"finding-local-extrema","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/pick\/2008\/05\/09\/finding-local-extrema\/","title":{"rendered":"Finding Local Extrema"},"content":{"rendered":"<div class=\"content\">\r\n\r\nMany times, I've wanted a quick way to find the local minima or maxima in my data. Carlos Adrian Vargas Aguilera's submission <a title=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadFile.do?objectId=12275&amp;objectType=file (link no longer works)\">EXTREMA<\/a> makes it easy to do, and is Brett's selection for the Pick of the Week.\r\n\r\n&nbsp;\r\n<h3>Contents<\/h3>\r\n<div>\r\n<ul>\r\n\t<li><a href=\"#1\">The Problem:<\/a><\/li>\r\n\t<li><a href=\"#2\">Finding local maxima and minima<\/a><\/li>\r\n\t<li><a href=\"#4\">What about smoothing those data?<\/a><\/li>\r\n<\/ul>\r\n<\/div>\r\n<h3>The Problem:<a name=\"1\"><\/a><\/h3>\r\nThis morning, I was asked to help a customer find local peaks (minima and maxima) in a trace from some sort of medical device.\r\nThe particulars of the signal are not really relevant here; what is important is that the signal was large and jagged, with\r\nmany local extrema. This clearly was not something the customer--or I!--wanted to do manually. Moreover, of course, there\r\nmight be more traces on which we would want to repeat the analysis, so any algorithm we developed should be able to be incorporated\r\nin an automation routine. My first thought was to search MATLAB's documentation for extrema detection. I found that the Signal\r\nProcessing Blockset has a Peak Detection Block that finds local minima and maxima, but that solution, of course, requires\r\nSimulink. Being the MATLAB geek that I am, I wanted to do this entirely in m-code. Next, though implementing my own algorithm\r\nwouldn't be too difficult, I thought to search for someone else's implementation of an extrema detector. (No sense reinventing\r\nthe wheel!)\r\n<h3>Finding local maxima and minima<a name=\"2\"><\/a><\/h3>\r\nA quick search turned up Carlos's highly rated, much-downloaded EXTREMA. I happily grabbed his code and took it for a test\r\nspin. Result: problem solved! Consider the following artificial noisy data:\r\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">t= 0:pi\/16:8*pi;\r\ny = sin(t).*rand(size(t));\r\nplot(t,y)<\/pre>\r\n<img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/pick\/extrema_potw_01.png\" alt=\"\" hspace=\"5\" vspace=\"5\" \/>\r\n\r\nNow consider how easy it is to find the extrema with Carlos's EXTREMA function:\r\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">figure\r\nplot(t,y)\r\n[ymax,imax,ymin,imin] = extrema(y);\r\nhold <span style=\"color: #a020f0;\">on<\/span>\r\nplot(t(imax),ymax,<span style=\"color: #a020f0;\">'r*'<\/span>,t(imin),ymin,<span style=\"color: #a020f0;\">'g*'<\/span>)<\/pre>\r\n<img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/pick\/extrema_potw_02.png\" alt=\"\" hspace=\"5\" vspace=\"5\" \/>\r\n<h3>What about smoothing those data?<a name=\"4\"><\/a><\/h3>\r\nBy the way, given a noisy source, it might also be nice to have a way to smooth the data. A quick search for SMOOTH in MATLAB's\r\nhelp browser shows how to do that with the always-useful <a href=\"https:\/\/www.mathworks.com\/products\/curvefitting\/\">Curve Fitting Toolbox<\/a>:\r\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid #c8c8c8;\">y2 = smooth(y,20);\r\nfigure\r\nplot(t,y2)\r\n[ymax2,imax2,ymin2,imin2] = extrema(y2);\r\nhold <span style=\"color: #a020f0;\">on<\/span>\r\nplot(t(imax2),ymax2,<span style=\"color: #a020f0;\">'r*'<\/span>,t(imin2),ymin2,<span style=\"color: #a020f0;\">'g*'<\/span>)\r\nhold <span style=\"color: #a020f0;\">off<\/span><\/pre>\r\n<img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/pick\/extrema_potw_03.png\" alt=\"\" hspace=\"5\" vspace=\"5\" \/>\r\n\r\n(Note that there are lots of options for SMOOTH. I've just implemented a [default] moving average filter, using a 20-point\r\nsliding neighborhood.)\r\n\r\nCarlos also bundled EXTREMA with a second function called EXTREMA2 that extends the functionality to three-dimensional data,\r\nand he provided a nice graphic that shows off the utility of his code. I see that his functions also inspired another submission,\r\ncalled <a title=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadFile.do?objectId=17997&amp;objectType=FILE (link no longer works)\">MinimaMaxima3D<\/a>. Very nice work, Carlos!\r\n\r\n<script>\/\/ <![CDATA[\r\nfunction grabCode_16addf283ceb49e9ac0f0448ab002bd3() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='16addf283ceb49e9ac0f0448ab002bd3 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 16addf283ceb49e9ac0f0448ab002bd3';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Brett Shoelson';\r\n        copyright = 'Copyright 2008 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('\r\n\r\n<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\r\n\r\n\r\n\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }\r\n\/\/ ]]><\/script>\r\n<p style=\"text-align: right; font-size: xx-small; font-weight: lighter; font-style: italic; color: gray;\">\r\n<a><span style=\"font-size: x-small; font-style: italic;\">Get\r\nthe MATLAB code\r\n<noscript>(requires JavaScript)<\/noscript><\/span><\/a>\r\n\r\nPublished with MATLAB\u00ae 7.6<\/p>\r\n\r\n<\/div>\r\n<!--\r\n16addf283ceb49e9ac0f0448ab002bd3 ##### SOURCE BEGIN #####\r\n%%\r\n% Many times, I've wanted a quick way to find the local minima or maxima in my data. <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadAuthor.do?objectId=1093874&objectType=author Carlos Adrian Vargas Aguilera>'s submission\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadFile.do?objectId=12275&objectType=file EXTREMA> makes it easy to do, and is <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadAuthor.do?objectType=author&objectId=1093599 Brett>'s selection for the Pick of the Week.\r\n%% The Problem:\r\n% This morning, I was asked to help a customer find local peaks (minima and\r\n% maxima) in a trace from some sort of medical device. The particulars of\r\n% the signal are not really relevant here; what is important is that the\r\n% signal was large and jagged, with many local extrema. This clearly was\r\n% not something the customerREPLACE_WITH_DASH_DASHor I!REPLACE_WITH_DASH_DASHwanted to do manually.  Moreover, of\r\n% course, there might be more traces on which we would want to repeat the\r\n% analysis, so any algorithm we developed should be able to be incorporated\r\n% in an automation routine. My first thought was to search MATLAB's\r\n% documentation for extrema detection. I found that the Signal Processing\r\n% Blockset has a Peak Detection Block that finds local minima and maxima,\r\n% but that solution, of course, requires Simulink. Being the MATLAB geek\r\n% that I am, I wanted to do this entirely in m-code. Next, though\r\n% implementing my own algorithm wouldn't be too difficult, I thought to\r\n% search for someone else's implementation of an extrema detector. (No\r\n% sense reinventing the wheel!)\r\n\r\n%% Finding local maxima and minima\r\n% A quick search turned up Carlos's highly rated, much-downloaded EXTREMA.\r\n% I happily grabbed his code and took it for a test spin. Result: problem\r\n% solved! Consider the following artificial noisy data:\r\n\r\nt= 0:pi\/16:8*pi;\r\ny = sin(t).*rand(size(t));\r\nplot(t,y)\r\n\r\n%%\r\n% Now consider how easy it is to find the extrema with Carlos's EXTREMA\r\n% function:\r\nfigure\r\nplot(t,y)\r\n[ymax,imax,ymin,imin] = extrema(y);\r\nhold on\r\nplot(t(imax),ymax,'r*',t(imin),ymin,'g*')\r\n\r\n%% What about smoothing those data?\r\n% By the way, given a noisy source, it might also be nice to have a way to\r\n% smooth the data. A quick search for SMOOTH in MATLAB's help browser shows\r\n% how to do that with the always-useful <https:\/\/www.mathworks.com\/products\/curvefitting\/ Curve Fitting Toolbox>:\r\ny2 = smooth(y,20);\r\nfigure\r\nplot(t,y2)\r\n[ymax2,imax2,ymin2,imin2] = extrema(y2);\r\nhold on\r\nplot(t(imax2),ymax2,'r*',t(imin2),ymin2,'g*')\r\nhold off\r\n%%\r\n% (Note that there are lots of options for SMOOTH. I've just implemented a\r\n% [default] moving average filter, using a 20-point sliding neighborhood.)\r\n\r\n%%\r\n% Carlos also bundled EXTREMA with a second function called EXTREMA2 that\r\n% extends the functionality to three-dimensional data, and he provided a\r\n% nice graphic that shows off the utility of his code. I see that his\r\n% functions also inspired another submission, called <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadFile.do?objectId=17997&objectType=FILE MinimaMaxima3D>. Very nice\r\n% work, Carlos!\r\n##### SOURCE END ##### 16addf283ceb49e9ac0f0448ab002bd3\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n\r\nMany times, I've wanted a quick way to find the local minima or maxima in my data. Carlos Adrian Vargas Aguilera's submission EXTREMA makes it easy to do, and is Brett's selection for the Pick of... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/pick\/2008\/05\/09\/finding-local-extrema\/\">read more >><\/a><\/p>","protected":false},"author":34,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/2214"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/users\/34"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/comments?post=2214"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/2214\/revisions"}],"predecessor-version":[{"id":7118,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/2214\/revisions\/7118"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media?parent=2214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/categories?post=2214"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/tags?post=2214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}