Página 1 de 4

Compressão de bytes

MensagemEnviado: 09 Nov 2009 12:42
por Diego_Oliveira
Minha ideia é a seguinte:

-Tenho de amazenar temperaturas de 0 a 50°C, em uma memoria eeprom do tipo "I2C", 24c512, são muitos dados digasse de passagem, mas são armazenados em sequencia.

-As temperaturas vão de 0 a 50 sendo 51 a indicação de aberto ou defeito.

Por se tratar de informaçoes de 0 a 51, e um byte armazena de 0 ... 255 pensei porque não comprimilos, unindo duas informaçoes em um byte só...

Claro neste meu caso eu não tenho grande ideia masacho que talvez conseguiria unir 3 talvez 4 mas duas informaçoes já estariam de bom tamanho.

Procurei na internet mas não achei nada especifico na area de microcontroladores, porém na area de computadores codecs ETC tem muita coisa, li algum materias porém não cheguei a grandes conclusoes !

Grato !!!!

MensagemEnviado: 09 Nov 2009 13:01
por Sergio38br
Boas, vc vai receber estes dados em dec. ou hex?

[ ]'s
Sergio

MensagemEnviado: 09 Nov 2009 13:08
por Diego_Oliveira
Não, é bem mais simples do que parece Sergio38br,

Esses dados o próprio microcontrolador vai varrer os sensores e armazenar...

Depois ele envia via USB mas ai já enviaria "desconpactado".

A ideia é só economizar ums bytes de memoria, pois são varios sensores e tenho de armazena-los de hora em hora...

MensagemEnviado: 09 Nov 2009 13:15
por Diego_Oliveira
Desculpa,

É em decimais não tinha entendido direito por causa da abreviação de dec. perdão...

MensagemEnviado: 09 Nov 2009 13:29
por Alesandro F Zagui
Você vai ter que criar o algoritmo pra isso na mão.

Como sua informacao vai de 0 a 51, você vai precisar de 6 bits pra armazenar cada informação.

suponhamos o seguinte:

AAAAAA - BITS DO PRIMEIRO VALOR
BBBBBB - BITS DO SEGUNDO VALOR
CCCCCC- BITS DO TERCEIRO VALOR
DDDDDD- BITS DO QUARTO VALOR

Hoje provavelmente vc armazena assim:

endereco 1
00AAAAAA
endereço 2
00BBBBBB
endereço 3
00CCCCCC
endereço 4
00DDDDDD

Voce teria que criar um rotina que organizasse os bits assim:

endereço 1
AAAAAABB
endereço 2
BBBBCCCC
endereço 3
CCDDDDDD


Antes precisa de 4 bytes e agora precisa de 3 pra armazenar a mesma informação.

MensagemEnviado: 09 Nov 2009 13:32
por Alesandro F Zagui
Qual PIC você está usando??

Porque não salva na eeprom dele, ou na própria memória flash do PIC?

MensagemEnviado: 09 Nov 2009 13:40
por Diego_Oliveira
Alesandro F Zagui escreveu:Qual PIC você está usando??

Porque não salva na eeprom dele, ou na própria memória flash do PIC?


PIC 16f876A + 24LC512

é que são da ordem de 100 mil leituras, a 24lc512 tem 64K bytes, mas se eu colocasse 2 informaçoes em um byte, atenderia..

A memoria interna já armazena outras coisas...

MensagemEnviado: 09 Nov 2009 13:45
por Jorge_Francisco
Eu conheço alguns algorimos de compressão : LZR, Huffman, etc. Mas usar num PIC, meio chatinho, tem um carinha aqui que fez um algoritmo otimizado para PIC, mas nem sei onde colocou.

Vlw

MensagemEnviado: 09 Nov 2009 13:51
por Djalma Toledo Rodrigues
t1
Rotaciona a Esquerda 2 x ---> t100
+ t2 -----------------------------> t1t2
Rotaciona a Esquerda 2 x ---> t1t200
+ t3 ------------------------------> t1t2t3




----------------------------
Cabem 3 de 51°C redondinho.
51 ? Uma boa idéia! l_l? l_l?
.

