-2

I wanna read a binary file (K7120127.SRS) with caractristhics detailed in the word file (Documentacion SRS DATA.doc) ,2.2. chapter, that adding in the next link

https://drive.google.com/folderview?id=0B_NlxFaQkpgHb00yTm5kU0MyaUU&usp=sharing

In the link is included a viewer of that data (Srsdisp.exe), but i wanna process this data not only view it, that's why I'd want to read it in Python.

I know plot using matplotlib, but work with binary files is new for me. I 'd wanna plot something like this (That plot was made using the viewer included in the link)

enter image description here

tshepang
  • 12,111
  • 21
  • 91
  • 136
nandhos
  • 681
  • 2
  • 16
  • 31

1 Answers1

2

Try that.

from struct import unpack

# constants from the file spec
RECORD_SIZE=826
RECORD_HEADER_SIZE=24
RECORD_ARRAY_SIZE=401

# verbosity values
VERBOSITY_ALL = 2    # print warnings and errors  
VERBOSITY_ERRORS = 1 # print errors
VERBOSITY_NONE = 0   # print nothing


class SRSRecord:
    """Holds one 826 byte SRS Record."""

    _site_to_name = {
        1: "Palehua",
        2: "Holloman",
        3: "Learmonth",
        4: "San Vito",
        # add new site names here ..
        }

    def __init__(self):
        self.year = None
        self.month = None
        self.day = None
        self.hour = None
        self.minute = None
        self.seconds = None

        self.site_number = None
        self.site_name = None
        self.n_bands_per_record = None

        self.a_start_freq = None
        self.a_end_freq = None
        self.a_num_bytes = None
        self.a_analyser_reference_level = None
        self.a_analyser_attenuation = None

        self.b_start_freq = None
        self.b_end_freq = None
        self.b_num_bytes = None
        self.b_analyser_reference_level = None
        self.b_analyser_attenuation = None

        # dictionary that maps frequency in mega hertz to level
        self.a_values = {}

        # dictionary that maps frequency in mega hertz to level
        self.b_values = {}        
        return


    def _parse_srs_file_header(self, header_bytes, verbosity = VERBOSITY_ALL):

        fields = unpack(
            #     General header information
            '>' #          (data packed in big endian format)
            'B' # 1        Year (last 2 digits)                   Byte integer (unsigned)
            'B' # 2        Month number (1 to 12)                    "
            'B' # 3        Day (1 to 31)                             "
            'B' # 4        Hour (0 to 23 UT)                         "
            'B' # 5        Minute (0 to 59)                          "
            'B' # 6        Second at start of scan (0 to 59)         "
            'B' # 7        Site Number (0 to 255)                    "
            'B' # 8        Number of bands in the record (2)         "

            # Band 1 (A-band) header information
            'h' # 9,10     Start Frequency (MHz)                  Word integer (16 bits)
            'H' # 11,12    End Frequency (MHz)                       "
            'H' # 13,14    Number of bytes in data record (401)      "
            'B' # 15       Analyser reference level               Byte integer
            'B' # 16       Analyser attenuation (dB)                 "

            # Band 2 (B-band) header information
            # 17-24         As for band 1
            'H'  # 17,18    Start Frequency (MHz)                 Word integer (16 bits)
            'H'  # 19,20    End Frequency (MHz)                       "
            'H'  # 21,22    Number of bytes in data record (401)      "
            'B'  # 23       Analyser reference level              Byte integer
            'B', # 24       Analyser attenuation (dB)                 "
            header_bytes)

        self.year = fields[0]
        self.month = fields[1]
        self.day = fields[2]
        self.hour = fields[3]
        self.minute = fields[4]
        self.seconds = fields[5]

        # read the site number and work out the site name
        self.site_number = fields[6]
        if self.site_number not in SRSRecord._site_to_name.keys():

            # got an unknown site number.. complain a bit..
            if verbosity >= VERBOSITY_ALL:
                print("Unknown site number: %s" % self.site_number)
                print("A list of known site numbers follows:")            
                for site_number, site_name in SRSRecord._site_to_name.items():
                    print("\t%s: %s" % (site_number, site_name))

            # then set the site name to unknown.
            self.site_name = "UnknownSite"
        else:
            # otherwise look up the site using our lookup table
            self.site_name = SRSRecord._site_to_name[self.site_number]

        # read the number of bands
        self.n_bands_per_record = fields[7] # should be 2
        if self.n_bands_per_record != 2 and verbosity >= VERBOSITY_ERRORS:
            print("Warning.. record has %s bands, expecting 2!" % self.n_bands_per_record)

        # read the a record meta data
        self.a_start_freq = fields[8]
        self.a_end_freq = fields[9]
        self.a_num_bytes = fields[10]
        if self.a_num_bytes != 401 and verbosity >= VERBOSITY_ERRORS:
            print("Warning.. record has %s bytes in the a array, expecting 401!" %
                  self.a_num_bytes)

        self.a_analyser_reference_level = fields[11]        
        self.a_analyser_attenuation = fields[12]

        # read the b record meta data
        self.b_start_freq = fields[13]
        self.b_end_freq = fields[14]
        self.b_num_bytes = fields[15]
        if self.b_num_bytes != 401 and verbosity >= VERBOSITY_ERRORS:
            print("Warning.. record has %s bytes in the b array, expecting 401!" %
                  self.b_num_bytes)
        self.b_analyser_reference_level = fields[16]
        self.b_analyser_attenuation = fields[17]        
        return


    def _parse_srs_a_levels(self, a_bytes):
        # unpack the frequency/levels from the first array
        for i in range(401):

            # freq equation from the srs file format spec
            freq_a = 25 + 50 * i / 400.0
            level_a = unpack('>B', a_bytes[i])[0]
            self.a_values[freq_a] = level_a
        return

    def _parse_srs_b_levels(self, b_bytes):
        for i in range(401):
            # freq equation from the srs file format spec
            freq_b = 75 + 105 * i / 400.0
            level_b = unpack('>B', b_bytes[i])[0]
            self.b_values[freq_b] = level_b
        return


    def __str__(self):
        return ("%s/%s/%s, %s:%s:%s  site: %s/%s bands: %s  "
                "[A %s->%s MHz ref_level: %s atten: %s dB], "
                "[B %s->%s MHz ref_level: %s atten: %s dB]"
                )% (
                    self.day, self.month, self.year, 
                    self.hour, self.minute, self.seconds,
                    self.site_number, self.site_name,            
                    self.n_bands_per_record,
                    self.a_start_freq, self.a_end_freq, 
                    self.a_analyser_reference_level, self.a_analyser_attenuation,
                    self.b_start_freq, self.b_end_freq, 
                    self.b_analyser_reference_level, self.b_analyser_attenuation,
                    )

    def _dump(self, values):        
        freqs = values.keys()
        freqs.sort()
        for freq in freqs:
            print "%5s %s" % (freq, values[freq])
        return

    def dump_a(self):
        self._dump(self.a_values)
        return

    def dump_b(self):
        self._dump(self.b_values)
        return


