Private Type Ty2Dcoord
x As Double
y As Double
End Type
Private Type TyCoordList
Coords() As Ty2Dcoord
End Type
Private Type TySIGMA
TySIGMAX As Double
TySIGMAY As Double
TySIGMAXY As Double
TySIGMAXX As Double
TySIGMAXXX As Double
TySIGMAXXXX As Double
TySIGMAXXY As Double
End Type
Private Type TyMatrix33
mat(1 To 3, 1 To 3) As Double
End Type
Private Type TyMatrix13
mat(1 To 3) As Double
End Type
Private Type TyXYrange
xmin As Double
ymin As Double
xmax As Double
ymax As Double
End Type
Sub LeastSquaresQuadratic()
Dim rad As Double
Dim cl As TyCoordList
Dim range As TyXYrange
Dim b As TyMatrix13
'/////////// Prob get the points from user selection or a file
'n = 4
'ReDim cl.Coords(n - 1)
'cl.Coords(0).x = -1.3: cl.Coords(0).y = 0.103
'cl.Coords(1).x = -0.1: cl.Coords(1).y = 1.099
'cl.Coords(2).x = 0.2: cl.Coords(2).y = 0.808
'cl.Coords(3).x = 1.3: cl.Coords(3).y = 1.897
'///////////////////////////////////////////////////////////////////
'n = 4
'ReDim cl.Coords(n - 1)
'cl.Coords(0).x = -2: cl.Coords(0).y = 5
'cl.Coords(1).x = -1: cl.Coords(1).y = 2
'cl.Coords(2).x = 1: cl.Coords(2).y = 2
'cl.Coords(3).x = 2: cl.Coords(3).y = 5
'reverse test calculate quadratic from known coefficients
n = 10
ReDim cl.Coords(n - 1)
x = -1.5
For i = 0 To n - 1
y = -0.5 * x ^ 2 + 2 * x + 2
cl.Coords(i).x = x
cl.Coords(i).y = y
x = x + 0.3
Next i
'//////////////////////////////////////////////////////////////////
rad = Abs(cl.Coords(0).x - cl.Coords(1).x) * 0.1
plotcoordinatepoints cl, rad 'plot the orginal points
range = findrange(cl)
b = FindQuadraticCoefficients(cl)
ActiveDrawing.Graphics.AddText "p(x) = " & CStr(b.mat(1)) & " + " & CStr(b.mat(2)) & "x + " _
& CStr(b.mat(3)) & "x^2", 2, 2, 0, rad * 10
plotquadtatic b.mat(1), b.mat(2), b.mat(3), range.xmin, range.xmax 'plot out the polynominal
DrawXYaxes range
End Sub
Private Function findrange(cl As TyCoordList) As TyXYrange
Dim i As Integer
xmin = cl.Coords(0).x
ymin = cl.Coords(0).y
xmax = cl.Coords(0).x + 0.000001
ymax = cl.Coords(0).y + 0.000001
For i = LBound(cl.Coords) + 1 To UBound(cl.Coords)
If cl.Coords(i).x < xmin Then xmin = cl.Coords(i).x
If cl.Coords(i).x > xmax Then xmax = cl.Coords(i).x
If cl.Coords(i).y < ymin Then ymin = cl.Coords(i).y
If cl.Coords(i).y > ymax Then ymax = cl.Coords(i).y
Next i
findrange.xmin = xmin
findrange.xmax = xmax
findrange.ymin = ymin
findrange.ymax = ymax
End Function
Private Sub plotquadtatic(b0 As Double, b1 As Double, b2 As Double, xmin As Double, xmax As Double)
'plot out a quadratic equations
'p(x) = b0 + b1*x + b2*x^2
Dim v As Vertex
Set gr = ActiveDrawing.Graphics.Add
x = xmin
For i = 0 To 100
y = b0 + b1 * x + b2 * x ^ 2
'ActiveDrawing.Graphics.AddCircleCenterAndPoint x, y, 0, x + 0.01, y, 0
Set v = gr.Vertices.Add(x, y, 0)
x = x + (xmax - xmin) / 100
Next i
Set v = Nothing
Set gr = Nothing
End Sub
Private Sub plotcoordinatepoints(cl As TyCoordList, circlerad As Double)
Dim c As Graphic
Dim i As Integer
For i = LBound(cl.Coords) To UBound(cl.Coords)
Set c = ActiveDrawing.Graphics.AddCircleCenterAndPoint(cl.Coords(i).x, cl.Coords(i).y, 0, cl.Coords(i).x + circlerad, cl.Coords(i).y, 0)
c.Properties("Info").Value = CStr(i)
c.Properties("PenColor").Value = RGB(255, 0, 0)
Next i
Set c = Nothing
End Sub
Private Function FindQuadraticCoefficients(cl As TyCoordList) As TyMatrix13
Dim sum As TySIGMA
Dim n As Integer
Dim a As TyMatrix33
Dim c As TyMatrix13
Dim b As TyMatrix13
sum = TySIGMA1(cl)
'MsgBox sum.TySIGMAX & " " & sum.TySIGMAY & " " & sum.TySIGMAXY & " " & sum.TySIGMAXX
n = UBound(cl.Coords) - LBound(cl.Coords)
'MsgBox n + 1
a.mat(1, 1) = n + 1: a.mat(2, 1) = sum.TySIGMAX: a.mat(3, 1) = sum.TySIGMAXX: c.mat(1) = sum.TySIGMAY
a.mat(1, 2) = sum.TySIGMAX: a.mat(2, 2) = sum.TySIGMAXX: a.mat(3, 2) = sum.TySIGMAXXX: c.mat(2) = sum.TySIGMAXY
a.mat(1, 3) = sum.TySIGMAXX: a.mat(2, 3) = sum.TySIGMAXXX: a.mat(3, 3) = sum.TySIGMAXXXX: c.mat(3) = sum.TySIGMAXXY
'MsgBox a.mat(1, 1) & " " & a.mat(2, 1) & " " & a.mat(3, 1) & " " & c.mat(1)
'MsgBox a.mat(1, 2) & " " & a.mat(2, 2) & " " & a.mat(3, 2) & " " & c.mat(2)
'MsgBox a.mat(1, 3) & " " & a.mat(2, 3) & " " & a.mat(3, 3) & " " & c.mat(3)
b = DooLittle(a, c)
'MsgBox b.mat(1) & " " & b.mat(2) & " " & b.mat(3)
FindQuadraticCoefficients.mat(1) = b.mat(1)
FindQuadraticCoefficients.mat(2) = b.mat(2)
FindQuadraticCoefficients.mat(3) = b.mat(3)
End Function
Private Function TySIGMA1(coordinates As TyCoordList) As TySIGMA
Dim i As Integer
Dim SX As Double
SX = 0
For i = LBound(coordinates.Coords) To UBound(coordinates.Coords)
SX = SX + coordinates.Coords(i).x
SY = SY + coordinates.Coords(i).y
SXY = SXY + coordinates.Coords(i).x * coordinates.Coords(i).y
SXX = SXX + coordinates.Coords(i).x * coordinates.Coords(i).x
SXXX = SXXX + coordinates.Coords(i).x * coordinates.Coords(i).x * coordinates.Coords(i).x
SXXXX = SXXXX + coordinates.Coords(i).x * coordinates.Coords(i).x * coordinates.Coords(i).x * coordinates.Coords(i).x
SXXY = SXXY + coordinates.Coords(i).x * coordinates.Coords(i).x * coordinates.Coords(i).y
Next i
TySIGMA1.TySIGMAX = SX
TySIGMA1.TySIGMAY = SY
TySIGMA1.TySIGMAXY = SXY
TySIGMA1.TySIGMAXX = SXX
TySIGMA1.TySIGMAXXX = SXXX
TySIGMA1.TySIGMAXXXX = SXXXX
TySIGMA1.TySIGMAXXY = SXXY
End Function
Sub DooLittletest()
Dim a As TyMatrix33
Dim b As TyMatrix13
Dim x As TyMatrix13
a.mat(1, 1) = 3: a.mat(1, 2) = 5: a.mat(1, 3) = 2: b.mat(1) = 8
a.mat(2, 1) = 0: a.mat(2, 2) = 8: a.mat(2, 3) = 2: b.mat(2) = -7
a.mat(3, 1) = 6: a.mat(3, 2) = 2: a.mat(3, 3) = 8: b.mat(3) = 26
x = DooLittle(a, b)
MsgBox x.mat(1) & " " & x.mat(2) & " " & x.mat(3)
End Sub
Private Function DooLittle(a As TyMatrix33, b As TyMatrix13) As TyMatrix13
'A = LU
u11 = a.mat(1, 1)
u12 = a.mat(1, 2)
u13 = a.mat(1, 3)
m21 = a.mat(2, 1) / u11
u22 = a.mat(2, 2) - m21 * u12
u23 = a.mat(2, 3) - m21 * u13
m31 = a.mat(3, 1) / u11
m32 = (a.mat(3, 2) - m31 * u12) / u22
u33 = a.mat(3, 3) - m31 * u13 - m32 * u23
'MsgBox "u11 =" & u11 & " u12=" & u12 & " u13=" & u13 & " m21=" & m21 & " u22=" & u22 & " u23=" & u23 & " " & m31 & " " & m32 & " " & u33
'Ly = b
y1 = b.mat(1)
y2 = b.mat(2) - m21 * y1
y3 = b.mat(3) - m32 * y2 - m31 * y1
'MsgBox y1 & " " & y2 & " " & y3
x3 = y3 / u33
x2 = (y2 - u23 * x3) / u22
x1 = (y1 - u13 * x3 - u12 * x2) / u11
'MsgBox x1 & " " & x2 & " " & x3
DooLittle.mat(1) = x1
DooLittle.mat(2) = x2
DooLittle.mat(3) = x3
End Function
Private Sub DrawXYaxes(range As TyXYrange)
Dim th As Double
th = (range.ymax - range.xmin) / 50
If range.ymin > 0 Then range.ymin = 0
ActiveDrawing.Graphics.AddLineSingle range.xmin, 0, 0, range.xmax, 0, 0
ActiveDrawing.Graphics.AddLineSingle 0, range.ymin, 0, 0, range.ymax, 0
ActiveDrawing.Graphics.AddText "0", 0, 0, 0, th
ActiveDrawing.Graphics.AddText "X", range.xmax, 0, 0, th
ActiveDrawing.Graphics.AddText "Y", 0, range.ymax, 0, th
End Sub