Аппроксимация квадратичной функцией

    • #76550
      Николай
      Ключник

      vix

      21 июл 2021, 10:54
      Добрый день, коллеги!
      Имеется некий датчик (ладно, не некий, а вполне конкретный), чья передаточная характеристика хорошо укладывается в функцию второго порядка, типа y = ax? + bx + c.
      В результате калибровки получаем несколько десятков пар значений x и y, по которым нужно найти приближеные коэффициенты a, b и c.
      Сейчас, на этапе отладки, решаю это в вольфраме (пример). Но в серии надо будет уметь считать это самому.
      Я в математике на уровне чайника, поэтому прошу помочь с алгоритмом или, возможно, с его реализацией.
      Заранне благодарен и с уважением, Виктор.

       

      tonyk

      21 июл 2021, 11:05
      Тут всё на пальцах описано и готовые примеры реализаций. Пользуйся!
      drive.google.com/file/d/1RezGyJFUR9PaWUeBkWXVvjS2fZ0BwN37/view?usp=sharing

       

      vix

      21 июл 2021, 14:21

      tonyk, спасибо за книжку, сохранил.
      Нашёл несколько готовых решений. Одно из них переделал на С, выкладываю на всяк. случай, может кому пригодится:

      Готовое решение
      #include &lt,stdio.h&gt,
      #include &lt,stdlib.h&gt,
      #include &lt,math.h&gt,
      /*
      // bragitoff.com/2015/09/c-program-for-polynomial-fit-least-squares/
      работает ок
      */
      void polinominal_fit
      // input
      double *x,
      double *y,
      int N,
      // output
      double *coeffs,
      int n
      {
      double X2*n+1, //Array that will store the values of sigmaxi,sigmaxi^2,sigmaxi^3….sigmaxi^2n
      for int i=0,i&lt,2*n+1,i++
      {
      Xi=0,
      for int j=0,j&lt,N,j++
      {
      Xi=Xi+powxj,i, //consecutive positions of the array will store N,sigmaxi,sigmaxi^2,sigmaxi^3….sigmaxi^2n
      }
      }
      double Bn+1n+2, //B is the Normal matrixaugmented that will store the equations, a is for value of the final coefficients
      double *a = coeffs,
      for int i=0,i&lt,=n,i++
      {
      for int j=0,j&lt,=n,j++
      {
      Bij=Xi+j, //Build the Normal matrix by storing the corresponding coefficients at the right positions except the last column of the matrix
      }
      }
      double Yn+1, //Array to store the values of sigmayi,sigmaxi*yi,sigmaxi^2*yi…sigmaxi^n*yi
      for int i=0,i&lt,n+1,i++
      {
      Yi=0,
      for int j=0,j&lt,N,j++
      {
      Yi=Yi+powxj,i*yj, //consecutive positions will store sigmayi,sigmaxi*yi,sigmaxi^2*yi…sigmaxi^n*yi
      }
      }
      for int i=0,i&lt,=n,i++
      {
      Bin+1=Yi, //load the values of Y as the last column of BNormal Matrix but augmented
      }
      n=n+1, //n is made n+1 because the Gaussian Elimination part below was for n equations, but here n is the degree of polynomial and for n degree we get n+1 equations
      for int i=0,i&lt,n,i++ //From now Gaussian Elimination startscan be ignored to solve the set of linear equations Pivotisation
      {
      for int k=i+1,k&lt,n,k++
      {
      if Bii&lt,Bki
      {
      for int j=0,j&lt,=n,j++
      {
      double temp=Bij,
      Bij=Bkj,
      Bkj=temp,
      }
      }
      }
      }
      for int i=0,i&lt,n-1,i++ //loop to perform the gauss elimination
      {
      for int k=i+1,k&lt,n,k++
      {
      double t=Bki/Bii,
      for int j=0,j&lt,=n,j++
      {
      Bkj=Bkj-t*Bij, //make the elements below the pivot elements equal to zero or elimnate the variables
      }
      }
      }
      for int i=n-1,i&gt,=0,i– //back-substitution
      { //x is an array whose values correspond to the values of x,y,z..
      ai=Bin, //make the variable to be calculated equal to the rhs of the last equation
      for int j=0,j&lt,n,j++
      {
      if j!=i //then subtract all the lhs values except the coefficient of the variable whose value is being calculated
      {
      ai=ai-Bij*aj,
      }
      }
      ai=ai/Bii, //now finally divide the rhs by the coefficient of the variable to be calculated
      }
      }
      int main
      {
      double coeffs3,
      double x =
      {
      8764, 8681, 8578, 8403, 8238, 8058, 7921, 7779, 7587, 7481,
      7232, 7001, 6924, 6694, 6544, 6364, 6224, 6115, 5625, 5489,
      5405, 5156, 5090, 4910, 4775, 4624, 4511
      },
      double y =
      {
      138.4299037967, 137.3283395755, 135.4923992069, 132.554894617, 129.9845781009, 127.4142615848,
      125.2111331424, 123.7423808475, 120.0705001102, 118.6017478152, 114.9298670779, 111.6251744143,
      110.1564221194, 106.8517294558, 104.2814129397, 101.7110964236, 99.1407799075, 97.6720276125,
      89.5938899905, 87.7579496218, 87.0235734743, 82.6173165896, 81.5157523684, 78.9454358522,
      76.7423074099, 74.1719908937, 72.3360505251
      },
      polinominal_fitx, y, 27, coeffs, 2,
      return 0,
      }

      Проблема решена.

       

       

    • #88399
      Николай
      Ключник

      Делал библиотечку для наименьших квадратов. Метод более устойчивый и точный чем через нормальные уравнения. Есть пример полиномиальной аппроксимации.
      sourceforge.net/p/liblse/code/ci/default/tree/

Viewing 1 reply thread
  • Вы должны войти в систему, чтобы ответить в этой теме.
Интepecнoe нa фopумe:
Авторизация
*
*
Регистрация
*
*
*
Генерация пароля
×