Has anyone done any linear regression algorithms in VB.NET?
I have a laser sensor which streams distance measurements via TCP. The minimum dimension is 700mm and the maximum is 3000mm. It takes measurements every 0.25degrees, from 55 degrees to 125 degrees - a total of 70 degrees => 280 measurements per scan. Sometimes the laser will not take a true reading, and will return 0mm.
When the laser has performed its scan, I need to evaluate all the measurements to find two "edges" which are perpendicular to each other. Once I have found these lines and proved that they are perpendicular, I can calculate the X and Y offset, and rotation, of the two edges. This information will then be passed by serial to a robot to perform a pick-and-place operation.
The point where the two "edges" meet will always (in theory) be the closest point to the laser centre.
Here's a totally stripped down version - the sample set of measurements is in the next post. A screenshot (with lines removed) is also attached.
The problem I have is that I am not sure how to do the linear regression lines without including some of the obviously invalid points. This is where I could do with some help (which would be GREATLY appreciated )
Code:
Option Explicit On
Option Strict On
Imports System.Drawing.Drawing2D
Public Class Form1
Structure MEASUREDVALUE
Public Distance As Integer
Public X As Integer
Public Y As Integer
End Structure
Public MeasuredPoints(280) As MEASUREDVALUE
Private iSmallestMeasurementFromLeft As Integer = Integer.MaxValue
Private iSmallestMeasurementScanNumberLeft As Integer = 0
Private iSmallestMeasurementFromRight As Integer = Integer.MaxValue
Private iSmallestMeasurementScanNumberRight As Integer = 0
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.UserPaint, True)
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.WindowState = FormWindowState.Maximized
For i As Integer = 1 To 280
MeasuredPoints(i).Distance = 0
MeasuredPoints(i).X = 0
MeasuredPoints(i).Y = 0
Next
SetupSampleData()
End Sub
Private Sub SetupSampleData()
'see next post
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
With e.Graphics
Dim mYFlip As Matrix = New Matrix(1, 0, 0, -1, 0, 0)
.Transform = mYFlip
.TranslateTransform(CSng(Me.ClientRectangle.Width / 2), 0 - (Me.ClientRectangle.Height - 100))
.ScaleTransform(0.2, 0.2)
.DrawEllipse(Pens.Black, -25, -25, 50, 50)
.DrawLine(Pens.Black, CSng(0 + (700 * Math.Cos(DTR(90 + 35)))), CSng(0 + (700 * Math.Sin(DTR(90 + 35)))), CSng(0 + (3000 * Math.Cos(DTR(90 + 35)))), CSng(0 + (3000 * Math.Sin(DTR(90 + 35)))))
.DrawLine(Pens.Black, CSng(0 - (700 * Math.Cos(DTR(90 + 35)))), CSng(0 + (700 * Math.Sin(DTR(90 + 35)))), CSng(0 - (3000 * Math.Cos(DTR(90 + 35)))), CSng(0 + (3000 * Math.Sin(DTR(90 + 35)))))
.DrawArc(Pens.Black, 0 - 3000S, 0 - 3000S, 3000S * 2, 3000S * 2, 90 - 35, 70)
.DrawArc(Pens.Black, 0 - 700S, 0 - 700S, 700S * 2, 700S * 2, 90 - 35, 70)
Dim Angle As Single = 0
For i As Integer = 1 To UBound(MeasuredPoints)
Angle = CSng((140 - i) * 0.25)
If MeasuredPoints(i).Distance >= 700 AndAlso MeasuredPoints(i).Distance <= 3000 Then
.DrawLine(Pens.Black, CSng(0 - (MeasuredPoints(i).Distance * Math.Cos(DTR(90 - Angle)))), CSng(0 + (MeasuredPoints(i).Distance * Math.Sin(DTR(90 - Angle)))), CSng(0 - (MeasuredPoints(i).Distance * Math.Cos(DTR(90 - Angle)))), CSng(0 + (MeasuredPoints(i).Distance * Math.Sin(DTR(90 - Angle)))) + 1)
End If
'if you want to identify a measured point, add a NumericUpDown control
'and set its minimum value to 1 and its maximum value to 280
If i = NumericUpDown1.Value Then
If MeasuredPoints(i).Distance >= 700 AndAlso MeasuredPoints(i).Distance <= 3000 Then
.DrawLine(Pens.Red, 0, 0, CSng(0 - (MeasuredPoints(i).Distance * Math.Cos(DTR(90 - Angle)))), CSng(0 + (MeasuredPoints(i).Distance * Math.Sin(DTR(90 - Angle)))) + 1)
Else
.DrawLine(Pens.Red, 0, 0, CSng(0 - (3000 * Math.Cos(DTR(90 - Angle)))), CSng(0 + (3000 * Math.Sin(DTR(90 - Angle)))) + 1)
End If
End If
Next
'find the smallest measurement working from left to right
iSmallestMeasurementFromLeft = Integer.MaxValue
iSmallestMeasurementScanNumberLeft = 0
For i As Integer = 1 To 280
If MeasuredPoints(i).Distance >= 700 AndAlso MeasuredPoints(i).Distance <= 3000 AndAlso MeasuredPoints(i).Distance < iSmallestMeasurementFromLeft Then
iSmallestMeasurementFromLeft = MeasuredPoints(i).Distance
iSmallestMeasurementScanNumberLeft = i
End If
Next
Angle = CSng((140 - iSmallestMeasurementScanNumberLeft) * 0.25)
.DrawLine(Pens.Green, 0, 0, CSng(0 - (MeasuredPoints(iSmallestMeasurementScanNumberLeft).Distance * Math.Cos(DTR(90 - Angle)))), CSng(0 + (MeasuredPoints(iSmallestMeasurementScanNumberLeft).Distance * Math.Sin(DTR(90 - Angle)))) + 1)
'TODO: calculate the linear regression line to the left
'find the smallest measurement working from left to right
iSmallestMeasurementFromRight = Integer.MaxValue
iSmallestMeasurementScanNumberRight = 0
For i As Integer = 280 To 1 Step -1
If MeasuredPoints(i).Distance >= 700 AndAlso MeasuredPoints(i).Distance <= 3000 AndAlso MeasuredPoints(i).Distance < iSmallestMeasurementFromRight Then
iSmallestMeasurementFromRight = MeasuredPoints(i).Distance
iSmallestMeasurementScanNumberRight = i
End If
Next
Angle = CSng((140 - iSmallestMeasurementScanNumberRight) * 0.25)
.DrawLine(Pens.Green, 0, 0, CSng(0 - (MeasuredPoints(iSmallestMeasurementScanNumberRight).Distance * Math.Cos(DTR(90 - Angle)))), CSng(0 + (MeasuredPoints(iSmallestMeasurementScanNumberRight).Distance * Math.Sin(DTR(90 - Angle)))) + 1)
'TODO: calculate the linear regression line to the right
End With
End Sub
Private Function DTR(ByVal whatDegrees As Double) As Double
DTR = (whatDegrees * Math.PI) / 180
End Function
Private Function RTD(ByVal whatRadians As Double) As Double
RTD = (whatRadians * 180) / Math.PI
End Function
Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown1.ValueChanged
Me.Invalidate()
End Sub
End Class