Manchester codifica un flusso di dati


14

La codifica Manchester è un protocollo di telecomunicazione utilizzato nelle comunicazioni radio che garantisce transizioni di bit a intervalli regolari in modo che un ricevitore possa recuperare la frequenza di clock dai dati stessi. Raddoppia il bitrate, ma è economico e semplice da implementare. È ampiamente utilizzato dagli operatori radioamatori.

Il concetto è molto semplice: a livello hardware, l'orologio e le linee dati sono semplicemente XORed insieme. Nel software, questo è rappresentato come la conversione di un flusso di input di bit in un flusso di output a doppia velocità, con ogni input '1' tradotto in '01' e ogni input '0' tradotto in '10'.

Questo è un problema facile, ma aperto a molte implementazioni a causa della sua natura bitstream. Cioè, la codifica è concettualmente un processo bit per bit anziché un processo byte per byte. Quindi siamo tutti d'accordo sull'endianness, i bit meno significativi dell'ingresso diventano il byte meno significativo dell'uscita.

Tempo di golf! Scrivere una funzione che, dato un array di byte di lunghezza arbitraria, restituisca un array di quei dati codificati manchester.

L'input e l'output devono essere considerati prima little-endian, byte meno significativi e BIT meno significativi per primi nel flusso di bit.

Disegno bitstream ASCII :

bit #      5 4 3 2 1 0                                5  4  3  2  1  0
IN ------- 1 0 1 0 1 1 ---> [manchester encoder] ---  01 10 01 10 01 01 ----> OUT

Esempi :

Example 1 (hex):
       LSB              MSB     <-- least sig BYTE first
IN : [0x10, 0x02]  
OUT: [0xAA, 0xA9, 0xA6, 0xAA]  

Example 1 (binary):
      msb  lsb                      msb  lsb  <-- translated hex, so msb first
BIN: [00010000, 00000010]                     <-- least sig NIBBLE...
BIN: [10101010, 10101001, 10100110, 10101010] <-- becomes least sig BYTE
         LSB                           MSB

Example 2
IN :  [0xFF, 0x00, 0xAA, 0x55]  
OUT: [0x55, 0x55, 0xAA, 0xAA, 0x66, 0x66, 0x99, 0x99]

Example 3
IN : [0x12, 0x34, 0x56, 0x78, 0x90]  
OUT: [0xA6, 0xA9, 0x9A, 0xA5, 0x96, 0x99, 0x6A, 0x95, 0xAA, 0x69] 

Example 4
IN : [0x01, 0x02, 0x03, 0xF1, 0xF2, 0xF3]  
OUT: [0xA9, 0xAA, 0xA6, 0xAA, 0xA5, 0xAA, 0xA9, 0x55, 0xA6, 0x55, 0xA5, 0x55]

Regole :

  • La soluzione richiede solo un algoritmo per convertire l'input in output.
  • L'acquisizione dell'input e la stampa dell'output NON sono una parte richiesta della soluzione, ma possono essere inclusi. Sei incoraggiato a fornire il tuo codice di prova / stampa se non incluso nella tua soluzione.
  • L'input è un array di byte a 8 bit (qualunque cosa ciò possa significare nella tua lingua preferita), NON una stringa di testo. È possibile utilizzare le stringhe come formato di archiviazione, se conveniente nella propria lingua, ma devono essere supportati caratteri non stampabili (ovvero 0xFF). L'input può anche richiedere una lunghezza, se necessario.
  • La memoria per l'output deve essere allocata dalla routine, non fornita. modifica: requisito non necessario
  • L'output è anche un array di byte a 8 bit e, se necessario, una lunghezza.
  • Deve supportare almeno 16 KB di input
  • Le prestazioni non devono essere troppo orribili: <10s per 16 KB
  • Il byte meno significativo per primo in memoria.

Sfida del canale laterale :

  • Sfida la risposta di un altro utente dimostrando che il tuo codice è più veloce, più efficiente in termini di memoria o produce un file binario più piccolo!

Prendi il golf! Il codice più corto vince!


2
"La memoria per l'output deve essere allocata dalla routine, non fornita." Sembra un requisito piuttosto strano poiché molte lingue hanno allocazione di memoria completamente automatica.
aaaaaaaaaaaa,

Cosa diavolo ti ha posseduto per usare un ordine così bizzarro?
Peter Taylor,

L'ordine dei bit ha senso se si considera il mezzo fisico per cui viene utilizzato; questo algoritmo è per un flusso di singoli bit che viaggiano attraverso l'aria. Il fatto che dobbiamo memorizzarlo in memoria e che scriviamo hex msb-> lsb, rende un po 'difficile tenere traccia di.
Mrmekon,

Risposte:


6

GolfScript 28 caratteri

