(Обратите внимание, что я также разместил это в списке программирования на Visual Basic 6 в группах Yahoo!, но он, кажется, устарел с 2017 года, поэтому я подумал, что тоже буду публиковать здесь.)
Я недавно взял на себя поддержку программы VB6 на работе, в которой есть процедура для преобразования точек данных из осевой плоскости в проецируемую плоскость с учетом осевой точки, измерения отведения, угла проекции, вектора (начальный угол, конечный угол , градиент) и спроецированная точка. Он написан как функция, которая возвращает логическое значение, чтобы указать, был ли он успешным.
Для этого необходимо рассчитать угол поворота от осевой плоскости и использовать итерационный метод Ньютона-Рафсона для определения значения этого угла. Для этого устанавливается верхний предел в 30 итераций, но для определенного набора параметров невозможно найти решение в пределах этих 30 итераций.
Кто-нибудь знает альтернативный метод для выполнения этого преобразования, пожалуйста? Эта программа используется для привода станка с ЧПУ с вычисленными точками данных, и я считаю, что эти параметры действительны, это просто метод, который мешает ему продолжить работу.
Я добавил выходной код регистрации, чтобы отследить проблему, и обнаружил, что он сводится к преобразованию между осевой и проецируемой плоскостями с определенным верхним значением для угла проекции (он также использует +/- поле для этого значения как часть процесса).
Код итерации не может найти решение, которое находится в пределах установленного допуска в пределах установленного максимального числа попыток (30).
Я пытался увеличить максимальное количество попыток, уменьшить приращения, увеличить допуск, а также уменьшить значение применяемого поля, но ничего из того, что я сделал до сих пор, не работает, или оно дублирует ту же ошибку.
Я ожидаю, что на выходе будет массив точек профиля, которые находятся на проецируемой плоскости и эквивалентны предоставленным точкам осевой плоскости, используя предоставленное измерение отведения и угол проекции, но я получаю ошибки, которые указывают, что процессу итерации не удалось найти решение в течение максимум 30 попыток.
Отредактировано, чтобы добавить:
Я написал следующий псевдокод на основе кода VB6, чтобы попытаться объяснить, как работает подпрограмма:
'AxialPoint, ProjectedPoint: structures with ProfileRadius, ProfileWidth,
'NormalAngle, UnwrapAngle and Attribute fields
'Lead: lead measurement
'ProjectionAngle: projection angle onto the projected plane in degrees
'Vector(): provides initial value of Beta, Last Beta value found, Last
'gradient) - set by the calling routine as (0, 0, 0) in this case
'Beta is the angle of rotation from the axial plane
Function AxialToProjected(AxialPoint, Lead, ProjectionAngle, Vector(),
ProjectedPoint):
LeadAngle := Atn(Lead / (2 * PI * AxialPoint.ProfileRadius)) 'radians
SA := Sin(LeadAngle)
CA = Cos(LeadAngle)
CT := -CosD(AxialPoint.NormalAngle)
ST := SinD(AxialPoint.NormalAngle)
SG := SinD(ProjectionAngle)
CG := CosD(ProjectionAngle)
C1 := SA * CG * CT
C2 := CA * CG * ST
C3 := CA * SG * CT
Iteration := 0
FBeta := 0.0001
While (Abs(FBeta) >= 0.0001) And (Iteration < 9) Do
NewValue(Beta, OldBeta, FBeta, Increment:=0.1, Gradient, SVB(),
Iteration, Multiplier:=10)
SB := Sin(Beta)
CB := Cos(Beta)
OldFBeta := FBeta
FBeta := C1 * CB + C2 * SB - C3
If Iteration >= 2 Then
Gradient := (Beta - OldBeta) / (FBeta - OldFBeta)
End If
End While
If (Abs(FBeta) > 0.0001) Then
'The code reaches this point with the specific parameters
Report "Iteration failed to find a solution within 30 tries" error
Else
'The code doesn't reach this point
X3 := Beta * Lead / 2 * PI + AxialPoint.ProfileWidth
With ProjectedPoint Do
.ProfileWidth := X3 * CG - AxialPoint.ProfileRadius * SB * SG
.ProfileRadius := AxialPoint.ProfileRadius * CB
.NormalAngle := ATan2(CA * CB * CG * ST - SA * SB * CG * CT,
-CA * CT) * RadToDeg
.Attribute := AxialPoint.Attribute
.UnwrapAngle := AxialPoint.UnwrapAngle
End With
End If
End AxialToProjected()
SinD () и CosD () принимают угол в градусах и преобразуют его в радианы, прежде чем передать его в обычные функции Sin () и Cos ().
Подпрограмма NewValue () вычисляет новое значение для Beta из значения OldBeta, используя FBeta, Increment, Gradient, SVB () и Multiplier, увеличивая значение Iteration:
'Beta: current axial plane rotation angle estimate
'OldBeta: previous current axial plane rotation angle estimate
'FBeta: gradient of tangent to the normal
'Increment: increment size to adjust Beta by
'Gradient: gradient for the Newton method
NewValue(Beta, OldBeta, FBeta, Increment, Gradient, SVB(), Iteration,
Multiplier):
If Iteration > 2 Then
MaxChange := Abs(Increment * Multiplier)
Change := -FBeta * Gradient
If Abs(Change) > MaxChange Then
Beta := Beta + TransferSign(MaxChange, Change)
'TransferSign() will return -MaxChange if Change < 0 or
'MaxChange if Change >= 0
Else
Beta := Beta + Change
End If
ElseIf Iteration = 2 Then
If SVB(3) = 0 Then
Beta := SVB(1) + Increment
Else
Beta := -FBeta * SVB(3)
End If
Else
Beta := SVB(1) 'Set Beta to initial value
End If
End NewValue()
Диаграмма будет загружена позже, так как мне нужно выяснить, как лучше всего нарисовать ее из моих писанинок:)
Просто чтобы добавить дополнительный контекст, процедура используется для вычисления точек на червях ZA и ZN типа станка с помощью станка с ЧПУ.
Это просто 1 определенный набор параметров для каждого типа, который вызывает ошибку, и я полагаю, что это вызвано тем, что первоначальная оценка находится слишком далеко от корня, чтобы быть разрешенной в пределах 30 попыток, но я не уверен, как выработать лучшую начальную оценку.
Отредактировано, чтобы добавить:
Извиняюсь за то, что не вернулся в поток раньше, так как я рассматривал эту проблему с других точек зрения, но мне удалось составить простую диаграмму, показывающую, как эти плоскости связаны, поэтому я надеюсь, что это поможет:
Координатные плоскости
Когда я изучал вычисление FBeta в коде, я обнаружил что-то полезное в своих поисках в Интернете на основе теоремы Пифагора:
- | С3 | \ le \ sqrt {C1 ^ 2 + C2 ^ 2} - итерационный цикл Ньютона сможет найти решение
- | С3 | > \ sqrt {C1 ^ 2 + C2 ^ 2} - итерационный цикл Ньютона не сможет найти решение
Я изменил код, чтобы выполнить эту проверку в начале и войти в цикл Ньютона, только если уравнение (1) выполнено, в противном случае в настоящее время он сообщает об ошибке, но я хотел бы найти альтернативный метод, чтобы найти решение.