ตัวกรองที่ปรับให้เรียบของ Savitzky-Golay มีระยะห่างไม่เท่ากัน


16

ฉันมีสัญญาณที่วัดได้ที่ 100Hz และฉันจำเป็นต้องใช้ตัวกรองการปรับให้เรียบของ Savitzky-Golay กับสัญญาณนี้ อย่างไรก็ตามในการตรวจสอบอย่างใกล้ชิดสัญญาณของฉันไม่ได้ถูกวัดที่อัตราคงที่ที่สมบูรณ์แบบเดลต้าระหว่างการวัดอยู่ระหว่าง 9.7 ถึง 10.3 มิลลิวินาที

มีวิธีใช้ตัวกรอง Savitzky-Golay กับข้อมูลที่มีระยะห่างไม่เท่ากันหรือไม่? มีวิธีอื่นที่ฉันสามารถสมัครได้หรือไม่?


1991 กระดาษโดย Gorry อยู่บนสวยมากเรื่องนี้แน่นอนdatapdf.com/... แต่ tldr คำตอบของนักดาต้าลิสต์เป็นแนวคิดหลักที่ถูกต้อง (local-squares น้อยที่สุด) สิ่งที่ Gorry สังเกตคือสัมประสิทธิ์ขึ้นอยู่กับตัวแปรอิสระเท่านั้นและเป็นเส้นตรงในตัวแปรตาม (เช่น Savitzky-Golay) จากนั้นเขาก็ให้วิธีการคำนวณพวกเขา แต่ถ้าคุณไม่ได้เขียนไลบรารีที่ปรับให้เหมาะสมที่สุด
Dave Pritchard

คำตอบ:


5

วิธีหนึ่งคือการสุ่มข้อมูลของคุณใหม่เพื่อให้มีระยะห่างเท่ากันจากนั้นคุณสามารถทำสิ่งที่คุณต้องการได้ การ จำกัด การสุ่มใหม่โดยใช้การกรองเชิงเส้นจะไม่เป็นตัวเลือกที่ดีเนื่องจากข้อมูลไม่ได้เว้นระยะอย่างสม่ำเสมอดังนั้นคุณสามารถใช้การแก้ไขพหุนามแบบท้องถิ่น (เช่นลูกบาศก์ Splines) เพื่อประเมินว่าค่าสัญญาณพื้นฐานอยู่ที่ "แน่นอน" ช่วงเวลา 10 มิลลิวินาที


ฉันมีวิธีแก้ปัญหานี้ในใจเป็นทางเลือกสุดท้าย ฉันสงสัยว่าในที่สุดวิธีการนี้จะให้ทางออกที่ดีกว่าเพียงแค่สมมติว่าสัญญาณของฉันถูกวัดด้วยอัตราคงที่
VLC

ฉันคิดว่าแม้ว่ามันจะเป็นตัวอย่างที่ไม่สม่ำเสมอคุณยังคงสามารถใช้การแก้ไขแบบ sinc () (หรือตัวกรองความถี่ต่ำที่แตกต่างกันตัวอย่างสูง) สิ่งนี้อาจให้ผลลัพธ์ที่ดีกว่าเส้นโค้งหรือ pchip
Hilmar

1
@Hilmar: ถูกต้อง มีหลายวิธีที่คุณสามารถทำการสุ่มตัวอย่างข้อมูลใหม่ได้ การประมาณค่า sinc โดยประมาณจะเป็นวิธี "อุดมคติ" สำหรับการเปลี่ยนรูปแบบ bandlimited อีกครั้ง
Jason R

15

เนื่องจากวิธีการที่ได้มาจากตัวกรอง Savitzky-Golay (เช่นเป็นพหุนามแบบสี่เหลี่ยมจัตุรัสที่น้อยที่สุดในท้องถิ่น) จึงมีลักษณะทั่วไปตามธรรมชาติในการสุ่มตัวอย่างแบบไม่เป็นรูปแบบ - มันมีราคาแพงกว่าการคำนวณ

ตัวกรอง Savitzky-Golay โดยทั่วไป

