Friday, July 17, 2020

การหา local maxima และ minima อย่างรวดเร็ว

สมมติว่าเรามีสัญญาณหนึ่ง แล้วเราต้องการหาว่าจุดยอดอยู่ที่ไหน คำสั่งใน MATLAB ที่ใช้เป็นปกติคือ findpeaks แต่ถ้าใครเคยใช้คำสั่งนี้ใน loop จะเห็นว่ามันช้ามาก ดังนั้นสำหรับฟังชั่นที่ไม่มีสัญญาณรบกวน มันมีวิธีอื่นที่ง่ายและเร็วกว่า วันนี้จะมาแสดงวิธีให้ดู

ก่อนอื่น สมมติเรามี sinc function signal ละกัน

x = linspace(-10,10,501);
y = sinc(x);
เราสามารถหาความชันของสัญญาณด้วยคำสั่ง diff

A = diff(y);
เมื่อเทียบกันสัญญาณรูปบน จะเห็นว่าจุดสูงสุดของสัญญาณคือจุดที่ค่าควาามชันเปลี่ยนจาก + เป็น - และจุดต่ำสุดของสัญญาณคือจุดที่ความชันเปลี่ยนจาก - เป็น + เพราะว่าเราสนใจแค่เครื่องหมาย เราจึงเปลี่ยนค่าความชันเป็นเครื่อง + หรือ - ด้วยคำสั่ง sign

A = sign(A)
หลังจากนั้นเราจะหาตำแหน่งที่สัญญาณเปลี่ยนเครื่องหมายจาก + เป็น -  และ - เป็น + ด้วยคำสั่ง conv


A = conv(A,[-1,1]);
ทีนี้เราก็จะหาจุดสูงสุดได้เมื่อ A = 2 และ จุดต่ำสุดที่ A = -2

maximas = find(A == 2);
minimas = find(A == -2);

เพื่อความกระชับ เราสามารถเขียนโค้ดทั้งหมดได้ในบรรทัดเดียวดังนี้

maximas = find(conv(sign(diff(y)),[-1,1]) == 2);
minimas = find(conv(sign(diff(y)),[-1,1]) == -2);

เพื่อยืนยันว่ามันใช้ได้เดี๋ยวจะขอพล๊อตกราฟให้ดู ดังนี้

x = linspace(-10,10,501);
y = sinc(x);
ymax = NaN(length(y));
ymin = ymax;
maximas = find(conv(sign(diff(y)),[-1,1]) == 2);
minimas = find(conv(sign(diff(y)),[-1,1]) == -2);
ymax(maximas) = y(maximas);
ymin(minimas) = y(minimas);
plot(x,y,'-b','LineWidth',2);hold on;
plot(x,ymax,'*r','LineWidth',2);
plot(x,ymin,'or','LineWidth',2);
set(gca,'FontSize',16);
hold off;

No comments:

Post a Comment