Code GRAY

Python est le langage de prédilection du Raspberry Pi

Modérateurs : Francois, Manfraid

MSG
Raspinaute
Messages : 119
Enregistré le : ven. 26 déc. 2014 18:31

Re: Code GRAY

Message par MSG » sam. 16 juil. 2022 18:42

Bonjour ,

@Artemus24
Il n'y a pas plus simple que ce qui a été indiqué , à savoir :

- L'encodage d'un nombre binaire en gray , c'est la comparaison de 2 bits consécutifs (en partant de la droite vers la gauche) , ils doivent être différent pour avoir comme résultat 1 et 0 si identique .
Cela se simplifie par un masque de ce nombre , décalé d'un rang vers la droite .

Code : Tout sélectionner

def bin2gray (n):
   masq = n >> 1     # le masque , soit n décalé d'un rang à droite 
   gray = n ^ masq   # comparaison des bits consécutifs
   print ("%2i 0b%04i <=> %2i 0b%04i" %(n, int(bin(n)[2:]), gray, int(bin(gray)[2:])))
   return 
Test :

Code : Tout sélectionner

>>> for n in range (16):
...     bin2gray(n)
... 
 0 0b0000 <=>  0 0b0000
 1 0b0001 <=>  1 0b0001
 2 0b0010 <=>  3 0b0011
 3 0b0011 <=>  2 0b0010
 4 0b0100 <=>  6 0b0110
 5 0b0101 <=>  7 0b0111
 6 0b0110 <=>  5 0b0101
 7 0b0111 <=>  4 0b0100
 8 0b1000 <=> 12 0b1100
 9 0b1001 <=> 13 0b1101
10 0b1010 <=> 15 0b1111
11 0b1011 <=> 14 0b1110
12 0b1100 <=> 10 0b1010
13 0b1101 <=> 11 0b1011
14 0b1110 <=>  9 0b1001
15 0b1111 <=>  8 0b1000
>>>

- Le décodage d'un nombre gray en binaire , c'est la somme des bits (en partant de la gauche vers la droite) , si la parité de la somme est paire le résultat est 0 et 1 si impaire .
Cela se simplifie par un masque (aussi) de ce nombre , mais qui se décale à chaque fois vers la droite pour supprimer un bit .

Code : Tout sélectionner

def gray2bin (n):
   binaire = 0
   masq = n                     # le masque
   while masq:
      binaire = binaire ^ masq  # application du masque , à chaque fois qu'un bit du masque est supprimé la parité restante change .
      masq >>= 1                # décalage du masque à droite , un bit est ainsi supprimé .
   print ("%2i 0b%04i <=> %2i 0b%04i" %(n, int(bin(n)[2:]), binaire, int(bin(binaire)[2:])))
   return 
Test :

Code : Tout sélectionner

>>> gray
[0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8]
>>> for n in gray:
...    gray2bin(n)
... 
 0 0b0000 <=>  0 0b0000
 1 0b0001 <=>  1 0b0001
 3 0b0011 <=>  2 0b0010
 2 0b0010 <=>  3 0b0011
 6 0b0110 <=>  4 0b0100
 7 0b0111 <=>  5 0b0101
 5 0b0101 <=>  6 0b0110
 4 0b0100 <=>  7 0b0111
12 0b1100 <=>  8 0b1000
13 0b1101 <=>  9 0b1001
15 0b1111 <=> 10 0b1010
14 0b1110 <=> 11 0b1011
10 0b1010 <=> 12 0b1100
11 0b1011 <=> 13 0b1101
 9 0b1001 <=> 14 0b1110
 8 0b1000 <=> 15 0b1111
>>>
Une autre version de décodage , peut-être plus simple à comprendre :

Code : Tout sélectionner

def gray2bin (n):
   l = list(bin(n)[2:])   # converti le nombre en suite de bits dans une liste
   binaire = 0
   parity = 0
   for bit in l:            # lecture de la liste
      if int(bit):
         parity ^= 1   # change la parité à chaque bit 1
      binaire <<= 1
      binaire += parity
   print ("%2i 0b%04i <=> %2i 0b%04i" %(n, int(bin(n)[2:]), binaire, int(bin(binaire)[2:])))
   return

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Code GRAY

Message par Artemus24 » sam. 16 juil. 2022 22:23

Salut MSG.

Je vois que tu t'amuses bien avec le code gray. :D
Merci de nous avoir communiqué tes deux solutions forts intéressantes pour passer d'un nombre binaire à un nombre gray directement. Ca peut toujours servir.

