Повышение точности решения трансцендентного уравнения

У меня есть конкретная кинематика как часть более сложной машины и нужно вычислить некоторые физические параметры, которые очень тяжелы (более чем невозможно) для измерения с правильной точностью с инструментами, которые у меня есть в моем распоряжении

[кинематика]

введите описание изображения здесь

На первый взгляд это простая 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 точечный dataset. Это дает мне систему n трансцендентных уравнений. Из этого я пытаюсь / предполагаю «все» возможности a0,y0,z0 помня о наилучшем решении (ближе всего к r0 )

[приближение a0, y0, z0]

аппроксимация основана на моем classе:

 //--------------------------------------------------------------------------- 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*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 pi) a-=pi2; if (a0.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 с сбросом SW ( 16000 steps/round ). Он сбрасывается, когда в положении a0 я не учитываю вибрации и эксцентриситет калибровочной трубки, о которых они уже заботятся, и моя первая цель – сделать эту работу без симуляции. Трубку y(t) можно расположить по свободной воле, а измерение a(t) можно выполнить по желанию.

В настоящее время процесс калибровки проверяется вдоль оси y (движение от a0 вниз). Вычисление с 6 recursionми занимает около 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 . Он измеряется и интерполируется из ситуации, когда arm получает первый контакт при прохождении трубки сверху вниз, но реальная позиция должна быть пересчитана с использованием используемого радиуса и 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] посмотреть, как работает поиск приближений

One Solution collect form web for “Повышение точности решения трансцендентного уравнения”

Если я правильно понимаю это, вы пытаетесь вывести (но не измерить ) радиус r0 трубки из измерений для y и a.

Применяя обычное распространение ошибки к вашей формуле для r0, получаем (оценку) ошибку полученного r0. В пределе малых углов (применимо здесь, так как a (t) ограничено 20 gradleусами), это дает грубо (с использованием малоуглового приближения для тригонометрических функций)

dr0 ^ 2 ~ = dy ^ 2 + z0 ^ 2 (pi * da / 180) ^ 2

Таким образом, в случае r0, много меньшего z0, относительная ошибка на r0 всегда намного больше относительных ошибок y и z0 * sin (a). Это уже ясно из вашего графика: измеренные величины слабо зависят от r0.

Другими словами, это не умный способ определить радиус r0. Вы не можете сделать этого фундаментального ограничения (за исключением того, что вы можете увеличить диапазон угла a). Выполнение многих измерений (обычный метод для снижения шума / ошибок), по-видимому, не поможет, поскольку эти измерения не зависят друг от друга из-за внутренней работы вашей машины. Таким образом, единственной помощью были бы более точные измерения.

Чтобы проанализировать ситуацию, я рекомендую сделать графики / фигуры, скажем, выведенного значения r0 как функции y или y как функции a при фиксированном r0.

Interesting Posts

Как закрыть приложение OS X из командной строки с помощью псевдонима, определенного в моем .bash_profile?

Каковы основные правила и идиомы для перегрузки оператора?

Уточнить лицензии Windows Server 2008?

Включить или отключить заставку в зависимости от профиля мощности?

Как разрешить двойную проблему Java Rounding

Побитовое и вместо оператора модуля

Использование Spring MVC Test для модульного тестирования многостраничного запроса POST

Выполнять команды с использованием sudo на удаленном сервере после входа в PuTTY через командный файл

Когда следует использовать double вместо десятичного?

MySQL> Таблица не существует. Но он (или должен)

Поиск точной информации, полученной установщиками

Как добавить функцию submitHandler при использовании jQuery Unobtrusive Validation?

4 ГБ оперативной памяти в MacOSX 10.5, только 3 ГБ в MacOSX 10.6

Настройка пользователя без пароля

Как загрузить org.w3c.dom.Document из XML в строку?

Давайте будем гением компьютера.