SPAD Absorbance v1.0


determine SPAD only using v1.0 MultispeQ
// CALCULATIONS FOR PROTON MOTIVE FORCE VIA ECS PORTION OF THE TRACE
//----------------------------

var output = {};
var spad;
var data = json.data_raw;
var quality_flag = 0;


// CALCULATIONS FOR ABSORBANCE / SPAD PORTION OF THE TRACE
//----------------------------

var abs_starts = 0; // when does the Phi2 measurement start
var data = json.data_raw;
var lights = [2,6];// define the lights to have absorbance measured
var wavelengths = ["650","940"];// define the lights to have absorbance measured
var raw_at_blank1 = [0,0,0,0,0,0,0,0];
var raw_at_blank2 = [0,0,0,0,0,0,0,0];
var raw_at_blank3 = [0,0,0,0,0,0,0,0];
var abs_at_blank1 = [0,0,0,0,0,0,0,0];
var abs_at_blank2 = [0,0,0,0,0,0,0,0];
var abs_at_blank3 = [0,0,0,0,0,0,0,0];
var trans_at_blank1 = [0,0,0,0,0,0,0,0];
var trans_at_blank2 = [0,0,0,0,0,0,0,0];
var trans_at_blank3 = [0,0,0,0,0,0,0,0];
var spad_at_blank1 = [0,0,0,0,0,0,0,0];
var spad_at_blank2 = [0,0,0,0,0,0,0,0];
var spad_at_blank3 = [0,0,0,0,0,0,0,0];
var minolta_spad1 = 0;
var minolta_spad2 = 0;
var minolta_spad3 = 0;
var minolta_spad = 0;
var minolta_spad_averages = 0;
var choose = 0;
var light;
var wavelengthString;
var pulses = 10;// number of pulses in a cycle

/* // this is what the recall object looks like --> 
"recall":{"colorcal_blank1[1]":0.000000,"colorcal_blank1[2]":0.000000,"colorcal_blank1[3]":0.000000,"colorcal_blank1[4]":0.00000
0,"colorcal_blank1[6]":0.000000,"colorcal_blank1[8]":0.000000,"colorcal_blank1[9]":0.000000,"colorcal_blank1[10]":0.000000,"colo
rcal_blank2[1]":0.000000,"colorcal_blank2[2]":0.000000,"colorcal_blank2[3]":0.000000,"colorcal_blank2[4]":0.000000,"colorcal_bla
nk2[6]":0.000000,"colorcal_blank2[8]":0.000000,"colorcal_blank2[9]":0.000000,"colorcal_blank2[10]":0.000000,"colorcal_blank3[1]"
:0.000000,"colorcal_blank3[2]":0.000000,"colorcal_blank3[3]":0.000000,"colorcal_blank3[4]":0.000000,"colorcal_blank3[6]":0.00000
0,"colorcal_blank3[8]":0.000000,"colorcal_blank3[9]":0.000000,"colorcal_blank3[10]":0.000000},
*/

/*
** Loop through the lights.  If it's zero, skip it.  If it's not in the acceptable range (>500 but <65534 (max)) skip it.
** Then choose the first blank (starting with 1 moving to 3) which fulfills this criteria
** Otherwise, calculate absorbance and transmittance and a 'spad'-like value using LED 6 (940 on clamp) to calibrate thickness
*/
//----------------------------

for (var i = 0;i<lights.length;i++) { // loop through and save one averaged 'point' for each of the cycles
  light = lights[i];
  wavelengthString = wavelengths[i];
  var value1 = MathMEDIAN(json.data_raw.slice((abs_starts + i*pulses+2),(abs_starts + i*pulses+8)));
  var value2 = MathMEDIAN(json.data_raw.slice((abs_starts + i*pulses+22),(abs_starts + i*pulses+28)));
  var value3 = MathMEDIAN(json.data_raw.slice((abs_starts + i*pulses+42),(abs_starts + i*pulses+48)));
  raw_at_blank1[light] = value1;
  raw_at_blank2[light] = value2;
  raw_at_blank3[light] = value3;
  if (json.recall["colorcal_blank1["+light+"]"] != 0 && raw_at_blank1[light] > 100 && raw_at_blank1[light] < 65534) {
    abs_at_blank1[light] = MathROUND(-1*MathLOG(raw_at_blank1[light]/json.recall["colorcal_blank1["+light+"]"]),3);
//    trans_at_blank1[light] = MathROUND(raw_at_blank1[light]/json.recall["colorcal_blank1["+light+"]"],3);
//	output ["light".concat(light.toString(),"_transmittance")]  = trans_at_blank1[light];
    output ["absorbance_".concat(wavelengthString)]  = abs_at_blank1[light];
//	output ["light".concat(light.toString(),"_blank1")]  = json.recall["colorcal_blank1["+light+"]"];
  }
}