Cordialement.
Artemus24.
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

MSG
Raspinaute
Messages : 119
Enregistré le : ven. 26 déc. 2014 18:31

Re: Code GRAY

Message par MSG » dim. 17 juil. 2022 15:14

Salut ,

Ça me fait travailler la programmation en python et si ça peut aider certains . Comme disait un prof , comprendre c'est bien , savoir l'expliquer c'est mieux !

j'ai donc codé deux petits programmes pour montrer le fonctionnement interne du décodage (j'aime comprendre comment ça marche) .

Code : Tout sélectionner

def gray2bin_1 (n):                        
   print ("  %08i binaire" %(int(bin(n)[2:])))
   masq = n >> 1                           
   while masq:                             
      print("^ %08i masq" %(int(bin(masq)[2:])))
      n ^= masq                            
      print ("= %08i binaire" %(int(bin(n)[2:])))
      masq >>= 1

Test :

Code : Tout sélectionner

>>> gray2bin_1 (0b01100100)
  01100100 binaire
^ 00110010 masq
= 01010110 binaire
^ 00011001 masq
= 01001111 binaire
^ 00001100 masq
= 01000011 binaire
^ 00000110 masq
= 01000101 binaire
^ 00000011 masq
= 01000110 binaire
^ 00000001 masq
= 01000111 binaire
>>> 
On voit que le masque se décale à chaque fois vers la droite supprimant 1 bit , il est aussitôt appliqué par l'opérande XOR "^" au résultat précédent.


Ma méthode

Code : Tout sélectionner

def gray2bin_2 (n):
   l = list(bin(n)[2:])
   print ("l = %s" %(l))
   parite = 0
   binaire = 0
   print ("l p binaire")
   for bit in l:
#      if int(bit): parite ^= 1
      parite ^= int(bit)	# ligne précédente optimisée
      binaire <<= 1
      binaire += parite
      print ("%1i %1i %08i" %(int(bit), parite, int(bin(binaire)[2:])))
Test:

Code : Tout sélectionner

>>> gray2bin_2 (0b01100100)
l = ['1', '1', '0', '0', '1', '0', '0']
l p binaire
1 1 00000001
1 0 00000010
0 0 00000100
0 0 00001000
1 1 00010001
0 1 00100011
0 1 01000111
>>> 
Nous avons :
- "l" la liste de tous les bits en code gray .
- "p" la parité qui correspond à la somme des bits rencontrés successivement . 1 (impair "p" vaut 1) +1 = 2 (pair "p" vaut 0) + 1 = 3 (impair "p" vaut 1) .... etc
Le décodage binaire résultant correspond à la valeur de la parité "p" (verticalement) qu'on a stocké au fur et à mesure.

La correspondance entre les deux méthodes est bien l'addition des bits .
Sur la première méthode , en supposant que la variable initiale de stockage n valait 0 , le bit le plus à gauche aura changer 1 fois de valeur , les suivants 2 fois , et à partir du 5 ème et les suivants auront changé 3 fois de valeur .

MSG
Raspinaute
Messages : 119
Enregistré le : ven. 26 déc. 2014 18:31

Re: Code GRAY

Message par MSG » sam. 23 juil. 2022 19:24

Bonjour ,
La suite logique est la construction d'un tableau de Karnaugh , dont l'inventeur est toujours parmi nous (chat) :P .
https://fr.wikipedia.org/wiki/Maurice_Karnaugh

Image

Le code n'est pas optimisé pour fonctionner comme je veux , mais ça fonctionne .
Après, j'intègrerais la table de vérité , il n'y aura plus que des 0 et des 1 à la place des nombres (index) .

MSG
Raspinaute
Messages : 119
Enregistré le : ven. 26 déc. 2014 18:31

Re: Code GRAY

Message par MSG » dim. 24 juil. 2022 10:35

j'ai amélioré mon code pour permuter les bits et dont l'indexation dans le tableau .
Image

Dans l'ordre que je veux ... et pouvoir ainsi faire des combinaisons de bits distants (3eme dimension) .
ex: liste des cases mitoyennes de la case 23 dans un tableau de 8 variables.

Code : Tout sélectionner

>>> def list_k (n, b=8):
...    r = []
...    for i in range(b):
...       bp = 2**i
...       r.append(n^bp)
...    print (r)
...    return
... 
>>> 
>>> list_k(23)
[22, 21, 19, 31, 7, 55, 87, 151]
Image