{2{base}:|~4|43691-~256|~\}%

Versione equivalente senza ottimizzazione offuscata:

{2base 4base 43691-~256base~\}%

Il codice accetta l'input come una matrice di numeri interi e restituisce idem.

Per ogni numero nella matrice il numero viene convertito nella forma di matrice di base 2, quindi viene riconvertito in un numero come se fosse la base 4, questo ha l'effetto di spaziare i bit con uno 0 tra ciascuno. 43691 viene quindi sottratto dal numero e il risultato viene invertito binario, questo equivale a sottrarre il numero da 43690 (43690 = 0b1010101010101010). Il numero viene quindi diviso in due parti convertendolo in un array di base 256, l'array viene decomposto e l'ordine dei due numeri risultanti viene invertito.

Esempio di input:

[1 2 3 241 242 243]

Esempio di output:

[169 170 166 170 165 170 169 85 166 85 165 85]

È ridicolmente breve e molto intelligente! Anche se non sembra soddisfare i 16 KB in un suggerimento sulle prestazioni <10s, almeno per me; il tuo impiega 43 secondi sul mio Mac dual-core per convertire un array di 16384 1 di. In confronto, la mia enorme implementazione (2419 caratteri) in pitone richiede 0,06 secondi per 16 KB.
Mrmekon,

Ci vogliono meno di 5 secondi sulla mia macchina (Win 7) e la maggior parte di ciò sta convertendo l'array in output di testo, che per quanto ho letto la tua domanda non fa parte del requisito, ma GolfScript lo fa automaticamente con tutto ciò che rimane in pila dopo l'esecuzione. Si potrebbe semplicemente fare in modo che il codice rilasci il risultato piuttosto che stamparlo (aggiungere; alla fine del codice). Se vuoi vedere l'output (anche se non fa parte delle specifiche della domanda.) Conosco due trucchi per accelerarlo, reindirizzarlo su un file e stamparlo esplicitamente in piccoli blocchi usando i comandi di stampa:{2{base}:|~4|43691-~256|~p p}%
aaaaaaaaaaaa

In un Ubuntu VM (su Windows), ottengo 8s per 16kb. Su un Mac con una CPU migliore ci sono voluti 1m18. Immagino che il rubino delle navi con OSX sia terribilmente lento
gnibbler

Sembra che la stampa rubino sia disgustosamente lenta sulla mia macchina. Solo 2 secondi con la stampa disattivata e Ruby 1.9 (e 5 secondi con la versione OSX nativa). È molto meglio!
mrmekon

3

c - 224 caratteri

Credo che questo sia funzionale, inclusa l'allocazione dei requisiti di memoria da quando è stata abbandonata.

#include <stdlib.h>
int B(char i){int16_t n,o=0xFFFF;for(n=0;n<8;++n)o^=((((i>>n)&1)+1))<<(2*n);
return o;}char* M(char*i,int n){char*o=calloc(n+1,2),*p=o;do{int r=B(*i++);
*p++=0xFF&r;*p++=(0xFF00&r)>>8;}while(--n);return o;}

La parte di lavoro del codice è un loop sui bit di ciascun carattere, osservando che ((bit + 1) esclusivo-o 3) è la coppia di bit di output e che applica molta logica di spostamento e mascheramento per allineare tutto.

Come fa c, funziona sui dati come caratteri. Lo scaffold di test non accetterà 0 byte (perché c li considera come fine stringa), ma il codice di lavoro non ha tale limitazione.

Potrebbe essere golfato un po 'di più copiando il lavoro di conversione dei byte in linea.

Esecuzione del test (con scaffold di prova migliorato):

$ gcc -g manchester_golf.c
$ ./a.out AB xyz U
'AB':
[ 0x41, 0x42 ]
[ 0xa9, 0x9a, 0xa6, 0x9a ]
'xyz':
[ 0x78, 0x79, 0x7a ]
[ 0x6a, 0x95, 0x69, 0x95, 0x66, 0x95 ]
'U':
[ 0x55 ]
[ 0x99, 0x99 ]

Commentato, meno dipendente dalla macchina e con impalcatura di prova

/* manchester.c
 *
 * Manchester code a bit stream least significant bit first
 *
 * Manchester coding means that bits are expanded as {0,1} --> {10, 01}
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>

/* Caller must insure that out points to a valid, writable two byte
   buffer filled with 0xFF */
int16_t manByte(char i){
  int16_t n,o=0xFFFF;
  printf("Manchester coding byte 0x%hx...\n",i);
  for(n=0; n<CHAR_BIT; ++n)
    o ^= (
      (
       (
        (i>>n)&1) /* nth bit of i*/
       +1) /* +1 */
      ) <<(2*n) /* shifted up 2*n bits */ 
      ;
  printf("\tas 0x%hx\n",o);
  return o;
}

