如何用Python读取Maestro生成的.Spe伽马能谱文件并转为数组?
np.genfromtxt Failure for Maestro .Spe Gamma Spectrum Files Hey there! I’ve worked with Maestro .Spe files before, so I know exactly why your np.genfromtxt call is failing—these files aren’t plain numeric arrays; they have a structured header packed with metadata (instrument settings, calibration details, etc.) before getting to the actual count data. Let’s fix this step by step.
Why np.genfromtxt Doesn’t Work
Maestro .Spe files start with dozens of lines of non-numeric header text. np.genfromtxt tries to parse every line as a number, which breaks immediately when it hits things like $MEAS_INFO: or instrument model names.
Solution: Read the File Properly
We need to skip the header, locate the count data block, and map it to corresponding channel numbers. Here’s modified code that does exactly this:
from scipy.optimize import curve_fit import numpy as np import matplotlib.pyplot as plt %matplotlib inline from scipy.integrate import quad import math from scipy.constants import c, h, k, sigma # Open and read the entire .Spe file with open("Gamma Spectrum Calibration.Spe", 'r') as spe_file: all_lines = spe_file.readlines() # Locate the start of the count data (marked by the $DATA: tag) data_start_line = None for idx, line in enumerate(all_lines): if "$DATA:" in line: # The line after $DATA: lists the channel range (e.g., "0 1023"), so data starts 2 lines later data_start_line = idx + 2 break # Extract count values and generate matching channel numbers counts = np.array([int(line.strip()) for line in all_lines[data_start_line:] if line.strip().isdigit()]) # Channels are sequential starting from 0 (default for most Maestro outputs) channels = np.arange(len(counts)) # Plot as you requested (counts on X-axis, channels on Y-axis) plt.plot(counts, channels, marker='o', markersize=3, color="red") plt.title('Gamma Radiation Calibration: Count vs Channel') plt.xlabel('Count (arb. units)') plt.ylabel('Channel') plt.show(block=False) plt.pause(3) plt.close()
Bonus: Handle Custom Channel Ranges
If your spectrum uses a non-zero starting channel (uncommon but possible), you can extract the exact range from the header:
# Add this right after finding data_start_line channel_range = all_lines[data_start_line - 1].strip().split() start_channel = int(channel_range[0]) end_channel = int(channel_range[1]) channels = np.arange(start_channel, end_channel + 1) # Ensure we only read the correct number of count lines counts = np.array([int(line.strip()) for line in all_lines[data_start_line:data_start_line + len(channels)] if line.strip().isdigit()])
Bonus Tip: Energy Calibration
Since your commented code references energy vs channel, note that Maestro files usually include energy calibration data under the $ENERGY_CAL: tag. You can extract that to convert channels to keV easily:
# Find energy calibration coefficients (linear fit: Energy = a*Channel + b) cal_coeffs = None for line in all_lines: if "$ENERGY_CAL:" in line: cal_coeffs = [float(val) for val in line.split()[1:]] break if cal_coeffs: energy = cal_coeffs[0] * channels + cal_coeffs[1] # Plot energy vs counts if that's what you need plt.plot(energy, counts, marker='o', markersize=3, color="blue") plt.title('Gamma Radiation Calibration: Energy vs Count') plt.xlabel('Energy (keV)') plt.ylabel('Count (arb. units)')
内容的提问来源于stack exchange,提问作者Dakota Keblbeck