สำหรับตัวกรองมาตรฐานความคิดคือให้พอดีกับพหุนามกับกลุ่มตัวอย่างท้องถิ่น [ใช้กำลังสองน้อยที่สุด] จากนั้นแทนที่ตัวอย่างกึ่งกลางด้วยค่าของพหุนามที่ดัชนีกลาง (เช่นที่ 0) นั่นหมายถึงค่าสัมประสิทธิ์ตัวกรอง SG มาตรฐานสามารถสร้างได้โดยการแปลงเมทริกซ์ Vandermondeของตัวบ่งชี้ตัวอย่าง ตัวอย่างเช่นหากต้องการสร้างพาราโบลาให้พอดีกับตัวอย่างห้าตัวอย่าง (ด้วยการบ่งชี้ในพื้นที่ -2, -1,0,1,2) ระบบของสมการการออกแบบA c = yจะเป็นดังนี้:Y0...Y4A=Y

[-20-21-22-10-11-12000102101112202122][012]=[Y0Y1Y2Y3Y4].

ในข้างต้นมีค่าสัมประสิทธิ์ที่ไม่รู้จักของสี่เหลี่ยมน้อยพหุนาม0 + 1 x + 2 x 2 เนื่องจากค่าของพหุนามที่x = 0เป็นแค่c 0 การคำนวณpseudoinverseของเมทริกซ์การออกแบบ (เช่นc = ( A T A ) - 1 A T y ) จะให้ค่าสัมประสิทธิ์ตัวกรอง SG ในแถวบนสุด ในกรณีนี้พวกเขาจะเป็น0...20+1x+2x2x=00=(ATA)-1ATY 

[012]=[-3121712-3-7-40475-3-5-35][Y0Y1Y2Y3Y4].

โปรดทราบว่าเนื่องจากอนุพันธ์ของคือc 1 + 2 c 2 xแถวที่สองของเมทริกซ์ (ซึ่งประเมินc 1 ) จะเป็นตัวกรองอนุพันธ์ที่ทำให้เรียบ อาร์กิวเมนต์เดียวกันนี้ใช้กับแถวที่ต่อเนื่องกัน - มันให้อนุพันธ์ที่มีลำดับสูงกว่าอย่างราบรื่น โปรดทราบว่าฉันปรับอัตราส่วนเมทริกซ์ที่ 35 ดังนั้นแถวแรกจะตรงกับค่าสัมประสิทธิ์การปรับให้เรียบใน Wikipedia (ด้านบน) ตัวกรองอนุพันธ์แตกต่างกันไปตามปัจจัยการปรับอื่น ๆ0+1x+2x21+22x1

การสุ่มตัวอย่างแบบ nonuniform

xnเสื้อn0

เสื้อ-2=x-2-x0เสื้อ-1=x-1-x0เสื้อ0=x0-x0เสื้อ1=x1-x0เสื้อ2=x2-x0

ดังนั้นแต่ละเมทริกซ์การออกแบบจะอยู่ในรูปแบบต่อไปนี้:

A=[เสื้อ-20เสื้อ-21เสื้อ-22เสื้อ-10เสื้อ-11เสื้อ-12เสื้อ00เสื้อ01เสื้อ02เสื้อ10เสื้อ11เสื้อ12เสื้อ20เสื้อ21เสื้อ22]=[1เสื้อ-2เสื้อ-221เสื้อ-1เสื้อ-121001เสื้อ1เสื้อ121เสื้อ2เสื้อ22].

A 0


ดูเหมือนว่าจะเปลี่ยนจาก O (log (n)) เป็น O (n ^ 2)
EngrStudent - Reinstate Monica

นี่คือการใช้ Scala ที่อธิบายโดยนักดาต้าลิสต์ขึ้นไป
แกนกลาง

1
@Mediumcore คุณไม่ได้เพิ่มลิงก์ไปยังโพสต์ดั้งเดิมของคุณ นอกจากนี้ฉันลบมันเพราะไม่ได้ให้คำตอบกับคำถาม โปรดลองแก้ไขโพสต์ของนักข้อมูลเพื่อเพิ่มลิงค์ มันจะถูกตรวจสอบหลังจากตรวจสอบแล้ว
ปีเตอร์เค

4


ยังไม่มีข้อความยังไม่มีข้อความ/2
-

