Сглаживание небольшого набора данных с квадратичной кривой второго порядка - PullRequest
3 голосов
/ 06 апреля 2010

Я делаю какой-то конкретный анализ сигнала, и мне нужен метод, который бы сгладил данную кривую распределения в форме колокола. Метод скользящего среднего не дает желаемых результатов. Я хочу сохранить минимальную / максимальную и общую форму моей подогнанной кривой нетронутой, но устранить несоответствия в выборке.

Вкратце: если бы вы предоставили набор данных, моделирующих простую квадратичную кривую, какой метод статистического сглаживания вы бы порекомендовали?

Если возможно, укажите ссылку на реализацию, библиотеку или фреймворк.

Спасибо, ТАК!

Редактировать : Некоторые полезные данные

(Возможный график сигнала)

альтернативный текст http://i40.tinypic.com/b49942.png

Темный квадратик - это моя «подогнанная» кривая светлых связанных точек данных.

Выборка @ -44 (приблиз.) - это проблема на моем графике (то есть потенциальная несогласованность выборки). Мне нужна эта кривая, чтобы лучше «подогнать» распределение и преодолеть значения, которые не соответствуют тренду. Надеюсь, это поможет!

Ответы [ 4 ]

3 голосов
/ 06 апреля 2010

«Квадратичная» кривая - это одно; «колоколообразный» обычно означает гауссово нормальное распределение. Получить гауссовский метод наилучшей оценки не может быть проще: вы вычисляете среднее значение и дисперсию выборки, и ваше гладкое приближение равно

y = exp(-squared(x-mean)/variance)

Если, с другой стороны, вы хотите аппроксимировать гладкую кривую квадратичным, я бы порекомендовал вычислить квадратичный полином с минимальной квадратной ошибкой. Я не могу вспомнить формулы для этого, но если у вас было дифференциальное исчисление, напишите формулу для общей квадратной ошибки (точечно) и дифференцируйте по коэффициентам вашей квадратичной. Установите первые производные на ноль и решите для наилучшего приближения. Или вы можете посмотреть это.

Наконец, если вы хотите, чтобы гладкая кривая приближалась к набору точек, кубические сплайны - ваша лучшая ставка. Кривые не обязательно что-то значат, но вы получите хорошее плавное приближение.

2 голосов
/ 09 августа 2011
#include <iostream>
#include <math.h>

struct WeightedData 
{
double x;
double y;
double weight;
};

void findQuadraticFactors(WeightedData *data, double &a, double &b, double &c, unsigned int const datasize)
{
double w1 = 0.0;
double wx = 0.0, wx2 = 0.0, wx3 = 0.0, wx4 = 0.0;
double wy = 0.0, wyx = 0.0, wyx2 = 0.0;
double tmpx, tmpy;
double den;

for (unsigned int i = 0; i < datasize; ++i) 
    {
    double x = data[i].x;
    double y = data[i].y;
    double w = data[i].weight;  

    w1 += w;
    tmpx = w * x;
    wx += tmpx;
    tmpx *= x;
    wx2 += tmpx;
    tmpx *= x;
    wx3 += tmpx;
    tmpx *= x;
    wx4 += tmpx;
    tmpy = w * y;
    wy += tmpy;
    tmpy *= x;
    wyx += tmpy;
    tmpy *= x;
    wyx2 += tmpy;
    }

den = wx2 * wx2 * wx2 - 2.0 * wx3 * wx2 * wx + wx4 * wx * wx + wx3 * wx3 * w1 - wx4 * wx2 * w1;
if (den == 0.0) 
    {
    a = 0.0;
    b = 0.0;
    c = 0.0;
    }
else    
    {
    a = (wx * wx * wyx2 - wx2 * w1 * wyx2 - wx2 * wx * wyx + wx3 * w1 * wyx + wx2 * wx2 * wy - wx3 * wx * wy) / den;
    b = (-wx2 * wx * wyx2 + wx3 * w1 * wyx2 + wx2 * wx2 * wyx - wx4 * w1 * wyx - wx3 * wx2 * wy + wx4 * wx * wy) / den;
    c = (wx2 * wx2 * wyx2 - wx3 * wx * wyx2 - wx3 * wx2 * wyx + wx4 * wx * wyx + wx3 * wx3 * wy - wx4 * wx2 * wy) / den;
    }

}

double findY(double const a, double const b, double const c, double const x)
{       
return a * x * x + b * x + c; 
};




int main(int argc, char* argv[])
{
WeightedData data[9];
data[0].weight=1; data[0].x=1; data[0].y=-52.0; 
data[1].weight=1; data[1].x=2; data[1].y=-48.0; 
data[2].weight=1; data[2].x=3; data[2].y=-43.0; 
data[3].weight=1; data[3].x=4; data[3].y=-44.0; 
data[4].weight=1; data[4].x=5; data[4].y=-35.0; 
data[5].weight=1; data[5].x=6; data[5].y=-31.0; 
data[6].weight=1; data[6].x=7; data[6].y=-32.0; 
data[7].weight=1; data[7].x=8; data[7].y=-43.0; 
data[8].weight=1; data[8].x=9; data[8].y=-52.0; 

double a=0.0, b=0.0, c=0.0;
findQuadraticFactors(data, a, b, c, 9);
std::cout << " x \t y" << std::endl;
for (int i=0; i<9; ++i)
    {
    std::cout << " " << data[i].x << ", " << findY(a,b,c,data[i].x) << std::endl;
    }
}
0 голосов
/ 06 апреля 2010

Как насчет простого цифрового фильтра нижних частот ?

y[0] = x[0];
for (i = 1; i < len; ++i)
    y[i] = a * x[i] + (1.0 - a) * y[i - 1];

В этом случае x [] - это ваши входные данные, а y[] - отфильтрованный вывод.Коэффициент a - это значение от 0 до 1, которое вы должны настроить.Значение a , равное 1, воспроизводит вход, а частота среза уменьшается при приближении a к 0.

0 голосов
/ 06 апреля 2010

Возможно, параметры вашего скользящего среднего значения заданы неверно (примерное окно слишком маленькое или большое)?

Это просто шум, накладываемый на вашу кривую звонка? Насколько близка частота шума к сигналу, который вы пытаетесь получить? Изображение того, что вы пытаетесь извлечь, может помочь нам найти решение.

Вы можете попробовать какой-нибудь алгоритм подбора, используя подбор по методу наименьших квадратов , если вы можете разумно угадать параметры функции. Такие методы часто имеют некоторую невосприимчивость к шуму.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...