Accuratezza crescente della soluzione dell’equazione trascendentale

Ho una cinematica specifica come parte di una macchina più complessa e ho bisogno di calcolare alcuni parametri fisici che sono molto difficili (più simili a quelli impossibili) da misurare con la precisione corretta con gli strumenti che ho a disposizione

[cinematica]

inserisci la descrizione dell'immagine qui

A prima vista è un semplice arm di 1 grado di libertà (nero) che può ruotare attorno all’asse x . Ha un peso da forzare a salire sempre fino a quando non raggiunge il punto finale meccanico (angolo a0 ) o un tubo (blu) con raggio r0 . Il centro di rotazione del arm è a y0 . Il tubo può essere spostato su qualsiasi altezza y(t) .

[uso]

Questo è usato per misurare il raggio di un tubo per ulteriori elaborazioni. Il raggio può essere calcolato (mediante goniometria di base) che porta all’equazione nella parte inferiore dell’immagine. Le costanti a0,y0,z0 sono molto difficili da misurare (è all’interno di un macchinario complesso) quindi l’accuratezza della misurazione per le distanze è di min 0.1 mm e l’angolo di 0.1 deg e anche questo è discutibile.

[calibrazione]

Così ho deciso di provare a calcolare questi parametri dal set di misurazioni effettuate dalla macchina stessa (auto-calibrazione). Quindi ho il tubo di calibrazione con raggio noto r0 . Tutti i parametri verdi possono essere gestiti come costanti. Ora posiziono il tubo lungo l’asse y per coprire il più ansible gli angoli del arm. Purtroppo l’intervallo è solo di circa 20 degrees (per l’impostazione corrente della macchina) ricordando misurato a(t) per il set di dati y(t) … come n punto preimpostato. Questo mi dà un sistema di n equazioni trascendenti. Da questo provo / indovina “tutte” le possibilità di a0,y0,z0 ricordando la soluzione migliore (più vicina a r0 )

[approssimazione di a0, y0, z0]

l’approssimazione è basata su questa mia class:

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

Cerca l’intera gamma della variabile singola di un passo iniziale, quindi trova il punto di deviazione minimo. Dopo di ciò, modifica l’intervallo e il passaggio per chiudere l’area di questo punto e aumentare ricorsivamente la precisione.

La soluzione stessa appare così:

 // (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 pi) a-=pi2; if (a0.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 

Questo porta alla soluzione vicino ai valori misurati ma all’interno della simulazione il risultato non è ancora sufficientemente accurato. È compreso tra 0,1 mm e 0,5 mm a seconda del numero di punti e della gamma di angoli. Se misuro correttamente z0 e ignoro la sua approssimazione, la precisione viene aumentata significativamente lasciando y0 senza errori (in simulazione) e a0 con errore intorno a 0,3 gradi

Q1 come posso migliorare ulteriormente la precisione della soluzione?

Non riesco ad aumentare la gamma angular. Il numero di punti è migliore intorno a 100 maggiore è la precisione, ma sopra 150 il risultato è instabile (per alcuni raggi è completamente spento). Non ho assolutamente idea del perché. Il numero di ricorsioni sopra 6 non ha molto effetto

Potrebbe aiutare a ponderare le deviazioni in base alla distanza angular da 0 degree ? Ma purtroppo a(t) intervallo a(t) non include necessariamente 0 degrees

la precisione desiderata è 0.01 mm per y0,z0 e 0.01 degree per a0

Q2 c’è qualcosa che mi è sfuggito?

Come approssimazioni erroneamente annidate o qualche semplificazione matematica o approccio diverso

[gli appunti]

L’angolo deve essere in forma di a(t)+a0 perché viene misurato da IRC con reset SW ( 16000 steps/round ). Viene resettato quando in posizione0 non contiamo le vibrazioni e l’eccentricità del tubo di calibrazione di cui sono già a conoscenza e il mio primo objective è far funzionare questo lavoro in simulazione senza di loro. Il tubo y(t) può essere posizionato a volontà libera e la misura a(t) può essere effettuata a volontà.

In questo momento i punti di scansione del processo di calibrazione lungo l’asse y (movimento da a0 basso). Il calcolo con 6 ricorsi richiede circa 35 secondi (quindi sii paziente). 5 ricorsi richiedono circa 22 secondi

[edit1] qui come è fatta la simulazione

 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; 

[modifica2] alcuni valori

Ho appena realizzato che avevo solo 4 ricorsioni nel codice di simulazione per far corrispondere l’accuratezza dell’ingresso IRC, quindi ci devono essere 6 ricorsioni. Dopo averlo modificato (anche nella modifica precedente) ecco alcuni risultati

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

