Speed up bitwise operations/converting byte data from serial to int - python-3.x

I have a ADC-device which is connected with USB to my Google Coral Dev Board. The device sends 2080 bytes of 16 bit sensor data with a serial port each ms to my Dev Board. There I read that data with pyserial and convert it to integers with the code below. The line commented with "Conversion" is the line, which converts the byte data to integer. I dont exactly understand this line but it was provided by the company who gave me the device.
So I got the problem that my Dev Board is working too slow with the conversion from byte to int. It takes around 2.3 seconds to convert 1 second of data and because the system should work in real time (the data is later processed by an AI model), obviously this is not working like this.
I measured the processing time of partions of that code and the bottleneck is the bitwise operations which take around 2 ms for 1 ms of data.
Is there a way to speed up the process? Actually I am not even sure if there is a problem with my Dev Board or if it is normal that it works so "slow" like this.
def fill_buffer(self):
total_data_per_ms_int = np.zeros(shape=[1040])
for i in range(0, self.buffer_time): #One iteration means 1 ms of data, 2080 bytes per iteration -> ae: 1000 bytes, vib_xyz: je 10 bytes, temp: 10 bytes
total_data_per_ms_bytes = self.ser.read(2080)
z = 0
for j in range(0, 2080, 2):
value_int = total_data_per_ms_bytes[j+1]<<8 | total_data_per_ms_bytes[j] #Conversion from byte to int
total_data_per_ms_int[z] = value_int
z = z+1
self.sensor1[0+i*1000:1000+i*1000] = (total_data_per_ms_int[0:1000]) #This part is for dividing the data which has a specific type to 5 different arrays
self.sensor2[0+i*10:10+i*10] = (total_data_per_ms_int[1000:1040:4]) #not important for understanding the problem
self.sensor3[0+i*10:10+i*10] = (total_data_per_ms_int[1001:1040:4])
self.sensor4[0+i*10:10+i*10] = (total_data_per_ms_int[1002:1040:4])
self.sensor5[0+i*10:10+i*10] = (total_data_per_ms_int[1003:1040:4])

Related

How to parse CAN bus data

I have a CAN bus charger which broadcasts battery charge level, but I am unable to parse the incoming data.
I use Node.js to capture the data and I receive (for example) following HEX values from the charger:
09e6000000
f5e5000000
Device datasheet states, that this message is 40 bits long. And it contains
Start bit 0, length 20, factor 0.001 - battery voltage
Start bit 20, length 18, factor 0.001 - charging current
Start bit 38, length 1, factor 1 - fault
Start bit 39, length 1, factor 1 - charging
I understand, that I should convert the HEX values to binary, using online calculator I can convert it as follows
09e6000000 -> 100111100110000000000000000000000000
Now if I extract first 20 values, 10011110011000000000 and again, using online calculator to convert it to demical I get 648704
If I take second HEX value and follow same process I get
f5e5000000 -> 1111010111100101000000000000000000000000 -> 11110101111001010000 -> 1007184
Something is terribly wrong, since these two HEX values should have been around 59.000. What I am doing wrong?

Why do you divide bit depth by 8 when computing PCM file size?

So basically, I thought the formula for computing pcm file size went as follows:
fileSize(in bits) = samples_per_sec x seconds x number_of_channels
And it worked just fine for me since I was exclusively dealing with pcm files which had 8 bit depth.
When I started to deal with 16 bit depth files, the formula didn't produce accurate results.
Through some googling I found out that my aformentioned formula was wrong, actually you have to adhere to this one:
fileSize(in bits) = samples_per_sec x seconds x number_of_channel x bit_depth/8
It explains why I was getting correct results with the incorrect formula since, you know, 8 / 8 = 1.
The thing that I don't get is this: why do you have to divide bit depth by eight?
In order to get bits as a result of your calculations, you have to get them on the right side of your formula as well:
bits = samples/seconds x seconds x num_of_channels(dimensionless) x bits/sample = bits
which is fine. So, it should work without division by eight. But it doesn't.
Where am I wrong?
In your notation style:
samples_per_sec x seconds x number_of_channels is total number of samples
samples_per_sec x seconds x number_of_channel x bit_depth is total number of bits
samples_per_sec x seconds x number_of_channel x bit_depth / 8 is total number of bytes
samples/seconds x seconds x num_of_channels(dimensionless) x bits/sample is sample_rate x duration_in_seconds x num_of_channels x bit_depth, which is again total number of bits
The main confusion is likely from bits and bytes. Audio sample size is typically described in bit depth not byte depth. File size / memory is described typically in bytes. To go from bits to bytes you simply divide by 8.

scull driver from LDD - scull_read and scull_write

