从二进制格雷码到任意进制格雷码(1)
目錄
1. 概要
1.1 格雷碼的定義[1]
1.2 格雷碼的特點[1]
2. 二進制格雷碼生成方法
2.1 鏡像法
2.2 異或轉換[1]
2.3 奇偶項
2.4 低位優先更新法
2.6?驗證
3. 后記
2021-10-06
1. 概要
????????本文介紹幾種常用的二進制格雷碼生成方法及并給出幾種python實現代碼。
????????進一步,將二進制格雷碼的基本定義擴展到任意M進制的格雷碼,并給出任意M進制的格雷碼的一種編碼算法及其python代碼實現。
1.1 格雷碼的定義[1]
????????典型的二進制格雷碼(Binary Gray Code)簡稱格雷碼,因1953年公開的弗蘭克·格雷(Frank Gray,18870913-19690523)專利“Pulse Code Communication”而得名,當初是為了通信,現在則常用于模擬-數字轉換和位置-數字轉換中。法國電訊工程師波特(Jean-Maurice-émile Baudot,18450911-19030328)在1880年曾用過的波特碼相當于它的一種變形。1941年George Stibitz設計的一種8元二進制機械計數器正好符合格雷碼計數器的計數規律。
????????我們通常所說的格雷碼一般是指二進制格雷碼,其(通俗非嚴謹)定義為:在一個固定長度的二進制編碼中,若任意兩個相鄰的代碼(包括首尾,即最大值與最小值之間)只有一位二進制數不同,則稱這種編碼為格雷碼(Gray Code)。由于最大數與最小數之間也僅一位數不同,即“首尾相連”,因此又稱循環碼或反射碼(reflected binary code?(RBC))。
????????在數字系統中,計數器的設計要求數碼按一定順序變化。例如,4比特二進制數按自然數遞增計數,若采用8421碼,則數0111變到1000時四位均要變化,而在實際電路中,4位的變化不可能絕對同時發生,則計數中可能出現短暫的其它代碼(1100、1111等)。在特定情況下可能導致電路狀態錯誤或輸入錯誤。使用格雷碼可以避免這種錯誤。
????????格雷碼在很多場合都有應用,比如通信系統中的編碼,比如數字設計中的狀態機的編碼,比如數字系統中異步FIFO設計中的計數器的編碼,機電開關系統中格雷碼被用來防止產生錯誤的輸出等等。
1.2 格雷碼的特點[1]
2. 二進制格雷碼生成方法
2.1 鏡像法
????????如上圖所示,(n+1)比特格雷碼可以基于n比特格雷碼進行構造,方法如下:
????????實現代碼如下:
def bin_gray1_2(N: int): #print('bin_gray1_2...')grayList = []grayList.append('0')grayList.append('1') # print(grayList)for k in range(2,N+1):for m in range(2**(k-1),2**k):grayList.append('1' + grayList[2**k - m - 1])for m in range(2**(k-1)):grayList[m] = '0' + grayList[m]return grayList2.2 異或轉換[1]
????????二進制碼→格雷碼(編碼):
????????此方法從對應的n位二進制碼字中直接得到n位格雷碼碼字,步驟如下:
????????公式表示(G:格雷碼,B:二進制碼):
????????如下圖所示為4比特2進制的格雷碼編碼過程示意圖([1])。
?????????實現代碼如下:
def bin_gray2(N: int):grayList = []for i in range(2**N):i_gray = i ^ (i>>1)grayList.append(i_gray) return grayList?????????格雷碼→二進制碼(解碼):
????????從左邊第二位起,將每位與左邊一位解碼后的值異或,作為該位解碼后的值(最左邊一位依然不變)。依次異或,直到最低位。依次異或轉換后的值(二進制數)就是格雷碼轉換后二進制碼的值。
????????公式表示:(G:格雷碼,B:二進制碼):
????????實現代碼待補充。
??
2.3 奇偶項
????????從0對應N比特的全零格雷碼開始:
? ? ? ? 實現代碼如下:
def bin_gray3(N: int):grayList = []grayList.append(0)prev = 0for k in range(1,2**N):if k%2 == 1: # odd numbergrayList.append(prev^1)prev = prev^1else: # even numberpstr = bin(prev)[2:]# print(pstr)i = len(pstr)-1while i>=0:# print(i)if pstr[i] == '1':breakelse:i -= 1cur = prev ^ (1<<(len(pstr)-i))grayList.append(cur)prev = cur return grayList2.4 低位優先更新法
????????自己杜撰的方法和名詞,不知道有無雷同^-^
????????由于格雷碼的定義要求每兩個相鄰數字的格雷碼最多只能有一個比特不同,因此以下基于深度優先搜索(DFS)的思路來給出二進制格雷碼編碼方法。
????????假定0~(k-1)的n比特格雷碼已經生成好,接下來考慮k的格雷碼的生成:以(k-1)的格雷碼為基礎,嘗試從最右邊碼元(LSB)開始尋找第一個滿足條件的可以翻轉的比特。算法流程如下:
????????實現代碼如下:
def bin_gray4(N: int):grayList = []grayList.append(0)prevGray = 0for k in range(1,2**N):cnt = 0while 1:curGray = prevGray ^ (1<<cnt)if curGray not in grayList:grayList.append(curGray)prevGray = curGraybreakelse: cnt += 1return grayList????????這個算法因為是從最根本的角度來考慮的,因此它具有普適性,即可以適用于任意M進制的格雷碼生成。而上面幾種生成方法都是只能適用于二進制格雷碼的生成方法。當然從實際生成結果來看,可以看出以上幾種特定的二進制格雷碼的生成方法與本算法的生成結果是一致的。從這個算法出發修改搜索策略的話,可以很容易的地生成其它形式的二進制格雷碼編碼。
2.6?驗證
????????以下以4比特二進制格雷碼為例運行以上各函數看看生成結果:
# -*- coding: utf-8 -*- """ Created on Fri Oct 1 08:11:24 2021@author: chenxy """import sys import time import datetime import math # import random from typing import List # from queue import Queue from collections import deque import itertools as it import numpy as np# Each function's definitionif __name__ == '__main__': print('bin_gray1_2...')grayList = bin_gray1_2(N)print(grayList, '\n')grayList = bin_gray2(N)print('bin_gray2...')print([format(grayList[k],'#06b')[2:] for k in range(len(grayList))])print('\n')grayList = bin_gray3(4)print('bin_gray3...')print([format(grayList[k],'#06b')[2:] for k in range(len(grayList))])print('\n')grayList = bin_gray4(4)print('bin_gray4...')print([format(grayList[k],'#06b')[2:] for k in range(len(grayList))]) print('\n')?運行結果:
3. 后記
? ? ? ? 本篇中給出了4種二進制格雷碼的生成方式,但是實際上,前三種都是利用了二進制格雷碼的已知碼結構特征的特殊的生成方法。這些生成方法沒有通用性,因為它們是屬于事后諸葛亮式,是先設計出了格雷碼,然后再根據碼的結構特征寫出各種技巧性的代碼。而且它們也僅僅代表了很多種可能的二進制格雷碼中的特殊的一種(當然也是最常用的一種)而已。
????????只有最后一種方法是從基本定義(the first principle)出發的生成方法,是具有通用性的。而且,即便是二進制的格雷碼,也有很多種設計方式,以上各種生成方法只代表了其中一個特定的方法(當然也是最常用的一種)。??????
? ? ? ? 下一篇我們將格雷碼推廣到任意M進制,并給出任意M進制的格雷碼的生成方式。任意M進制格雷碼可能因為缺乏(最常用的)二進制格雷碼那種明顯的結構特征,因此二進制格雷碼的特定的生成方法就無法適用。但是從基本定義(the first principle)出發的生成方法則是可以通用的。參見下一篇:從二進制格雷碼到任意進制格雷碼(2)https://blog.csdn.net/chenxy_bwave/article/details/120622134https://blog.csdn.net/chenxy_bwave/article/details/120622134
2021-10-06
?????????Hann Yang在評論區提供了一個很簡潔緊湊的二進制的自然碼與格雷碼相互轉換的程序,列舉如下供大家參考:
# Hann Yang def N2G(n,m=1):return bin(n^n>>1)[2:].rjust(m,'0')def G2N(G):for i in range(2**len(G)):if G==bin(i^i>>1)[2:]:breakreturn i[1] https://baike.baidu.com/item/格雷碼/6510858
[2] Gray code - Wikipedia
總結
以上是生活随笔為你收集整理的从二进制格雷码到任意进制格雷码(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ajax相关介绍
- 下一篇: angular使用动态组件后属性值_An