提高超越方程求解的精度

Increasing accuracy of solution of transcendental equation

提问人:Spektre 提问时间:3/20/2015 最后编辑:Hasan HaghniyaSpektre 更新时间:6/14/2022 访问量:1019

问:

我有一个特定的运动学作为更复杂机器的一部分,需要计算一些非常困难(更像是不可能)的物理参数,这些参数很难用我掌握的仪器以适当的精度测量

[运动学]

enter image description here

乍一看,它是一个简单的自由度臂(黑色),可以绕轴旋转。它有一个重量来迫使它始终向上移动,直到它击中机械端点(角度)或一些具有半径的管子(蓝色)。手臂旋转中心位于 。管子可以移动到任何高度。1xa0r0y0y(t)

[用法]

这用于测量管子的半径,以便进一步加工。半径可以计算(通过基本的测角法),从而在图像底部得出方程。常数很难测量(它是在复杂的机械中),因此距离的测量精度是最小和角度,即使这样也是值得怀疑的。a0,y0,z00.1 mm0.1 deg

[校准]

因此,我决定尝试从机器本身完成的一组测量值(自动校准)中计算这些参数。所以我有已知半径的校准管。所有绿色参数都可以作为常量处理。现在,我将管子沿轴放置,以覆盖尽可能多的手臂角度。可悲的是,范围只是关于(对于当前的机器设置)记住为预设测量的......作为点数据集。这给了我超验方程组。由此,我尝试/猜测记住最佳解决方案的“所有”可能性(最接近r0y20 degreesa(t)y(t)nna0,y0,z0r0)

[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 度z0y0a0

Q1 如何进一步提高解决方案的准确性?

我无法增加角度范围。点数越多越好,精度越好,但高于 150 点,结果不稳定(对于某些半径,它完全关闭)。完全不知道为什么。上面的递归数没有太大影响1006

可以帮助根据角距离对偏差进行加权?但遗憾的是,范围并不一定包括0 degreea(t)0 degrees

所需的精度是 for 和 for0.01 mmy0,z00.01 degreea0

Q2 我错过了什么吗?

比如错误的嵌套近似值或一些数学简化或不同的方法

[注意事项]

角度必须采用以下形式,因为它是由 IRC 通过 SW 复位 () 测量的。当处于不计算振动和校准管偏心率的位置时,它会被重置,它们已经得到了处理,我的第一个目标是在没有它们的情况下在模拟中完成这项工作。管子可以随意定位,测量可以随意进行。a(t)+a016000 steps/rounda0y(t)a(t)

现在,校准过程沿轴扫描点(从下移动)。使用递归的计算大约需要几秒钟(所以请耐心等待)。 递归大约需要几秒钟ya0635522

[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 精度,那么必须有递归。更改它后(也在之前的编辑中),这里有一些结果46

                | 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|

因此,测量的精度几乎在期望的范围内,但在未知的情况下,误差仍然比所需的大几倍。提高模拟精度对递归没有影响,也没有意义,因为实际输入数据也不会更准确。z0z0~106

以下是使用上述模拟设置进行测试的模拟/测量点:

 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 个连接三角形组成的半径(基本三角函数)r090 degree

红色的东西:

  • y(t)是电机位置,它是已知的
  • a(t)IRC状态也为人所知

绿色的东西:

  • a0,y0,z0是机械尺寸,是已知的,但不精确,所以我用已知的校准管测量了许多不同位置,并从中计算出更高的精度a(t)y(t)r0a0,y0,z0

精度进一步提高

实际上,我设法通过从特殊校准运动中测量来使其更精确,精度更高。它是手臂就位轴与管运动轴之间的交点高度。它是根据管子从上到下时手臂第一次接触的情况进行测量和插值的,但实际位置必须通过使用的半径和......因为接触点不在这个轴上......(除非)。这也消除了校准中的一个近似环路,因为它们是相互依赖的,并且可以相互计算。此外,由于测量方式和位置的不连续,从IRC的测量中消除双重混叠,有助于提高精度和计算稳定性(在真实机器上)。我现在无法可靠地评估准确性,因为通过对许多测量周期的分析,我发现机器上存在一些机械问题,所以我等到它修复后再进行。无论如何,两种方法的校准与模拟精度,现在是:y1=y0+z0*cos(a0)0.03 mma0ya0r0=0.0y1,a0,z0a(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

校准越大,精度越低(由于范围更有限),这是通过计算所有直接测量或已知的。这已经是可以接受的,但正如我之前所写的,需要在机器准备好时检查机器。为了完成这里,模拟测量现在的样子是这样的:r0a(t)a0,y0,(y1),z1

simulation measurements

[编辑4] 请参阅近似搜索的工作原理

C++ 数学 几何 近似超越 方程

评论

1赞 duffymo 3/20/2015
+1 表示一个非常详细的问题。不知道这是否是家庭作业,但它本身肯定很漂亮。
0赞 Spektre 3/20/2015
@duffymo不,这是我在工作中面临的一个问题......参数会随着时间的推移而变化,并直接在机器上测量它们是疯狂的,所以我寻找其他解决方案,这是最接近我需要的解决方案a0,y0,z0
0赞 Ben 4/8/2015
您能解释一下您的测量值吗?我不明白这是如何测量蓝色部分的半径的。是不是蓝色部分的角度和 y 和 x 质心测量有噪声?这如何给出它的半径?
0赞 Spektre 4/8/2015
@Ben阅读我的问题中的最新更新,已经为您和我的进展更新增加了一些澄清......
2赞 Alnitak 4/8/2015
这听起来像是 math.stackexchange.com

答:

0赞 Walter 4/8/2015 #1

如果我理解正确的话,您正在尝试从 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 的函数的绘图/数字。

评论

1赞 Spektre 4/8/2015
你把它倒过来,计算是可以的(更准确,我需要对半径的依赖就足够了,但是是的,这是用于测量 r0) 问题是在没有实际测量它们的情况下获得机械常数的精确值。因此,我在整个范围内获取已知半径的测量曲线(最后一张图像中的每条红色曲线都是单个半径的测量曲线),然后我发现产生与测量曲线接近的曲线,然后使用结果而不是不准确测量的机械常数。我需要以如此精确的精度进行测量是不可能的......r0a0,y0,z0a0,y0,z0
1赞 Walter 4/8/2015
从不测量 r0。把这个概念从你的脑海中抹去。
0赞 Ben 4/8/2015
好的,对于 y0,您可以设置 r0=0,然后绘制 a(t) 与 y(t) 并查找极值。至于精度,您可以考虑使用非常大的管子进行校准,因为 da/dy 变得非常大。
1赞 Spektre 4/8/2015
在校准过程中,使用已知的测量半径,可以足够精确地测量...在正常操作期间,半径由和 ...它已实现并正常工作,因此请不要尝试我的说服(如果不是真的,机器将无法正常运行)。问题是机械常数会随着时间而变化,物理测量它们是疯狂的(这意味着拆卸机器和使用非常昂贵的测量设备,这在实验室之外是不可能的)这个问题是关于校准而不是测量......r0a(t)y(t)a0,y0,z0r0
0赞 Spektre 4/8/2015
这种方法已经比测量本身更精确......正如我在上次更新中所写的那样,它已经是可以接受的,但如果它可以得到更多的提升,我会很高兴......