Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Friday, December 18, 2015

Can i send a 2 byte size variable as 1 byte size variable?

Can i send a 2 byte size variable as 1 byte size variable?


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

Answer by user2357112 for Can i send a 2 byte size variable as 1 byte size variable?


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.

Answer by user2345 for Can i send a 2 byte size variable as 1 byte size variable?


You can convert those in the sending side and multiply with 2 and join a '.' at the 2nd position.. This method works( but not very accurate)

(4088*5)/4096 = 4.990234   

use the first 3 digits and remove the decimal point

499   

divide the value by 2 so that it can be sent using one signed byte (0-255)

499/2 = 249  

send the value using your regular data transfer method

send[0] = 249   

On receiving section multiply the value with 2 and add a decimal point

adc1 = 249*2  newvalue= adc1[:1]+'.'+adc1[1:]  # you get newvalue = 4.98 ( But you loose the accuracy of the converted adc values )  

Answer by etuardu for Can i send a 2 byte size variable as 1 byte size variable?


If I correctly deciphered your problem, it seems that:

  • you have values in the range 0x000 - 0xfff
  • you will make some math with those values ((val * 5) / 4096 ) and only care about the first two decimals after the comma of the resulting number

If this is your question, you can first of all verify how much information you loose if you throw away the least significant byte from your values after the math:

>>> (0x010 * 5) / 4096  0.01953125  

This means that if you spare the last byte you will have an error of ~0.02.

If you are ok with that, you can then skip it and encode your value in a single byte. You just need to right-shift by 4 your value before sending:

 0    f    f    8      >> 4    [  0    0  ] f    f  0000 1111 1111 1000            [ 0000 0000]1111 1111  

On the receiving side, you will left-shift it again and then process:

>>> b = 0xff << 4  >>> (b * 5) / 4096  4.98046875  

Answer by Clifford for Can i send a 2 byte size variable as 1 byte size variable?


It cannot be done without loosing bits and therefore precision. Essentially you would need treat your ADC as if it were 8 bit. That may not be as bad as it sounds, for example, if your ADC is 12 bit (not clear in your question), you loose just 4 bits.

uint8_t send = (adc_high_byte << 6) | (adc_low_byte >> 2) ;  

then in the receiver:

adc1 = (float(data * 80)) / 4096 ;  

In your example 4088 is sent as 4088/16 = 255 and at th ereceiver its is transfromed:

(float(255*80))/4096 = 4.98  

but note that

(float(254*80))/4096 = 4.96,   

so you end up with a precision of approximately 0.02 (precisely speaking, if your maximum value represented by 255 is 5.0, then the precision is 5.0/256 = 0.01953125). This compares to the original precision of 5/4096 = 0.00122

A further refinement is possible using companding. In some applications, such as audio, it is more important to retain detail a small signal levels than high, so you can transform the 12 bit data to 8 using a non-linear encoding so that the difference between say 0 and 1 is much smaller than between 254 and 255. The applicability and success of this will be application dependent - it works well for audio. In other applications a different non-linear encoding may be appropriate, for example for battery monitoring you might use high resolution at the knee of the discharge curve, where rate of voltage drop increases rapidly (in some battery chemistries).

Finally as suggested by @chux, you can transmit delta (changes in level) in fewer bits and retain the full resolution (with some loss of absolute accuracy), but that was his suggestion so I won't elaborate, except to say that the technique can be used with commanding.

Answer by chux for Can i send a 2 byte size variable as 1 byte size variable?


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.


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 71

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.