提高超越方程解的精度

时间:2015-03-20 12:44:16

标签: c++ math geometry approximation transcendental-equation

我有一个特定的运动学作为一个更复杂的机器的一部分,需要计算一些非常坚硬(更像是不可能)的物理参数,以适当的准确度来衡量使用我可以使用的乐器

[运动学]

enter image description here

首先看它是一个简单的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的{​​{1}}和y0,z0的{​​{1}}所需的准确度为<{1}}

Q2有什么我错过了吗?

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

[注释]

角度必须采用0.01 degree的形式,因为它是由IRC通过SW重置(a0)测量的。它在a(t)+a0位置时被重置,我不计算振动和校准管偏心,它们已经被照顾,我的第一个目标是在没有它们的情况下进行模拟。管16000 steps/round可以自由定位,a0测量可以随意进行。

现在,校准过程沿y(t)轴扫描点(从a(t)向下移动)。使用y递归进行计算大约需要a0秒(因此请耐心等待)。 6递归大约35

[edit1]此处模拟的完成方式

5

[edit2]一些值

刚才意识到我在模拟代码中只有22递归以匹配输入IRC的准确性,那么必须有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; 递归。更改后(也在之前的编辑中)这里有一些结果

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

[edit3]进度更新

@Ben的一些澄清

如何运作

第一张图片下方的彩色等式为您提供半径6,它由2个连接的 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 三角形组成(基本三角法)

红色的东西:

  • r0是运动位置,已知
  • 90 degree是IRC州也知道

绿色的东西:

  • y(t)是机械尺寸且已知但不准确,因此我使用已知校准管a(t)a0,y0,z0的不同位置测量了多个a(t)并计算{{1}它具有更高的精度

进一步提高准确度

我实际上通过在y(t)左右精确测量来自特殊校准运动的r0来设法让它更精确。它是a0,y0,z0位置的臂与管y1=y0+z0*cos(a0)运动轴之间的交叉高度。当管子从上到下进行第一次接触但是实际位置必须由使用的半径和0.03 mm重新计算时,它是根据情况进行测量和插补的...因为接触点不在此轴上... (除非a0)。这也消除了校准的一个近似循环,因为y是相互依赖的并且可以相互计算。同时,由于不连续的测量方式和a0位置,从IRC测量中消除双混叠有助于提高精度和计算稳定性(在实际机器上)。我现在无法可靠地评估准确性,因为通过对许多测量周期的分析,我在机器上发现了一些机械问题,所以我等到它被修复了。无论如何,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 没有直接测量或已知的。这已经可以接受,但正如我之前所写,需要在准备好时检查机器。这里要完成模拟测量的现状:

simulation measurements

[edit4]请参阅How approximation search works

1 个答案:

答案 0 :(得分:0)

如果我理解正确,你会尝试从y和a的测量结果推断(但 测量)管的半径r0。 / p>

将通常的误差传播应用于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的函数。