-2

so I think questions like this have been asked before but I'm having quite a bit of trouble getting this implemented.

I'm dealing with CSV files that contain floating points between -1 and 1. All of these floating points have to be converted to 16 bit 2s complement without the leading '0b'. From there, I will convert that number to a string representation of the 2s complement, and all of those from the CSV will be written will be written to a .dat file with no space in between. So for example, if I read in the CSV file and it has two entries [0.006534, -.1232], I will convert each entry to their respective 2s complement and write them one after another onto a .dat file.

The problem is I'm getting stuck in my code on how to convert the floating point to a 16 bit 2s complement. I've been looking at other posts like this and I've been told to use the .float() function but I've had no luck.

Can someone help me write a script that will take in a floating point number, and return the 16 bit 2s complement string of it? It has to be exactly 16 bits because I'm dealing with the MIT 16 standard.

I am using python 3.4 btw

Community
  • 1
  • 1
likeabbas
  • 115
  • 1
  • 10
  • "16 bit 2s complement" describes a 16-bit integer type. It can't be used to represent fractional values. Do you mean that you want to scale the values from [-1…1] to [-32768…32767]? –  Jul 16 '15 at 20:36
  • Hmm I'm not entirely sure. Let me ask my supervisor. – likeabbas Jul 16 '15 at 20:36
  • I'm dealing with ECG data that has been recorded on a device, converted to WAV, extracting the decimal values of that. I guess I need to do more research – likeabbas Jul 16 '15 at 20:37
  • This is what I got "Each sample is represented by a 16-bit two's complement amplitude stored least significant byte first. Any unused high-order bits are sign-extended from the most significant bit. The format used for MIT-BIH and AHA database distribution 9-track tapes is format 16, with the addition of a logical EOF (octal 0100000) and null-padding after the logical EOF." – likeabbas Jul 16 '15 at 20:40
  • *"16-bit two's complement amplitude stored least significant byte first."* is what you get with `' – jfs Jul 17 '15 at 02:33
  • You probably need to convert Python floats to [IEEE 754-2008 (binary16) format](https://en.wikipedia.org/wiki/Half-precision_floating-point_format). How many float numbers in the input csv file? – jfs Jul 17 '15 at 04:01
  • @J.F.Sebastian: ISTM that he merely has to convert a WAV with floats as values to a different format WAV with 16 bit integers as values. This can be done by simple scaling. – Rudy Velthuis Jul 17 '15 at 10:17
  • @RudyVelthuis: I can't tell from the description. How can you tell? I assume the input is text e.g., `0.006534, -.1232` (decimal, ascii) i.e., the file starts with `b"\x30\x2e\x30\x30\x36"`. And the corresponding output is [`binary16(0.006534) == b'\xb0\x1e'` and `binary16(-.1232) == b'\xe2\xaf'`](https://gist.github.com/zed/59a413ae2ed4141d2037) – jfs Jul 17 '15 at 17:50
  • Hi, I apologize for the late response I didn't see the replies. What I'm doing is taking a Wav file of an ECG recording, we have a program that extracts the digital value (from the analog value) in a CSV file. Now I'm trying to convert this CSV file to the proper MIT format of ECGs. I was considering making a different stack overflow post on this – likeabbas Jul 17 '15 at 20:25
  • @J.F.Sebastian: I wrote ISTM, which means "it seems to me". I never said I knew for sure. If I had known for sure, I would have written an answer. – Rudy Velthuis Jul 18 '15 at 10:56
  • @AbbasDharamsey: your description is unclear. What is your input? Is it a csv file (text) or is it a wav file (binary data). Don't put additional info in the comments; [edit] your question instead. If your input is a wav file in PCM 16bit integer format then it is easy to save amplitudes as [ecg mit signal format 16](http://ecg.mit.edu/dbag/signal-5.htm#sect3) – jfs Jul 18 '15 at 16:05
  • @J.F.Sebastian My goal was to save the amplitudes as the ecg mit signal format 16 as you stated above. I have figured it out, .wav format only allows for 8 bits of data to be stored. My boss required me to use the MIT16 format and not the 12 bit format. What I had to do was multiply the floating point values of the amplitude by (2^14 - 1)/(2^8), then convert that to an integer. Then I would take the 16 bit 2's complement of all of those integers, and do some bit manipulation because the MIT format required the opposite Endian of whatever Python stores, and it ended up working. – likeabbas Jul 20 '15 at 19:14
  • 1
    @J.F.Sebastian I apologize for replying in comments. Originally, the input is a .CSV file containing the f.p. values of the amplitude from a .WAV file (which is the recording of an ECG). So I have a .WAV and a .CSV file. First, I attempted to use the WAV2MIT.c file provided by physionet but ran into some complications. However, in my last comment I state how I was able to convert the f.p. values to the correct 2s complement format. – likeabbas Jul 20 '15 at 19:17
  • @AbbasDharamsey: if you think you've found an answer; you could post it yourself. [It is explicitly encouraged](http://stackoverflow.com/help/self-answer) – jfs Jul 20 '15 at 20:02

1 Answers1

0

To answer the question in the title: to convert a Python float to IEEE 754 half-precision binary floating-point format, you could use binary16:

>>> from binary16 import binary16
>>> binary16(0.006534)
b'\xb0\x1e'
>>> binary16(-.1232)
b'\xe2\xaf'

numpy produces similar results:

>>> import numpy as np
>>> np.array([0.006534, -.1232], np.float16).tostring()
b'\xb1\x1e\xe3\xaf'
>>> np.array([0.006534, -.1232], '>f2').tostring() # big-endian
b'\x1e\xb1\xaf\xe3'

My goal was to save the amplitudes as the ecg mit signal format 16
..snip..
the input is a .CSV file containing the f.p. values of the amplitude from a .WAV file (which is the recording of an ECG).

You could read the wav file directly and write the corresponding 16-bit two's complement amplitudes in little-endian byte order where any unused high-order bits are sign-extended from the most significant bit ('<h' struct format):

#!/usr/bin/env python3
import wave

with wave.open('ecg.wav') as wavfile, open('ecg.mit16', 'wb') as output_file:
    assert wavfile.getnchannels() == 1 # mono
    assert wavfile.getsampwidth() == 2 # 16bit
    output_file.writelines(iter(lambda: wavfile.readframes(4096), b''))

There is a bug in Python 3 that .readframes() returns str instead of bytes sometimes. To workaround it, use if not data test that works on both empty str and bytes:

#!/usr/bin/env python3
import wave

with wave.open('ecg.wav') as wavfile, open('ecg.mit16', 'wb') as output_file:
    assert wavfile.getnchannels() == 1 # mono
    assert wavfile.getsampwidth() == 2 # 16bit
    while True:
        data = wavfile.readframes(4096)
        if not data:
            break
        output_file.write(data)
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • I got this as an error when trying to run your code. C:\matlab2>py test.py Traceback (most recent call last): File "test.py", line 7, in output_file.writelines(iter(lambda: wavfile.readframes(4096), 'b')) TypeError: 'str' does not support the buffer interface – likeabbas Jul 21 '15 at 21:02
  • @AbbasDharamsey: it is a bug in Python. I've posted a workaround. – jfs Jul 21 '15 at 21:36
  • Thank you for that @J.F. Sebastian. This was almost perfect except there is no demodulation. I have a demodulation .exe that a former intern has written and everything works perfectly, but thank you for helping me see if I could easily grab the ECG data from a .wav file :) I would post the demodulation app to github but it is not mine and it is owned by my company :( – likeabbas Jul 21 '15 at 23:20
  • @AbbasDharamsey: do you mean your data is the 3rd case (AM signal) [from this description](http://www.physionet.org/physiotools/wag/wav2mi-1.htm#sect2)? [Does `wav2mit` work for you?](http://www.physionet.org/physiotools/wfdb/convert/wav2mit.c) – jfs Jul 21 '15 at 23:41