// so the raw value needs to be >~2000, while the 940 needs to be greater than ~5000, otherwise it's out of range
// the acceptable range is different for each blank (1,2,3) thus a separate if statement for each blank.
// once you hit an intensity which is within the acceptable range, then keep that value and skip the rest

for (var i = 0;i<8;i++) { // loop through and save one averaged SPAD value for each of the cycles.  If we have additional calibration values (like minolta spad) use those and output that value
  light = lights[i];
  wavelengthString = wavelengths[i];
  spad_at_blank2[light] = MathROUND(100*MathLOG((raw_at_blank2[6] / json.recall["colorcal_blank2[6]"])/(raw_at_blank2[light] / json.recall["colorcal_blank2["+light+"]"])),2);
  minolta_spad2 = (spad_at_blank2[2] - json.recall["colorcal_intensity2_yint[2]"]) / json.recall["colorcal_intensity2_slope[2]"];
  output ["light".concat(String(),"_minolta_spad2")]  = MathROUND(minolta_spad2,2);
  spad_at_blank1[light] = MathROUND(100*MathLOG((raw_at_blank1[6] / json.recall["colorcal_blank1[6]"])/(raw_at_blank1[light] / json.recall["colorcal_blank1["+light+"]"])),2);
   minolta_spad1 = (spad_at_blank1[2] - json.recall["colorcal_intensity1_yint[2]"]) / json.recall["colorcal_intensity1_slope[2]"];	
   	output ["light".concat(String(),"_minolta_spad1")]  = MathROUND(minolta_spad1,2);
  spad_at_blank3[light] = MathROUND(100*MathLOG((raw_at_blank3[6] / json.recall["colorcal_blank3[6]"])/(raw_at_blank3[light] / json.recall["colorcal_blank3["+light+"]"])),2);
     minolta_spad3 = (spad_at_blank3[2] - json.recall["colorcal_intensity3_yint[2]"]) / json.recall["colorcal_intensity3_slope[2]"];
    output ["light".concat(String(),"_minolta_spad3")]  = MathROUND(minolta_spad3,2);
  
  if (light == 2) { // if it's the red light, the also calculate minolta spad
    /*
    output ["light".concat(light.toString(),"_raw1")]  = raw_at_blank1[light];
    output ["light6_raw1"]  = raw_at_blank1[6];
    output ["spad_raw1"]  = spad_at_blank1[2];
    output ["light".concat(light.toString(),"_raw2")]  = raw_at_blank2[light];
    output ["light6_raw2"]  = raw_at_blank2[6];
    output ["spad_raw2"]  = spad_at_blank2[2];
    output ["light".concat(light.toString(),"_raw3")]  = raw_at_blank3[light];
    output ["light6_raw3"]  = raw_at_blank3[6];
    output ["spad_raw3"]  = spad_at_blank3[2];
    */
  }
  if (json.recall["colorcal_blank1["+light+"]"] != 0 && raw_at_blank1[light] > 500 && raw_at_blank1[light] < 65534 
      && raw_at_blank1[6] > 4500 && raw_at_blank1[6] < 65534) {
    if (light == 2) { // if it's the red light, the also calculate minolta spad
      minolta_spad = (spad_at_blank1[2] - json.recall["colorcal_intensity1_yint[2]"]) / json.recall["colorcal_intensity1_slope[2]"];	
      output ["SPAD_".concat(wavelengthString)]  = MathROUND(minolta_spad,2);
      output ["SPAD_".concat(wavelengthString,"_intensity")]  = 1;
        choose = 1;
      continue;
    }
    else if (light != 6) {
      output ["SPAD_".concat(wavelengthString)] = MathROUND(spad_at_blank1[light],2);
      output ["SPAD_".concat(wavelengthString,"_intensity")] = 1;
//      output ["SPAD1_".concat(wavelengthString)] = MathROUND(spad_at_blank1[light],2);
//      output ["SPAD1_".concat(wavelengthString,"_intensity")] = 1;
      continue;
    }
  }
  if (json.recall["colorcal_blank2["+light+"]"] != 0 && raw_at_blank2[light] > 750 && raw_at_blank2[light] < 65534 
      && raw_at_blank2[6] > 3000 && raw_at_blank2[6] < 65534) {
    if (light == 2) { // if it's the red light, the also calculate minolta spad
      minolta_spad = (spad_at_blank2[2] - json.recall["colorcal_intensity2_yint[2]"]) / json.recall["colorcal_intensity2_slope[2]"];
//      output ["SPAD_".concat(wavelengthString)] = MathROUND(minolta_spad,2);
//      output ["SPAD_".concat(wavelengthString,"_intensity")] = 2;
        choose = 2;
      continue;
    }
    else if (light != 6) {
      output ["SPAD_".concat(wavelengthString)] = MathROUND(spad_at_blank2[light],2);
      output ["SPAD_".concat(wavelengthString,"_intensity")] = 2;
//      output ["SPAD2_".concat(wavelengthString)] = MathROUND(spad_at_blank2[light],2);
//      output ["SPAD2_".concat(wavelengthString,"_intensity")] = 2;
      continue;
    }
  }
  if (json.recall["colorcal_blank3["+light+"]"] != 0 && raw_at_blank3[light] > 750 && raw_at_blank3[light] < 65534 
      && raw_at_blank3[6] > 3000 && raw_at_blank3[6] < 65534) {
    if (light == 2) { // if it's the red light, the also calculate minolta spad
      minolta_spad = (spad_at_blank3[2] - json.recall["colorcal_intensity3_yint[2]"]) / json.recall["colorcal_intensity3_slope[2]"];
      output ["SPAD_".concat(wavelengthString)]  = MathROUND(minolta_spad,2);
      output ["SPAD_".concat(wavelengthString,"_intensity")]  = 3;
      choose = 3;
      continue;
    }
    else if (light != 6) {
      output ["SPAD_".concat(wavelengthString)] = MathROUND(spad_at_blank3[light],2);
      output ["SPAD_".concat(wavelengthString,"_intensity")] = 3;
      output ["SPAD3_".concat(wavelengthString)] = MathROUND(spad_at_blank3[light],2);
      output ["SPAD3_".concat(wavelengthString,"_intensity")] = 3;
      continue;
    }
  }
}


