提问人:Spektre 提问时间:3/20/2015 最后编辑:Hasan HaghniyaSpektre 更新时间:6/14/2022 访问量:1019
提高超越方程求解的精度
Increasing accuracy of solution of transcendental equation
问:
我有一个特定的运动学作为更复杂机器的一部分,需要计算一些非常困难(更像是不可能)的物理参数,这些参数很难用我掌握的仪器以适当的精度测量
[运动学]
乍一看,它是一个简单的自由度臂(黑色),可以绕轴旋转。它有一个重量来迫使它始终向上移动,直到它击中机械端点(角度)或一些具有半径的管子(蓝色)。手臂旋转中心位于 。管子可以移动到任何高度。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 毫米不等,具体取决于点数和角度范围。如果我正确测量并忽略其近似值,则精度会显着提高,而不会出现误差(在模拟中),误差约为 0.3 度z0
y0
a0
Q1 如何进一步提高解决方案的准确性?
我无法增加角度范围。点数越多越好,精度越好,但高于 150 点,结果不稳定(对于某些半径,它完全关闭)。完全不知道为什么。上面的递归数没有太大影响100
6
可以帮助根据角距离对偏差进行加权?但遗憾的是,范围并不一定包括0 degree
a(t)
0 degrees
所需的精度是 for 和 for0.01 mm
y0,z0
0.01 degree
a0
Q2 我错过了什么吗?
比如错误的嵌套近似值或一些数学简化或不同的方法
[注意事项]
角度必须采用以下形式,因为它是由 IRC 通过 SW 复位 () 测量的。当处于不计算振动和校准管偏心率的位置时,它会被重置,它们已经得到了处理,我的第一个目标是在没有它们的情况下在模拟中完成这项工作。管子可以随意定位,测量可以随意进行。a(t)+a0
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] 一些值
刚刚意识到我在模拟代码中只有递归来匹配输入 IRC 精度,那么必须有递归。更改它后(也在之前的编辑中),这里有一些结果4
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的一些澄清
运作方式
第一张图片下方的彩色方程为您提供了由 2 个连接三角形组成的半径(基本三角函数)r0
90 degree
红色的东西:
y(t)
是电机位置,它是已知的a(t)
IRC状态也为人所知
绿色的东西:
a0,y0,z0
是机械尺寸,是已知的,但不精确,所以我用已知的校准管测量了许多不同位置,并从中计算出更高的精度a(t)
y(t)
r0
a0,y0,z0
精度进一步提高
实际上,我设法通过从特殊校准运动中测量来使其更精确,精度更高。它是手臂就位轴与管运动轴之间的交点高度。它是根据管子从上到下时手臂第一次接触的情况进行测量和插值的,但实际位置必须通过使用的半径和......因为接触点不在这个轴上......(除非)。这也消除了校准中的一个近似环路,因为它们是相互依赖的,并且可以相互计算。此外,由于测量方式和位置的不连续,从IRC的测量中消除双重混叠,有助于提高精度和计算稳定性(在真实机器上)。我现在无法可靠地评估准确性,因为通过对许多测量周期的分析,我发现机器上存在一些机械问题,所以我等到它修复后再进行。无论如何,两种方法的校准与模拟精度,现在是:y1=y0+z0*cos(a0)
0.03 mm
a0
y
a0
r0=0.0
y1,a0,z0
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
[编辑4] 请参阅近似搜索的工作原理
答:
如果我理解正确的话,您正在尝试从 y 和 a 的测量值中推断(但不是测量)管子的半径 r0。
将通常的误差传播应用于 r0 的公式,可以得到(估计)结果 r0 的误差。在小角度的限制下(这里适用,因为 a(t) 被限制为 20 度),这大致给出(使用三角函数的小角度近似)
dr0^2 ~= dy^2 + z0^2 (pi*da/180)^2
因此,在 r0 远小于 z0 的情况下,r0 上的相对误差总是远大于 y 和 z0*sin(a) 的相对误差。从您的图中已经很清楚了:测量的量仅微弱地依赖于 r0。
换句话说,这不是确定半径 r0 的聪明方法。对于这个基本限制,你无能为力(除了你可以增加角度a的范围)。进行许多测量(降低噪声/误差的常用方法)可能无济于事,因为由于机器的内部工作,这些测量不是相互独立的。因此,唯一的帮助是更准确的测量。
为了分析这种情况,我建议将推断出的 r0 作为 y 的函数或 y 作为固定 r0 的函数的绘图/数字。
评论
r0
a0,y0,z0
a0,y0,z0
r0
a(t)
y(t)
a0,y0,z0
r0
评论
a0,y0,z0