MensagemEnviado: 09 Nov 2009 13:56
por Sergio38br
Me diga uma coisa, qual a taxa de compressão que vc quer?? tem uma forma de quardar a temperatura em BCD que pode reduzir em 2 para 1:

ex. 35

em hex 33 e 35 , subtraia 30 de cada desloque o primeiro 4 casa a esquerda e some com o segundo, pronto vc tem 35 em BCD

[ ]'s
Sergio

MensagemEnviado: 09 Nov 2009 15:23
por MOR_AL
Acredito que a determinação do período de uma hora tenha sido por ser uma escolha conveniente. Então, por conveniência, porque que você não monitora a temperatura de 2 em 2 horas?
MOR_AL

MensagemEnviado: 09 Nov 2009 15:28
por Diego_Oliveira
MOR_AL escreveu:Acredito que a determinação do período de uma hora tenha sido por ser uma escolha conveniente. Então, por conveniência, porque que você não monitora a temperatura de 2 em 2 horas?
MOR_AL


Na verdade não é por conveniencia, isso foi pedido pelo cliente, eu até tentei convencer do contrario porém realmente é necessário de 1 em 1 hora....

MensagemEnviado: 09 Nov 2009 17:19
por MOR_AL
Acho que a sugestão do Alesandro F Zagui é a que concentra mais os dados sem perder informação, porém ainda assim ficaria fora de sua necessidade:
Você dispõe de 64kB.
Você quer armazenar 100k valores compreendidos entre 0 e 51.
Com a sugestão do Alesandro F Zagui, você comprimiria os 100k valores em X bytes, onde:
x = 100kB /(1 + 1/3) = 75kB..... Ainda maior que 64kB. :!:
Eu não saberia como reduzir ainda mais sem: alterar o hardware, reduzir o período entre a transferência dos dados ao PC, ou perder informação.
Lamento...
MOR_AL

MensagemEnviado: 09 Nov 2009 20:49
por ivan
De uma olhada nas rotinas compress e expand. Se vc tiver um compilador C para o PIC q está usando, testa pra ver o tamanho que as rotinas irão ocupar.
Como a compressão é maior com a repetição de caracteres, o seu range de valores é pequeno e com muitas leituras, pode ser caiba uma rotina de compressão junto com o seu código.

Apenas uma sugestão.

http://marknelson.us/1989/10/01/lzw-data-compression/


[code]

/*******************************************************************
**
** Copyright (c) 1989 Mark R. Nelson
**
** LZW data compression/expansion demonstration program.
**
** April 13, 1989
**
** Minor mods made 7/19/2006 to conform with ANSI-C - prototypes, casting,
** and argument agreement.
**
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BITS 12 /* Setting the number of bits to 12, 13*/
#define HASHING_SHIFT (BITS-8) /* or 14 affects several constants. */
#define MAX_VALUE (1 << BITS) - 1 /* Note that MS-DOS machines need to */
#define MAX_CODE MAX_VALUE - 1 /* compile their code in large model if*/
/* 14 bits are selected. */
#if BITS == 14
#define TABLE_SIZE 18041 /* The string table size needs to be a */
#endif /* prime number that is somewhat larger*/
#if BITS == 13 /* than 2**BITS. */
#define TABLE_SIZE 9029
#endif
#if BITS <= 12
#define TABLE_SIZE 5021
#endif

void *malloc();

int *code_value; /* This is the code value array */
unsigned int *prefix_code; /* This array holds the prefix codes */
unsigned char *append_character; /* This array holds the appended chars */
unsigned char decode_stack[4000]; /* This array holds the decoded string */

/*
* Forward declarations
*/
void compress(FILE *input,FILE *output);
void expand(FILE *input,FILE *output);
int find_match(int hash_prefix,unsigned int hash_character);
void output_code(FILE *output,unsigned int code);
unsigned int input_code(FILE *input);
unsigned char *decode_string(unsigned char *buffer,unsigned int code);

/********************************************************************
**
** This program gets a file name from the command line. It compresses the
** file, placing its output in a file named test.lzw. It then expands
** test.lzw into test.out. Test.out should then be an exact duplicate of
** the input file.
**
*************************************************************************/

