Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can i send a 2 byte size variable as 1 byte size variable? [closed]

Tags:

python

c

byte

I am working on some ADC(Analog-to-Digital) value conversions and need to send those values over the UART but due to the speed and other size limitations I want to convert those to one byte size

The ADC is 12 bit for a range 0.0 to 5.0.

Currently I am splitting the 2 byte variable to two separate bytes and joining them back in the receiver section

Sending (C)

// i am trying to send 0xFF8 (4088) which is read from that register 
send[0] = (VADC_G5RES4.B.RESULT) >> 8 ;
send[1] = (VADC_G5RES4.B.RESULT) & 0x0FF;
 .
send[30] = .....

Receiving (Python)

adc1 = data[3]
adc1 = adc1 << 8 | data[4]
adc1 = (float(adc1 * 5) / 4096)
# gives me 4.990234 as the value 

Is there any way that i can send the value in just one byte (maybe by performing the calculation on the sending side)

Only 2 digits after the decimal (4.99) would be fine

like image 647
user2345 Avatar asked Mar 09 '26 15:03

user2345


2 Answers

If there were some magic way to stuff two-byte values into one-byte values, we would do it to everything, and then we would do it again, and we would keep doing it and keep halving the size of everything until we were shoving all the world's information into a single byte. Such magic is not possible.

If you instead throw away half your data, you can reduce the size of things, but you say you want at least 2 digits after the decimal point. A byte can only encode 256 different values, and encoding everything from 0.00 to 9.99 takes 1000 different values, so you still can't do it.


UPDATE: With the additional information that these are only 12-bit values, rather than 16-bit, and that the maximum value is 5.0, we can do a lot better, though still not quite 3 significant figures in 8 bits.

First, instead of wasting 4 bits per value, we can pack 2 values into 3 bytes. That'd look something like

def pack(val1, val2):
    byte1 = val1 >> 4
    byte2 = ((val1 & 0xf) << 4) | (val2 >> 8)
    byte3 = val2 & 0xff
    return byte1, byte2, byte3

You might need to deal with a trailing half-byte.

If 1.5 bytes per value is still too much, there are lossy encoding options. For example, we can just throw away the 4 least-significant bits of every value:

encoded = val >> 4

and decode appropriately:

decoded = encoded * 5.0 / 256

This keeps a precision of 5/256, or about 0.02. Other encodings might perform better, depending on what you expect the signal to look like. For example, chux's solution encodes values exactly as long as the values don't change too fast, but only has a precision of about 0.04 when the values are changing quickly.

like image 193
user2357112 supports Monica Avatar answered Mar 12 '26 04:03

user2357112 supports Monica


Use temporal compression.

Trade time for accuracy. When the ADC is changing fast, sent a 7-bit approximation. When it changes slow, send the delta.

The following is a coarse implementation idea.

Assume 2-byte ADC value in the ranges 0-3FFF.

 sample = ADC();
 encode_value = sample >> 7;
 send(encode_value);
 diff = sample - (encode_value << 7);

 loop:
   previous_sample = sample
   sample = ADC();
   diff = previous_sample - sample;
   if (diff >= -64 && diff <= 63)  {
     send(diff | 0x80);
     diff = 0;
   } else {
     encode_value = sample >> 7;
     send(encode_value);
     diff = sample - (encode_value << 7);
   }

// Receive

valid = 0;
loop:
  sample = receive()
  if (sample & 0x80) {
    delta = sample & 0x7F
    if (delta & 0x40) delta -= 128;
    ADC += delta;
  } else {
    ADC = sample << 9;
    valid = 1;
  } 

Likely should reserve another bit to detect a missed sequence when sending a delta. Other considerations apply, yet here it is to give the OP another point of view.

Refinements include having the delta give up 2 bits of mantissa for a 2-bit exponent.


[Edit]

12 bits of random data do not fit in 8 bits. Some ideas:

  1. Give up precision. Simple divide the 12-bit value by 16, send those 8 bits and multiply by 16 on the receiving end.

  2. Send the first A/D sample in 2 parts by cutting the 12-bit value into 2 6-bits halves. Use the MSB to distinguish if the upper or lower is sent. The receiving end needs 2 samples to put things back together. The 2nd A/D sample on the transmits end is thrown away.

  3. Like #2, but send 2 out of every 3 samples. 24-bits of data in 3 8-bit messages.

  4. As answered in the beginning of this answer. Sometimes sending the course value, other times, the delta.

  5. As commented below @Clifford always send a signed 8-bit delta. Might need a minor adjustment to insure any bias in the receiving sum eventually works its way out.

  6. Take a couple 1000 (million) samples and write it as packed 12-bit data into a file. Zip (compress) the file. What every the ration of compression is found, is an indicator of the best compression scheme we could derive. If it is not at least 33%, then you best to accept that data is too dynamic to be completely transmitted with the requirements given.

like image 41
chux - Reinstate Monica Avatar answered Mar 12 '26 04:03

chux - Reinstate Monica



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!