2017-01-23 5 views
0

Ich versuche, den Winkel zwischen einigen Vektoren in Python2.7 zu berechnen. Ich verwende die folgende Identität, um den Winkel zu finden.übergibt einen Float an eine Funktion mit einer begrenzten Domäne

theta = acos (v w/| v || w |.)

für eine bestimmte Instanz ist mein Code:

v = numpy.array([1.0, 1.0, 1.0]) 
w = numpy.array([1.0, 1.0, 1.0]) 
a = numpy.dot(v, w)/(numpy.linalg.norm(v) * numpy.linalg.norm(w)) 
theta = math.acos(a) 

Als ich das laufen bekomme ich die Fehler ValueError: math domain error

Ich nehme an, dies ist, weil Acos nur auf der Domäne [-1,1] definiert ist und mein Wert 'a' ist ein Float, der sehr nahe bei 1 ist, aber tatsächlich ein bisschen größer. Ich kann dies mit print Decimal(a) bestätigen und ich bekomme 1,0000000000000002220446 ...

Was ist der beste Weg, um dieses Problem zu umgehen?

Alles, was ich mir vorstellen kann, ist zu überprüfen, ob Werte von 'a' größer als 1 (oder kleiner als -1) sind und sie genau auf 1 runden. Das scheint eine klebrige Arbeit zu sein. Gibt es einen besseren/konventionellen Weg, um dieses Problem zu lösen?

Antwort

0

numpy.clip: verwendet wurde, in Angles between two n-dimensional vectors in Python

numpy.nan_to_num: sieht auch wie ein guter Patch, wenn Sie neu ordnen, um die Mathematik

und könnte mit Ihrem Code mit meiner theta = atan2(b,a) Formulierung modifiziert verwendet werden 1 + eps Probleme mit acos zu vermeiden (das war mein mein 1. Durchlauf mit: b = np.nan_to_num(np.sqrt(1 - a ** 2)))

Aber ich habe Probleme mit dem nahen universellen Gebrauch des Punktproduktes allein mit acos für den Winkel zwischen dem Vektoren Problem, insbesondere in 2 und 3 D wo wir ein np.cross Produkt

Ich bevorzuge das Kreuzprodukt b „sine“ Term gebildet wird, sowohl den nicht-normieren a „Cosinus“ Term vorbei und meine b zu atan2 :

import numpy as np 
v = np.array([1.0, 1.0, 1.0]) 
w = np.array([1.0, 1.0, 1.0]) 

a = np.dot(v, w) 
c = np.cross(v, w) 
b = np.sqrt(np.dot(c,c)) 

theta = np.arctan2(b,a) 

die atan2(b, a) Formulierung keine Ausnahme mit 1 + eps Schwimmer Fehler von linalg.norm Gleitkomma-Toleranz werfen, wenn Sie die normierter args verwenden - und atan2 braucht nicht normierter args sowieso

Ich glaube, es mit dem Kreuzprodukt b Begriff und atan2 geben eine bessere Genauigkeit insgesamt als nur anhand der Informationen in der a Skalarprodukt „Cosinus“ Begriff mit acos

bearbeiten mehr numerisch robust ist: (ein bisschen ein Math explaination, nicht gleich a, b, c, wie in dem obigen Code, etwas Vektor Mathematik in getippten Text gemischt, da Mathjax scheint nicht auf diesem Forum)

ein * b aktiviert sein = | a || b | cos (w )

c = ax b = | a || b | sin (w) c_unit_vector

sqrt (c * c) = | a || b | sin (w) seit c_unit_vector * c_unit_vector = 1

, so dass wir mit atan (am Ende | a || b | sin (w) | a || b | cos (w)) und die | a || b | Ausgleichen in der Verhältnisrechnung intern zu Atan

+0

Ich habe diese tan Lösung implementiert. Es funktioniert gut (danke), aber wie funktioniert es? Es sieht so aus, als würde es den Winkel zwischen der Projektion eines Vektors auf den anderen und einer Orthogonalen nehmen. – Jemma

Verwandte Themen