Et la taille que je veux .
Image

C'est plus pratique en Python que sur un tableur , particulièrement les calculs en boucle .

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Code GRAY

Message par Artemus24 » jeu. 28 juil. 2022 12:30

Salut à tous.

Je me suis amusé à créer deux fonctions en 'c', l'une faisant la conversion binaire vers de code de gray et l'autre la fonction inverse. Voici le programme en c :

Code : Tout sélectionner

/*********************/
/*                   */
/*     Code Gray     */
/*                   */
/*********************/

#include <stdio.h>
#include <stdlib.h>


/*********************/
/*                   */
/*     Functions     */
/*                   */
/*********************/

int gray(int n)
{
        return ((n >> 1) ^ n);
}

int igray(int n)
{
        int i;

        for (i=0; n>0; n=n >> 1)        i ^= n;

        return i;
}

/**************************/
/*                        */
/*     Main Procedure     */
/*                        */
/**************************/

int main(void)
{
        printf("\e[1;1H\e[2J");         /* Clear Screen */
        printf("+-------------------+\n");
        printf("|     Code Gray     |\n");
        printf("+-------------------+\n\n");

        for (int i=0; i<32; i++)
                printf("I : %2d  Gray : %2d  Inverse Gray : %2d\n", i, gray(i), igray(gray(i)));

        exit(0);
}
Et voici le résultat à l'exécution de ce programme 'c' :

Code : Tout sélectionner

+-------------------+
|     Code Gray     |
+-------------------+

I :  0  Gray :  0  Inverse Gray :  0
I :  1  Gray :  1  Inverse Gray :  1
I :  2  Gray :  3  Inverse Gray :  2
I :  3  Gray :  2  Inverse Gray :  3
I :  4  Gray :  6  Inverse Gray :  4
I :  5  Gray :  7  Inverse Gray :  5
I :  6  Gray :  5  Inverse Gray :  6
I :  7  Gray :  4  Inverse Gray :  7
I :  8  Gray : 12  Inverse Gray :  8
I :  9  Gray : 13  Inverse Gray :  9
I : 10  Gray : 15  Inverse Gray : 10
I : 11  Gray : 14  Inverse Gray : 11
I : 12  Gray : 10  Inverse Gray : 12
I : 13  Gray : 11  Inverse Gray : 13
I : 14  Gray :  9  Inverse Gray : 14
I : 15  Gray :  8  Inverse Gray : 15
I : 16  Gray : 24  Inverse Gray : 16
I : 17  Gray : 25  Inverse Gray : 17
I : 18  Gray : 27  Inverse Gray : 18
I : 19  Gray : 26  Inverse Gray : 19
I : 20  Gray : 30  Inverse Gray : 20
I : 21  Gray : 31  Inverse Gray : 21
I : 22  Gray : 29  Inverse Gray : 22
I : 23  Gray : 28  Inverse Gray : 23
I : 24  Gray : 20  Inverse Gray : 24
I : 25  Gray : 21  Inverse Gray : 25
I : 26  Gray : 23  Inverse Gray : 26
I : 27  Gray : 22  Inverse Gray : 27
I : 28  Gray : 18  Inverse Gray : 28
I : 29  Gray : 19  Inverse Gray : 29
I : 30  Gray : 17  Inverse Gray : 30
I : 31  Gray : 16  Inverse Gray : 31
/warehouse/Prog_C/28.Gray/ex_01>
Cordialement.
Artemus24.
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

MSG
Raspinaute
Messages : 119
Enregistré le : ven. 26 déc. 2014 18:31

Re: Code GRAY

Message par MSG » jeu. 28 juil. 2022 13:38

Bonjour ,

Quand on a compris le truc , on ne peut faire plus simple ! :lol:

Code : Tout sélectionner

