Source code for jii_multispeq_protocols.protocols.calibrations.leaf_clamp_leds_calibration

"""
Leaf Clamp LEDs Calibration
===========================

new version of CaliQ LED output calibration using PAR matching...

qpar matching 1
testing CaliQ step 4 Calibrate LOWER PAR LEDs

.. warning:: This calibration requires a CaliQ

2279

"""

import numpy as np
from scipy import stats
from jii_multispeq.analysis import GetProtocolByLabel

_protocol = [
  {
    "v_arrays": [
      [
        6000
      ],
      [
        25,
        600,
        3000
      ],
      [
        600,
        3000,
        6000
      ]
    ],
    "set_repeats": 1,
    "_protocol_set_": [
      {
        "label": "cal_led_7",
        "qpar_led_cal": [
          7,
          "@p1",
          "@p2",
          20
        ],
        "protocol_repeats": "#l1"
      }
    ]
  }
]

[docs] def _analyze( _data ): """ * Macro for data evaluation on PhotosynQ.org * by: David M. Kramer * created: July 17, 2020 10:10 AM """ ## Define the output object here output = {} ## THe MultispeQ uses the following fixed PAR values ## as reference points for linear interpolation of the ## DAC settings for desired PAR values. set_points = [0,150,300,600,1200,3000,6000,10000] ## Check if the key time exists in json if "time" in _data: ## Add key time and value to output output["time"] = _data["time"] all_labels = [] _set = _data["set"] output["toDevice"] = "" for i in range(len(_set)): if "label" in _set[i]: if "cal_led_" in _set[i]["label"]: all_labels.append(_set[i]["label"]) unique_LEDs = list( set(all_labels) ) v_arrays = _data["v_arrays"] max_allowed_par = v_arrays[0] output["max_allowed_par"] = repr(max_allowed_par) output["toDevice"] = "" for led_index, _ in enumerate(unique_LEDs): led_label = unique_LEDs[led_index] set_number = 0 led2 = GetProtocolByLabel(led_label, _data, True) LED = led2[0]["led_to_qpar0"][0] all_settings = [] all_amplitudes = [] all_slopes=[] all_b = [] for set_number, _ in enumerate(led2): fit_points = [] settings = [] for i in range(1, len(led2[set_number]["qpar_led_cal"])): fit_points.append(led2[set_number]["qpar_led_cal"][i][1]) settings.append(led2[set_number]["qpar_led_cal"][i][0]) all_settings.append(settings) all_amplitudes.append(fit_points) slope, intercept, r_value, p_value, std_err = stats.linregress(fit_points, settings) output[("r2_%s:%s") % (led_label,set_number)] = np.round(r_value**2, 4) all_b.append(intercept) all_slopes.append(slope) ## find the ranges over which each equation applies. ## there should be n+2 ranges, where n is the number of entries ## in the v_arrays. ## PAR = 0 to PAR = element 0 ## element 0 to element 1 ## ... ## last element to PAR = 10,000 ## BUT, these par_ranges = [] lower_bounds_ranges = led_index * 2 + 1 upper_bounds_ranges = led_index * 2 + 2 par_ranges.append([0,v_arrays[lower_bounds_ranges][0]]) for range_index in range( len(v_arrays[lower_bounds_ranges])): par_ranges.append([v_arrays[lower_bounds_ranges][range_index], v_arrays[upper_bounds_ranges][range_index]]) par_ranges.append([v_arrays[upper_bounds_ranges][len(v_arrays[upper_bounds_ranges]) -1], max_allowed_par[led_index]]) set_point_values = [] set_point_indexes = [] set_points_to_fit = [] ## The set point for dark (PAR=0) is jus the Y-intercept for the ## first series of LED PAR vs. settings set. set_point_values.append(np.round(all_b[0]-1,0)) ## The maximum setting is that for the max_allowed_par, using the ## final (highest) LED PAR versus setting curve. max_par_range_index = len(all_slopes) - 1 m = all_slopes[max_par_range_index] b = all_b[max_par_range_index] max_calibrated_setpoint = np.round(m * max_allowed_par[led_index] + b,0) if max_calibrated_setpoint > 4095: max_calibrated_setpoint=4095 if max_calibrated_setpoint < 0: max_calibrated_setpoint=0 output["max_setpoint_for_led:%s" % led_index] = np.round(max_calibrated_setpoint,0) ## Go through the remainting set points and determine which line to use ## for estimating the setting value. for set_point_index in range(1, len(set_points)): set_point_par = set_points[set_point_index] ## the PAR value we are trying to fit. set_points_to_fit.append(set_point_par) ## go through each PAR range and find the one that fits for par_range_index,_ in enumerate(par_ranges): if set_point_par >= max_allowed_par[led_index]: set_point_values.append(max_calibrated_setpoint) set_point_indexes.append(par_range_index) break elif set_point_par >= par_ranges[par_range_index][0]: set_point_indexes.append(par_range_index) m = all_slopes[par_range_index] b = all_b[par_range_index] calibrated_setpoint = m * set_point_par + b set_point_values.append(np.round(calibrated_setpoint,0)) break output["toDevice"] += "par_to_dac_lin+%s+" % LED for cal_index in range(len(set_point_values)): output["toDevice"] += "%s+" % set_point_values[cal_index] output["toDevice"] += "par_max_setting+%s+%s+" % (LED, max_calibrated_setpoint) ## end of led loop ## Return data return output
_example = { "time": 1598118193361, "device_name": "MultispeQ", "device_version": "2", "device_id": "41:00:08:6b", "device_battery": 101, "device_firmware": 2.3432, "sample": [ [ { "time": 1598118193361, "v_arrays": [ [ 6000 ], [ 25, 600, 3000 ], [ 600, 3000, 6000 ] ], "set_repeats": 1, "protocol_id": 1, "set": [ { "time": 1598118193376, "led_to_qpar0": [ 7, 25, 0, 50 ], "led_to_qpar1": [ 7, 600, 964.81, 472 ], "qpar_led_cal": [ [ 50, 0 ], [ 71, 2 ], [ 92, 48 ], [ 113, 80 ], [ 134, 111 ], [ 155, 150 ], [ 176, 220 ], [ 197, 253 ], [ 218, 291 ], [ 239, 370 ], [ 260, 403 ], [ 281, 445 ], [ 302, 521 ], [ 323, 553 ], [ 344, 597 ], [ 365, 676 ], [ 386, 711 ], [ 407, 796 ], [ 428, 832 ], [ 449, 868 ], [ 470, 955 ], [ 491, 993 ] ], "label": "cal_led_7", "data_raw": [ ] }, { "time": 1598118224113, "led_to_qpar0": [ 7, 600, 0, 50 ], "led_to_qpar1": [ 7, 3000, 3970.15, 1593 ], "qpar_led_cal": [ [ 50, 0 ], [ 127, 67 ], [ 204, 233 ], [ 281, 466 ], [ 358, 592 ], [ 435, 799 ], [ 512, 1050 ], [ 589, 1177 ], [ 666, 1389 ], [ 743, 1642 ], [ 820, 1774 ], [ 897, 1991 ], [ 974, 2246 ], [ 1051, 2390 ], [ 1128, 2605 ], [ 1205, 2861 ], [ 1282, 3003 ], [ 1359, 3222 ], [ 1436, 3485 ], [ 1513, 3626 ], [ 1590, 3864 ], [ 1667, 4141 ] ], "label": "cal_led_7", "data_raw": [ ] }, { "time": 1598118256069, "led_to_qpar0": [ 7, 3000, 3995.94, 1593 ], "led_to_qpar1": [ 7, 6000, 7802.95, 2876 ], "qpar_led_cal": [ [ 1593, 1986 ], [ 1657, 4173 ], [ 1721, 4376 ], [ 1785, 4491 ], [ 1849, 4695 ], [ 1913, 4889 ], [ 1977, 4997 ], [ 2041, 5209 ], [ 2105, 5421 ], [ 2169, 5539 ], [ 2233, 5746 ], [ 2297, 5965 ], [ 2361, 6088 ], [ 2425, 6292 ], [ 2489, 6496 ], [ 2553, 6637 ], [ 2617, 6863 ], [ 2681, 7046 ], [ 2745, 7198 ], [ 2809, 7492 ], [ 2873, 7769 ], [ 2937, 7858 ] ], "label": "cal_led_7", "data_raw": [ ] } ], "data_raw": [ ] } ] ], "app_os": "macOS 17.7.0", "app_name": "PhotosynQ", "app_version": "1.8.4", "app_device": "x64", "location": [ "42.6912313", "-84.4464580" ], "time_offset": "America/Detroit" }