main(int argc, char *argv[])
{
FILE *input_file;
FILE *output_file;
FILE *lzw_file;
char input_file_name[81];

/*
** The three buffers are needed for the compression phase.
*/
code_value=(int*)malloc(TABLE_SIZE*sizeof(int));
prefix_code=(unsigned int *)malloc(TABLE_SIZE*sizeof(unsigned int));
append_character=(unsigned char *)malloc(TABLE_SIZE*sizeof(unsigned char));
if (code_value==NULL || prefix_code==NULL || append_character==NULL)
{
printf("Fatal error allocating table space!\n");
exit(-1);
}
/*
** Get the file name, open it up, and open up the lzw output file.
*/
if (argc>1)
strcpy(input_file_name,argv[1]);
else
{
printf("Input file name? ");
scanf("%s",input_file_name);
}
input_file=fopen(input_file_name,"rb");
lzw_file=fopen("test.lzw","wb");
if (input_file==NULL || lzw_file==NULL)
{
printf("Fatal error opening files.\n");
exit(-1);
};
/*
** Compress the file.
*/
compress(input_file,lzw_file);
fclose(input_file);
fclose(lzw_file);
free(code_value);
/*
** Now open the files for the expansion.
*/
lzw_file=fopen("test.lzw","rb");
output_file=fopen("test.out","wb");
if (lzw_file==NULL || output_file==NULL)
{
printf("Fatal error opening files.\n");
exit(-2);
};
/*
** Expand the file.
*/
expand(lzw_file,output_file);
fclose(lzw_file);
fclose(output_file);

free(prefix_code);
free(append_character);
}

/*
** This is the compression routine. The code should be a fairly close
** match to the algorithm accompanying the article.
**
*/

void compress(FILE *input,FILE *output)
{
unsigned int next_code;
unsigned int character;
unsigned int string_code;
unsigned int index;
int i;

next_code=256; /* Next code is the next available string code*/
for (i=0;i<TABLE_SIZE;i++) /* Clear out the string table before starting */
code_value[i]=-1;

i=0;
printf("Compressing...\n");
string_code=getc(input); /* Get the first code */
/*
** This is the main loop where it all happens. This loop runs util all of
** the input has been exhausted. Note that it stops adding codes to the
** table after all of the possible codes have been defined.
*/
while ((character=getc(input)) != (unsigned)EOF)
{
if (++i==1000) /* Print a * every 1000 */
{ /* input characters. This */
i=0; /* is just a pacifier. */
printf("*");
}
index=find_match(string_code,character);/* See if the string is in */
if (code_value[index] != -1) /* the table. If it is, */
string_code=code_value[index]; /* get the code value. If */
else /* the string is not in the*/
{ /* table, try to add it. */
if (next_code <= MAX_CODE)
{
code_value[index]=next_code++;
prefix_code[index]=string_code;
append_character[index]=character;
}
output_code(output,string_code); /* When a string is found */
string_code=character; /* that is not in the table*/
} /* I output the last string*/
} /* after adding the new one*/
/*
** End of the main loop.
*/
output_code(output,string_code); /* Output the last code */
output_code(output,MAX_VALUE); /* Output the end of buffer code */
output_code(output,0); /* This code flushes the output buffer*/
printf("\n");
}

/*
** This is the hashing routine. It tries to find a match for the prefix+char
** string in the string table. If it finds it, the index is returned. If
** the string is not found, the first available index in the string table is
** returned instead.
*/

int find_match(int hash_prefix,unsigned int hash_character)
{
int index;
int offset;

index = (hash_character << HASHING_SHIFT) ^ hash_prefix;
if (index == 0)
offset = 1;
else
offset = TABLE_SIZE - index;
while (1)
{
if (code_value[index] == -1)
return(index);
if (prefix_code[index] == hash_prefix &&
append_character[index] == hash_character)
return(index);
index -= offset;
if (index < 0)
index += TABLE_SIZE;
}
}

/*
** This is the expansion routine. It takes an LZW format file, and expands
** it to an output file. The code here should be a fairly close match to
** the algorithm in the accompanying article.
*/

