rhöhung der Genauigkeit der Lösung der transzendentalen Gleichu
Ich habe eine bestimmte Kinematik als Teil einer komplexeren Maschine und muss einige physikalische Parameter berechnen, diesehr schwe (eher unmöglich) zu messen mit richtigenRichtigkei mit Instrumenten, die ich zur Verfügung habe
[Kinematik
Auf den ersten Blick ist es ein einfaches1
Freiheitsgrad Arm (schwarz), der sich drehen kannx
Achse. Es hat ein Gewicht, das es zwingt, immer nach oben zu fahren, bis es den mechanischen Endpunkt erreicht (Winkela0
) oder eine Röhre (blau) mit Radiusr0
. Das Rotationszentrum des Arms liegt beiy0
. Die Röhre kann zu jedem @ verschoben werdy(t)
height.
[Verwendung
Dies wird verwendet, um den Radius eines Rohrs für die weitere Verarbeitung zu messen. Der Radius kann (durch grundlegende Goniometrie) berechnet werden, was zu einer Gleichung im unteren Teil des Bildes führt. Die Konstantena0,y0,z0
sind sehr schwer zu messen (es befindet sich in komplexen Maschinen), daher ist die Messgenauigkeit für Entfernungen min0.1 mm
und Winkel0.1 deg
und auch das ist fraglich.
[Kalibrierung
So habe ich mich entschlossen, diese Parameter aus einer Reihe von Messungen zu berechnen, die von der Maschine selbst durchgeführt wurden (automatische Kalibrierung). Ich habe also ein Kalibrierrohr mit bekanntem Radiusr0
. Alle grünen Parameter können als Konstanten behandelt werden. Jetzt positioniere ich die Röhre entlangy
Achse, um so viele Winkel des Arms abzudecken, wie ich konnte. Leider geht es in der Reichweite nur um20 degrees
(für das aktuelle Maschinen-Setup) Speichern des gemessenena(t)
für Presety(t)
... wien
point-Datensatz. Das gibt mir System vonn
transzendente Gleichungen. Daraus versuche ich "alle" Möglichkeiten vona0,y0,z0
Erinnerung an die beste Lösung (am nächsten anr0
)
[Approximation von a0, y0, z0]
approximation basiert auf meiner Klasse:
//---------------------------------------------------------------------------
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
}
}
};
//---------------------------------------------------------------------------
Es durchsucht den gesamten Bereich einer einzelnen Variablen nach einem Anfangsschritt und ermittelt dann den minimalen Abweichungspunkt. Ändern Sie danach den Bereich und den Schritt, um den Bereich dieses Punkts zu schließen und die Genauigkeit rekursiv zu erhöhen.
Die Lösung selbst sieht folgendermaßen aus:
// (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
Dies führt zu einer Lösung in der Nähe der gemessenen Werte, aber in der Simulation ist das Ergebnis immer noch nicht genau genug. Sie liegt je nach Punktzahl und Winkelbereich zwischen 0,1 mm und 0,5 mm. Wenn ich richtig messez0
und ignorieren Sie seine Annäherung, dann wird die Präzision deutlich erhöht und @ verlassy0
ohne Fehler (in der Simulation) unda0
mit einem Fehler um 0,3 Grad
F1 Wie kann ich die Genauigkeit der Lösung weiter verbessern?
Ich kann den Winkelbereich nicht vergrößern. Die Anzahl der Punkte ist am besten um100
je mehr desto besser die Genauigkeit, aber über 150 ist das Ergebnis instabil (für einige Radien ist es völlig aus). Habe absolut keine Ahnung warum. Die Rekursionsnummer über6
hat nicht viel Wirkung
Könnte helfen, die Abweichungen nach Winkelabstand von @ zu gewicht0 degree
? Aber traurigerweisea(t)
range beinhaltet nicht unbedingt0 degrees
Gewünschte Genauigkeit ist0.01 mm
zumy0,z0
und0.01 degree
zuma0
Q2 habe ich etwas verpasst?
Wie falsch verschachtelte Näherungen oder eine mathematische Vereinfachung oder einen anderen Ansatz
[Anmerkungen
Der Winkel muss in Form von @ sea(t)+a0
weil es von IRC mit SW-Reset gemessen wird 16000 steps/round
). Es wird zurückgesetzt, wenn ina0
position Ich zähle nicht die Vibrationen und die Exzentrizität des Kalibrierrohrs, für die sie bereits gesorgt haben, und mein erstes Ziel ist es, diese Arbeit in der Simulation ohne sie zu machen. Tubey(t)
kann frei positioniert werden und dasa(t)
Messung kann nach Belieben durchgeführt werden.
Rechts jetzt scannt der Kalibrierungsprozess die Punkte entlangy
Achse (Bewegung vona0
Nieder). Berechnung mit6
Rekursionen nehmen um35
Sekunden (also etwas Geduld).5
Rekursionen nehmen um22
Sekunden
[edit1] hier wie die simulation gemacht wird
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] einige Werte
Nur realisiert, dass ich nur @ hat4
Rekursionen im Simulationscode, die mit der IRC-Genauigkeit der Eingabe übereinstimmen, dann muss es @ geb6
Rekursionen. Nach der Änderung (auch in der vorherigen Bearbeitung) sind hier einige Ergebnisse
| 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|
So die Genauigkeit mitz0
gemessen ist fast im gewünschten Bereich, aber mitz0
unbekannt der Fehler ist immer noch~10
mal größer als nötig. Die Erhöhung der Simulationsgenauigkeit hat keine Auswirkungen über6
Rekursionen und auch keinen Sinn, weil echte Eingabedaten auch nicht genauer sein werden.
Hier sind die simulierten / gemessenen Punkte zum Testen mit den oben simulierten Einstellungen:
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] Fortschrittsaktualisierung
einige Klarstellungen für @ Ben
wie es funktionier
die farbige Gleichung unter dem ersten Bild gibt Ihnen den Radiusr0
es besteht aus 2 verbundenen90 degree
Dreiecke (grundlegende Trigonometrie)
red stuff:
y(t)
ist Motorposition und es ist bekannt,a(t)
ist der IRC-Status auch bekanntGrünzeug
a0,y0,z0
sind mechanische Maße und sind bekannt, aber nicht genau, deshalb messe ich vielea(t)
für verschiedene Positionen vony(t)
mit bekanntem Kalibrierröhrchenr0
und berechne dasa0,y0,z0
mit höherer Präzision darausweitere Genauigkeitsverbesserung
Ich habe es tatsächlich geschafft, es durch Messen genauer zu macheny1=y0+z0*cos(a0)
von speziellen Kalibrierungsbewegung mit Präzision um0.03 mm
und besser. Es ist die Schnitthöhe zwischen Arm ina0
Position und Tubey
Bewegungsachse. Es wird gemessen und aus der Situation interpoliert, in der der Arm das erste Mal berührt wird, wenn das Rohr von oben nach unten kommt. Die tatsächliche Position muss jedoch mit dem verwendeten Radius und @ neu berechnet werdea0
... weil der Kontaktpunkt nicht auf dieser Achse liegt ... (außerr0=0.0
). Dies eliminiert auch eine Approximationsschleife aus der Kalibrierung, day1,a0,z0
sind abhängig und können voneinander berechnet werden. Entfernen von Double Aliasing bei der Messung von IRC aufgrund von diskontinuierlichen Messmethoden unda(t),y(t)
-Positionen haben wesentlich zur Erhöhung der Präzision und der Rechenstabilität (auf realen Maschinen) beigetragen. Ich kann die Genauigkeit momentan nicht zuverlässig beurteilen, da ich bei der Analyse vieler gemessener Zyklen einige mechanische Probleme an der Maschine festgestellt habe und warte, bis sie repariert ist. Wie auch immer, die Kalibrierung vs. Simulationsgenauigkeit fürr0=80.03 mm
mit Buchhaltung beide Ansätze und_irc_calib_n=30
ist jetzt
; 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
Je größer die Kalibrierungr0
die geringere Genauigkeit (aufgrund begrenztera(t)
range) Dies erfolgt durch Berechnung von alla0,y0,(y1),z1
nichts wird direkt gemessen oder ist bekannt. Dies ist bereits akzeptabel, aber wie ich bereits geschrieben habe, muss die Maschine überprüft werden, wenn sie bereit ist. Um hier vollständig zu sein, sehen simulierte Messungen jetzt so aus:
[edit4] sieheWie die Annäherungssuche funktioniert