//-------------------------------------------------------------------- private void TemperatureCorrection(Assay recalc) { // get last valid temp in temperature table (table must be monotonic) int indexLast = 0; while ((indexLast < recalc.cal.TempTable.Length - 1) && (recalc.cal.TempTable[indexLast + 1].temp > recalc.cal.TempTable[indexLast].temp)) { indexLast++; } // walk thru table to get line segment endpoints int index = 1; while ((recalc.TempAvg > recalc.cal.TempTable[index].temp) && index < indexLast) { index++; } float tempLow = recalc.cal.TempTable[index - 1].temp; float tempHigh = recalc.cal.TempTable[index].temp; float factorLow = recalc.cal.TempTable[index - 1].factor; float factorHigh = recalc.cal.TempTable[index].factor; float correctionFactor = (factorHigh - factorLow) / (tempHigh - tempLow); correctionFactor = correctionFactor * (recalc.TempAvg - tempLow) + factorLow; float result = recalc.SWCValue * (correctionFactor / 1000.0f); recalc.TempCorrected = (uint)(result + 0.5f); }
//-------------------------------------------------------------------- private bool BaselineCorrection(Assay recalc) { int left = IndexOfMinimum(recalc.CorrectedTable, recalc.cal.Min1, recalc.cal.Min2); int right = IndexOfMinimum(recalc.CorrectedTable, recalc.cal.Min3, recalc.cal.Min4); float rise = recalc.CorrectedTable[right] - recalc.CorrectedTable[left]; float run = right - left; float slope = rise / run; recalc.LowerMinimum = (ushort)left; recalc.UpperMinimum = (ushort)right; recalc.Slope = (short)(slope * 100.0f); if ((recalc.CorrectedTable[right] == 0) && (recalc.CorrectedTable[left] == 0)) { return(false); } float adjuster = -slope * left; short baseline = recalc.CorrectedTable[left]; int correctedIndex = 0; for (int i = 0; i < recalc.StepCount; i++) { float temp = recalc.CorrectedTable[i]; temp = temp - adjuster; temp = temp - baseline; temp = temp + 0.5f; recalc.CorrectedTable[correctedIndex++] = (short)temp; adjuster = adjuster + slope; } return(true); }
/// <summary> /// get difference between forward and reverse curves and /// set recal assay error if ADC overflow in resulting table /// </summary> /// <param name="rawDiffTable">must be same size as Forward & Reverse tables</param> private void GetDifferenceCurve(Assay recalc, short[] rawDiffTable) { for (int i = 0; i < StepCount; i++) { int adjustedForward = recalc.ForwardTable[i] - recalc.ForwardTable[recalc.cal.Min1]; int adjustedReverse = recalc.ReverseTable[i] - recalc.ReverseTable[recalc.cal.Min1]; int difference = adjustedForward - adjustedReverse; if (difference > short.MaxValue) { difference = short.MaxValue; if (i >= recalc.cal.Min1 && i <= recalc.cal.Min4) { recalc.Error = 17; } } if (difference < short.MinValue) { difference = short.MinValue; if (i >= recalc.cal.Min1 && i <= recalc.cal.Min4) { recalc.Error = 17; } } rawDiffTable[i] = (short)difference; } }
//-------------------------------------------------------------------- private void TranslateBLL(Assay recalc) { if (recalc.TempCorrected > recalc.cal.MaxADCcount) { recalc.BLLCorrected = Assay.HighLead; return; } ushort scaledSWC = (ushort)((65535.0f * recalc.TempCorrected / recalc.cal.MaxADCcount) + 0.5f); recalc.SWCscaled = scaledSWC; int indexLast = LastSwcIndex(recalc.cal); // if value ouside table bounds then set result and exit if (scaledSWC < recalc.cal.SwcTable[0].swc) { recalc.BLLCorrected = Assay.LowLead; return; } else if (scaledSWC >= recalc.cal.SwcTable[indexLast].swc) { recalc.BLLCorrected = Assay.HighLead; return; } // walk thru table and get line segment endpoints int index = 1; while (scaledSWC > recalc.cal.SwcTable[index].swc) { index++; } float swcLow = recalc.cal.SwcTable[index - 1].swc; float bllLow = recalc.cal.SwcTable[index - 1].bll; float swcHigh = recalc.cal.SwcTable[index].swc; float bllHigh = recalc.cal.SwcTable[index].bll; // interpolate to obtained corrected BLL float bllResult = (bllHigh - bllLow) / (swcHigh - swcLow); bllResult = (scaledSWC - swcLow) * bllResult + bllLow; // round and convert recalc.BLLCorrected = (uint)(bllResult + 0.5); }
//-------------------------------------------------------------------- private void TestAgainstCurrentLimit(Assay recalc, short[] forward, short[] reverse) { short ADClimit = 26344; bool currentOK = true; for (int i = recalc.cal.Min1; i <= recalc.cal.Min4; i++) { if (Math.Abs(forward[i]) > ADClimit) { currentOK = false; } if (Math.Abs(reverse[i]) > ADClimit) { currentOK = false; } } // 17 is the high current error number if (!currentOK) { recalc.Error = 17; } }
//-------------------------------------------------------------------- public Assay ReCalcResults() { Calibration newCal = this.cal.Clone() as Calibration; // no need to recal LC3 results, since they were done on PC in first place if (Source == Analyzer.LeadCare3) { return((Assay)this.Clone()); } // create new assay, set calibration,zero result Assay recalc = (Assay)this.Clone(); recalc.cal = newCal.Clone() as Calibration; recalc.Result = 0; recalc.SWCValue = 0; // only recalc if we have raw data if (recalc.ForwardADC == null || recalc.ReverseADC == null || recalc.StepCount == 0) { return(recalc); } // intermediate data tables for filtering short[] avgForwardTable = new short[recalc.StepCount]; short[] avgReverseTable = new short[recalc.StepCount]; short[] rawDiffTable = new short[recalc.StepCount]; // first fill with raw ADC reads for (int step = 0; step < recalc.StepCount; step++) { if (Source == Analyzer.LeadCare3) { avgForwardTable[step] = ConvertLc3AdcReading(ForwardADC[step]); avgReverseTable[step] = ConvertLc3AdcReading(ReverseADC[step]); } else { avgForwardTable[step] = ForwardADC[step]; avgReverseTable[step] = ReverseADC[step]; } } TestAgainstCurrentLimit(recalc, avgForwardTable, avgReverseTable); // apply boxcar filter to averaged reads to get final forward & reverse tables Filter(recalc.ForwardTable, avgForwardTable, BoxcarFilter); Filter(recalc.ReverseTable, avgReverseTable, BoxcarFilter); // get difference table with ADC overflow flagging and then filter with FFT GetDifferenceCurve(recalc, rawDiffTable); Filter(recalc.DifferenceTable, rawDiffTable, FFTfilter); // fill raw corrected table and apply baseline correction for (int i = 0; i < recalc.StepCount; i++) { recalc.CorrectedTable[i] = recalc.DifferenceTable[i]; } recalc.BCiterations = 0; for (int i = 0; i < 3; i++) { if (BaselineCorrection(recalc)) { ++recalc.BCiterations; } } // integrate to get square wave capacitance recalc.SWCValue = 0; for (int i = recalc.LowerMinimum; i <= recalc.UpperMinimum; i++) { if (recalc.CorrectedTable[i] > 0) { recalc.SWCValue += (uint)recalc.CorrectedTable[i]; } } // final correction and conversion TemperatureCorrection(recalc); TranslateBLL(recalc); if (recalc.Error == 0) { recalc.Result = recalc.BLLCorrected; } // debug test for calculation bool recalcOK = true; try { for (int step = 0; step < recalc.StepCount; step++) { if (recalc.ForwardTable[step] != this.ForwardTable[step]) { recalcOK = false; } if (recalc.ReverseTable[step] != this.ReverseTable[step]) { recalcOK = false; } if (recalc.DifferenceTable[step] != this.DifferenceTable[step]) { recalcOK = false; } if (recalc.CorrectedTable[step] != this.CorrectedTable[step]) { recalcOK = false; } } if (recalc.SWCValue != this.SWCValue) { recalcOK = false; } if (recalc.TempCorrected != this.TempCorrected) { recalcOK = false; } if (recalc.SWCscaled != this.SWCscaled) { recalcOK = false; } if (recalc.BLLCorrected != this.BLLCorrected) { recalcOK = false; } } catch (Exception) { recalcOK = false; } if (recalcOK) { } return(recalc); }