ap-- / python-seabreeze

Python module for OceanOptics spectrometers
https://python-seabreeze.readthedocs.io
MIT License
215 stars 82 forks source link

Intensities incorrect for ST-VIS-25 #272

Open roboticsmick opened 4 hours ago

roboticsmick commented 4 hours ago

spectrometer and system information

current problem

When I try to use the script Seabreeze script I get a different array size of intensities array than when I do with the OceanDirect script. I'm not sure if the corrections are applied either? We want to run on an ARM processor

Seabreeze: First 10 values: [1505. 0. 1563. 0. 1570. 0. 1544. 0. 1522. 0.] Size: 3032

OceanDirect: First 10 values: [14.654972076416016, 14.654972076416016, 13.45759105682373, -2.121690034866333, -0.9224371910095215, 4.272670745849609, 5.471170902252197, -2.521484851837158, 5.471170902252197, 3.8731637001037598] Size: 1516

steps to reproduce

(venv) ~/seabreeze$ python3 Python 3.10.12 (main, Nov 6 2024, 20:22:13) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information.

import seabreeze seabreeze.use('pyseabreeze') from seabreeze.spectrometers import Spectrometer spec = Spectrometer.from_first_available() print(f"Connected to spectrometer: {spec.model}, Serial: {spec.serial_number}") Connected to spectrometer: ST, Serial: ST02185 spec.integration_time_micros(100000) spec.wavelengths() array([348.31332397, 348.65684909, 349.00031106, ..., 811.36221513, 811.64102486, 811.91981221]) print(f"Wavelengths shape: {spec.wavelengths().shape}") Wavelengths shape: (1516,) print(f"First 10 values: {spec.wavelengths()[:10]}") First 10 values: [348.31332397 348.65684909 349.00031106 349.3437099 349.68704565 350.03031833 350.37352796 350.71667458 351.05975821 351.40277888] spec.intensities() array([1515., 0., 1527., ..., 0., 1524., 0.]) print(f"Intensities shape: {spec.intensities().shape}") Intensities shape: (3032,) print(f"First 10 values: {spec.intensities()[:10]}") First 10 values: [1505. 0. 1563. 0. 1570. 0. 1544. 0. 1522. 0.]

When I run a similar script using the the OceanDirect script I get these response from the spectrometer:

Connected to spectrometer: OBP2Device, Serial: ST02185 Dark Pixel Information: Number of electric dark pixels: 13 Dark pixel indices: [1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515]

Raw spectrum values at dark pixel locations: Index 1503: 33.334922790527344 Index 1504: 5.809284210205078 Index 1505: 5.809284210205078 Index 1506: 17.7861270904541 Index 1507: -18.186737060546875 Index 1508: -20.58944320678711 Index 1509: -3.78235125541687 Index 1510: -9.781708717346191 Index 1511: -50.67084884643555 Index 1512: -74.79936981201172 Index 1513: -27.80094337463379 Index 1514: 45.27930450439453 Index 1515: 96.47938537597656

OceanDirect Formatted Spectrum: Length: 1516 First 10 values: [50.05310821533203, 50.05310821533203, 81.02778625488281, 45.27930450439453, -2.5829029083251953, -4.981940746307373, 45.27930450439453, -6.181671142578125, -20.58944320678711, -6.181671142578125] INFO: Buffer size returned: 4

Calibration Coefficients: Nonlinearity coefficients: [0.8339769840240479, 4.907249967800453e-05, 3.217550004208647e-09, -3.677040009281152e-12, 6.984339868505382e-16, -6.182079710757103e-20, 2.6929200754414477e-24, -4.671669886348679e-29] Wavelength coefficients: [348.3133239746094, 0.3435567021369934, -3.158873732900247e-05, 4.492421545876368e-09] Integration time set to 0.1 seconds. Scans to average set to 3.

Wavelengths array details: Size: 1516 First 10 values: [348.3133239746094, 348.6568603515625, 349.00030517578125, 349.3437194824219, 349.6870422363281, 350.0303039550781, 350.37353515625, 350.7166748046875, 351.05975341796875, 351.40277099609375] Last 10 values: [809.409912109375, 809.6889038085938, 809.9678344726562, 810.2467651367188, 810.525634765625, 810.8045654296875, 811.0833740234375, 811.3621826171875, 811.6410522460938, 811.9197998046875]