>>> for n in range(32) : print("I= %2i : Gray= %2i : invGray= %2i" %( n,  n^n>>1,  (n^n>>1)^n>>1 ))
... 
I=  0 : Gray=  0 : invGray=  0
I=  1 : Gray=  1 : invGray=  1
I=  2 : Gray=  3 : invGray=  2
I=  3 : Gray=  2 : invGray=  3
I=  4 : Gray=  6 : invGray=  4
I=  5 : Gray=  7 : invGray=  5
I=  6 : Gray=  5 : invGray=  6
I=  7 : Gray=  4 : invGray=  7
I=  8 : Gray= 12 : invGray=  8
I=  9 : Gray= 13 : invGray=  9
I= 10 : Gray= 15 : invGray= 10
I= 11 : Gray= 14 : invGray= 11
I= 12 : Gray= 10 : invGray= 12
I= 13 : Gray= 11 : invGray= 13
I= 14 : Gray=  9 : invGray= 14
I= 15 : Gray=  8 : invGray= 15
I= 16 : Gray= 24 : invGray= 16
I= 17 : Gray= 25 : invGray= 17
I= 18 : Gray= 27 : invGray= 18
I= 19 : Gray= 26 : invGray= 19
I= 20 : Gray= 30 : invGray= 20
I= 21 : Gray= 31 : invGray= 21
I= 22 : Gray= 29 : invGray= 22
I= 23 : Gray= 28 : invGray= 23
I= 24 : Gray= 20 : invGray= 24
I= 25 : Gray= 21 : invGray= 25
I= 26 : Gray= 23 : invGray= 26
I= 27 : Gray= 22 : invGray= 27
I= 28 : Gray= 18 : invGray= 28
I= 29 : Gray= 19 : invGray= 29
I= 30 : Gray= 17 : invGray= 30
I= 31 : Gray= 16 : invGray= 31
>>> 

MSG
Raspinaute
Messages : 119
Enregistré le : ven. 26 déc. 2014 18:31

Re: Code GRAY

Message par MSG » jeu. 28 juil. 2022 14:02

Ou plus épuré en résultat , mais pas en code !

Code : Tout sélectionner

>>> for n in range(32) : print(( "  n | Gray | invG |\n" * (n==0) + "%3i | %4i | %4i |" %( n,  n^n>>1,  (n^n>>1)^n>>1 )))
... 
  n | Gray | invG |
  0 |    0 |    0 |
  1 |    1 |    1 |
  2 |    3 |    2 |
  3 |    2 |    3 |
  4 |    6 |    4 |
  5 |    7 |    5 |
  6 |    5 |    6 |
  7 |    4 |    7 |
  8 |   12 |    8 |
  9 |   13 |    9 |
 10 |   15 |   10 |
 11 |   14 |   11 |
 12 |   10 |   12 |
 13 |   11 |   13 |
 14 |    9 |   14 |
 15 |    8 |   15 |
 16 |   24 |   16 |
 17 |   25 |   17 |
 18 |   27 |   18 |
 19 |   26 |   19 |
 20 |   30 |   20 |
 21 |   31 |   21 |
 22 |   29 |   22 |
 23 |   28 |   23 |
 24 |   20 |   24 |
 25 |   21 |   25 |
 26 |   23 |   26 |
 27 |   22 |   27 |
 28 |   18 |   28 |
 29 |   19 |   29 |
 30 |   17 |   30 |
 31 |   16 |   31 |
>>> 

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Code GRAY

Message par Artemus24 » jeu. 28 juil. 2022 23:08

Salut MSG.
MSG a écrit :Ou plus épuré en résultat , mais pas en code !
L'important est le code. Il doit être concis et facilement lisible ainsi que performant.

La solution passe par la fonction XOR qui possède des propriétés intéressante.
Si a=b^c alors tu as aussi c=a^b, ainsi que b=a^c.
A partir de deux valeurs connues, tu peux retrouver la troisième.

Cordialement.
Artemus24.
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

MSG
Raspinaute
Messages : 119
Enregistré le : ven. 26 déc. 2014 18:31

Re: Code GRAY

Message par MSG » jeu. 28 juil. 2022 23:57

C'est vrai que c'est surprenant , c'est comme une formule mathématique , exemple U = R.I , où en passant un élément de l'autre côté de l'égalité , on passe de la multiplication , à la division . U/R = I et U/I=R . Sauf que l'opérateur inverse de XOR c'est XOR lui même .

Ça se vérifie aussi avec la règle de trois où A*B=C*D , A=C*D/B , B=C*D/A , C=A*B/D , D=A*B/C , A/C=D/B , A/D=C/B , B/C=D/A , B/D=C/A
Ex: A*2=3*4 , A=3*4/2=6 , 6*2=3*4
Avec XOR c'est pareil où A=B^C^D , B=C^D^A, C=D^A^B , D=A^B^C , A^B=C^D
A=2^3^4=5 , 2^3=4^5

C'est dingue ! :shock:

Répondre

Retourner vers « Python »