I am going through LDD from Rubini to learn driver programming.Currently, I am going through 3rd chapter - writing character driver "scull". However, In the example code provided by the authors, I am not able to understand the following lines in scull_read() and scull_write() methods :
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum;
I have spent quite a time on it in vain( and still working on it) . Can someone please help me understand the functionality of the above code snippet??
Regards,
Roy
Suppose you have set quantum area size to 4000 bytes in scull driver and qset array size to 10. In that case, value of itemsize would be 40000. f_pos is a position from where read/write should start, which is coming as a parameter to read/write function. suppose read request has come and f_pos is 50000.
Now,
item = (long)*f_pos / itemsize; so item would be 50000/40000 = 1
rest = (long)*f_pos % itemsize; so rest would be 50000%40000 = 10000
s_pos = rest / quantum; so s_pos would be 10000/4000 = 2
q_pos = rest % quantum; so q_pos would be 10000%4000 = 2000
If you have read description of scull driver in chapter 3 carefully then each scull device is a linked list of pointers (of scull_qset) and in our case each scull_qset points to array of pointers which points to quantum area of 4000 bytes as we have set quantum area size 4000 bytes and array size in our case is 10. So, our each scull_qset is an array of 10 pointers and each pointer points to 4000 bytes. So, one scull_qset has capacity of 40000 bytes.
In our read request, f_pos is 50000, so obviously this position would not be in first scull_qset which is proven by calculation of item. As item is 1, it will point to second scull_qset(value of item would be 0 for first scull_qset, for more information see scull_follow function definition).
Value of rest will help to find out at which position in second scull_qset read should start. As each quantum area is of 4000 bytes, s_pos gives out of 10 pointers of second scull_qset which pointer should be used and qset tells that in a particular quantum area pointed by pointer found in s_pos, at which particular location read should start.

How to change the volume of a PCM data stream (failed experiment)

Solved
My code was never before used for processing signed values and as such bytes -> short conversion was incorrectly handling the sign bit. Doing that properly solved the issue.
The question was...
I'm trying to change the volume of a PCM data stream. I can extract single channel data from a stereo file, do various silly experimental effects with the samples by skipping/duplicating them/inserting zeros/etc but I can't seem to find a way to modify actual sample values in any way and get a sensible output.
My attempts are really simple: http://i.imgur.com/FZ1BP.png
source audio data
values - 10000
values + 10000
values * 0.9
values * 1.1
(value = -value works fine -- reverses the wave and it sounds the same)
The code to do this is equally simple (I/O uses unsigned values in range 0-65535) <-- that was the problem, reading properly signed values solved the issue:
// NOTE: INVALID CODE
int sample = ...read unsigned 16 bit value from a stream...
sample -= 32768;
sample = (int)(sample * 0.9f);
sample += 32768;
...write unsigned 16 bit value to a stream...
// NOTE: VALID CODE
int sample = ...read *signed* 16 bit value from a stream...
sample = (int)(sample * 0.9f);
...write 16 bit value to a stream...
I'm trying to make the sample quieter. I'd imagine making the amplitude smaller (sample * 0.9) would result in a quieter file but both 4. and 5. above are clearly invalid. There is a similar question on SO where MusiGenesis saying he got correct results with 'sample *= 0.75' type of code (yes, I did experiment with other values besides 0.9 and 1.1).
The question is: am I doing something stupid or is the whole idea of multiplying by a constant wrong? I'd like the end result to be something like this: http://i.imgur.com/qUL10.png
Your 4th attempt is definitely the the correct approach. Assuming your sample range is centered around 0, multiplying each sample by another value is how you can change the volume or gain of a signal.
In this case though, I'd guess something funny happening behind the scenes when you're multiplying an int by a float and casting back to int. Hard to say without knowing what language you're using, but that might be what's causing the problem.

Libsox encoding

Why do i get distorted output if I convert a wav file using libsox to:
&in->encoding.encoding = SOX_ENCODING_UNSIGNED;
&in->encoding.bits_per_sample = 8;
using the above code?
The input file has bits_per_sample = 16.
So you're saying that you tell SOX to read a 16 bit sample WAV file as an 8 bit sample file? Knowing nothing about SOX, I would expect it to read each 16 bit sample as two 8 bit samples... the high order byte and the low order byte like this: ...HLHLHLHLHL...
For simplicity, we'll call high order byte samples 'A' samples. 'A' samples carry the original sound with less dynamic range, because the low order byte with the extra precision has been chopped off.
We'll call the low order byte samples "B samples." These will be roughly random and encode noise.
So, as a result we'll have the original sound, the 'A' samples, shifted down in frequency by a half. This is because there's a 'B' sample between every 'A' sample which halves the rate of the 'A' samples. The 'B' samples add noise to the original sound. So we'll have the original sound, shifted down by a half, with noise.
Is that what you're hearing?
Edit Guest commented that the goal is to downconvert a WAV to 8 bit audio. Reading the manpage for SoX, it looks like SoX always uses 32 bit audio in memory as a result of sox_read(). Passing it a format will only make it attempt to read from that format.
To downconvert in memory, use SOX_SAMPLE_TO_SIGNED_8BIT or SOX_SAMPLE_TO_UNSIGNED_8BIT from sox.h, ie:
sox_format_t ft = sox_open_read("/file/blah.wav", NULL, NULL);
if( ft ) {
sox_ssample_t buffer[100];
sox_size_t amt = sox_read(ft, buffer, sizeof(buffer));
char 8bitsample = SOX_SAMPLE_TO_SIGNED_8BIT(buffer[0], ft->clips);
}
to output a downconverted file, use the 8 bit format when writing instead of when reading.

Resources