|
910 | 910 | {
|
911 | 911 | "data": {
|
912 | 912 | "text/plain": [
|
913 |
| - "'hi-3i9f7hfhfhfhf8hfhi-S-h-Z'" |
| 913 | + "'hi-3i9f7hfhfhfhf8hfhi-*Z'" |
914 | 914 | ]
|
915 | 915 | },
|
916 | 916 | "execution_count": null,
|
|
934 | 934 | "id": "d38a5b21-8a4f-4191-8f39-9e8ec4312191",
|
935 | 935 | "metadata": {},
|
936 | 936 | "outputs": [
|
| 937 | + { |
| 938 | + "name": "stdout", |
| 939 | + "output_type": "stream", |
| 940 | + "text": [ |
| 941 | + "[b'\\x0cRoHS 50 Hi-Z\\x01']\n" |
| 942 | + ] |
| 943 | + }, |
937 | 944 | {
|
938 | 945 | "data": {
|
939 | 946 | "text/html": [
|
|
1157 | 1164 | " </tr>\n",
|
1158 | 1165 | " <tr>\n",
|
1159 | 1166 | " <th>39</th>\n",
|
1160 |
| - " <td>RoHS 50 Hi-Z</td>\n", |
1161 |
| - " <td>TubeSpec?</td>\n", |
1162 |
| - " </tr>\n", |
1163 |
| - " <tr>\n", |
1164 |
| - " <th>40</th>\n", |
1165 |
| - " <td>1</td>\n", |
| 1167 | + " <td>[b'\\x0cRoHS 50 Hi-Z\\x01']</td>\n", |
1166 | 1168 | " <td>??</td>\n",
|
1167 | 1169 | " </tr>\n",
|
1168 | 1170 | " <tr>\n",
|
1169 |
| - " <th>41</th>\n", |
| 1171 | + " <th>40</th>\n", |
1170 | 1172 | " <td>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ...</td>\n",
|
1171 |
| - " <td>2048 counts</td>\n", |
| 1173 | + " <td>Intensity_2048_channels</td>\n", |
1172 | 1174 | " </tr>\n",
|
1173 | 1175 | " </tbody>\n",
|
1174 | 1176 | "</table>\n",
|
|
1215 | 1217 | "36 1017.0 \n",
|
1216 | 1218 | "37 2048 \n",
|
1217 | 1219 | "38 38 \n",
|
1218 |
| - "39 RoHS 50 Hi-Z \n", |
1219 |
| - "40 1 \n", |
1220 |
| - "41 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ... \n", |
| 1220 | + "39 [b'\\x0cRoHS 50 Hi-Z\\x01'] \n", |
| 1221 | + "40 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ... \n", |
1221 | 1222 | "\n",
|
1222 | 1223 | " param_keys \n",
|
1223 | 1224 | "0 block_type \n",
|
|
1259 | 1260 | "36 NosePressureInMilliBars \n",
|
1260 | 1261 | "37 NumberOfChannels \n",
|
1261 | 1262 | "38 NoseTemperatureInC \n",
|
1262 |
| - "39 TubeSpec? \n", |
1263 |
| - "40 ?? \n", |
1264 |
| - "41 2048 counts " |
| 1263 | + "39 ?? \n", |
| 1264 | + "40 Intensity_2048_channels " |
1265 | 1265 | ]
|
1266 | 1266 | },
|
1267 | 1267 | "metadata": {},
|
|
1394 | 1394 | "source": [
|
1395 | 1395 | "#|export \n",
|
1396 | 1396 | "\n",
|
| 1397 | + "# 'hi-3i9f7hfhfhfhf8hfhi-S-h-Z'\n", |
| 1398 | + "\n", |
1397 | 1399 | "PDZ_25_STRUCTURE_DICT = {\n",
|
1398 | 1400 | " 25: {'xformat': 'hi-10X-i', \n",
|
1399 | 1401 | " 'param_keys': ['pdz_type', 'block_size', 'FileFormatString?', '??']}, \n",
|
|
1404 | 1406 | " 'param_keys': ['block_type', 'block_size', '??', 'RawCounts', 'ValidCounts', '??', '??', \n",
|
1405 | 1407 | " '??', 'ActiveTimeInSeconds', 'DeadTimeInSeconds', 'ResetTimeInSeconds', \n",
|
1406 | 1408 | " 'LiveTimeInSeconds', 'TotalElapsedTimeInSeconds', '??']}, \n",
|
1407 |
| - " 3: {'xformat': 'hi-3i9f7hfhfhfhf8hfhi-S-h-Z', \n", |
| 1409 | + " 3: {'xformat': 'hi-3i9f7hfhfhfhf8hfhi-*Z', \n", |
1408 | 1410 | " 'param_keys': ['block_type', 'block_size', '??', 'RawCounts', 'ValidCounts', \n",
|
1409 | 1411 | " '??', '??', '??', 'ActiveTimeInSeconds', 'DeadTimeInSeconds', \n",
|
1410 | 1412 | " 'ResetTimeInSeconds', 'LiveTimeInSeconds', 'XrayVoltageInkV', 'XrayFilamentCurrentInMicroAmps', \n",
|
|
1413 | 1415 | " '??', '??', 'eVPerChannel', '??', 'eVStart', \n",
|
1414 | 1416 | " 'Year', 'Month', 'AM/PM code?', 'Day', 'Hour', 'Minutes', 'Seconds', \n",
|
1415 | 1417 | " '??', 'NosePressureInMilliBars', 'NumberOfChannels', 'NoseTemperatureInC', \n",
|
1416 |
| - " 'TubeSpec?', '??', '2048 counts']}}\n", |
| 1418 | + " '??', 'Intensity_2048_channels']}}\n", |
1417 | 1419 | "\n",
|
| 1420 | + "# moved extract_spectra() function to legacy module \n", |
1418 | 1421 | "\n",
|
1419 |
| - "def extract_spectra(pdz_file, to_csv=True, verbose=True): \n", |
1420 |
| - " '''Directly extract spectral data from `pdz_file`. \n", |
1421 |
| - " \n", |
1422 |
| - " Robust extraction of spectrum counts and energy calibration. Other meta data is ignored. '''\n", |
1423 |
| - "\n", |
1424 |
| - " pdz_bytes = file_to_bytes(pdz_file)\n", |
1425 |
| - " block_list = get_blocks(pdz_bytes, verbose=False) \n", |
1426 |
| - " \n", |
1427 |
| - " # select type 3 blocks\n", |
1428 |
| - " b3_list = [b for b in block_list if b['block_type'] == 3] \n", |
1429 |
| - " n_spectra = len(b3_list) \n", |
1430 |
| - "\n", |
1431 |
| - " # parsing spectrum parameters \n", |
1432 |
| - " #from first block to compute channel energies (keV) \n", |
1433 |
| - " # (assuming that these are similar for all spectra in the pdz file) \n", |
1434 |
| - " \n", |
1435 |
| - " arr = b3_list[0]['bytes'] # only using first spectrum! \n", |
1436 |
| - " spectrum_params = multiparse('hi-3i9f7hfhfhfhf8hfhi-S-h', arr, verbose=False)[0] \n", |
1437 |
| - " tube_keV = spectrum_params[12] # FYI \n", |
1438 |
| - " delta_keV = spectrum_params[25] / 1000\n", |
1439 |
| - " start_keV = spectrum_params[27] / 1000 \n", |
1440 |
| - " n_channels = spectrum_params[37] \n", |
1441 |
| - " if n_channels != 2048: \n", |
1442 |
| - " print(f'Found unexpected number of channels in pdz metadata: {n_channels}')\n", |
1443 |
| - " \n", |
1444 |
| - " stop_keV = start_keV + delta_keV * (n_channels -1)\n", |
1445 |
| - " x_keV = np.linspace(start_keV, stop_keV, num=n_channels) \n", |
1446 |
| - "\n", |
1447 |
| - " # initialize array \n", |
1448 |
| - " \n", |
1449 |
| - " spectra_df = pd.DataFrame(index=x_keV)\n", |
1450 |
| - "\n", |
1451 |
| - " # TODO: Test if computed channel energies `x_keV` are reasonable, \n", |
1452 |
| - " # Parsing of spectrum parameters might fail \n", |
1453 |
| - " # if Bruker messes with file format. \n", |
1454 |
| - " # otherwise fall back on 0-40 keV range \n", |
1455 |
| - "\n", |
1456 |
| - " spectrum_list = [] \n", |
1457 |
| - "\n", |
1458 |
| - " for i, b3 in enumerate(b3_list): \n", |
1459 |
| - " arr = b3['bytes'] \n", |
1460 |
| - " counts = np.array(parse(f'{n_channels}i', arr[-4*n_channels:], verbose=False)[0]) \n", |
1461 |
| - "\n", |
1462 |
| - " spectra_df[f'spectrum #{i+1}'] = counts\n", |
1463 |
| - "\n", |
1464 |
| - " if to_csv == True: \n", |
1465 |
| - " csv_file = f'{pdz_file}.csv' \n", |
1466 |
| - " print(f'Saving spectral data to: {csv_file}')\n", |
1467 |
| - " spectra_df.to_csv(csv_file, float_format='%10.5f')\n", |
1468 |
| - "\n", |
1469 |
| - " return spectra_df\n", |
1470 |
| - " \n", |
1471 | 1422 | "\n",
|
1472 | 1423 | "def multiparse(xformat, arr, param_keys=None, verbose=True): \n",
|
1473 | 1424 | " '''Parse segments in extendend format string `xformat` e.g. '<i5f-2S-T-3S-S-f' '''\n",
|
|
1483 | 1434 | " result, arr = read_table(p, arr, verbose=False) \n",
|
1484 | 1435 | " elif 'X' in p: \n",
|
1485 | 1436 | " result, arr = skip_bytes(p, arr, verbose=False) \n",
|
1486 |
| - " elif 'Z' in p: \n", |
| 1437 | + " \n", |
| 1438 | + " # four spectral data scenarios here: \n", |
| 1439 | + "\n", |
| 1440 | + " # (1) 2048 channels at end of array and skip any bytes before\n", |
| 1441 | + " elif p == '*Z': \n", |
| 1442 | + " # split array \n", |
| 1443 | + " n_channels = 2048 \n", |
| 1444 | + " arr_0 = arr[:-n_channels*4] # head \n", |
| 1445 | + " arr_1 = arr[-n_channels*4:] # tail \n", |
| 1446 | + " skipped, _ = skip_bytes('*X', arr_0, verbose=False)\n", |
| 1447 | + " counts, arr = read_counts('Z', arr_1 , verbose=False) # arr should now be empty \n", |
| 1448 | + " result = [skipped, counts] \n", |
| 1449 | + " # (2) 1024 channels at end of array and skip any bytes before\n", |
| 1450 | + " elif p == '*z': \n", |
| 1451 | + " # split array \n", |
| 1452 | + " n_channels = 1024 \n", |
| 1453 | + " arr_0 = arr[:-n_channels*4] # head \n", |
| 1454 | + " arr_1 = arr[-n_channels*4:] # tail \n", |
| 1455 | + " \n", |
| 1456 | + " skipped, _ = skip_bytes('*X', arr_0, verbose=False)\n", |
| 1457 | + " counts, arr = read_counts('z', arr_1 , verbose=False) # arr should now be empty \n", |
| 1458 | + " result = [skipped, counts] \n", |
| 1459 | + " # (3) 2048 channels not at end of array \n", |
| 1460 | + " elif p == 'Z': \n", |
1487 | 1461 | " result, arr = read_counts(p, arr, verbose=False)\n",
|
1488 | 1462 | " result = [result]\n",
|
1489 |
| - " elif 'z' in p: \n", |
1490 |
| - " result, arr = read_counts(p, arr, n_channels=1028, verbose=False)\n", |
| 1463 | + " # (4) 1024 channels not at end of array \n", |
| 1464 | + " elif p == 'z': \n", |
| 1465 | + " result, arr = read_counts(p, arr, verbose=False)\n", |
1491 | 1466 | " result = [result] \n",
|
1492 | 1467 | " \n",
|
1493 | 1468 | " else: \n",
|
|
1620 | 1595 | " return table, arr\n",
|
1621 | 1596 | "\n",
|
1622 | 1597 | "\n",
|
1623 |
| - "def read_counts(xformat, arr, n_channels=2048, verbose=True): \n", |
| 1598 | + "def read_counts(xformat, arr, verbose=True): \n", |
1624 | 1599 | " '''Extract counts. '''\n",
|
1625 | 1600 | "\n",
|
1626 |
| - " assert xformat == 'Z' or xformat == 'z', 'Incorrect format string'\n", |
1627 |
| - "\n", |
1628 |
| - " format = f'<{n_channels}i'\n", |
| 1601 | + " assert xformat == 'Z' or xformat == 'z', 'Incorrect spectral data format string. Should be `Z` or `z`' \n", |
| 1602 | + " \n", |
| 1603 | + " if xformat == 'Z': \n", |
| 1604 | + " n_channels = 2048 \n", |
| 1605 | + " elif xformat == 'z': \n", |
| 1606 | + " n_channels = 1024 \n", |
| 1607 | + " \n", |
| 1608 | + " # make struct compatible format string \n", |
| 1609 | + " _format = f'<{n_channels}i'\n", |
1629 | 1610 | "\n",
|
1630 |
| - " counts, arr = parse(format, arr, verbose=False) \n", |
| 1611 | + " counts, arr = parse(_format, arr, verbose=False) \n", |
1631 | 1612 | " counts = np.array(counts)\n",
|
1632 | 1613 | " \n",
|
1633 | 1614 | " if verbose: \n",
|
|
0 commit comments