Raw spectrum array details: Size: 1516 First 10 values: [14.654972076416016, 14.654972076416016, 13.45759105682373, -2.121690034866333, -0.9224371910095215, 4.272670745849609, 5.471170902252197, -2.521484851837158, 5.471170902252197, 3.8731637001037598] Last 10 values: [15.054130554199219, 14.654972076416016, 0.27667462825775146, -0.522741973400116, -10.120340347290039, -20.127416610717773, -0.9224371910095215, 13.45759105682373, 1.4756454229354858, -5.720295429229736]

minimal code example and error (very helpful if available)

`import seabreeze seabreeze.use("pyseabreeze") # Ensure the pyseabreeze backend is used from seabreeze.spectrometers import Spectrometer, list_devices from datetime import datetime import csv import matplotlib.pyplot as plt import pytz import numpy as np

Configuration Variables

INTEGRATION_TIME_MICROS = 100000 # Integration time in microseconds (e.g., 100000 = 100 ms) SCANS_TO_AVERAGE = 3 # Number of scans to average TIMEZONE = "Australia/Brisbane" # Set your desired timezone or "UTC"

def capture_spectrum_and_plot(): try:

Initialize the spectrometer

    spec = Spectrometer.from_first_available()
    print(f"Connected to spectrometer: {spec.model}, Serial: {spec.serial_number}")

    # Set integration time
    spec.integration_time_micros(INTEGRATION_TIME_MICROS)
    print(f"Integration time set to {INTEGRATION_TIME_MICROS / 1e6} seconds.")

    # Retrieve wavelengths and average multiple spectra
    wavelengths = spec.wavelengths()
    intensities_list = []
    print(f"Wavelengths shape: {wavelengths.shape}")
    print(spec.wavelengths())
    for _ in range(SCANS_TO_AVERAGE):
        intensities_list.append(spec.intensities(correct_dark_counts=True, correct_nonlinearity=True))
    intensities = np.mean(intensities_list, axis=0)
    print(f"Intensities shape: {intensities.shape}")
    print(spec.intensities())

    # Get timestamp with timezone
    tz = pytz.timezone(TIMEZONE)
    now = datetime.now(tz)
    timestamp = now.isoformat()
    filename_timestamp = now.strftime("%Y%m%d%H%M%S")
    output_csv = f"spectrum_{filename_timestamp}.csv"
    output_png = f"spectrum_{filename_timestamp}.png"

    # Save data to CSV
    with open(output_csv, mode="w", newline="") as file:
        writer = csv.writer(file)
        writer.writerow(["Timestamp", timestamp])
        writer.writerow(["Model", spec.model])
        writer.writerow(["Serial Number", spec.serial_number])
        writer.writerow(["Integration Time (s)", INTEGRATION_TIME_MICROS / 1e6])
        writer.writerow(["Scans Averaged", SCANS_TO_AVERAGE])
        writer.writerow([])
        writer.writerow(["Wavelength (nm)"] + list(wavelengths))
        writer.writerow(["Intensity"] + list(intensities))
    print(f"Spectrum data saved to {output_csv}")

    # Create and save plot
    plt.figure(figsize=(10, 6))
    plt.plot(wavelengths, intensities, label="Spectrum", color="blue", linewidth=1.5)
    plt.title(f"Spectrum - {timestamp}", fontsize=14)
    plt.xlabel("Wavelength (nm)", fontsize=12)
    plt.ylabel("Intensity", fontsize=12)
    plt.grid(True, linestyle="--", alpha=0.6)
    plt.legend(loc="upper right")
    plt.tight_layout()
    plt.savefig(output_png, dpi=300)
    print(f"Spectrum plot saved to {output_png}")

    # Close the spectrometer connection
    spec.close()

except Exception as e:
    print(f"Error: {e}")

Run the function

if name == "main": capture_spectrum_and_plot()

`

roboticsmick commented 3 hours ago

Changing to a 32-bit signed integer and increasing the integration time from 100000 to 1000000 got a similar plot to OceanDirect: ` class SeaBreezeSpectrometerFeatureOBP2(SeaBreezeSpectrometerFeatureOBP): def getintensities(self) -> NDArray[np.float]: tmp = self._get_spectrum_raw()

Skip the 32-byte metadata header

    ret = tmp[32:].view(numpy.dtype("<i4")).astype(numpy.double)
    return ret * self._normalization_value

` Seabreeze: spectrum_20241126165622 OceanDirect: spectrum_20241126_130540