SRL Archive - Research & Development Lounge

TPointArray.Trendline()


Camel

2015-05-20 23:04:16

I made a function that returns the trendline of a TPA. I found it useful for doing things around the wild wall.

function TPointArray.Trendline() : TPointArray;
var
TPA : TPointArray;
LowX, HighX, i, SumX, SumY, A, B, C, D : integer;
Slope, Yintercept :Extended;
begin
TPA := Self;
TPA.sortByXValue(true);

LowX := TPA[0].X;
HighX := TPA[Length(TPA) - 1].X;

For i := 0 to Length(TPA) -1 do
begin
A := A + (TPA[i].x * TPA[i].y);
SumX := SumX + TPA[i].X;
SumY := SumY + TPA[i].Y;
C := C + (TPA[i].X * TPA[i].X);
end;
A := A * Length(TPA);
B := SumX * SumY;
C := C * Length(TPA);
D := SumX * SumX;

Slope := (A - B) / (C - D);
YIntercept := (SumY - (Slope * SumX)) / Length(TPA);

Result := TPAFromLine(LowX,Round(Slope * LowX + YIntercept),HighX,Round(Slope * HighX + YIntercept));
end;

Here is an example


Turpinator

2015-05-20 23:35:16

pretty neat, but… what if i want a different kind of fit?

Kasi

2015-05-21 07:16:54

I have code if anyone wants to convert it.

https://paste.villavu.com/show/6729/


/**
* echelon transformation
*
* @param Matrix
* a matrix in non-row echelon form
* @return returns a matrix in row echelon form
*/
private double[][] Echelon(double[][] Matrix) {
// N, M = get the rows and columns of the matrix
int N = Matrix.length;
int M = Matrix[0].length;
int I = 0, J = 0;
int K;
double[] Temp;
// find all values that arent 0 and remove them
while ((I < N) && (J < M)) {

K = I;
// finds the next value at 0
while ((K < N) && (Matrix[K][J] == 0))
K++;
if (K < N) {

// swap the row and column elements
if (K != I) {
Temp = Matrix[I];
Matrix[I] = Matrix[K];
Matrix[K] = Temp;
}
// if the swapped index isnt 1 divide that entire row by the
// value at that index (normalization)
if (Matrix[I][J] != 1) {
for (int Q = J + 1; Q < M; Q++)
Matrix[I][Q] /= Matrix[I][J];
Matrix[I][J] = 1;
}

// go through and remove all other elements which arent 0
for (int Q = 0; Q < N; Q++) {
if (Q != I && Matrix[Q][J] != 0) {
for (int P = J + 1; P < M; P++)
Matrix[Q][P] -= Matrix[Q][J] * Matrix[I][P];
Matrix[Q][J] = 0;
}
}
I++;
}
J++;
}
return Matrix;
}

/**
* finds the estimated value of y for x depending on the provided terms
*
* @param x
* value of x to estimate y for
* @param Terms
* Polynomial terms regarding which way the curve is going
* @return estimated / predicted value for y given x.
*/
private double Regression(double x, ArrayList<Double> Terms) {
double a = 0;
int exp = 0;
// find f(x) by multiplying out exponents to terms.
for (int I = 0; I < Terms.size(); I++) {
a += Terms.get(I) * Math.pow(x, exp);
exp++;
}
return a;
}

/**
* @param X
* x values, normally the controlled. such as array size.
* @param Y
* y values, normally the measured. such as time taken.
* @param Degree
* degree of terms, a greater degree allows room for more flux in
* the curve
* @return returns terms used to primarily calculate f(x); a predicted y
* value given an x.
*/
private ArrayList<Double> Coefficients(double X[], double Y[], int Degree) {
Degree++;
int N = X.length;
int DF = (2 * Degree) - 1;
// create a "Routh–Hurwitz" matrix
double[][] RH = new double[Degree][Degree + 1];

// create a resulting matrix
double[] Res = new double[DF];
Res[0] = N;
for (int I = 0; I < N; I++) {
// apply regression using the data we have
for (int II = 1; II < DF; II++)
Res[II] += Math.pow(X[I], II);

// apply Routh–Hurwitz's stability criterion
RH[0][Degree] += Y[I];
for (int II = 1; II < Degree; II++)
RH[II][Degree] += Math.pow(X[I], II) * Y[I];
}

// assign the Resulting values to our RH matrix
for (int R = 0; R < Degree; R++)
for (int C = 0; C < Degree; C++)
RH[R][C] = Res[R + C];

// apply echelon transformation
RH = Echelon(RH);

// copy our calculated terms over into a result list.
ArrayList<Double> Result = new ArrayList<Double>();
for (int I = 0; I < RH.length; I++)
Result.add(RH[I][Degree]);
return Result;
}