Quindi la precisione con z0 misurata è quasi nell’intervallo desiderato, ma con z0 sconosciuto l’errore è ancora ~10 volte più grande di quello necessario. Aumentare la precisione della simulazione non ha alcun effetto oltre le 6 ricorsioni e anche non ha senso perché i dati di input reali non saranno più accurati.

Qui i punti simulati / misurati per testare con le impostazioni simulate sopra:

  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 

[modifica3] aggiornamento progress

qualche chiarimento per @ Ben

come funziona

l’equazione colorata sotto la prima immagine ti dà il raggio r0 è fatto da 2 triangoli uniti a 90 degree (trigonometria di base)

roba rossa:

  • y(t) è la posizione del motore ed è noto
  • a(t) è anche noto lo stato IRC

roba verde:

  • a0,y0,z0 sono dimensioni meccaniche e sono noti ma non precisi quindi misuro molti a(t) per diverse posizioni di y(t) con il tubo di calibrazione noto r0 e calcoliamo a0,y0,z0 con maggiore precisione da esso

ulteriore miglioramento della precisione

In realtà sono riuscito ad ottenere un risultato più preciso misurando y1=y0+z0*cos(a0) da un movimento di calibrazione speciale con una precisione di circa 0.03 mm e migliore. È l’altezza dell’intersezione tra il arm in posizione0 e l’asse del movimento del tubo y . Viene misurato e interpolato dalla situazione in cui il arm ottiene il primo contatto quando il tubo arriva dall’alto verso il basso ma la posizione reale deve essere ricalcasting dal raggio usato e a0 … perché il punto di contatto non è su questo asse … (a meno che r0=0.0 ). Ciò elimina anche un ciclo di approssimazione dalla calibrazione poiché y1,a0,z0 sono dipendenti e possono essere calcolati l’uno dall’altro. Inoltre, rimuovendo il doppio aliasing dalla misurazione dell’IRC a causa della modalità di misurazione discontinua e le posizioni a(t),y(t) aiutato molto ad aumentare la precisione e la stabilità del calcolo (sulla macchina reale). Non riesco ad analizzare attendibilmente la precisione in questo momento perché, analizzando molti cicli misurati, ho riscontrato alcuni problemi meccanici sulla macchina, quindi aspetto che venga riparata. In ogni caso, la precisione della calibrazione rispetto alla simulazione per r0=80.03 mm con la contabilità di entrambi gli approcci e _irc_calib_n=30 ora è:

  ; 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 

Più grande è la calibrazione r0 minore è la precisione (a causa di a(t) intervallo a(t) più limitato) ciò avviene calcolando tutti a0,y0,(y1),z1 nulla viene misurato direttamente o conosciuto. Questo è già accettabile ma, come ho scritto prima, è necessario controllare la macchina quando è pronta. Per essere completo, ecco come appaiono le misure simulate ora:

misure di simulazione

[edit4] vedi Come funziona la ricerca dell’approssimazione

Se ho capito bene, stai cercando di dedurre (ma non misurare ) il raggio r0 del tubo dalle misure per y e a.

Applicando la normale propagazione degli errori alla formula per r0, si ottiene (una stima per) l’errore del r0 risultante. Nel limite dei piccoli angoli (applicabile qui, dal momento che a (t) è limitato a 20 gradi), questo dà approssimativamente (usando l’approssimazione ad angolo piccolo per le funzioni trigonometriche)

dr0 ^ 2 ~ = dy ^ 2 + z0 ^ 2 (pi * da / 180) ^ 2

Quindi, nel caso di r0 molto più piccolo di z0, l’errore relativo su r0 è sempre molto maggiore degli errori relativi di y e z0 * sin (a). Questo è già chiaro dal grafico: le quantità misurate dipendono solo debolmente su r0.

In altre parole, questo non è un modo intelligente per determinare il raggio r0. Non c’è molto che puoi fare per questa limitazione fondamentale (eccetto che puoi aumentare il raggio d’azione a). Effettuare molte misurazioni (il solito metodo per eliminare il rumore / errori) presumibilmente non aiuterà, poiché queste misurazioni non sono indipendenti l’una dall’altra a causa del funzionamento interno della macchina. Quindi, l’unico aiuto sarebbe misurazioni più accurate.

Per analizzare la situazione, raccomando di fare grafici / figure di, ad esempio, la r0 dedotta come funzione di y o di y come funzione di a per fisso r0.