Повышение точности решения трансцендентного уравнения
У меня есть определенная кинематика как часть более сложной машины, и мне нужно вычислить некоторые физические параметры, которыеочень сложно (скорее как невозможно) измерить с должнымточность с инструментами, которые у меня есть в моем распоряжении
[кинематика]
На первый взгляд это просто1
степень свободы руки (черный), который может вращаться вокругx
ось. У него есть вес, чтобы заставить его идти всегда вверх, пока он не достигнет конечной точки механики (уголa0
) или какая-нибудь трубка (синяя) с радиусомr0
, Центр вращения рычага находится наy0
, Трубку можно перенести на любуюy(t)
рост.
[использование]
Это используется для измерения радиуса трубы для дальнейшей обработки. Радиус может быть вычислен (с помощью базовой гониометрии), что приводит к уравнению внизу изображения. Константыa0,y0,z0
очень трудно измерить (это внутри сложного оборудования), поэтому точность измерения расстояний составляет минимум0.1 mm
и угол0.1 deg
и даже это сомнительно.
[Калибровка]
Поэтому я решил попробовать вычислить эти параметры из набора измерений, выполненных самой машиной (автокалибровка). Итак, у меня есть калибровочная трубка с известным радиусомr0
, Все зеленые параметры могут быть обработаны как константы. Теперь я размещаю трубку вдольy
ось, чтобы покрыть как можно больше углов руки. К сожалению, диапазон только о20 degrees
(для текущей настройки машины) запоминание измеренногоa(t)
для предустановкиy(t)
... какn
точечный набор данных. Это дает мне системуn
трансцендентные уравнения. Из этого я пытаюсь / угадываю "все" возможностиa0,y0,z0
помня лучшее решение (ближе всего кr0
)
[приближение a0, y0, z0]
аппроксимация основана на этом моем классе:
//---------------------------------------------------------------------------
class approx
{
public:
double a,aa,a0,a1,da,*e,e0;
int i,n;
bool done,stop;
approx() { a=0.0; aa=0.0; a0=0.0; a1=1.0; da=0.1; e=NULL; e0=NULL; i=0; n=5; done=true; }
approx(approx& a) { *this=a; }
~approx() {}
approx* operator = (const approx *a) { *this=*a; return this; }
//approx* operator = (const approx &a) { ...copy... return this; }
void init(double _a0,double _a1,double _da,int _n,double *_e)
{
if (_a0<=_a1) { a0=_a0; a1=_a1; }
else { a0=_a1; a1=_a0; }
da=fabs(_da);
n =_n ;
e =_e ;
e0=-1.0;
i=0; a=a0; aa=a0;
done=false; stop=false;
}
void step()
{
if ((e0<0.0)||(e0>*e)) { e0=*e; aa=a; } // better solution
if (stop) // increase accuracy
{
i++; if (i>=n) { done=true; a=aa; return; } // final solution
a0=aa-fabs(da);
a1=aa+fabs(da);
a=a0; da*=0.1;
a0+=da; a1-=da;
stop=false;
}
else{
a+=da; if (a>a1) { a=a1; stop=true; } // next point
}
}
};
//---------------------------------------------------------------------------
Он выполняет поиск по всему диапазону одной переменной на каком-то начальном этапе, затем находит точку минимального отклонения. После этого измените диапазон и шаг, чтобы закрыть область этой точки и рекурсивно увеличить точность.
Само решение выглядит так:
// (global) input data
#define _irc_calib_n 100
#define _irc_approx_n 5
int irc_calib_ix; // number of measured points
double irc_calib_y[_irc_calib_n]; // y(t)
double irc_calib_a[_irc_calib_n]; // a(t)
double irc_calib_r; // calibration tube radius + arm radius
// approximation
int ix=0;
double e,a,deg=M_PI/180.0;
approx aa,ay,az;
// min max step recursions ErrorOfSolutionVariable
for (aa.init(-90.0*deg,+90.0*deg,10.0*deg,_irc_approx_n,&e);!aa.done;aa.step())
for (ay.init( 0.0 ,200.0 ,10.0 ,_irc_approx_n,&e);!ay.done;ay.step())
for (az.init( 50.0 ,400.0 ,10.0 ,_irc_approx_n,&e);!az.done;az.step())
{
for (e=0.0,ix=0;ix<_irc_calib_n;ix++) // test all measured points (e is cumulative error)
{
a=irc_calib_a[ix]+aa.a;
if (a> pi) a-=pi2;
if (a<-pi) a+=pi2;
if (fabs(a)>0.5*pi) { e=100.0; break; } // ignore too far angles
e+=fabs(+(cos(a)*(irc_calib_y[ix]-ay.a))
-(sin(a)*(az.a))
-(irc_calib_r));
}
}
// here aa.a,ay.a,az.a holds the result
Это приводит к решению, близкому к измеренным значениям, но внутри моделирования результат все еще недостаточно точен. Он составляет от 0,1 мм до 0,5 мм в зависимости от количества точек и диапазона углов. Если я правильно измеритьz0
и игнорировать его приближение, то точность значительно повышается, оставляяy0
без ошибок (в симуляции) иa0
с погрешностью около 0,3 градуса
Q1, как я могу еще больше повысить точность решения?
Я не могу увеличить угловой диапазон. Количество очков лучше всего вокруг100
чем больше, тем выше точность, но выше 150 результат нестабилен (для некоторых радиусов он полностью выключен). Понятия не имею почему. Количество рекурсий выше6
не имеет большого эффекта
Может помочь взвешивания отклонений в зависимости от углового расстояния от0 degree
? Но к сожалениюa(t)
диапазон не обязательно включает0 degrees
желаемая точность0.01 mm
заy0,z0
а также0.01 degree
заa0
Q2 есть что-то, что я пропустил?
Как неправильно вложенные аппроксимации или математическое упрощение или другой подход
[заметки]
Угол должен быть в формеa(t)+a0
потому что измеряется IRC с сбросом ПО (16000 steps/round
). Это сбрасывается, когда вa0
Положение Я не считаю вибрации и эксцентриситет калибровочной трубки, о которых они уже позаботились, и моя первая цель - сделать эту работу в симуляции без них. тубаy(t)
могут быть размещены по собственному желанию иa(t)
Измерение может быть сделано по желанию.
Сейчас процесс сканирования калибровки указывает вдольy
ось (движение отa0
вниз). Вычисление с6
рекурсии35
секунд (так что наберитесь терпения).5
рекурсии22
секунд
[edit1] здесь, как делается симуляция
approx aa; double e;
for (aa.init(-90.0*deg,+90.0*deg,10.0*deg,6,&e);!aa.done;aa.step())
e=fabs(+(cos(aa.a)*(y(t)-y0))
-(sin(aa.a)*(z0))
-(irc_calib_r));
if (aa.a<a0) aa.a=a0;
[edit2] некоторые значения
Просто понял, что у меня было только4
рекурсии в коде моделирования, чтобы соответствовать точности входного IRC, то должно быть6
. рекурсии После изменения (также в предыдущем редактировании) вот некоторые результаты
| a0[deg]| y0[mm] | z0[mm] |
simulated | -7.4510|191.2590|225.9000|
z0 known | -7.4441|191.1433|225.9000|
z0 unknown | -7.6340|191.8074|225.4971|
Так что точность сz0
измеряется почти в желаемом диапазоне, но сz0
неизвестно ошибка все еще~10
раз больше, чем нужно. Увеличение точности моделирования не имеет эффекта выше6
рекурсии, а также нет смысла, потому что реальные входные данные также не будут более точными.
Вот смоделированные / измеренные точки для тестирования с вышеизложенными симуляциями:
ix a [deg] y [mm]
0 -0.2475 +105.7231
1 -0.4500 +104.9231
2 -0.6525 +104.1231
3 -0.8550 +103.3231
4 -1.0575 +102.5231
5 -1.2600 +101.7231
6 -1.4625 +100.9231
7 -1.6650 +100.1231
8 -1.8675 +99.3231
9 -2.0700 +98.5231
10 -2.2725 +97.7231
11 -2.4750 +96.9231
12 -2.6775 +96.1231
13 -2.8575 +95.3077
14 -3.0600 +94.5154
15 -3.2625 +93.7231
16 -3.4650 +92.9308
17 -3.6675 +92.1385
18 -3.8700 +91.3462
19 -4.0725 +90.5538
20 -4.2750 +89.7615
21 -4.4877 +88.9692
22 -4.6575 +88.1769
23 -4.8825 +87.3615
24 -5.0850 +86.5154
25 -5.2650 +85.7000
26 -5.4675 +84.9077
27 -5.6700 +84.1154
28 -5.8725 +83.3231
29 -6.0750 +82.5308
30 -6.2775 +81.7000
31 -6.5025 +80.8462
32 -6.6825 +80.0462
33 -6.8850 +79.2538
34 -7.0875 +78.4615
35 -7.2900 +77.6538
36 -7.5159 +76.7692
37 -7.6725 +75.9769
38 -7.8750 +75.1846
39 -8.1049 +74.3692
40 -8.2800 +73.5000
41 -8.4825 +72.7077
42 -8.6850 +71.9154
43 -8.9100 +71.0308
44 -9.0900 +70.2231
45 -9.2925 +69.4308
46 -9.5175 +68.5462
47 -9.6975 +67.7462
48 -9.9000 +66.9462
49 -10.1025 +66.0615
50 -10.3148 +65.2692
51 -10.4850 +64.3769
52 -10.6875 +63.5846
53 -10.9125 +62.7462
54 -11.0925 +61.9077
55 -11.2950 +61.0846
56 -11.4975 +60.2231
57 -11.7000 +59.3923
58 -11.9025 +58.5308
59 -12.1288 +57.6692
60 -12.3075 +56.8385
61 -12.5100 +55.9462
62 -12.7125 +55.1538
63 -12.9150 +54.2615
64 -13.1175 +53.4000
65 -13.2975 +52.5769
66 -13.5000 +51.6846
67 -13.7025 +50.7923
68 -13.9050 +50.0000
69 -14.1075 +49.1077
70 -14.3100 +48.2154
71 -14.5350 +47.3615
72 -14.7150 +46.5308
73 -14.9175 +45.6385
74 -15.1200 +44.7462
75 -15.3225 +43.8538
76 -15.5250 +42.9615
77 -15.7490 +42.0692
78 -15.9075 +41.2769
79 -16.1100 +40.3846
80 -16.3125 +39.4923
81 -16.5150 +38.6000
82 -16.7175 +37.7077
83 -16.9200 +36.8154
84 -17.1225 +35.9231
85 -17.3250 +34.9308
86 -17.5275 +34.0385
87 -17.7300 +33.1462
88 -17.9325 +32.2538
89 -18.1350 +31.3615
90 -18.3405 +30.4692
91 -18.5175 +29.4769
92 -18.7200 +28.5846
93 -18.9225 +27.6923
94 -19.1250 +26.8000
95 -19.3275 +25.8077
96 -19.5300 +24.9154
97 -19.7325 +23.9231
98 -19.9350 +23.0308
99 -20.1375 +22.1385
[edit3] обновление прогресса
некоторые разъяснения для @Ben
как это устроено
цветное уравнение под первым изображением дает радиусr0
сделано из 2-х объединенных90 degree
треугольники (базовая тригонометрия)
красный материал:
y(t)
это моторное положение, и это известноa(t)
также известно состояние IRCзеленый материал:
a0,y0,z0
являются механическими размерами и известны, но не точные, поэтому я измеряю многоa(t)
для разных позицийy(t)
с известной калибровочной трубкойr0
и вычислитьa0,y0,z0
с большей точностью из этогодальнейшее повышение точности
На самом деле мне удалось получить более точное измерениеy1=y0+z0*cos(a0)
от специального калибровочного движения с точностью вокруг0.03 mm
и лучше. Это высота пересечения руки вa0
положение и трубкаy
ось движения. Он измеряется и интерполируется из ситуации, когда рука впервые контактирует, когда трубка идет сверху вниз, но реальное положение должно быть пересчитано по используемому радиусу иa0
... потому что точка контакта не на этой оси ... (еслиr0=0.0
). Это также исключает один цикл аппроксимации из калибровки, потому чтоy1,a0,z0
являются зависимыми и могут быть вычислены друг от друга. Также устранение двойного алиасинга из измерения IRC из-за прерывистого способа измерения иa(t),y(t)
позиции очень помогли повысить точность и стабильность вычислений (на реальной машине). Я не могу достоверно оценить точность прямо сейчас, потому что, анализируя множество измеренных циклов, я обнаружил некоторые механические проблемы на машине, поэтому я жду, пока она отремонтируется. В любом случае калибровка против точности моделирования дляr0=80.03 mm
с учетом обоих подходов и_irc_calib_n=30
сейчас:
; computed simulated |delta|
a0= -6.915840 ; -6.916710 +0.000870 deg
y0=+186.009765 ;+186.012822 +0.003057 mm
y1=+158.342452 ;+158.342187 +0.000264 mm
z0=+228.102470 ;+228.100000 +0.002470 mm
Чем больше калибровкаr0
меньшая точность (из-за более ограниченногоa(t)
диапазон) это вычисляя всеa0,y0,(y1),z1
ничего не измеряется прямо или известно. Это уже приемлемо, но, как я уже писал ранее, нужно проверить машину, когда она будет готова. Просто чтобы завершить, вот как выглядят смоделированные измерения сейчас:
[edit4] см.Как работает поиск приближения