void expand(FILE *input,FILE *output)
{
unsigned int next_code;
unsigned int new_code;
unsigned int old_code;
int character;
int counter;
unsigned char *string;

next_code=256; /* This is the next available code to define */
counter=0; /* Counter is used as a pacifier. */
printf("Expanding...\n");

old_code=input_code(input); /* Read in the first code, initialize the */
character=old_code; /* character variable, and send the first */
putc(old_code,output); /* code to the output file */
/*
** This is the main expansion loop. It reads in characters from the LZW file
** until it sees the special code used to inidicate the end of the data.
*/
while ((new_code=input_code(input)) != (MAX_VALUE))
{
if (++counter==1000) /* This section of code prints out */
{ /* an asterisk every 1000 characters */
counter=0; /* It is just a pacifier. */
printf("*");
}
/*
** This code checks for the special STRING+CHARACTER+STRING+CHARACTER+STRING
** case which generates an undefined code. It handles it by decoding
** the last code, and adding a single character to the end of the decode string.
*/
if (new_code>=next_code)
{
*decode_stack=character;
string=decode_string(decode_stack+1,old_code);
}
/*
** Otherwise we do a straight decode of the new code.
*/
else
string=decode_string(decode_stack,new_code);
/*
** Now we output the decoded string in reverse order.
*/
character=*string;
while (string >= decode_stack)
putc(*string--,output);
/*
** Finally, if possible, add a new code to the string table.
*/
if (next_code <= MAX_CODE)
{
prefix_code[next_code]=old_code;
append_character[next_code]=character;
next_code++;
}
old_code=new_code;
}
printf("\n");
}

/*
** This routine simply decodes a string from the string table, storing
** it in a buffer. The buffer can then be output in reverse order by
** the expansion program.
*/

unsigned char *decode_string(unsigned char *buffer,unsigned int code)
{
int i;

i=0;
while (code > 255)
{
*buffer++ = append_character[code];
code=prefix_code[code];
if (i++>=MAX_CODE)
{
printf("Fatal error during code expansion.\n");
exit(-3);
}
}
*buffer=code;
return(buffer);
}

/*
** The following two routines are used to output variable length
** codes. They are written strictly for clarity, and are not
** particularyl efficient.
*/

unsigned int input_code(FILE *input)
{
unsigned int return_value;
static int input_bit_count=0;
static unsigned long input_bit_buffer=0L;

while (input_bit_count <= 24)
{
input_bit_buffer |=
(unsigned long) getc(input) << (24-input_bit_count);
input_bit_count += 8;
}
return_value=input_bit_buffer >> (32-BITS);
input_bit_buffer <<= BITS;
input_bit_count -= BITS;
return(return_value);
}

void output_code(FILE *output,unsigned int code)
{
static int output_bit_count=0;
static unsigned long output_bit_buffer=0L;

output_bit_buffer |= (unsigned long) code << (32-BITS-output_bit_count);
output_bit_count += BITS;
while (output_bit_count >= 8)
{
putc(output_bit_buffer >> 24,output);
output_bit_buffer <<= 8;
output_bit_count -= 8;
}
}
[/code]

MensagemEnviado: 10 Nov 2009 05:23
por barboza
Alesandro F Zagui escreveu:Você vai ter que criar o algoritmo pra isso na mão.

Como sua informacao vai de 0 a 51, você vai precisar de 6 bytes pra armazenar cada informação.

suponhamos o seguinte:

AAAAAA - BYTES DO PRIMEIRO VALOR
BBBBBB - BYTES DO SEGUNDO VALOR
CCCCCC- BYTES DO TERCEIRO VALOR
DDDDDD- BYTES DO QUARTO VALOR

Hoje provavelmente vc armazena assim:

endereco 1
00AAAAAA
endereço 2
00BBBBBB
endereço 3
00CCCCCC
endereço 4
00DDDDDD

Voce teria que criar um rotina que organizasse os bytes assim:

endereço 1
AAAAAABB
endereço 2
BBBBCCCC
endereço 3
CCDDDDDD


Antes precisa de 4 bytes e agora precisa de 3 pra armazenar a mesma informação.



Acho que vc quis dizer 6 bits.....