Partage
  • Partager sur Facebook
  • Partager sur Twitter

détermination du nord magnétique par son azimut

implémenté en kotlin

Sujet résolu
    27 août 2024 à 16:17:09

    Bonjour à tous!

    J'essaie d'implémenter en kotlin sous android une fonction qui, lorsque je prends l'étoile polaire en photo, détermine la position géographique du nord magnétique grâce à son azimut, relevé au moyen de l’accéléromètre de l'appareil.

    Pour ce faire j'utilise la fonction suivante:

    private fun takePhoto(acc: Accelerometer) {
            val position = Sphere.getcartesian(longitude, latitude)
            val plane = computePlaneFromVectorAndPoint(position)
    
            var north = ColumnVector(3)
            north.set(0, 0.0)
            north.set(1, 0.0)
            north.set(2, 1.0)
            val q = Quaternion(north)
            q.create_rotate_vector(position, acc.z + PI / 2)
            q.rotate()
            north = q.value.getSubvector(1,4)
            north = projected(north, plane).minus(position)
            val v = north.crossProduct(plane.getSubvector(0,3))
            val azimuthPlane = ColumnVector(4)
            azimuthPlane[0] = v[0]
            azimuthPlane[1] = v[1]
            azimuthPlane[2] = v[2]
            azimuthPlane[3] = -v.dotProduct(position)
            north = projected(Sphere.getcartesian(-110.8, 81.3), azimuthPlane).normalize()
            val (theta, phi) = Sphere.getpolar(north, true)
            model.modifyCoordinatesPoleLocation(theta * 180 / PI, phi * 180 / PI)
            cameraProvider?.unbindAll()
        }



    Que je m' empresse de traduire...

    Afin d’obtenir les coordonnées cartésiennes du lieu d’observation, j’utilise la fonction « getcartesian » de la classe « Sphere » de ma confection…

    Sa définition est la suivante :

    fun getcartesian(longitude: Double, latitude: Double): ColumnVector {
        val cartesian = ColumnVector(3)
        cartesian[0] = cos(latitude) * cos(longitude)
        cartesian[1] = sin(longitude) * cos(latitude)
        cartesian[2] = sin(latitude)
    
        return cartesian
    }

    elle prend donc la longitude et la latitude du lieu et retourne un point 3D sur la sphère.

    Je l’utilise de la sorte :

    val position = Sphere.getcartesian(longitude, latitude)

    j’obtiens ainsi mon point position représentant les coordonnées géographiques du lieu d’observation.

    Ensuite il me faut déterminer l’équation du plan tangent à la sphère au lieu d’observation…

    Pour ce faire, j’utilise la fonction suivante de ma confection :

    fun computePlaneFromVectorAndPoint(vector: ColumnVector): ColumnVector {
        val plane = ColumnVector(4)
        plane.set(0, vector[0])
        plane.set(1, vector[1])
        plane.set(2, vector[2])
        val d = -vector.dotProduct(vector)
        plane.set(3, d)
    
        return plane
    }

    Cette simple fonction calcul l’équation du plan en question. Remarquez que j’utilise la fonction « dotProduct » qui calcule le produit scalaire.

    Je l’utilise de la sorte :

    val plane = computePlaneFromVectorAndPoint(position)

    Ainsi j’obtiens « plane », un plan tangent à la sphère au point « position ».

    Puis je définis les coordonnées du nord géographique. C' est un vecteur colonne qui est positif sur l’axe des Z:

    var north = ColumnVector(3)
    north.set(0, 0.0)
    north.set(1, 0.0)
    north.set(2, 1.0)

    Ensuite je définis un quaternion à partir de mon point « north », car il doit subir une rotation de l’azimut entre le nord magnétique et le véritable nord autour du vecteur « position » ;

    val q = Quaternion(north)
    q.create_rotate_vector(position, acc.z + PI / 2)
    q.rotate()

    notez que j’ajoute PI / 2 à l’angle de l’azimut ( acc.z ) car mon application nécessite que le téléphone soit penché sur le côté, en mode paysage.

    Ensuite je prends le sous-vecteur du quaternion précédemment calculé pour qu’il ne reste que les coordonnées cartésiennes du point « north ». puis je projette le point obtenu sur le plan précédemment calculé… Ensuite je crée un vecteur à partir du point « north » obtenu d’origine « position », afin d’assigner le vecteur résultant à north :

    north = q.value.getSubvector(1,4)
    north = projected(north, plane).minus(position)

    voici l’implémentation de ma fonction « projected » :

    fun projected(point: ColumnVector, plane: ColumnVector): ColumnVector {
        val subplane = plane.getSubvector(0, 3)
        val k = -(subplane.dotProduct(point) + plane[3]) / subplane.frobeniusNormSquared()
        val cardinal = ColumnVector(3)
        cardinal.set(0, subplane[0].times(k) + point[0])
        cardinal.set(1, subplane[1].times(k) + point[1])
        cardinal.set(2, subplane[2].times(k) + point[2])
    
        return cardinal
    }

    Au final, j’obtiens le vecteur « north » ( sur le plan « plane » tangent à la sphère et passant par position ) qui est dévié de l’azimut entre le nord magnétique et le nord véritable.

    Pour créer le plan passant par l'azimut, il faut obtenir un vecteur qui soit à la fois normal à « north » et au vecteur générateur de « plane » ( plan passant par « position » et tangent à la sphère ). Pour ce faire j’utilise le produit vectoriel du vecteur « north » avec le vecteur générateur de « plane », puis j’assigne le résultat au plan « azimuthPlane »:

    val azimuthPlane = ColumnVector(4)
            azimuthPlane[0] = v[0]
            azimuthPlane[1] = v[1]
            azimuthPlane[2] = v[2]
            azimuthPlane[3] = -v.dotProduct(position)



    Ici j’utilise la fonction « crossProduct » issue d’une librairie importée...

    Ensuite je calcule le point du cercle formé par « azimuthPlane » et la sphère le plus proche des coordonnées du nord magnétique relevées par les observatoires.

    le nord magnétique que nous calculons se situe sur le point formé par le projeté du nord magnétique, issu de relevé par des observatoires, sur le plan « azimuthPlane ». Il faut donc le normaliser afin qu’il soit sur la sphère. Voici la fonction utilisée :

    north = projected(Sphere.getcartesian(-110.8, 81.3), azimuthPlane).normalize()

    Sachant que les relevés du nord magnétique le situent à la longitude 110,8 W et la latitude 81,3 N.

    Ensuite j’utilise la fonction « getpolar » de ma classe « Sphere » pour trouver les coordonnées géographiques du point « north » ( nord magnétique corrigé ) :

    val (longitude, latitude) = Sphere.getpolar(north, true)

    la fonction « getpolar » est définie telle que ce qui suit :

    fun getpolar(cartesian: ColumnVector, equatorial: Boolean): List<Double> {
        var r = 0.0
        r = sqrt(cartesian[0].pow(2) + cartesian[1].pow(2) + cartesian[2].pow(2))
        var latitude = acos(cartesian[2] / r)
        var longitude = atan2(cartesian[1], cartesian[0])
        if (equatorial)
            latitude = PI / 2.0 - latitude
    
        return listOf(longitude, latitude)
    }

    et voilà on a fait le tour... C'est juste de la géométrie!

    Mon programme me donne à l'heure actuelle des coordonnées complèrement erronées.

    J'ai bô chercher l'erreur je ne la trouve pas.

    Si qq'un a la gentillesse de corriger mes mathématiques ce sera avec joie!

    En attendant je vais dormir un peu... pour changer!

    merci à tous!











    -
    Edité par amaurybenard 2 septembre 2024 à 17:37:22

    • Partager sur Facebook
    • Partager sur Twitter
      28 août 2024 à 12:58:41

      Bonjour ! Il est possible que je puisse t'aider, mais je trouve que ce que tu fais est drôlement compliqué (et j'ai tout oublié concernant les quaternions).

      Surtout, j'ai besoin d'une précision.

      > J'essaie d'implémenter en kotlin sous android une fonction qui, lorsque je prends l'étoile polaire en photo, détermine la position géographique du nord magnétique

      Qu'appelles-tu la position géographique du nord ? Le nord est une direction et n'a donc pas de position (c'est un vecteur, pas un point). Et une position géographique, c'est quoi ? Géocentrique (par rapport au centre de la Terre) ?

      En fait, que doit retourner la fonction ? Un triplet de nombres ? Qui représentent quoi ?

      Peux-tu donner un exemple (ficitif) de résultat ?

      > Afin d’obtenir les coordonnées cartésiennes du lieu d’observation, j’utilise la fonction « getcartesian » de la classe « Sphere » de ma confection… Sa définition est la suivante :

      C'est quoi, c'est coordonnées ? Ce ne sont pas des coordonnées géocentriques puisque tu ne fais pas intervenir le rayon terrestre. Est-ce que les longitude et latitude doivent être données en radians, et est-ce que ça ne pourrait pas être une cause d'erreur ?

      > elle prend donc la longitude et la latitude du lieu et retourne un point 3D sur la sphère.

      Elle retourne les coordonnées cartésiennes d'un point sur la sphère unité, j'ai l'impression que ça représente une direction.

      Est-ce que tu suis un algorithme précis ? J'ai l'impression qu'il est compliqué...

      Mais bon, puisque je ne sais pas ce qu'on cherche à calculer, c'est normal que je n'arrive pas à suivre.

      Conseil : quand un calcul se fait en plusieurs étapes, vérifie les résultats de chaque étape, pas seulement de la dernière. Si par exemple le souci vient des unités, tu le verras dès la première étape. Si tu as fait ces vérifications, dis-nous les conclusions.

      -
      Edité par robun 28 août 2024 à 13:14:01

      • Partager sur Facebook
      • Partager sur Twitter
        28 août 2024 à 15:00:58

        Ce qui m'embête est le fait de chercher le nord "magnétique" et non le nord "géographique"
        • Partager sur Facebook
        • Partager sur Twitter

        Le Tout est souvent plus grand que la somme de ses parties.

          28 août 2024 à 16:27:34

          Ça ne me choque pas : il connaît le nord géographique grâce à la photo de l'étoile Polaire, et apparemment son accéléromètre est sensible au nord magnétique (je n'y connais rien, je suppose que ça marche comme une boussole). Peut-être qu'il s'intéresse à l'écart entre les deux ?

          -
          Edité par robun 28 août 2024 à 16:27:53

          • Partager sur Facebook
          • Partager sur Twitter
            2 septembre 2024 à 14:28:19

            Tout d’abord, merci de prendre mon problème en considération…
            @robun ,Je vois que tu ne comprends pas l’utilité de ma fonction…
            je vais répondre dans l’ordre à tes questions.
             
            Tout d’abord, j’ai besoin de la position géographique du nord magnétique ( qui est distinct du véritable nord ) afin de corriger la position des astres, dans ma carte du ciel, de son azimut.
            Si je parle de coordonnées géographiques, c’est que je souhaite en réalité une longitude et une latitude ( donc dans le référentiel terrestre ).
            Donc ma fonction est censée me retourner une paire d’angles ( la latitude phi et la longitude theta ) que je convertis en degrés à la ligne 22 :
            model.modifyCoordinatesPoleLocation(theta * 180 / PI, phi * 180 / PI)


             
            > Peux-tu donner un exemple (ficitif) de résultat ?
            Comme je le disais dans mon premier message, les coordonnées du nord magnétique en 2024 sont :
            latitude : 81,3°N
            longitude :110,8°W
            Ainsi, ma fonction est censée me donner ( avec un offset dû à la prise de la photo – tremblements etc ) :
            latitude:82,5°
            longitude :-108°
             
            >> Afin d’obtenir les coordonnées cartésiennes du lieu d’observation, j’utilise la fonction « getcartesian » de la classe « Sphere » de ma confection… Sa définition est la suivante :
            > C'est quoi, c'est coordonnées ? Ce ne sont pas des coordonnées géocentriques puisque tu ne fais pas intervenir le rayon terrestre.
             
            Ce sont les coordonnées sur une Terre fictive de rayon 1. Inutile de faire intervenir le rayon terrestre pour mes calculs… Ils n’utilisent que les angles.
             
            >Est-ce que les longitude et latitude doivent être données en radians, et est-ce que ça ne pourrait pas être une cause d'erreur ?
             
            Non, la latitude et la longitude de la fonction getcartesian sont bien en radians… pas de problème ici.
             
            >> elle prend donc la longitude et la latitude du lieu et retourne un point 3D sur la sphère.
            Elle retourne les coordonnées cartésiennes d'un point sur la sphère unité, j'ai l'impression que ça représente une direction.
             
            Point ou direction, c’est du même ordre… elle me renvoie un vecteur position ColumnVector(3) sur une sphère ( la terre de rayon 1 ) dont le centre est l’origine du repère.
             
            >Est-ce que tu suis un algorithme précis ? J'ai l'impression qu'il est compliqué..
             
            C’est un algo de ma conception qui ne fait qu’utiliser des propriétés géométriques dans l’espace des plans, des vecteurs et des sphères.
            >Conseil : quand un calcul se fait en plusieurs étapes, vérifie les résultats de chaque étape, pas seulement de la dernière. Si par exemple le souci vient des unités, tu le verras dès la première étape. Si tu as fait ces vérifications, dis-nous les conclusions.
             
            Je ne peux pas vérifier les résultats intermédiaires… Je ne sais pas ce qu’ils devraient être. Je ne peux que me fier au résultat final de la fonction, sachant que le résultat doit correspondre approximativement à la position géographique du nord magnétique.
            Quant aux unités, je n’ai rien relevé de choquant en me relisant. ( PS: lire le PS )
             
            > Ça ne me choque pas : il connaît le nord géographique grâce à la photo de l'étoile Polaire, et apparemment son accéléromètre est sensible au nord magnétique (je n'y connais rien, je suppose que ça marche comme une boussole). Peut-être qu'il s'intéresse à l'écart entre les deux ?
             
            Ce n'est pas du tout ce que cherche à faire… l’écart en azimut entre le nord magnétique et le nord véritable est une donnée de ma fonction… il est donné à la ligne 10 sous le nom « acc.z ».
             
            Mon programme, je le répète, consiste à calculer la position géographique du nord magnétique à partir de l’azimut relevé depuis mon android.
             
            La question que j’attendais était plutôt :
            « Pourquoi tu calcules des coordonnées à l’aide d’une fonction qui utilise ces mêmes coordonnées ? »
             
            En effet, je vous signale qu’à la ligne 20 de la fonction, j’utilise ces mêmes coordonnées que je cherche en réalité…
             
            north = projected(Sphere.getcartesian(-110.8, 81.3), azimuthPlane).normalize()



             
            En fait, j’utilise ces coordonnées pour trouver le point que s’en rapproche le plus ! Ensuite mon programme conservera en mémoire le relevé effectué à l’aide de la caméra, jusqu’au prochain relevé où j’utiliserai le relevé précédent pour calibrer la position du nord magnétique.
             
            Voilà, j’espère que c’est un peu plus clair...


            PS: j'y suis arrivé!!! C'était en effet au niveau de ma fonction getcartesian où j'utilisais les degrés au lieu de radians!

            Merci à toi @robun ! C'est fantastique! Lorsque j'aurai terminé mon projet je le mettrai sur Github pour en faire profiter la galerie...

            Merci encore une fois! Les erreurs d'inattention...

            -
            Edité par amaurybenard 2 septembre 2024 à 18:13:18

            • Partager sur Facebook
            • Partager sur Twitter
              7 septembre 2024 à 22:26:46

              Merci pour les précisions, je comprends beaucoup mieux, en effet ce n'était pas du tout ce que je croyais...

              amaurybenard a écrit:

              Tout d’abord, j’ai besoin de la position géographique du nord magnétique ( qui est distinct du véritable nord ) afin de corriger la position des astres, dans ma carte du ciel, de son azimut.

              Tu as besoin de la position géographique (sur la Terre) du pôle nord magnétique ! Désolé mais ça change tout, je n'avais pas deviné que tu parlais de ça (comme tu as fait une photo du ciel, j'imaginais la direction du nord, celle approximativement donnée par une boussole).

              Pôle nord magnétique qui est distinct du pôle nord géographique (celui défini par l'axe de la Terre), OK.

              Et c'est là que j'ai compris : tu veux établir une carte du ciel, donc tu as besoin de la direction du nord, mais ce n'est pas celle donnée par la boussole, il y a une correction à faire. (C'est pas du tout ça ? Ah, zut ;) )

              (Pour info, une de mes activité favorites de programmeur du dimanche est d'écrire des programmes de carte du ciel. Il y a quelques années, j'avais écrit un « simulateur de pointage d'astres » pour apprendre à viser de mémoire les objets du ciel. Mais je n'ai jamais géré le problème du pôle nord magnétique, je trouve ça original.)

              amaurybenard a écrit:

              PS: j'y suis arrivé!!! C'était en effet au niveau de ma fonction getcartesian où j'utilisais les degrés au lieu de radians!

              Merci à toi @robun ! C'est fantastique! Lorsque j'aurai terminé mon projet je le mettrai sur Github pour en faire profiter la galerie...

              Ah, c'était juste une erreur bête, tant mieux ! :)

              -
              Edité par robun 7 septembre 2024 à 22:29:44

              • Partager sur Facebook
              • Partager sur Twitter
                25 novembre 2024 à 11:24:41 - Message modéré pour le motif suivant : Message complètement hors sujet


                  26 novembre 2024 à 1:25:14

                  Il y en a un qui a perdu le nord?
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Le Tout est souvent plus grand que la somme de ses parties.

                  détermination du nord magnétique par son azimut

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  • Editeur
                  • Markdown