Répondre à la discussion
Affichage des résultats 1 à 9 sur 9

Problème calcul mathématiques avec et sans UART



  1. #1
    SportsEngine

    Exclamation Problème calcul mathématiques avec et sans UART

    Bonjour,

    Pour un projet j'ai besoin de faire l'interpolation de points pour suivre une trajectoire. J'ai un tableau de 500 points à partir desquels je veux ressortir 2000 points.
    J'ai choisi d'utiliser la méthode d'interpolation de Lagrange pour faire cela, et dans un cas particulier ça "tombe en marche".

    J'utilise un PIC24EP512GU810 qui mouline à 120MHz (60 MIPS) et l'UART1 pour le debug transmet à 921600 bauds (débit max que mon terminal peut gérer).

    Je pense que mon problème se situe dans la fonction getInterpolationDot. Lorsque je dé-commente l'instruction UART1_writeString(buff);(*), les valeurs que cette fonction renvoie sont bonnes, et sont identiques à celles renvoyées dans la boucle for du main.

    MAIS lorsque je commente l'instruction UART1_writeString(buff) dans la fonction getInterpolationDot, les valeurs renvoyées par la boucle for du main ne correspondent plus du tout...

    Je pensais à un problème de temps d'exécution qui diffère entre l'activation ou non de l'envoi sur l'UART. J'ai essayé d'ajouter une suite de Nop() puis une instruction __delay_ms(N); dans la fonction getInterpolationDot. Mais ça ne change rien... J'ai essayé des délais jusqu'à 50 ms, c'est super long, mais pas de résultats satisfaisants.

    Concernant le reste du programme, les différentes variables ne sont appelées que dans les fonctions présentées, et le Timer1 actif, qui entre dans le vecteur d'interruption toutes les 1 ms, mais il ne fait que la remise à 0 du flag (il sera utilisé par la suite).

    Voici mes différentes fonctions :

    * Calcul de l'interpolation de Lagrange de 16 points à partir de 4 points connus :
    Code:
    UINT16 LagrangeInterpolation(UINT16 y[4], UINT16 a)
    {
      double s = 1, t = 1, k;
      double x[4] = {0};
      UINT8 i, j;
      UINT16 value=0;
      for(i = 0; i < 4; i++)
        {
          x[i] = i * 4;
        }
      for(i = 0; i < 4; i++)
        {
          s = 1;
          t = 1;
          for(j = 0; j < 4; j++)
            {
              if(j != i)
                {
                  s = s * ((double)a - x[j]);
                  t = t * (x[i] - x[j]);
                }
            }
          k += (double)((s / t) * (double)y[i]);
        }
      value = (UINT16)k;
      return value;
    }
    * Calcul de 2000 points à partir des 500 points connus en faisant appel à l'interpolation de Lagrange dans une routine :
    Code:
    INT32 getInterpolationDot(UINT16 *inputBuffer, UINT16 *outputBuffer)
    {
      UINT8 j = 0;
      UINT8 i = 0;
      UINT16 k = 0;
      UINT16 inData[4] = {0};
      UINT16 outData = 0;
      char buff[64];
      for(j = 0; j < 125; j++)
        {
          for(i = 0; i < 4; i++)
            {
              k = i + (j * 4);
              inData[i] = inputBuffer[k];
            }
          for(i = 0; i < 16; i++)
            {
              k = i + (j * 16);
              outputBuffer[k] = LagrangeInterpolation(inData, i);
              sprintf(buff, "x=%04u;y=%05u\r\n", k, outputBuffer[k]);
              UART1_writeString(buff); // (*) Instruction qui fait fonctionner le programme
              // __delay_ms(50);
            }
        }
      return 0;
    }
    * Et enfin ma fonction main qui appelle la fonction :
    Code:
    int main(int argc, char** argv)
    {
      UINT16 k = 0;
      UINT16 memoryBuffer[500] = {500 valeurs prédéfinies}; // 500 valeurs stockées en mémoire
      UINT16 accelerationProfile[2000] = {0}; // 2000 valeurs à calculer
      getInterpolationDot(memoryBuffer, accelerationProfile); // convertit les 500 points d'entrée en 2000 points de sortie
      for(k = 0; k < 2000; k++)
        {
          sprintf(buff, "x=%04u;y=%05u\r\n", k, accelerationProfile[k]); // envoie les 2000 valeurs calculées sur le terminal pour vérification
          UART1_writeString(buff);
          __delay_ms(10);
        }
    }
    Pour ceux qui auraient une petite idée... Merci

    -----


  2. Publicité
  3. #2
    SportsEngine

    Re : Problème calcul mathématiques avec et sans UART

    PS : en complément je donne le tableau de 500 valeurs avec lequel je fais mes tests (une période de sinus d'amplitude 65535, centrée sur 32767, avec un arrondi à l'unité, créée sous Excel tout simplement) :
    Code:
    UINT16 memoryBuffer[500]=
    {32767,
    33179,
    33590,
    34002,
    34413,
    34824,
    35235,
    35646,
    36056,
    36465,
    36874,
    37282,
    37689,
    38096,
    38502,
    38907,
    39311,
    39714,
    40116,
    40516,
    40916,
    41314,
    41711,
    42106,
    42500,
    42893,
    43283,
    43672,
    44060,
    44446,
    44829,
    45211,
    45591,
    45969,
    46345,
    46719,
    47090,
    47459,
    47826,
    48191,
    48553,
    48912,
    49269,
    49624,
    49975,
    50324,
    50671,
    51014,
    51355,
    51692,
    52027,
    52359,
    52687,
    53012,
    53335,
    53653,
    53969,
    54281,
    54590,
    54896,
    55198,
    55496,
    55791,
    56082,
    56369,
    56653,
    56933,
    57209,
    57482,
    57750,
    58014,
    58275,
    58531,
    58784,
    59032,
    59276,
    59516,
    59752,
    59983,
    60210,
    60433,
    60652,
    60866,
    61075,
    61280,
    61481,
    61677,
    61869,
    62056,
    62238,
    62415,
    62588,
    62757,
    62920,
    63079,
    63233,
    63382,
    63526,
    63666,
    63801,
    63930,
    64055,
    64175,
    64290,
    64400,
    64505,
    64604,
    64699,
    64789,
    64874,
    64954,
    65028,
    65098,
    65162,
    65221,
    65276,
    65325,
    65369,
    65407,
    65441,
    65469,
    65493,
    65511,
    65524,
    65531,
    65534,
    65531,
    65524,
    65511,
    65493,
    65469,
    65441,
    65407,
    65369,
    65325,
    65276,
    65221,
    65162,
    65098,
    65028,
    64954,
    64874,
    64789,
    64699,
    64604,
    64505,
    64400,
    64290,
    64175,
    64055,
    63930,
    63801,
    63666,
    63526,
    63382,
    63233,
    63079,
    62920,
    62757,
    62588,
    62415,
    62238,
    62056,
    61869,
    61677,
    61481,
    61280,
    61075,
    60866,
    60652,
    60433,
    60210,
    59983,
    59752,
    59516,
    59276,
    59032,
    58784,
    58531,
    58275,
    58014,
    57750,
    57482,
    57209,
    56933,
    56653,
    56369,
    56082,
    55791,
    55496,
    55198,
    54896,
    54590,
    54281,
    53969,
    53653,
    53335,
    53012,
    52687,
    52359,
    52027,
    51692,
    51355,
    51014,
    50671,
    50324,
    49975,
    49624,
    49269,
    48912,
    48553,
    48191,
    47826,
    47459,
    47090,
    46719,
    46345,
    45969,
    45591,
    45211,
    44829,
    44446,
    44060,
    43672,
    43283,
    42893,
    42500,
    42106,
    41711,
    41314,
    40916,
    40516,
    40116,
    39714,
    39311,
    38907,
    38502,
    38096,
    37689,
    37282,
    36874,
    36465,
    36056,
    35646,
    35235,
    34824,
    34413,
    34002,
    33590,
    33179,
    32767,
    32355,
    31944,
    31532,
    31121,
    30710,
    30299,
    29888,
    29478,
    29069,
    28660,
    28252,
    27845,
    27438,
    27032,
    26627,
    26223,
    25820,
    25418,
    25018,
    24618,
    24220,
    23823,
    23428,
    23034,
    22641,
    22251,
    21862,
    21474,
    21088,
    20705,
    20323,
    19943,
    19565,
    19189,
    18815,
    18444,
    18075,
    17708,
    17343,
    16981,
    16622,
    16265,
    15910,
    15559,
    15210,
    14863,
    14520,
    14179,
    13842,
    13507,
    13175,
    12847,
    12522,
    12199,
    11881,
    11565,
    11253,
    10944,
    10638,
    10336,
    10038,
    9743,
    9452,
    9165,
    8881,
    8601,
    8325,
    8052,
    7784,
    7520,
    7259,
    7003,
    6750,
    6502,
    6258,
    6018,
    5782,
    5551,
    5324,
    5101,
    4882,
    4668,
    4459,
    4254,
    4053,
    3857,
    3665,
    3478,
    3296,
    3119,
    2946,
    2777,
    2614,
    2455,
    2301,
    2152,
    2008,
    1868,
    1733,
    1604,
    1479,
    1359,
    1244,
    1134,
    1029,
    930,
    835,
    745,
    660,
    580,
    506,
    436,
    372,
    313,
    258,
    209,
    165,
    127,
    93,
    65,
    41,
    23,
    10,
    3,
    0,
    3,
    10,
    23,
    41,
    65,
    93,
    127,
    165,
    209,
    258,
    313,
    372,
    436,
    506,
    580,
    660,
    745,
    835,
    930,
    1029,
    1134,
    1244,
    1359,
    1479,
    1604,
    1733,
    1868,
    2008,
    2152,
    2301,
    2455,
    2614,
    2777,
    2946,
    3119,
    3296,
    3478,
    3665,
    3857,
    4053,
    4254,
    4459,
    4668,
    4882,
    5101,
    5324,
    5551,
    5782,
    6018,
    6258,
    6502,
    6750,
    7003,
    7259,
    7520,
    7784,
    8052,
    8325,
    8601,
    8881,
    9165,
    9452,
    9743,
    10038,
    10336,
    10638,
    10944,
    11253,
    11565,
    11881,
    12199,
    12522,
    12847,
    13175,
    13507,
    13842,
    14179,
    14520,
    14863,
    15210,
    15559,
    15910,
    16265,
    16622,
    16981,
    17343,
    17708,
    18075,
    18444,
    18815,
    19189,
    19565,
    19943,
    20323,
    20705,
    21088,
    21474,
    21862,
    22251,
    22641,
    23034,
    23428,
    23823,
    24220,
    24618,
    25018,
    25418,
    25820,
    26223,
    26627,
    27032,
    27438,
    27845,
    28252,
    28660,
    29069,
    29478,
    29888,
    30299,
    30710,
    31121,
    31532,
    31944,
    32355};

  4. #3
    SportsEngine

    Re : Problème calcul mathématiques avec et sans UART

    Bon petite avancée mais je ne comprends toujours pas : lorsque je commentais le UART1_writeString(buff);, je commentais aussi sprintf(buff, "x=%04u;y=%05u\r\n", k, outputBuffer[k]);.
    J'ai fait un essai en dé-commentant sprintf(buff, "x=%04u;y=%05u\r\n", k, outputBuffer[k]); et en laissant UART1_writeString(buff); et ça fonctionne. Le problème ne vient donc pas de l'envoi sur l'UART mais de sprintf, ce que je ne comprends toujours pas...

  5. #4
    paulfjujo

    Re : Problème calcul mathématiques avec et sans UART

    bonjour,


    je ne connais pas les PIC24 ..

    mais avec les PIC18 , la fonction sprintf consomme beaucoup de ressources
    et peut generer des problemes de debordement de taille tableau
    qui ne sont pas toujours "visibles" au premier abord . (effets de bords)
    Sous mikroC, on voit tout de suite ce que la fonction sprintf occupe en taille memoire programme..
    et il vaut mieux eviter de s'en servir si le PIC utilisé est trop flagada en ressources Flash ROM e RAM.

    avec un PIC24 musclé ?

  6. #5
    DAUDET78

    Re : Problème calcul mathématiques avec et sans UART

    Citation Envoyé par paulfjujo Voir le message
    la fonction sprintf consomme beaucoup de ressources
    J'avais fait un stage de langage C . On m'avait mis en garde sur les effets néfastes de sprintf
    L'age n'est pas un handicap .... Encore faut-il arriver jusque là pour le constater !

  7. A voir en vidéo sur Futura
  8. #6
    SportsEngine

    Re : Problème calcul mathématiques avec et sans UART

    Bonjour,

    Merci pour ces indications, mais justement le problème est l'inverse... si j'utilise l'instruction sprintf ça fonctionne (sans même envoyer sur l'UART), mais si je l'enlève ça marche plus

    Pour le PIC pas de problème de RAM ou de FLASH, c'est un des plus costauds de la gamme PIC24 (PIC24EP512GU810)

  9. Publicité
  10. #7
    Vincent PETIT

    Re : Problème calcul mathématiques avec et sans UART

    Salut,
    Tu as un problème de portée de variable dans ton main, ton compilateur devrait t'alerter sur les deux lignes ci dessous.
    Code:
    int main(int argc, char** argv)
    {
      ...
      ...
      ...
          sprintf(buff, "x=%04u;y=%05u\r\n", k, accelerationProfile[k]); // envoie les 2000 valeurs calculées sur le terminal pour vérification
          UART1_writeString(buff);
      ...
      ...
    }
    Tu ne peux pas avoir accès à la variable buff dans le main puisqu'elle est locale à la fonction getInterpolationDot
    Code:
    INT32 getInterpolationDot(UINT16 *inputBuffer, UINT16 *outputBuffer)
    {
      ...
      ...
      char buff[64];
      ...
      ...
              sprintf(buff, "x=%04u;y=%05u\r\n", k, outputBuffer[k]);
              UART1_writeString(buff); // (*) Instruction qui fait fonctionner le programme
      ...
      ...
    }
    A mon avis voilà ce qui se passe !
    Ton compilateur n'est pas con, et en l'état actuel, il comprend que sprintf et UART1_writeString qui se trouve dans le main ne servent a rien puisque tu les utilises déjà dans la fonction getInterpolationDot. Je suis presque sur que le processus d'optimisation supprime simplement sprintf et UART1_writeString qui se trouve dans le main.

    Par contre si tu commentes la ligne mis en évidence ci dessus (en orange dans la fonction getInterpolationDot) alors le compilateur prend en compte sprintf et UART1_writeString qui se trouve dans le main et tu as un problème de portée car buff n'existe pas dans main.

    Si tu rends char buff[64]; global à tout ton source alors ça devrait fonctionner :
    Code:
    char buff[64]; // variable globale
    
    
    
    UINT16 LagrangeInterpolation(UINT16 y[4], UINT16 a)
    {
      double s = 1, t = 1, k;
      double x[4] = {0};
      UINT8 i, j;
      UINT16 value=0;
      for(i = 0; i < 4; i++)
        {
          x[i] = i * 4;
        }
      for(i = 0; i < 4; i++)
        {
          s = 1;
          t = 1;
          for(j = 0; j < 4; j++)
            {
              if(j != i)
                {
                  s = s * ((double)a - x[j]);
                  t = t * (x[i] - x[j]);
                }
            }
          k += (double)((s / t) * (double)y[i]);
        }
      value = (UINT16)k;
      return value;
    }
    
    
    
    
    INT32 getInterpolationDot(UINT16 *inputBuffer, UINT16 *outputBuffer)
    {
      UINT8 j = 0;
      UINT8 i = 0;
      UINT16 k = 0;
      UINT16 inData[4] = {0};
      UINT16 outData = 0;
    
      for(j = 0; j < 125; j++)
        {
          for(i = 0; i < 4; i++)
            {
              k = i + (j * 4);
              inData[i] = inputBuffer[k];
            }
          for(i = 0; i < 16; i++)
            {
              k = i + (j * 16);
              outputBuffer[k] = LagrangeInterpolation(inData, i);
              sprintf(buff, "x=%04u;y=%05u\r\n", k, outputBuffer[k]);
              UART1_writeString(buff); // (*) Instruction qui fait fonctionner le programme
              // __delay_ms(50);
            }
        }
      return 0;
    }
    
    
    
    
    int main(int argc, char** argv)
    {
      UINT16 k = 0;
      UINT16 memoryBuffer[500] = {500 valeurs prédéfinies}; // 500 valeurs stockées en mémoire
      UINT16 accelerationProfile[2000] = {0}; // 2000 valeurs à calculer
      getInterpolationDot(memoryBuffer, accelerationProfile); // convertit les 500 points d'entrée en 2000 points de sortie
      for(k = 0; k < 2000; k++)
        {
          sprintf(buff, "x=%04u;y=%05u\r\n", k, accelerationProfile[k]); // envoie les 2000 valeurs calculées sur le terminal pour vérification
          UART1_writeString(buff);
          __delay_ms(10);
        }
    }
    Là où il n'y a pas de solution, il n'y a pas de problème.

  11. #8
    SportsEngine

    Smile Re : Problème calcul mathématiques avec et sans UART

    Ah ça c'est une erreur de ma part, en réalité dans mon main j'ai une machine à état (switch-case) où il y a l'initialisation des périphériques, et d'autres états qui sont déjà fonctionnels. Pour rendre la chose plus lisible sur le forum j'ai copié/collé juste ce qui m'intéressait (juste un état précis de la machine à état) et j'ai oublié de copier la variable locale buff[64] qui était avant le "switch". J'aurais dû l'appeler autrement d'ailleurs, mais le problème n'était pas là malheureusement, MAIS je pense avoir trouvé! (en tout cas j'espère )

    A force de tourner en rond, j'en suis venu à encore simplifier ma fonction main, avec toujours des erreurs de calcul :

    Bien que je doute que l'erreur vienne de là, j'ai enlevé les boucles for imbriquées en faisant la copie à la main (heureusement que j'ai pas choisi un nombre important de valeurs)... Il ne reste donc que l'appel de la fonction LagrangeInterpolation :
    * Fonction de calcul d'interpolation de Lagrange (inchangée par rapport aux postes précédents):
    Code:
    UINT16 LagrangeInterpolation(UINT16 y[4], UINT16 a)
    {
      double s = 1, t = 1, k; // il est pas initialisé!!!
      double x[4] = {0};
      UINT8 i, j;
      UINT16 value = 0;
      for(i = 0; i < 4; i++)
        {
          x[i] = i * 4;
        }
      for(i = 0; i < 4; i++)
        {
          s = 1;
          t = 1;
          for(j = 0; j < 4; j++)
            {
              if(j != i)
                {
                  s = s * ((double)a - x[j]);
                  t = t * (x[i] - x[j]);
                }
            }
          k += (double)((s / t) * (double)y[i]); // Un truc pas initialisé + une inconnue ça donne rarement ce qu'on attend!
        }
      value = (UINT16)k; //roundValue(k);
      return value;
    }
    * Nouvelle fonction main :
    Code:
    int main(int argc, char** argv)
    {
      UINT16 memoryBuffer[500] = {500 valeurs prédéfinies}; // 500 valeurs stockées en mémoire
      UINT16 accelerationProfile[2000] = {0}; // 2000 valeurs à calculer
      UINT16 inData[125][4] = {{0}};
      UINT16 j = 0;
      UINT16 k = 0;
      char valBuff[64] = {0};
    
      // Effectue 125 itérations pour récupérer 2000 points
      for(j = 0; j < 125; j++)
        {
          // Initialise les 4 valeurs d'entrée
          inData[j][0] = memoryBuffer[0 + (j << 2)];
          inData[j][1] = memoryBuffer[1 + (j << 2)];
          inData[j][2] = memoryBuffer[2 + (j << 2)];
          inData[j][3] = memoryBuffer[3 + (j << 2)];
          // Récupère les 16 valeurs de sortie
          accelerationProfile1[0 + (j << 4)] = LagrangeInterpolation(inData[j], 0);
          accelerationProfile1[1 + (j << 4)] = LagrangeInterpolation(inData[j], 1);
          accelerationProfile1[2 + (j << 4)] = LagrangeInterpolation(inData[j], 2);
          accelerationProfile1[3 + (j << 4)] = LagrangeInterpolation(inData[j], 3);
          accelerationProfile1[4 + (j << 4)] = LagrangeInterpolation(inData[j], 4);
          accelerationProfile1[5 + (j << 4)] = LagrangeInterpolation(inData[j], 5);
          accelerationProfile1[6 + (j << 4)] = LagrangeInterpolation(inData[j], 6);
          accelerationProfile1[7 + (j << 4)] = LagrangeInterpolation(inData[j], 7);
          accelerationProfile1[8 + (j << 4)] = LagrangeInterpolation(inData[j], 8);
          accelerationProfile1[9 + (j << 4)] = LagrangeInterpolation(inData[j], 9);
          accelerationProfile1[10 + (j << 4)] = LagrangeInterpolation(inData[j], 10);
          accelerationProfile1[11 + (j << 4)] = LagrangeInterpolation(inData[j], 11);
          accelerationProfile1[12 + (j << 4)] = LagrangeInterpolation(inData[j], 12);
          accelerationProfile1[13 + (j << 4)] = LagrangeInterpolation(inData[j], 13);
          accelerationProfile1[14 + (j << 4)] = LagrangeInterpolation(inData[j], 14);
          accelerationProfile1[15 + (j << 4)] = LagrangeInterpolation(inData[j], 15);
        }
      // Mise en forme et récupération sur l'UART des 2000 points calculés
      for(k=0;k<2000;k++)
        {
          sprintf(valBuff,"%04u,%05u\r\n",k,accelerationProfile1[k]);
          UART1_writeString(valBuff);
          __delay_ms(1);
        }
    }
    Et là surprise! dans la fonction LagrangeInterpolation() la variable k n'est pas initialisée (que celui qui vient de dire "erreur de débutant" lève la main!)

    Du coup j'ai repris mes anciennes fonctions avec les petites boucles for, mon buffer d'entrée et mon buffer de sortie, en mettant bien k à 0 au départ, et ça semble fonctionner pour une raison inconnue le sprintf faisait que ça tombait en marche
    Dernière modification par SportsEngine ; 09/05/2017 à 11h44.

  12. #9
    RISC

    Re : Problème calcul mathématiques avec et sans UART

    Salut,

    Faire des calculs flottants ...voire double sur un micro 16 bits est très pénalisant en temps de calcul car ce micro n'a pas d'unité de calcul flottant intégré dans le coeur mais peut-être que le temps de calcul n'est pas critique dans ton application...
    Comme précisé ci-dessus les fonctions printf, sprintf ne sont pas adaptées pour les microcontroleurs...sauf le temps d'exécution n'est pas critique...
    Elle consomme beaucoup de temps processeur

    a+
    Ma marotte ? les microcontrôleurs ;=)

Sur le même thème :

Discussions similaires

  1. [Programmation] probléme d'uart avec pic 18f6620
    Par abir93 dans le forum Électronique
    Réponses: 0
    Dernier message: 24/04/2016, 18h14
  2. problème avec spi uart pic 16f4500
    Par zetaa dans le forum Électronique
    Réponses: 4
    Dernier message: 13/08/2015, 08h40
  3. Probléme avec le convertisseur UART/USB MCP2200
    Par Tevz dans le forum Électronique
    Réponses: 0
    Dernier message: 18/02/2011, 17h45
  4. (Rx) RS232 -> UART TTL sans MAX232
    Par Seb.26 dans le forum Électronique
    Réponses: 12
    Dernier message: 25/07/2009, 18h47
  5. probleme d'UART sur uC Atmel 8515 programme avec IccAvr
    Par Thorhck dans le forum Électronique
    Réponses: 23
    Dernier message: 06/02/2004, 21h43