mapping.py 2.98 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"""Helpers specific to the mapping mode."""

from .stats import stats_from_mapping_mode


def dword(array, index, bitsize=16):
    """Extract a dword value from two words starting at the given index."""
    return array[index] | array[index+1] << bitsize


def parse_mapping_buffer(raw):
    """Parse the given mapping buffer and return a (spectrums, statistics) tuple.

    Both results are dictionaries of dictionaries, first indexed by pixel,
    then channels:
    - spectrums: <pixel: <channel: spectrum (1D array)>
    - statistics: <pixel: <channel: stats (Stats object)>
    """
    spectrums, statistics = {}, {}

21
22
23
24
25
26
27
28
    # XMAP/Mercury parsing
    if raw[1] == 0:
        raw = raw[::2]
        spectrum_type = 'uint16'
    # FalconX parsing
    else:
        spectrum_type = 'uint32'

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    # Header advance
    header = raw[0:256]
    current = 256

    # Header parsing
    assert header[0] == 0x55aa
    assert header[1] == 0xaa55
    assert header[2] == 0x100
    mapping_mode = header[3]
    buffer_index = dword(header, 4)
    buffer_id = header[7]
    pixel_number = header[8]
    starting_pixel = dword(header, 9)
    module_serial_number = header[11]
    channel_ids = header[12:20:2]
    channel_detector_ids = header[13:20:2]

    # Checks
    assert mapping_mode == 1  # MCA mapping mode
    assert starting_pixel == dword(raw, 256+4)
    assert buffer_id in (0, 1)

    # Unused information, should we do something with it?
    buffer_index, module_serial_number, channel_detector_ids

    # Iterate over pixels
    for _ in range(pixel_number):

        # Pixel header advance
        pixel_header = raw[current:current+256]
        current += 256

        # Pixel header parsing
        assert pixel_header[0] == 0x33cc
        assert pixel_header[1] == 0xcc33
        assert pixel_header[2] == 0x100
        assert pixel_header[3] == mapping_mode
        pixel = dword(pixel_header, 4)
        total_size = dword(pixel_header, 6)
        sizes = pixel_header[8:12]

        # Statistics block
        stats_block = [
            [dword(pixel_header, 32 + 8 * i + 2 * j) for j in range(4)]
            for i in range(4)]

        # Iterate over channels
        spectrums[pixel] = {}
        statistics[pixel] = {}
        remaining = total_size - 256
        for index, channel_id, size in zip(range(4), channel_ids, sizes):

            # Update remaining size
            assert remaining >= 0
            if remaining == 0:
                break
            remaining -= size

            # Sectrum Advance
            spectrum = raw[current:current+size]
89
            spectrum.dtype = spectrum_type
90
91
            current += size

92
93
94
95
            # Discard garbage
            if channel_id in spectrums[pixel]:
                continue

96
97
98
99
100
101
102
103
104
105
            # Set data
            stats = stats_from_mapping_mode(stats_block[index])
            spectrums[pixel][channel_id] = spectrum
            statistics[pixel][channel_id] = stats

        # Checks
        assert remaining == 0

    # Return results
    return spectrums, statistics