char* manBuf(const char*i, int n){
  char*o=calloc(n+1,2),*p=o;
  do{
    int16_t r=manByte(*i++);
    *p++= 0xFF&r;
    *p++=(0xFF00&r)>>8;
  } while(--n);
  return o;
}

void pbuf(FILE* f, char *buf, int len){
  int i;
  fprintf(f,"[");
  for(i=0; i<len-1; i++)
    fprintf(f," 0x%hhx,",buf[i]);
  fprintf(f," 0x%hhx ]\n",buf[len-1]);
}

int main(int argc, char**argv){
  int i;
  for(i=1; i<argc; i++){
    int l=strlen(argv[i]);
    char *o=manBuf(argv[i],l);
    printf("'%s':\n",argv[i]);
    pbuf(stdout,argv[i],l);
    pbuf(stdout,o,l*2);
    free(o);
  }
  return 0;
}

3

J, 36

,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0)

Schema di spiegazione (vedi Vocabolario J per riferimento):

  • ,@:(3 :'...'"0)applica il ... a ciascun "byte" di input come y, risultando in due byte (numeri interi) ciascuno. Il risultato è appiattito da ,.
  • y#:~8#2è equivalente 2 2 2 2 2 2 2 2 #: yo vettore delle 8 cifre meno significative di base 2 di y.
  • 4|. scambia i 4 bit anteriori e posteriori ruotando di 4 posizioni.
  • (,.~-.)equivale 3 :'(-. y) ,. y'o no all'argomento 'cucito' all'argomento (prendendo forma 8 2).
  • #.2 8$, appiattisce il risultato dando il flusso di bit, rimodella in 2 file di 8 e converte dalla base 2.

Esempio di utilizzo (J, interattivo):

    ,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0) 1 2 3 241 242 243
,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0) 1 2 3 241 242 243
169 170 166 170 165 170 169 85 166 85 165 85

Informazioni sulla velocità (J, interattivo):

   manchester =: ,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0)
