Simplifier fonction d'interpolation exponentielle

Discussion générale entre passionnés et amateurs de mathématiques sur des sujets mathématiques variés
sylvainmahe
Messages: 2
Enregistré le: 10 Juin 2015, 23:23

Simplifier fonction d'interpolation exponentielle

par sylvainmahe » 11 Juin 2015, 12:05

Bonjour :lol3:

Par passion je créé actuellement un framework pour les microcontrôleurs de la gamme avr Atmel, dans un premier temps pour le très connu atmega 328p, et j'ai besoin de votre aide pour simplifier une fonction d'interpolation que j'avais fait il y a quelques années déjà et que je traîne de langages de programmation en langages de programmation...

C'est une fonction qui permet d'interpoler des déplacements d'objets, des valeurs quelconques, ...

La voici:
Code: Tout sélectionner
int32_t Math::curve (const double POSITION_START, const double POSITION_CURRENT, const double POSITION_END, const double INTERPOLATION_START, const double INTERPOLATION_END, const uint8_t CURVE)
{
   double value = 0;
   
   if (POSITION_CURRENT  POSITION_START && POSITION_CURRENT  INTERPOLATION_START)
      {
         if (CURVE == 0)
         {
            value = INTERPOLATION_START + ((INTERPOLATION_END - INTERPOLATION_START) / ((POSITION_END - POSITION_START) / (POSITION_CURRENT - POSITION_START)));
         }
         else if (CURVE == 1)
         {
            value = INTERPOLATION_START + (((INTERPOLATION_END - INTERPOLATION_START) / ((POSITION_END - POSITION_START) / (POSITION_CURRENT - POSITION_START))) / ((POSITION_END - POSITION_START) / (POSITION_CURRENT - POSITION_START)));
         }
         else if (CURVE == 2)
         {
            value = (INTERPOLATION_START + ((INTERPOLATION_END - INTERPOLATION_START) / ((POSITION_END - POSITION_START) / (POSITION_CURRENT - POSITION_START)))) + ((INTERPOLATION_END - (INTERPOLATION_START + ((INTERPOLATION_END - INTERPOLATION_START) / ((POSITION_END - POSITION_START) / (POSITION_CURRENT - POSITION_START))))) / ((POSITION_END - POSITION_START) / (POSITION_CURRENT - POSITION_START)));
         }
         else if (CURVE == 3)
         {
            if (POSITION_CURRENT - POSITION_START  A1 && B1  A2)
      {
         if (CURVE == 0)
         {
            B2 = A2 + ((C2 - A2) / ((C1 - A1) / (B1 - A1)));
         }
         else if (CURVE == 1)
         {
            B2 = A2 + (((C2 - A2) / ((C1 - A1) / (B1 - A1))) / ((C1 - A1) / (B1 - A1)));
         }
         else if (CURVE == 2)
         {
            B2 = (A2 + ((C2 - A2) / ((C1 - A1) / (B1 - A1)))) + ((C2 - (A2 + ((C2 - A2) / ((C1 - A1) / (B1 - A1))))) / ((C1 - A1) / (B1 - A1)));
         }
         else if (CURVE == 3)
         {
            if (B1 - A1 < ((C1 - A1) / 2) + 0.5)
            {
               B2 = (A2 + (((C2 - ((C2 - A2) / 2)) - A2) / (((C1 - A1) / 2) / (B1 - A1)))) + (((C2 - ((C2 - A2) / 2)) - (A2 + (((C2 - ((C2 - A2) / 2)) - A2) / (((C1 - A1) / 2) / (B1 - A1))))) / (((C1 - A1) / 2) / (B1 - A1)));
            }
            else if (B1 - A1 == ((C1 - A1) / 2) + 0.5)
            {
               B2 = A2 + ((C2 - A2) / 2);
            }
            else
            {
               B2 = (A2 + ((C2 - A2) / 2)) + (((C2 - (A2 + ((C2 - A2) / 2))) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2)))) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2))));
            }
         }
         else if (CURVE == 4)
         {
            if (B1 - A1 < ((C1 - A1) / 2) + 0.5)
            {
               B2 = A2 + (((C2 - A2) / (((C1 - A1) / 2) / (B1 - A1))) / ((C1 - A1) / (B1 - A1)));
            }
            else if (B1 - A1 == ((C1 - A1) / 2) + 0.5)
            {
               B2 = A2 + ((C2 - A2) / 2);
            }
            else
            {
               B2 = (A2 + ((C2 - A2) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2))))) + ((C2 - (A2 + ((C2 - A2) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2)))))) / ((C1 - A1) / (B1 - A1)));
            }
         }
      }
      else
      {
         if (CURVE == 0)
         {
            B2 = A2 - ((A2 - C2) / ((C1 - A1) / (B1 - A1)));
         }
         else if (CURVE == 1)
         {
            B2 = A2 - (((A2 - C2) / ((C1 - A1) / (B1 - A1))) / ((C1 - A1) / (B1 - A1)));
         }
         else if (CURVE == 2)
         {
            B2 = (A2 - ((A2 - C2) / ((C1 - A1) / (B1 - A1)))) - (((A2 - ((A2 - C2) / ((C1 - A1) / (B1 - A1)))) - C2) / ((C1 - A1) / (B1 - A1)));
         }
         else if (CURVE == 3)
         {
            if (B1 - A1 < ((C1 - A1) / 2) + 0.5)
            {
               B2 = (A2 - ((A2 - (C2 + ((A2 - C2) / 2))) / (((C1 - A1) / 2) / (B1 - A1)))) - (((A2 - ((A2 - (C2 + ((A2 - C2) / 2))) / (((C1 - A1) / 2) / (B1 - A1)))) - (C2 + ((A2 - C2) / 2))) / (((C1 - A1) / 2) / (B1 - A1)));
            }
            else if (B1 - A1 == ((C1 - A1) / 2) + 0.5)
            {
               B2 = A2 - ((A2 - C2) / 2);
            }
            else
            {
               B2 = (A2 - ((A2 - C2) / 2)) - ((((A2 - ((A2 - C2) / 2)) - C2) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2)))) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2))));
            }
         }
         else if (CURVE == 4)
         {
            if (B1 - A1 < ((C1 - A1) / 2) + 0.5)
            {
               B2 = A2 - (((A2 - C2) / (((C1 - A1) / 2) / (B1 - A1))) / ((C1 - A1) / (B1 - A1)));
            }
            else if (B1 - A1 == ((C1 - A1) / 2) + 0.5)
            {
               B2 = A2 - ((A2 - C2) / 2);
            }
            else
            {
               B2 = (A2 - ((A2 - C2) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2))))) - (((A2 - ((A2 - C2) / (((C1 - A1) / 2) / ((B1 - A1) - ((C1 - A1) / 2))))) - C2) / ((C1 - A1) / (B1 - A1)));
            }
         }
      }
   }
   else
   {
      B2 = C2;
   }
   
   return B2 + 0.5;
}