if (choose == 0) {
  output ["SPAD_650"]  = 0;
  danger("Chlorophyll content SPAD is outside the acceptable range.  The leaf may be too thick, too thin, or have holes in it.", output);
}
else if (minolta_spad <= 2) {
  danger("Chlorophyll Content SPAD is very low.  If leaf is visibly green, ensure leaf completely covers the light guide and retry.  If still too low, consider recalibrating device.", output);
}
else if (minolta_spad >= 100) {
  danger("Chlorophyll Content SPAD is very high.  If this value is associated with a typical leaf, consider recalibrating device.", output);
}

// Finally, use the "order" object to define the order of the outputs (focus on the top 6 most important for the user to see)
//----------------------------
//output["Relative Chlorophyll"] = MathROUND(minolta_spad,2);
//output ["Rel Chl intensity"]  = choose;  	
output["SPAD2"] = MathROUND(minolta_spad2,2);
output["SPAD1"] = MathROUND(minolta_spad1,2);
output["SPAD3"] = MathROUND(minolta_spad3,2);
//maxvalue = MathMAX([json.r,json.g,json.b]);
//output["r"] = json.r;
//output["g"] = json.g;
//output["b"] = json.b;
//output["rval"] = json.r*(255/maxvalue);
//output["gval"] = json.g*(255/maxvalue);
//output["bval"] = json.b*(255/maxvalue);



