# Autres langages > Autres langages > VHDL >  Calcul flottant

## electron22

Bonjour,
J'ai un tableau  utiliser des arctan(2^-i) qui sont des valeur flottantes que j'aimerais utiliser dans le calcul de l'quation :
A = A + arctan(2^-i).
je sais qu'il faut dclarer le tableau de la manire suivante:Type TAB is array (Positive range <>) of real; mais je ne sais pas comment manipuler des nombres flottants en VHDL.
merci de m'aider.

----------


## titiri

Bonjour,

    Un tableau de "real" n'est pas une bonne ide en synthse. Il faut plutt utiliser des nombres dcimaux  virgule fixe, ce qui revient  considrer qu'un std_logic_vector de N bit est constitu de N0 bits pour la partie entire et N1 bits pour la partie dcimale (avec, of course, N=N0+N1).
    Si, par hasard, il s'agit de faire un CORDIC, allez voir http://en.wikiversity.org/wiki/CORDI...mplementations, puis 2.4

Cordialement

----------


## electron22

je vous remercie, effectivement c'est pour le calcul cordic
j'ai en fait j'ai multipli toutes les variables  * 1000 (X, Y, alpha...), ce qui fait que toutes mes variables se constituent d'une partie entire et dcimale, et a simplifie en sortie puisque : tan(alpha) = Y/X
Sauf que tan(alpha) = Y/X est un float ! puisque dans un intervalle alpha = [0,1,2...45] tan(alpha) varie dans l'intervalle [0,1], j'aimerais savoir comment rcuprer la partie entire et la partie dcimale du rsultat de la division !!

----------


## mith06

```
Sauf que tan(alpha) = Y/X est un float ! puisque dans un intervalle alpha = [0,1,2...45] tan(alpha) varie dans l'intervalle [0,1], j'aimerais savoir comment récupérer la partie entière et la partie décimale du résultat de la division !!
```

Ce la va dpendre du nombre de bit que tu vas choisir coder l'ensemble de sortie [0:1].
Exemple:
Si tu choisi 8 bits il faut normaliser le rsulta par 1/(2^8)=1/256=0.00390625.
Ton ensemble de sortie sera [0 : 1 : 255] <=> [0 : 0.00390625 : 0.99609375] (notation Matlab/Scilab)
Remarque la valeur 1 n'est pas exactement reprsente.
Si tu veux que ton ensemble de sortie contiennent exactement la valeur 1, il faut utiliser N bit et normaliser le rsultat par 1/(2^(N-1))

----------


## electron22

Donc il faut normaliser le rsultat ne fonction du nombre de bit du registre qui contient le rsultat,
mais le souci est que lors de la division, je perd le rsultat puisque les signaux de calculs :


```

```

et comme la division se fait comme suit : Res<=Y/X; j'ai toujours 0 en sortie puisque le rsultat maximal est 1 !

----------


## mith06

> et comme la division se fait comme suit : Res<=Y/X; j'ai toujours 0 en sortie puisque le rsultat maximal est 1 !


Certes... zro divis par X a fait zro... Je ne suis pas sure de savoir o tu veux en venir...

Tu cherche alpha en fonction de Y et X? Correct?
Si c'est le cas = alpha (radian) = atan2(y,x)
http://fr.wikipedia.org/wiki/Atan2

Dans tous les cas vite de faire des divisions en VHDL.
=> 
deux solutions:
-cordic je le l'ai jamais utilis...
-une ROM, qui renvoie la valeur de alpha pour tout les couple possible de Y&X. (Attention a devient trs vite trs gros)
Il y a des moyen de rduire par 4 la taille de la ROM en utilisant des proprit de symtrie de la fonction atan2.

----------


## electron22