manchester =: ,@:(3 :'#.2 8$,(,.~-.)4|.y#:~8#2'"0)
   data =: 256 | i. 16384
data =: 256 | i. 16384
   100 (6!:2) 'manchester data'
100 (6!:2) 'manchester data'
0.243138

Il tempo medio per 16kb è appena sotto .25s, Intel Core Duo 1.83Ghz o simile.


3

Haskell, 76 caratteri

import Bits
z a=170-sum[a.&.p*p|p<-[1,2,4,8]]
y a=[z a,z$a`div`16]
m=(>>=y)

Esecuzioni di test:

> testAll 
input      [10, 02]
encoded    [AA, A9, A6, AA]
  pass
input      [FF, 00, AA, 55]
encoded    [55, 55, AA, AA, 66, 66, 99, 99]
  pass
input      [12, 34, 56, 78, 90]
encoded    [A6, A9, 9A, A5, 96, 99, 6A, 95, AA, 69]
  pass
input      [01, 02, 03, F1, F2, F3]
encoded    [A9, AA, A6, AA, A5, AA, A9, 55, A6, 55, A5, 55]
  pass

Le prestazioni rientrano nelle specifiche. a 1 MB in ~ 1,2 secondi sul mio laptop vecchio stile. Soffre perché l'input viene convertito in e da un elenco, anziché elaborato come un ByteArray.

> dd bs=1m count=1 if=/dev/urandom | time ./2040-Manchester > /dev/null
1+0 records in
1+0 records out
1048576 bytes transferred in 1.339130 secs (783028 bytes/sec)
        1.20 real         1.18 user         0.01 sys

Il sorgente, 2040-Manchester.hs , include il codice, i test e la funzione principale per un filtro da riga di comando.


3

Batterie OCaml +, 138 117 caratteri

let m s=Char.(String.(of_enum[?chr(170-Enum.sum[?d land
p*p|p<-List:[1;2;4;8]?])|c<-enum s/@code;d<-List:[c;c/16]?]))

test:

Con

let hex s = String.(enum s/@(Char.code|-Printf.sprintf "%02x")|>List.of_enum|>join" ")

I risultati sono:

m "\x12\x34\x56\x78\x90" |> hex;;
- : string = "a6 a9 9a a5 96 99 6a 95 aa 69"
m "\x10\x02" |> hex;;
- : string = "aa a9 a6 aa"
m "\xFF\x00\xAA\x55" |> hex;;
- : string = "55 55 aa aa 66 66 99 99"
m "\x12\x34\x56\x78\x90" |> hex;;
- : string = "a6 a9 9a a5 96 99 6a 95 aa 69"
m "\x01\x02\x03\xF1\xF2\xF3" |> hex;;  
- : string = "a9 aa a6 aa a5 aa a9 55 a6 55 a5 55"

Come punto di riferimento, con:

let benchmark n =
  let t = Unix.gettimeofday() in
  assert(2*n == String.(length (m (create n))));
  Unix.gettimeofday() -. t

Ottengo:

# benchmark 16_384;;
- : float = 0.115520954132080078

sul mio MacBook.


1

Python, 87 caratteri

Mè la funzione richiesta nel problema. Richiede Nogni nybble e ricombina tutto in un elenco.

N=lambda x:170-(x&1|x*2&4|x*4&16|x*8&64)
M=lambda A:sum([[N(a),N(a>>4)]for a in A],[])

print map(hex,M([0x10,0x02]))
print map(hex,M([0xff,0x00,0xaa,0x55]))
print map(hex,M([0x12, 0x34, 0x56, 0x78, 0x90]))
print map(hex,M([0x01, 0x02, 0x03, 0xF1, 0xF2, 0xF3]))

genera

['0xaa', '0xa9', '0xa6', '0xaa']
['0x55', '0x55', '0xaa', '0xaa', '0x66', '0x66', '0x99', '0x99']
['0xa6', '0xa9', '0x9a', '0xa5', '0x96', '0x99', '0x6a', '0x95', '0xaa', '0x69']
['0xa9', '0xaa', '0xa6', '0xaa', '0xa5', '0xaa', '0xa9', '0x55', '0xa6', '0x55', '0xa5', '0x55']

1

APL (Dyalog Extended) , 22 byte

∊(⌽(2256)⊤43690-4⊥⊤)¨

Provalo online!

Porta della risposta GolfScript.

∊(⌽(2256)⊤43690-4⊥⊤)¨       Monadic train:
  ⌽(2256)⊤43690-4⊥⊤         Define a helper function taking an integer n:
                               Convert n to base 2. Monadic  is an Extended feature.
                  4            Convert the result from base 4.
                                This puts the 1 digits of n 
                                in odd indices of the intermediate result.
            43960-              Subtract from 43690.
    (2256)⊤                    Convert to 2 base-256 digits, corresponding to
                                nibbles of n.
                              Reverse the order of these bytes.
 (                          Call the helper function for each element of the input
                             and flatten the results into a list.

0

C, 164 byte

Comprende una serie di byte esadecimali e si converte in flusso binario manchester.

#include <stdio.h>
main(int c,char **v){int i,b,x,j=0;while(++j<c{sscanf(v[j],"%x",&b);x=b^0xff;for(i=9;--i;){printf("%d%d",x&1,b&1);x=x>>1;b=b>>1;}printf("\n");}}

#include <stdio.h>
main(int c,char **v){
int i,b,x,j=0;
while(++j<c){
    sscanf(v[j],"%x",&b);
    x=b^0xff;
    for(i=9;--i;){
        printf("%d%d",x&1,b&1);
        x=x>>1;b=b>>1;}
    printf("\n");}}

Test:

./a.out 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0

Produzione:

1010101010101010
0110101010101010
1001101010101010
0101101010101010
1010011010101010
0110011010101010
1001011010101010
0101011010101010
1010100110101010
0110100110101010
1001100110101010
0101100110101010
1010010110101010
0110010110101010
1001010110101010
0101010110101010
1010101010101010
1010101001101010
1010101010011010
1010101001011010
1010101010100110
1010101001100110
1010101010010110
1010101001010110
1010101010101001
1010101001101001
1010101010011001
1010101001011001
1010101010100101
1010101001100101
1010101010010101
1010101001010101

Generatore di set di dati di test 16kb:

test_data.c:

#include <stdio.h>
void main()
{
int i=16*1024;
while(i--)
{
    printf("0x%02x ", i&0xFF);
}
printf("\n");
}

cc test_data.c -o test_data

1.6G cronometro i5dual core:

time ./a.out `./test_data` > test.out 
real    0m0.096s
user    0m0.090s
sys 0m0.011s

Bel primo post, ma generalmente non proviamo a offuscare il nostro codice. Più breve sì, più difficile leggere no.
R

0

PHP, 156 byte

function f($i){foreach($i as$n){$b=str_split(str_replace([0,1,2],[2,'01',10],
str_pad(decbin($n),8,0,0)),8);$o[]=bindec($b[1]);$o[]=bindec($b[0]);}return$o;}

Dato l'input [0, 1, 2, 3, 4, 5], restituisce:

[170, 170, 169, 170, 166, 170, 165, 170, 154, 170, 153, 170]

Codifica 16 KiB di dati in 0,015 secondi e 1 MiB di dati in circa 0,9 secondi.

Il codice non golfato, un'altra implementazione (più lunga e circa due volte più lenta) e i casi di test sono disponibili nella pagina delle mie soluzioni di code-golf su Github.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.