Есть ли альтернативный способ преобразования точек из осевой в проецируемую плоскость в VB6? - PullRequest
0 голосов
/ 15 мая 2019

(Обратите внимание, что я также разместил это в списке программирования на 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 в коде, я обнаружил что-то полезное в своих поисках в Интернете на основе теоремы Пифагора:

  1. | С3 | \ le \ sqrt {C1 ^ 2 + C2 ^ 2} - итерационный цикл Ньютона сможет найти решение
  2. | С3 | > \ sqrt {C1 ^ 2 + C2 ^ 2} - итерационный цикл Ньютона не сможет найти решение

Я изменил код, чтобы выполнить эту проверку в начале и войти в цикл Ньютона, только если уравнение (1) выполнено, в противном случае в настоящее время он сообщает об ошибке, но я хотел бы найти альтернативный метод, чтобы найти решение.

...