En fait le but est de calculer la valeur de tan(alpha), alpha pour moi est une entre.
tan(alpha) est calcule  partir d'une succession de calcul de X et Y et au final tan(alpha)=Y/X, et ce en se servant de 16 valeurs de l'arctan(2^-i) via une table sauvegard "table(i);"
X= 1000 --abscisse et Y=0 --ordonne : ce n'est que l'initialisation, mais X et Y se calculent dans une boucle (de 16 itrations par ex) via les trois quations ci-dessous, aprs avoir test si l'angle calcul dpasse ou pas l'angle  calculer:



```

```

Le souci est que X/Y donne tout le temps 0 puisque le rsultat n'atteint jamais 1

----------


## mith06

OK tu fais un cordic en fait...

Dans ton cas Y <=> sin(alpha), et X <=> cos(alpha), tan(alpha) = Y/X = sin(alpha)/cos(alpha);
Si alpha est une entre pour toi, comment tu choisi les valeurs initiales du couple X et Y?

Si tu veux calculer tan(alpha) utilise plutt une ROM, a te donnera le rsultat en 1 cycle horloge.
-Attention pour alpha = +/- Pi/2.....

----------


## electron22

Effectivement je peux avoir la valeur de tan(alpha) en un cycle d'horloge en utilisant la ROM, mais le cordic c'est plus utilis pour avoir une valeur beaucoup plus prcise (plusieurs chiffres aprs la virgule), car on ne peux pas stocker un nombre trs important de valeur dans la Rom.
J'initialise mes variables comme suit: A = 0 (angle calcul) donc labscisse X=1 et l'ordonn Y=0 , par contre je multiplie ces variables par 1000 pour viter de manipuler des flottants, c'est pour a j'aimerais savoir comment utiliser les nombres  virgules fixes pour effectuer le calcul.

----------


## mith06

> A = 0 (angle calcul) donc labscisse X=1 et l'ordonn *Y=0*



*Y <= Y + shift_right(X,i);* <=> Y <= 0 + 0/(2^i) <=> *Y <= 0*
*Y <= Y - shift_right(X,i);* <=> Y <= 0 - 0/(2^i) <=>* Y <= 0*

a ne peux pas marcher avec Y = 0....
Pourquoi choisi tu ces valeurs pour initialisation et pas d'autre?

----------


## electron22

C'est la rotation trigonomtrique, au dbut quand l'angle est nul, a veut dire que les cordonnes sont ( l'abscisse X=1) et (l'ordonne Y=0), puis on effectue une premire rotation d'un angle alpha tel que A = artan(2^-i) , a permet de changer le plan et donc augmenter Y et diminuer X, on continue  augmenter Y et diminuer X tout en testant l'angle A  alpha jusqu' dpasser l'angle qu'on cherche  calculer, en ce cas on diminue Y et on augmente X, ce qui permet de s'approcher finement  l'angle qu'on souhaite calculer. 
J'ai compris grce  ce lien, a explique bien le principe et comment arriver aux 3 dernires quations:
http://www.robote2i2009.toile-libre....id=111&lang=fr

pour les quations c'est plutt :
Au dbut :


```
Y <= Y + shift_right(X,i); <=> Y <= 0 + X/(2^i)
```

Si on dpasse l'angle  calculer :


```
Y <= Y - shift_right(X,i); <=> Y <= Y - X/(2^i)
```

----------


## mith06

> pour les quations c'est plutt :
> 
> 
> ```
> 
> ```


A oui pardon je me suis gour... ::oops:: 
Ok ca devrait converger vers quelque chose.

Que valent Y et X avant de faire la division?
Si par exemple Y = 500 et X = 1000, tu voudrais que Y/X te renvoie quel rsultat?

----------


## electron22

En je suis cens utiliser des nombres flottants puisque X et Y ont comme maximum 1. j'ai donc multipli ces variables par 1000 afin de simplifier le calcul, sauf que Y/X donne tout le temps 0 puisque a ne dpasse pas 1. (Si Y = 500 et X = 1000, Y/X=0.5 ... )
Normalement je dois utiliser des nombres  virgule fixe pour localiser ma virgule dans un registre et donc utiliser la partie entire et dcimale du rsultat, la chose que je n'arrive pas  faire ...