output["Relative Chlorophyll"] = MathROUND(minolta_spad);
output["Light Intensity (PAR)"] = MathROUND(json.light_intensity);
output["Leaf Temperature Differential"] = MathROUND(json.contactless_temp - json.temperature);
output["Ambient Temperature"] = MathROUND(json.temperature);
output["Ambient Humidity"] = MathROUND(json.humidity);
output["Leaf Angle"] = MathROUND(json.angle);

output["order"] = ["Relative Chlorophyll", "Leaf Temperature Differential", "Ambient Temperature"];


return output;
{
  "time_offset": 300,
  "time": 1511892794683,
  "device_name": "MultispeQ",
  "device_version": "1",
  "device_id": "01:12:35:39",
  "device_battery": 91,
  "device_firmware": 1.23,
  "sample": [
    {
      "time": 1511892794699,
      "protocol_id": 1,
      "label": "",
      "light_intensity": 14.236,
      "r": 12,
      "g": 6,
      "b": 3,
      "light_intensity_raw": 21,
      "temperature": 27.14,
      "humidity": 23.459,
      "pressure": 981.622,
      "contactless_temp": 26.93,
      "thickness": 0.07,
      "compass_direction": "E",
      "compass": 90,
      "angle": 1.129,
      "angle_direction": "S",
      "pitch": 1.12,
      "roll": 0.18,
      "recall": {
        "time": 1511892794923,
        "colorcal_blank1[1]": 20871,
        "colorcal_blank1[2]": 27168.5,
        "colorcal_blank1[3]": 31199,
        "colorcal_blank1[4]": 38450,
        "colorcal_blank1[6]": 37576,
        "colorcal_blank1[8]": 36523.5,
        "colorcal_blank1[9]": 30400,
        "colorcal_blank1[10]": 37413,
        "colorcal_blank2[1]": 22445.5,
        "colorcal_blank2[2]": 20498,
        "colorcal_blank2[3]": 23846,
        "colorcal_blank2[4]": 19758.5,
        "colorcal_blank2[6]": 16667,
        "colorcal_blank2[8]": 18292,
        "colorcal_blank2[9]": 18363,
        "colorcal_blank2[10]": 16517.5,
        "colorcal_blank3[1]": 20989.5,
        "colorcal_blank3[2]": 10927.5,
        "colorcal_blank3[3]": 20771.5,
        "colorcal_blank3[4]": 14427.5,
        "colorcal_blank3[6]": 5931.5,
        "colorcal_blank3[8]": 6755,
        "colorcal_blank3[9]": 5473.5,
        "colorcal_blank3[10]": 6030,
        "colorcal_intensity1_slope[2]": 2.232,
        "colorcal_intensity1_yint[2]": 2,
        "colorcal_intensity2_slope[2]": 2.375,
        "colorcal_intensity2_yint[2]": 4.1,
        "colorcal_intensity3_slope[2]": 2.581,
        "colorcal_intensity3_yint[2]": -18.1,
        "ir_baseline_slope[5]": 11955,
        "ir_baseline_yint[5]": 18207.5,
        "ir_baseline_slope[3]": 620.5,
        "ir_baseline_yint[3]": 773.5
      },
      "data_raw": [
        1185,
        1187,
        1187,
        1186,
        1186,
        1186,
        1184,
        1185,
        1185,
        1185,
        4129,
        4041,
        4036,
        4034,
        4033,
        4035,
        4037,
        4034,
        4036,
        4033,
        7411,
        7429,
        7429,
        7427,
        7428,
        7427,
        7429,
        7427,
        7427,
        7427,
        14706,
        14727,
        14728,
        14729,
        14731,
        14733,
        14733,
        14735,
        14732,
        14735,
        16460,
        16491,
        16489,
        16487,
        16490,
        16487,
        16486,
        16489,
        16487,
        16487,
        14726,
        14728,
        14731,
        14729,
        14727,
        14734,
        14730,
        14729,
        14729,
        14730
      ]
    }
  ],
  "app_os": "win",
  "app_name": "PhotosynQ",
  "app_version": "0.3.9",
  "app_device": "x86-64",
  "location": [
    "42.7225748",
    "-84.4746489"
  ],
  "ConsoleMacro": "382"
}
Screen shot 2017 05 31 at 12.23.10 pm
Created by

PhotosynQ Admin


Protocol connections:
5
Latest Update:
Jan 2018