Precisión creciente de la solución de la ecuación trascendental

Tengo una cinemática específica como parte de una máquina más compleja y necesito calcular algunos parámetros físicos que sonmuy duro (más como imposible) medir con la adecuadaexactitud con instrumentos que tengo a mi disposición

[cinemática]

A primera vista es un simple1 brazo de grado de libertad (negro) que puede girarx eje. Tiene un peso para forzarlo a subir siempre hasta que llegue al punto final mecánico (ánguloa0) o algún tubo (azul) con radior0. El centro de rotación del brazo está eny0. El tubo se puede mover a cualquiery(t) altura.

[uso]

Esto se utiliza para medir el radio de un tubo para su posterior procesamiento. El radio se puede calcular (por goniometría básica) que conduce a la ecuación en la parte inferior de la imagen. Las constantesa0,y0,z0 son muy difíciles de medir (está dentro de maquinaria compleja), por lo que la precisión de medición para distancias es mínima0.1 mm y ángulo0.1 deg e incluso eso es cuestionable.

[calibración]

Así que decidí intentar calcular estos parámetros a partir del conjunto de mediciones realizadas por la propia máquina (autocalibración). Entonces tengo un tubo de calibración con radio conocidor0. Todos los parámetros verdes se pueden manejar como constantes. Ahora coloco el tubo a lo largoy eje para cubrir tantos ángulos de brazo como pude. Lamentablemente, el rango es solo sobre20 degrees (para la configuración actual de la máquina) recordando medidasa(t) para preajustey(t) ... comon conjunto de datos de puntos. Esto me da un sistema den Ecuaciones trascendentes. De esto intento / adivino "todas" las posibilidades dea0,y0,z0 recordando la mejor solución (más cercana ar0)

[aproximación de a0, y0, z0]

la aproximación se basa en esta clase de mina:

//---------------------------------------------------------------------------
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
            }
        }
    };
//---------------------------------------------------------------------------

Busca el rango completo de una sola variable por algún paso inicial y luego encuentra el punto de desviación mínima. Después de eso, cambie el rango y el paso para cerrar el área de este punto y aumente recursivamente la precisión.

La solución en sí se ve así:

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

Esto lleva a una solución cercana a los valores medidos, pero dentro de la simulación el resultado aún no es lo suficientemente preciso. Es de 0.1 mm a 0.5 mm dependiendo del número de puntos y el rango del ángulo. Si mido bienz0 e ignorar su aproximación, entonces la precisión se aumenta significativamente dejandoy0 sin error (en simulación) ya0 con error alrededor de 0.3 grados

Q1, ¿cómo puedo mejorar aún más la precisión de la solución?

No puedo aumentar el rango angular. La cantidad de puntos es mejor100 cuanto más, mejor precisión, pero por encima de 150 el resultado es inestable (para algunos radios está completamente apagado). No tengo ni idea de por qué. El número de recursiones arriba6 no tiene mucho efecto

Podría ayudar a ponderar las desviaciones según la distancia angular desde0 degree ? Pero tristementea(t) el rango no necesariamente incluye0 degrees

la precisión deseada es0.01 mm paray0,z0 y0.01 degree paraa0

Q2 ¿hay algo que me haya perdido?

Como aproximaciones erróneamente anidadas o alguna simplificación matemática o enfoque diferente

[notas]

El ángulo debe estar en forma dea(t)+a0 porque es medido por IRC con SW reset (16000 steps/round) Se restablece cuando ena0 posición No cuento las vibraciones y la excentricidad del tubo de calibración ya se han solucionado y mi primer objetivo es hacer que esto funcione en simulación sin ellas. Tuboy(t) puede posicionarse a voluntad y ela(t) La medición se puede hacer a voluntad.

En este momento el proceso de calibración explora puntos a lo largoy eje (movimiento desdea0 abajo). Computación con6 las recursiones toman alrededor35 segundos (así que sea paciente).5 las recursiones toman alrededor22 segundos

[edit1] aquí cómo se realiza la simulación

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] algunos valores

Acabo de darme cuenta de que solo tenía4 recursiones en el código de simulación para que coincida con la precisión del IRC de entrada, entonces debe haber6 recurrencias Después de cambiarlo (también en la edición anterior) aquí hay algunos resultados

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

Entonces la precisión conz0 medido está casi en el rango deseado pero conz0 desconocido el error sigue siendo~10 veces más grande de lo necesario. El aumento de la precisión de la simulación no tiene ningún efecto arriba6 recursiones y tampoco tiene sentido porque los datos de entrada reales tampoco serán más precisos.

Aquí los puntos simulados / medidos para probar con s, ettings simulados anteriormente:

 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] actualización de progreso

algunas aclaraciones para @Ben

cómo funciona

la ecuación coloreada debajo de la primera imagen te da el radior0 está hecho de 2 unidos90 degree triángulos (trigonometría básica)

cosas rojas:

y(t) es la posición del motor y se sabea(t) es el estado IRC también conocido

Cosa verde:

a0,y0,z0 son dimensiones mecánicas y son conocidas pero no precisas, así que mido muchasa(t) para diferentes posiciones dey(t) con tubo de calibración conocidor0 y calcular ela0,y0,z0 con mayor precisión

mejora de precisión adicional

En realidad logré hacerlo más preciso midiendoy1=y0+z0*cos(a0) del movimiento de calibración especial con precisión alrededor0.03 mm y mejor. Es la altura de la intersección entre el brazo ena0 posición y tuboy eje de movimiento. Se mide e interpola a partir de la situación en la que el brazo se pone en contacto por primera vez cuando el tubo sale de arriba hacia abajo, pero la posición real debe calcularse nuevamente con el radioa0... porque el punto de contacto no está en este eje ... (a menos quer0=0.0) Esto también elimina un bucle de aproximación de la calibración porquey1,a0,z0 son dependientes y pueden calcularse entre sí. También elimina el doble alias de la medición de IRC debido a la forma discontinua de medición ya(t),y(t) Las posiciones ayudaron mucho a aumentar la precisión y la estabilidad de cálculo (en una máquina real). No puedo evaluar con precisión la precisión en este momento porque al analizar muchos ciclos medidos encontré algunos problemas mecánicos en la máquina, así que espero hasta que se repare. De todos modos, la precisión de calibración vs. simulación parar0=80.03 mm con la contabilidad de ambos enfoques y_irc_calib_n=30 es ahora:

    ;      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

Cuanto mayor es la calibraciónr0 la menor precisión (debido a más limitadaa(t) rango) esto es calculando todoa0,y0,(y1),z1 nada se mide directamente o se conoce. Esto ya es aceptable, pero como escribí antes, es necesario verificar la máquina cuando esté lista. Solo para completar aquí es cómo se ven las mediciones simuladas ahora:

[edit4] verCómo funciona la búsqueda de aproximación

Respuestas a la pregunta(1)

Su respuesta a la pregunta