bolza
Membre Relatif
Messages: 449
Enregistré le: 04 Juin 2015, 10:15

par bolza » 11 Juin 2015, 17:44

Bonjour,

sans regarder en détail, ce que fait le code,

je trouve que tu fais beaucoup de division,
(et les division c'est la plus gourmande en cycle des 4 opérations élémentaire)

Donc tu pourrai essayer de réduire le nombre de division.
par exemple : au lieu de A/(B/C) tu peux faire A*C/B tu remplace ainsi une division par une multiplication
et je pense que la multiplication est un peu moins couteuse.
(sauf les division par 2, si tu code bien, normalement ça coute pratiquement rien.)

aussi je remplacerai (A-B)/2+0.5 par (A-B+1)/2 (je n'en suis absolument pas certains mais ça me semble mieux)

Et puis à certain endroit tu fais un même calcul deux fois, tu pourrais le faire qu'une seule fois et ensuite
simplement réutiliser le résultat.

Bon après tous ça, ne sont que de modestes améliorations, mais si la fonction est utiliser dans une boucle,
eh bien ça peut quand même faire gagner quelques cycles au final.

Après si tu veux faire comprendre ton problème à des matheux, tu devrais plutôt commencer par préciser si tu es
dans le plan ou dans l'espace. Si c'est dans le plan par exemple, alors tu as un point qui a comme position initial
et que la position suivante est calculer en fonction de de tel ou tel
manière selon la valeur de curve, etc... (ou un truc dans ce genre là ^^) :lol3:

mathelot

par mathelot » 12 Juin 2015, 08:19

en C/C++, tu pourrais mettre un pointeur sur fonction,
ce qui permettrait de faire de l'interpolation autre que linéaire.

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 26 Juin 2015, 07:42

je sais pas si tu vas avoir bcp de problèmes d'arrondis...

mais tu peux pas écrire un truc style newton?

genre tu écris que que si tu as f(x)
alors f(x+dx) = f(x)+f'(x)dx + o(dx^2)

avec ta fonction expo centrée que tu def par:
o = (positionStart+positionEnd)/2
e^(-(x-o)^2) (on la centre en 0)

tstart = e^(-(positionStart-o)^2)
(pour que la première valeur commence avec interpolationStart = 0)
e^(-(x-o)^2) - tstart
puis comme l'expo c'est courant, tu passes par séries avec les termes principaux:
e^(-(x-o)^2) = 1+(-(x-o)^2)+(-(x-o)^2) ^2/2! +(-(x-o)^2)^3/3!...

la dérivée de (-(x-o)^2) ^n/n! étant (-2(x-o))(-(x-o)^2) ^(n-1)/(n-1)!

du coup le calcul de f'(x) peux ressembler à f(x)
si tu calcules f_n(x) à l'itération n,
à l'itération n+1, tu as f'(x) = -2(x-o) [ f_n(x) -1]

du coup l'algo ressemblerait à qqch style
Code: Tout sélectionner
step=0.1
positionStart = -3
positionEnd = 2
interpStart=interpEnd=4
oldFx = 0
fx = 0
while(positionCurrent+step<positionEnd){
 
 fxstep = fx+-2(x-o)(oldFx-1)
 oldFx = fx
 fx = fxstep
 positionCurrent+=step
}


après yaura ptet des erreurs d'arrondis... et moyennant l'offset du début que j'ai paumé par mégarde
la vie est une fête :)

 

Retourner vers ⚜ Salon Mathématique

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 17 invités

Tu pars déja ?



Fais toi aider gratuitement sur Maths-forum !

Créé un compte en 1 minute et pose ta question dans le forum ;-)
Inscription gratuite

Identification

Pas encore inscrit ?

Ou identifiez-vous :

Inscription gratuite