Згладжуючий фільтр Savitzky-Golay для не однаково розташованих даних


16

У мене є сигнал, який вимірюється 100 ГГц, і мені потрібно застосувати фільтр згладжування Савіцького-Голая до цього сигналу. Однак при більш детальному огляді мій сигнал не вимірюється з абсолютно постійною швидкістю, дельта між вимірюваннями становить від 9,7 до 10,3 мс.

Чи є спосіб використовувати фільтр Савіцького-Голая для не однаково розташованих даних? Чи існують інші методи, які я можу застосувати?


Документ Горрі 1991 року майже на цій точній темі datapdf.com/… . Але tldr, відповідь datageist - це правильна головна ідея (локальні найменші квадрати). Що зауважує Горрі, це те, що коефіцієнти залежать лише від незалежних змінних і є лінійними в залежних змінних (наприклад, Савіцкі-Голай). Тоді він дає можливість їх обчислити, але якщо ви не пишете оптимізовану бібліотеку, можна використати будь-який старий монтажник з мінімальними квадратами.
Дейв Притчард

Відповіді:


5

Одним із методів було б переупорядкувати свої дані, щоб вони були однаково розташовані, тоді ви можете робити будь-яку обробку, яка вам подобається. Діапазонне перекомплектування з використанням лінійної фільтрації не буде найкращим варіантом, оскільки дані не є рівномірно розташованими, тому ви можете використовувати якусь локальну поліноміальну інтерполяцію (наприклад, кубічні сплайни), щоб оцінити, які значення базового сигналу є "точними". 10-мілісекундні інтервали.


Це рішення я мав на увазі в крайньому випадку. Мені цікаво, чи врешті-решт такий підхід дає краще рішення, ніж просто припускати, що мій сигнал вимірюється постійною швидкістю.
VLC

Я думаю, навіть якщо це нерівномірно відібрана проба, ви все ще можете використовувати інтерполяцію sinc () (або різний високопробований фільтр низьких частот). Це може дати кращі результати , ніж сплайн або pchip
Hilmar

1
@Hilmar: Ти маєш рацію. Існує ряд способів переупорядкувати дані; Орієнтовна синполяційна інтерполяція була б "ідеальним" методом для смугового переутворення.
Джейсон R

15

Через те, як виходить фільтр Савіцького-Голая (тобто, як локальний мінімум квадратів прилягає), існує природне узагальнення для неоднорідного відбору проб - це просто набагато дорожче обчислювально.

Фільтри Савіцького-Голая взагалі

Для стандартного фільтра ідея полягає в тому, щоб поліном підходити до локального набору зразків [з використанням найменших квадратів], а потім замінювати центральний зразок значенням полінома на центральний показник (тобто на 0). Це означає, що стандартні коефіцієнти фільтру SG можуть бути створені шляхом інвертування матриці Вандермондта зразкових показників. Наприклад, для створення локального параболічного пристосування через п’ять зразків (з локальними показниками -2, -1,0,1,2) система проектних рівнянь A c = y була б такою:у0у4Аc=у

[-20-21-22-10-11-12000102101112202122][c0c1c2]=[у0у1у2у3у4].

c0c2c0+c1х+c2х2х=0c0c=(АТА)-1АТу 

[c0c1c2]=[-3121712-3-7-40475-3-5-35][у0у1у2у3у4].

c0+c1х+c2х2c1+2c2хc1

Неоднорідний відбір проб

хнтн0

т-2=х-2-х0т-1=х-1-х0т0=х0-х0т1=х1-х0т2=х2-х0

то кожна матриця проектування буде мати таку форму:

А=[т-20т-21т-22т-10т-11т-12т00т01т02т10т11т12т20т21т22]=[1т-2т-221т-1т-121001т1т121т2т22].

А c0


звучить так, як він рухається від O (log (n)) до O (n ^ 2).
EngrStudent

Ось реалізація Scala, описана datageist вгору.
Середнє ядро

1
@Mediumcore Ви не додали посилання на своє початкове повідомлення. Також я видалив його, оскільки він не дав відповіді на запитання. Будь ласка, спробуйте відредагувати публікацію datageist, щоб додати посилання; він буде модерований після огляду.
Петро К.

4


fNN/2
-

(виведення когось?)


±N/2тт
тii


1

Я з'ясував, що в Matlab існує два способи використання алгоритму savitzky-golay. Один раз як фільтр і раз як функція згладжування, але в основному вони повинні робити те саме.

  1. yy = sgolayfilt (y, k, f): Тут вважаються, що значення y = y (x) однаково розташовані в x.
  2. yy = гладкий (x, y, span, 'sgolay', градус): Тут ви можете мати x як додатковий вхід, а звернення до довідки Matlab 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;
}

згладжування

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.