def read_srs_file(fname):
    """Parses an srs file and returns a list of SRSRecords."""

    # keep the records we read in here
    srs_records = []

    f = open(fname, "rb")
    while True:

        # read raw record data
        record_data = f.read(RECORD_SIZE)

        # if the length of the record data is zero we've reached the end of the data
        if len(record_data) == 0:
            break

        # break up the record bytes into header, array a and array b bytes
        header_bytes = record_data[:RECORD_HEADER_SIZE]
        a_bytes = record_data[RECORD_HEADER_SIZE : RECORD_HEADER_SIZE + RECORD_ARRAY_SIZE]
        b_bytes = record_data[RECORD_HEADER_SIZE + RECORD_ARRAY_SIZE :
                              RECORD_HEADER_SIZE + 2 * RECORD_ARRAY_SIZE]

        # make a new srs record
        record = SRSRecord()
        record._parse_srs_file_header(header_bytes, verbosity = VERBOSITY_ERRORS)
        record._parse_srs_a_levels(a_bytes)
        record._parse_srs_b_levels(b_bytes)
        srs_records.append(record)

    return srs_records




if __name__ == "__main__":

    # parse the file.. (this is where the magic happens ;)
    srs_records = read_srs_file(fname = "K7120127.SRS")

    # play with the data
    for i in range(3):
        print srs_records[i]

    r0 = srs_records[0]
    r0.dump_a()
    r0.dump_b()
demented hedgehog
  • 7,007
  • 4
  • 42
  • 49
  • In the link there are a viewer, If would i like plot this data like that? – nandhos Mar 15 '14 at 10:26
  • Graphing with python is usually done with matplotlib.. http://matplotlib.org/ Put a picture of the graph you want somewhere. I'm on linux and can't be bothered dealing with microsoft stuff on my days off :) – demented hedgehog Mar 15 '14 at 11:20
  • alternatively check out gnuplot or print out csv and import into ms excel (or gnumeric) and graph from there. – demented hedgehog Mar 15 '14 at 11:29
  • that is the picture @demented hedgehog – nandhos Mar 16 '14 at 17:46
  • Well, I'd wanna plot that data in three dimension vertical (Frequency), horizontal (Time) and Flux Intensity (Color intensity). eg . the picture shows. – nandhos Apr 01 '14 at 01:48