Base de Conhecimento

Curva polinomial de melhor ajuste

Contexto

Recentemente, um cliente nos solicitou que calculássemos uma curva de melhor ajuste para um conjunto de pontos. O software que estávamos implementando é usado para acionar uma máquina de usinagem de metais e precisava produzir uma saída que fosse uma curva suave, com base em um conjunto de pontos amostrados. Tendo trabalhado em problemas semelhantes anteriormente, eu tinha uma ideia aproximada de como isso deveria funcionar matematicamente, mas, como geralmente acontece no desenvolvimento de software, eu tinha certeza de que alguém já teria resolvido esse problema específico.

Requisitos

Temos um conjunto de pontos com coordenadas X e Y. O software precisa calcular uma curva que seja o melhor ajuste para os pontos. Ao fazer isso, ele também deve introduzir pontos intermediários adicionais para que a curva seja a mais suave possível. Por exemplo, para um conjunto de entrada de 400 pontos, o software produzirá 5.000 pontos que se encontram na curva de melhor ajuste.

Pesquisa

Uma rápida pesquisa no Google identificou algumas possíveis soluções Delphi para esse problema.

A que parecia mais promissora era a unidade de ajuste de curva de mínimos quadrados de David Taylor: https://www.satsignal.eu/software/components.html#CurveFit

Essa era uma única unidade Delphi que não tinha dependências de componentes de terceiros e simplesmente usava a unidade System.Math.
A rotina foi escrita em Delphi 5, mas o projeto de teste foi compilado na versão mais recente do Delphi sem nenhum problema, como seria de se esperar de uma biblioteca puramente matemática.

Uso da biblioteca

Entradas

A função principal aceita:

  • Uma matriz de valores X de ponto flutuante.
  • Uma matriz de valores Y de ponto flutuante.
  • O número de termos a serem usados.

O número de termos está relacionado ao grau da fórmula polinomial que será usada.

Um único termo equivale a uma linha horizontal em um gráfico, por exemplo   y = 2

O uso de dois termos equivale a uma linha reta em um gráfico, por exemplo  y = 3x + 2

O uso de três termos equivale a uma equação quadrática, por exemplo,  y = 4x² + 3x + 2

Saídas

A função de cálculo preencherá uma matriz de valores de ponto flutuante que correspondem aos coeficientes da equação. Por exemplo, se quisermos usar três termos (uma equação quadrática), podemos passar uma matriz de três números de ponto flutuante. No exemplo quadrático acima, os coeficientes seriam 2, 3 e 4, respectivamente. O cálculo também retorna um coeficiente de correlação, que nos diz o quanto a curva se correlaciona com os pontos de entrada fornecidos. Quanto mais próximo de 1 for esse coeficiente, mais preciso será o ajuste.

Resultados

Ao usar a biblioteca, os testes unitários foram escritos usando um conjunto de pontos de teste fornecidos pelo nosso cliente. Os pontos fornecidos eram típicos das amostras que seriam usadas na produção. Com esses pontos de amostra, a curva mais precisa foi produzida ao chamar a função com seis termos. Isso equivale a uma função polinomial de quinto grau.

Ao usar mais de seis termos, ocasionalmente ocorreram erros de estouro de ponto flutuante, provavelmente porque os coeficientes calculados eram muito pequenos para serem representados em um tipo Double no Delphi. Ao usar menos de seis termos, a rotina ainda calculava uma curva de melhor ajuste, mas é claro que o ajuste não era tão preciso. Com menos termos, o coeficiente de correlação foi menor.

Com seis termos, recebemos seis coeficientes de volta na matriz fornecida à função.

Quando tivermos os coeficientes, poderemos calcular o valor Y para qualquer valor de X. Para obter a curva desejada, foi calculada uma matriz de 5.000 pontos X uniformemente espaçados, delimitados pelos valores X máximo e mínimo da amostra.

function CalculateY(const X: Double; const Coefficients: TArray<Double>): Double;
begin
  var yc := 0.0;
  var xc := 1.0;

  for var i := Low(Coefficients) to High(Coefficients) do
  begin
    yc := yc + Coefficients[i] * xc;
    xc := xc * X;
  end;

  Result := yc;
end;

Aqui está uma amostra de alguns dos pontos de entrada:

No software, a curva de melhor ajuste resultante é calculada e sobreposta aos pontos da seguinte forma:

Implementação

Esta função utiliza um algoritmo de ajuste de curva de mínimos quadrados usando a eliminação de Gauss-Jordan.

Esse é um algoritmo bem conhecido para encontrar uma curva polinomial de melhor ajuste para um conjunto de pontos.

Conclusão

Vimos que uma biblioteca matemática originalmente escrita em Turbo Pascal e nas primeiras versões do Delphi pode ser usada nas versões mais recentes do Delphi sem modificações.

Essa biblioteca pode produzir curvas precisas e suaves para o melhor ajuste de um conjunto de pontos de dados.
Quanto maior o número de termos e, portanto, o grau do polinômio, mais preciso será o ajuste.

Written by James Goodger
Diretor, UK

Contato

Deixe-nos ajudá-lo a realizar seus sonhos.