(มาทุกคนหรือไม่)


±ยังไม่มีข้อความ/2เสื้อเสื้อ
เสื้อผมผม


1

ฉันพบว่ามีสองวิธีในการใช้อัลกอริทึม savitzky-golay ใน Matlab เมื่อเป็นตัวกรองและฟังก์ชั่นปรับให้เรียบ แต่โดยทั่วไปแล้วพวกเขาควรทำเช่นเดียวกัน

  1. yy = sgolayfilt (y, k, f): ที่นี่ค่า y = y (x) จะถือว่ามีระยะห่างเท่ากันใน x
  2. yy = smooth (x, y, span, 'sgolay', degree): ที่นี่คุณสามารถมี x เป็นอินพุตพิเศษและอ้างอิงถึง Matlab help x ไม่จำเป็นต้องเว้นระยะเท่ากัน!

0

หากเป็นความช่วยเหลือใด ๆ ฉันได้ใช้งาน C ของวิธีการที่อธิบายโดย datageist ฟรีที่จะใช้ความเสี่ยงของคุณเอง

/**
 * @brief smooth_nonuniform
 * Implements the method described in  /signals/1676/savitzky-golay-smoothing-filter-for-not-equally-spaced-data
 * free to use at the user's risk
 * @param n the half size of the smoothing sample, e.g. n=2 for smoothing over 5 points
 * @param the degree of the local polynomial fit, e.g. deg=2 for a parabolic fit
 */
bool smooth_nonuniform(uint deg, uint n, std::vector<double>const &x, std::vector<double> const &y, std::vector<double>&ysm)
{
    if(x.size()!=y.size()) return false; // don't even try
    if(x.size()<=2*n)      return false; // not enough data to start the smoothing process
//    if(2*n+1<=deg+1)       return false; // need at least deg+1 points to make the polynomial

    int m = 2*n+1; // the size of the filter window
    int o = deg+1; // the smoothing order

    std::vector<double> A(m*o);         memset(A.data(),   0, m*o*sizeof(double));
    std::vector<double> tA(m*o);        memset(tA.data(),  0, m*o*sizeof(double));
    std::vector<double> tAA(o*o);       memset(tAA.data(), 0, o*o*sizeof(double));

    std::vector<double> t(m);           memset(t.data(),   0, m*  sizeof(double));
    std::vector<double> c(o);           memset(c.data(),   0, o*  sizeof(double));

    // do not smooth start and end data
    int sz = y.size();
    ysm.resize(sz);           memset(ysm.data(), 0,sz*sizeof(double));
    for(uint i=0; i<n; i++)
    {
        ysm[i]=y[i];
        ysm[sz-i-1] = y[sz-i-1];
    }

    // start smoothing
    for(uint i=n; i<x.size()-n; i++)
    {
        // make A and tA
        for(int j=0; j<m; j++)
        {
            t[j] = x[i+j-n] - x[i];
        }
        for(int j=0; j<m; j++)
        {
            double r = 1.0;
            for(int k=0; k<o; k++)
            {
                A[j*o+k] = r;
                tA[k*m+j] = r;
                r *= t[j];
            }
        }

        // make tA.A
        matMult(tA.data(), A.data(), tAA.data(), o, m, o);

        // make (tA.A)-¹ in place
        if (o==3)
        {
            if(!invert33(tAA.data())) return false;
        }
        else if(o==4)
        {
            if(!invert44(tAA.data())) return false;
        }
        else
        {
            if(!inverseMatrixLapack(o, tAA.data())) return false;
        }

        // make (tA.A)-¹.tA
        matMult(tAA.data(), tA.data(), A.data(), o, o, m); // re-uses memory allocated for matrix A

        // compute the polynomial's value at the center of the sample
        ysm[i] = 0.0;
        for(int j=0; j<m; j++)
        {
            ysm[i] += A[j]*y[i+j-n];
        }
    }

    std::cout << "      x       y       y_smoothed" << std::endl;
    for(uint i=0; i<x.size(); i++) std::cout << "   " << x[i] << "   " << y[i]  << "   "<< ysm[i] << std::endl;

    return true;
}

การขจัดอุปสรรค

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.