Precisão crescente da solução da equação transcendental

Eu tenho uma cinemática específica como parte de uma máquina mais complexa e preciso calcular alguns parâmetros físicos que sãomuito difícil impossível de medir com a devidaprecisão com instrumentos que tenho à minha disposição

[cinemática]

À primeira vista, é uma simples1 braço de grau de liberdade (preto) que pode girar em tornox eixo. Ele tem um peso para forçá-lo a subir sempre até atingir o ponto final mecânico (ânguloa0) ou algum tubo (azul) com raior0. O centro de rotação do braço está emy0. O tubo pode ser movido para qualquery(t) altura.

[uso]

Isso é usado para medir o raio de um tubo para processamento adicional. O raio pode ser calculado (por goniometria básica), o que leva à equação na parte inferior da imagem. As constantesa0,y0,z0 são muito difíceis de medir (é dentro de máquinas complexas), portanto a precisão da medição para distâncias é mínima0.1 mm e ângulo0.1 deg e até isso é questionável.

[calibração]

Por isso, decidi tentar calcular esses parâmetros a partir do conjunto de medições feitas pela própria máquina (calibração automática). Então eu tenho tubo de calibração com raio conhecidor0. Todos os parâmetros verdes podem ser tratados como constantes. Agora eu posiciono o tubo juntoy eixo para cobrir tantos ângulos de braço quanto eu poderia. Infelizmente, o alcance é apenas de cerca de20 degrees (para configuração atual da máquina) lembrar as medidasa(t) para predefiniçãoy(t) ... Comon conjunto de dados de pontos. Isso me dá um sistema den equações transcendentes. A partir disso, tento / acho que "todas" as possibilidades dea0,y0,z0 lembrando a melhor solução (mais próximar0)

[aproximação de a0, y0, z0]

aproximação é baseada nesta minha classe:

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

Ele pesquisa toda a gama de variáveis únicas por algum passo inicial e depois encontra o ponto de desvio mínimo. Depois disso, altere o alcance e vá para fechar a área deste ponto e aumentar recursivamente a precisão.

A solução em si é assim:

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

Isso leva a uma solução próxima aos valores medidos, mas dentro da simulação o resultado ainda não é preciso o suficiente. É de 0,1 mm a 0,5 mm, dependendo do número de pontos e faixa de ângulo. Se eu medir adequadamentez0 e ignorar sua aproximação, a precisão é aumentada significativamente, deixandoy0 sem erro (em simulação) ea0 com erro em torno de 0,3 graus

Q1 como posso melhorar ainda mais a precisão da solução?

Não posso aumentar o alcance angular. O número de pontos é melhor em torno100 quanto mais, melhor a precisão, mas acima de 150 o resultado é instável (para alguns raios, é completamente desativado). Não tenho absolutamente nenhuma idéia do porquê. O número de recursões acima6 não tem muito efeito

Poderia ajudar a ponderar os desvios de acordo com a distância angular da0 degree ? Mas, infelizmentea(t) intervalo não inclui necessariamente0 degrees

precisão desejada é0.01 mm paray0,z0 e0.01 degree paraa0

Q2 há algo que eu perdi?

Como aproximações incorretamente aninhadas ou alguma simplificação matemática ou abordagem diferente

[notas]

O ângulo deve estar na forma dea(t)+a0 porque é medido pelo IRC com reset do SW (16000 steps/round) É redefinido quando ema0 posição Não conto vibrações e excentricidade do tubo de calibração de que eles já foram atendidos e meu primeiro objetivo é fazer com que isso funcione em simulação sem eles. Tuboy(t) pode ser posicionado à vontade ea(t) a medição pode ser feita à vontade.

No momento, os pontos de verificação do processo de calibraçãoy eixo (movimento dea0 baixa). Computação com6 recursões levam em torno de35 segundos (seja paciente).5 recursões levam em torno de22 segundos

[edit1] aqui como a simulação é feita

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

Só percebi que eu tinha apenas4 recursões no código de simulação para corresponder à precisão do IRC de entrada, deve haver6 recursões. Depois de alterá-lo (também na edição anterior), aqui estão alguns 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|

Portanto, a precisão comz0 medido está quase na faixa desejada, mas comz0 desconhecido o erro ainda é~10 vezes maior que o necessário. Aumentar a precisão da simulação não tem efeito acima6 recursões e também não faz sentido, porque os dados reais de entrada também não serão mais precisos.

Aqui, os pontos simulados / medidos para teste com s simulados acima, configurações:

 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 

atualização de progresso

alguns esclarecimentos para @Ben

como funciona

a equação colorida sob a primeira imagem fornece o raior0 é feito de 2 juntou90 degree triângulos (trigonometria básica)

coisas vermelhas:

y(t) é a posição do motor e é conhecidoa(t) é o estado IRC também conhecido

coisas verdes:

a0,y0,z0 são dimensões mecânicas e são conhecidas, mas não precisas, então eu medo muitasa(t) para diferentes posições dey(t) com tubo de calibração conhecidor0 e calcular oa0,y0,z0 com maior precisão

melhoria da precisão adicional

Na verdade, consegui ser mais preciso medindoy1=y0+z0*cos(a0) movimento de calibração especial com precisão0.03 mm e melhor. É a altura da interseção entre o braço ema0 posição e tuboy eixo de movimento. É medido e interpolado da situação em que o braço entra em contato pela primeira vez quando o tubo vem de cima para baixo, mas a posição real deve ser recalculada pelo raio usado ea0... porque o ponto de contato não está neste eixo ... (a menos quer0=0.0) Isso também elimina um loop de aproximação da calibração porquey1,a0,z0 são dependentes e podem ser calculados um do outro. Também remover o duplo aliasing da medição do IRC devido à maneira descontínua de medição ea(t),y(t) posições ajudaram muito a aumentar a precisão e a estabilidade da computação (em máquinas reais). No momento, não posso avaliar com precisão a precisão porque, pela análise de muitos ciclos medidos, encontrei alguns problemas mecânicos na máquina, então espero até que ela seja reparada. De qualquer forma, a calibração vs. precisão da simulação parar0=80.03 mm com contabilidade ambas as abordagens e_irc_calib_n=30 é agora:

    ;      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

Quanto maior a calibraçãor0 menor precisão (devido a limitações dea(t) alcance), isto é, computando tudoa0,y0,(y1),z1 nada é medido diretamente ou conhecido. Isso já é aceitável, mas como escrevi antes, é necessário verificar a máquina quando estiver pronta. Apenas para concluir aqui é como as medições simuladas se parecem agora:

[edit4] verComo a pesquisa por aproximação funciona

questionAnswers(1)

yourAnswerToTheQuestion