----------


## mith06

Effectivement si tu multiplie Y et X par 1000, le rsultat de la division est inchang.
Par contre si tu fais (1000*Y)/X .....

L'ensemble rsultat sera [0 : 1 : 999] <=> [0 : 0.001 : 0.999]

Plus gnralement si tu multiplie Y par N.
L'ensemble rsultat sera [0 : 1 : N-1] <=> [0 : 1/N : 1-1/N]
Rien ne tempche de prendre N = une puissance de 2

Pas besoin d'utiliser les flottants.

----------


## electron22

Effectivement si j'effectue la multiplication (1000*Y)/X  la fin du calcul, a donnera un rsultat variant dans l'intervalle [0 : 0.001 : 0.999]
Par contre je ne peux pas effectuer le calcul de ces quations sans considrer que les variables X et Y sont des flottants, puisqu'elles varient dans l'intervalle [0.0 : x.y : 1.0]  


```

```

et 


```

```

Et si je multiplie Y au dbut pas 1000, le calcul sera incompatible...

----------


## titiri

Bonsoir,

     Euh, justement, les valeurs d'initialisation X0 et Y0 n'ont rien d'alatoire. Pour calculer
𝑥_𝑛=∏_𝑛 𝐾_𝑖 ∙(𝑥_0∙cos⁡(alpha)−𝑦_0∙sin⁡(alpha) )
𝑦_𝑛=∏_𝑛 𝐾_𝑖 ∙(𝑦_0∙cos⁡(alpha)+𝑥_0∙sin⁡(alpha) )

    Donc
X0 = 1/An. (o An est la limite o converge le produit ∏_𝑛 𝐾_𝑖 ≈0.607252959).Y0 = 0A0 = angle dont cos & sin sont  calculer

Les dtails dans le lien fourni dans mon 1er message:
Formules : http://upload.wikimedia.org/wikivers...A.20120607.pdf, page 7An : http://upload.wikimedia.org/wikivers...A.20120409.pdf, page 12An (suite) : http://upload.wikimedia.org/wikivers...A.20120607.pdf, page 21

Je vous invite vraiment  lire tous ces documents qui,  mon avis, devraient rpondre  toutes vos questions.

Une implmentation possible est de prendre un std_logic_vector de 32 bits et d'en prendre 7 bits pour la partie entire et 25 bits pour la partie dcimale. Le CORDIC permettant de calculer un angle d'au maximum ~99.88, on se limite au 1er quadrant (0  90) et l'on calcule les 3 autres par les formules de trigo classiques (il y a juste  modifier le signe des rsultats en fonction du quadrant "destinataire")

Cordialement

----------


## mith06

Merci Titiri pour les liens.

Je n'ai jamais utilis de cordic, car je n'en jamais eu besoin.
Pour calculer le sin ou le cos d'un nombre j'ai toujours utilis une ROM. Avec les ressources mmoire des FPGA rcents, ou peu facilement atteindre 13 bits de rsolution en phase et 12 bits de rsolution en amplitude (#75db de SFDR) avec un seul bloc mmoire.

Je n'ai jamais eu a implmenter une division dans un seul de mes design.
Je n'ai jamais utilis le calcul flottant.




> Et si je multiplie Y au dbut pas 1000, le calcul sera incompatible...


Certes, c'est pour a qu'il faut faire la multiplication un fois que les itrations sont termins




> Par contre je ne peux pas effectuer le calcul de ces quations sans considrer que les variables X et Y sont des flottants, puisqu'elles varient dans l'intervalle [0.0 : x.y : 1.0]


Je te garanti que tu n'a pas besoin d'utiliser le calcul flottant.

Aprs si tu veux vraiment utiliser les flottant, sache que ce n'est pas un type natif/synthtisable en VHDL (ni en verilog), tu peux toujours d'amuser  implmenter/utiliser une FPU  ::aie::

----------

