Browse Source

update

tags/v0
zhaohe 9 months ago
parent
commit
ceabc32908
  1. 8
      src/main/java/a8k/a8kproj/A8kIdCardDataParseService.java
  2. 24
      src/main/java/a8k/a8kproj/A8kOptScanResultAnalyzer.java
  3. 25
      src/main/java/a8k/a8kproj/fakeoptpeak/FakeOptPeakFactory.java
  4. 2
      src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_01_FLOW1.java
  5. 2
      src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_02_FLOW2.java
  6. 2
      src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_03.java
  7. 2
      src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_04.java
  8. 2
      src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_05.java
  9. 2
      src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_06.java
  10. 2
      src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_07_EXPIRED.java
  11. 12
      src/main/java/a8k/a8kproj/fakeproj/FakeProjInfo.java
  12. 8
      src/main/java/a8k/a8kproj/fakeproj/FakeProjInfoFactory.java
  13. 216
      src/main/java/a8k/a8kproj/fakeprojcontext/FakeProjInfoContextFactory.java
  14. 241
      src/main/java/a8k/a8kproj/optalgo/A8kOptAlgo.java
  15. 18
      src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeak.java
  16. 10
      src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeakArea.java
  17. 14
      src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeakAreas.java
  18. 19
      src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeaks.java
  19. 6
      src/main/java/a8k/a8kproj/optanalyzer/A8kOptXGetter.java
  20. 3
      src/main/java/a8k/a8kproj/optanalyzer/OptChecker.java
  21. 68
      src/main/java/a8k/a8kproj/optanalyzer/PeakNameAssigner.java
  22. 2
      src/main/java/a8k/a8kproj/optanalyzer/context/OptAnalyzeContext.java
  23. 2
      src/main/java/a8k/a8kproj/opttype/A8kOptX.java
  24. 2
      src/main/java/a8k/a8kproj/opttype/PeakDivision.java
  25. 2
      src/main/java/a8k/a8kproj/opttype/PeakName.java
  26. 14
      src/main/java/a8k/service/app/appctrl/AppConsumablesScanService.java
  27. 4
      src/main/java/a8k/service/app/appctrl/mainflowctrl/action/PLATE_OPT_SCAN.java
  28. 2
      src/main/java/a8k/service/app/appctrl/mainflowctrl/action/SEQ5_PROCESS.java
  29. 6
      src/main/java/a8k/service/app/appdata/ProjCfgMgrService.java
  30. 4
      src/main/java/a8k/service/app/appdata/ReactionRecordMgrService.java
  31. 4
      src/main/java/a8k/service/app/appdata/UtilsProjectColorAllocer.java
  32. 2
      src/main/java/a8k/service/app/appstate/TubeStateMgrService.java
  33. 4
      src/main/java/a8k/service/app/appstate/type/SampleInfo.java
  34. 21
      src/main/java/a8k/service/app/appstate/type/TubeProcessContext.java
  35. 2
      src/main/java/a8k/service/app/devicectrl/ctrlservice/OptScanModuleCtrlService.java
  36. 4
      src/main/java/a8k/service/app/devicectrl/script/DeviceCtrlScripter.java
  37. 96
      src/main/java/a8k/service/app/devicectrl/test/OptAlgoTest.java
  38. 16
      src/main/java/a8k/service/dao/type/ProjInfoCard.java
  39. 6
      src/main/java/a8k/service/dao/type/ProjOptInfo.java
  40. 12
      src/main/java/a8k/service/dao/type/a8kidcard/A8kNormalFn.java
  41. 13
      src/main/java/a8k/service/dao/type/a8kidcard/A8kPiecewiseFn.java
  42. 13
      src/main/java/a8k/service/dao/type/a8kidcard/A8kResultBuilderFn.java
  43. 2
      src/main/java/a8k/service/test/MainflowCtrlTestService.java
  44. 2
      src/main/java/a8k/service/test/TestStateMgrService.java
  45. 4
      src/main/java/a8k/service/test/VirtualDeviceSimulationTest.java
  46. 53
      src/main/java/a8k/test/TestOptAnalyzer.java
  47. 5
      src/main/java/a8k/type/ReactionResult.java
  48. 16
      src/main/java/a8k/utils/ProjInfoContext.java
  49. 20
      src/main/java/a8k/utils/ProjProcessContextUtils.java
  50. 6
      src/main/java/a8k/utils/ZObjectUtils.java

8
src/main/java/a8k/a8kproj/A8kIdCardDataParseService.java

@ -1,7 +1,7 @@
package a8k.a8kproj;
import a8k.hardware.type.a8kcanprotocol.A8kEcode;
import a8k.opttype.A8kOptX;
import a8k.a8kproj.opttype.A8kOptX;
import a8k.service.dao.A8kProjInfoDao;
import a8k.service.dao.type.ProjectInfo;
import a8k.service.dao.type.a8kidcard.A8kNormalFn;
@ -330,15 +330,15 @@ public class A8kIdCardDataParseService {
ASSERT_IS_TRUE(a8kProjInfo != null, A8kEcode.APPE_A8K_PROJ_UNSUPPORTED, "PROJECT ID %d NOT FOUND", idcard.projId);
if (a8kProjInfo.subProjNum >= 1) {
idcard.pj1FnInfo = parseA8kProjFn(
idcard.projFnFormual1 = parseA8kProjFn(
PROJ1_FN_TYPE_OFF, PROJ1_NOR_FN_OFF, PROJ1_PIECEWISE_FN_OFF, PROJ1_RESULT_BUILDER_FN_OFF);
}
if (a8kProjInfo.subProjNum >= 2) {
idcard.pj2FnInfo = parseA8kProjFn(
idcard.projFnFormual2 = parseA8kProjFn(
PROJ2_FN_TYPE_OFF, PROJ2_NOR_FN_OFF, PROJ2_PIECEWISE_FN_OFF, PROJ2_RESULT_BUILDER_FN_OFF);
}
if (a8kProjInfo.subProjNum >= 3) {
idcard.pj3FnInfo = parseA8kProjFn(
idcard.projFnFormual3 = parseA8kProjFn(
PROJ3_FN_TYPE_OFF, PROJ3_NOR_FN_OFF, PROJ3_PIECEWISE_FN_OFF, PROJ3_RESULT_BUILDER_FN_OFF);
}
}

24
src/main/java/a8k/a8kproj/A8kOptScanResultAnalyzer.java

@ -1,5 +1,6 @@
package a8k.a8kproj;
import a8k.a8kproj.optalgo.type.A8kOptPeaks;
import a8k.a8kproj.optalgo.type.OptScanResult;
import a8k.a8kproj.optanalyzer.A8kOptXGetter;
import a8k.a8kproj.optanalyzer.OptChecker;
@ -14,12 +15,14 @@ import a8k.service.dao.type.a8kidcard.zenum.A8kFnType;
import a8k.type.ReactionResult;
import a8k.type.reaction_result_type.ReactionResultStatus;
import a8k.utils.ProjInfoContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
//
// 光学结果分析器
//
@Slf4j
public class A8kOptScanResultAnalyzer {
@ -51,8 +54,8 @@ public class A8kOptScanResultAnalyzer {
//普通函数
static Double callNorFn(OptAnalyzeContext optcxt, A8kNormalFn fn, OptScanResult optScanResult) throws A8kOptProcessException {
Double X = A8kOptXGetter.getX(fn.x, optcxt.getProjOptInfo(), optScanResult.peaks);
static Double callNorFn(OptAnalyzeContext optcxt, A8kNormalFn fn, A8kOptPeaks peaks) throws A8kOptProcessException {
Double X = A8kOptXGetter.getX(fn.x, optcxt.getProjOptInfo(), peaks);
OptChecker.checkX(X, fn.xMin, fn.xMax);
Double result1 = fn.A * X * X + fn.B * X + fn.C;
@ -61,15 +64,15 @@ public class A8kOptScanResultAnalyzer {
}
// 分段函数系数
static Double callPiecewiseFn(OptAnalyzeContext optcxt, A8kPiecewiseFn fn, OptScanResult optScanResult) throws A8kOptProcessException {
Double pwFnJudeX = A8kOptXGetter.getX(fn.judeX, optcxt.getProjOptInfo(), optScanResult.peaks);
static Double callPiecewiseFn(OptAnalyzeContext optcxt, A8kPiecewiseFn fn, A8kOptPeaks peaks) throws A8kOptProcessException {
Double pwFnJudeX = A8kOptXGetter.getX(fn.judeX, optcxt.getProjOptInfo(), peaks);
Double X = null;
Double result1 = null;
if (pwFnJudeX < fn.judeThres) {
X = A8kOptXGetter.getX(fn.lX, optcxt.getProjOptInfo(), optScanResult.peaks);
X = A8kOptXGetter.getX(fn.lX, optcxt.getProjOptInfo(), peaks);
result1 = fn.A0 * X * X + fn.B0 * X + fn.C0;
} else {
X = A8kOptXGetter.getX(fn.hX, optcxt.getProjOptInfo(), optScanResult.peaks);
X = A8kOptXGetter.getX(fn.hX, optcxt.getProjOptInfo(), peaks);
result1 = fn.A1 * X * X + fn.B1 * X + fn.C1;
}
OptChecker.checkX(X, fn.xMin, fn.xMax);
@ -87,7 +90,7 @@ public class A8kOptScanResultAnalyzer {
return reactionResult;
}
static private ReactionResult analyzeResult(OptAnalyzeContext optcxt, OptScanResult optScanResult) throws A8kOptProcessException {
static private ReactionResult analyzeResult(OptAnalyzeContext optcxt, A8kOptPeaks optScanResult) throws A8kOptProcessException {
A8kOptFnFormula fnFormual = optcxt.projInfoCxt.getA8kOptFnFormula(optcxt.subProjIndex);
Double result1 = null;
if (fnFormual.fnType.equals(A8kFnType.NormalFn)) {
@ -105,10 +108,13 @@ public class A8kOptScanResultAnalyzer {
return buildResult(optcxt, fnFormual.resultBuilderFn, result1);
}
static public ReactionResult analyze(SampleInfo sampleInfo, ProjInfoContext projInfoCxt, int subProjIndex, OptScanResult optScanResult) {
static public ReactionResult analyze(SampleInfo sampleInfo, ProjInfoContext projInfoCxt, int subProjIndex, A8kOptPeaks peaks) {
log.info("analyze: {} proj:[{}:{}], peaks={}", sampleInfo.sampleId, projInfoCxt.getProjId(), subProjIndex, peaks);
OptAnalyzeContext optAnalyzeContext = new OptAnalyzeContext(sampleInfo, projInfoCxt, subProjIndex);
try {
return analyzeResult(optAnalyzeContext, optScanResult);
return analyzeResult(optAnalyzeContext, peaks);
} catch (A8kOptProcessException e) {
return new ReactionResult(optAnalyzeContext.getProjOptInfo().subProjName, optAnalyzeContext.getProjOptInfo().subProjShortName, e.status, e.errorMsg);
}

25
src/main/java/a8k/a8kproj/fakeoptpeak/FakeOptPeakFactory.java

@ -0,0 +1,25 @@
package a8k.a8kproj.fakeoptpeak;
import a8k.a8kproj.optalgo.type.A8kOptPeak;
import a8k.a8kproj.optalgo.type.A8kOptPeaks;
import a8k.a8kproj.optalgo.type.PeakFindState;
import a8k.a8kproj.optanalyzer.PeakNameAssigner;
public class FakeOptPeakFactory {
public static A8kOptPeaks build(Integer projId, Integer peakNameRefNum, Double area) {
A8kOptPeaks a8kOptPeaks = new A8kOptPeaks();
A8kOptPeak a8kOptPeak = new A8kOptPeak();
a8kOptPeak.area = area;
a8kOptPeak.state = PeakFindState.FIND_PEAK;
a8kOptPeaks.P040 = a8kOptPeak.deepCopy();
a8kOptPeaks.P080 = a8kOptPeak.deepCopy();
a8kOptPeaks.P120 = a8kOptPeak.deepCopy();
a8kOptPeaks.P160 = a8kOptPeak.deepCopy();
a8kOptPeaks.P200 = a8kOptPeak.deepCopy();
PeakNameAssigner.assignPeakName(projId, peakNameRefNum, a8kOptPeaks);
return a8kOptPeaks;
}
}

2
src/main/java/a8k/service/test/fakeproj/FAKE_PROJ_01_FLOW1.java → src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_01_FLOW1.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;

2
src/main/java/a8k/service/test/fakeproj/FAKE_PROJ_02_FLOW2.java → src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_02_FLOW2.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;

2
src/main/java/a8k/service/test/fakeproj/FAKE_PROJ_03.java → src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_03.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;

2
src/main/java/a8k/service/test/fakeproj/FAKE_PROJ_04.java → src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_04.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;

2
src/main/java/a8k/service/test/fakeproj/FAKE_PROJ_05.java → src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_05.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;

2
src/main/java/a8k/service/test/fakeproj/FAKE_PROJ_06.java → src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_06.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;

2
src/main/java/a8k/service/test/fakeproj/FAKE_PROJ_07_EXPIRED.java → src/main/java/a8k/a8kproj/fakeproj/FAKE_PROJ_07_EXPIRED.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;

12
src/main/java/a8k/service/test/fakeproj/FakeProjInfo.java → src/main/java/a8k/a8kproj/fakeproj/FakeProjInfo.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.ProjInfoCard;
import a8k.service.dao.type.ProjOptInfo;
@ -40,7 +40,7 @@ public class FakeProjInfo {
FakeProjInfo() {}
public ProjInfoCard buildA8kIDCardInfo() {
public ProjInfoCard buildProjCardInfo() {
ProjInfoCard idCardInfo = new ProjInfoCard();
idCardInfo.projName = projName;
@ -56,7 +56,7 @@ public class FakeProjInfo {
return idCardInfo;
}
public ProjectInfo buildA8kProjectInfo() {
public ProjectInfo buildA8kProjInfo() {
ProjectInfo projInfo = new ProjectInfo();
projInfo.projId = projId;
projInfo.projName = projName;
@ -74,7 +74,7 @@ public class FakeProjInfo {
return projInfo;
}
public List<ProjOptInfo> buildA8kProjOptConfigList() {
public List<ProjOptInfo> buildProjOptInfoList() {
List<ProjOptInfo> projOptInfoList = new ArrayList<>();
for (int subIndex = 0; subIndex < subProjNum; subIndex++) {
@ -88,8 +88,8 @@ public class FakeProjInfo {
projOptInfo.subProjShortName = String.format("%s_%d", projShortName, subIndex);
projOptInfo.optType = A8kOptType.FOPT;
projOptInfo.optScanRange = 200;
projOptInfo.optScanPeakNum = 3;
projOptInfo.optPeakNameAssginRefPeakNum = 3;
projOptInfo.optScanPeakNum = 3;
projOptInfo.peakNameRefNum = 3;
projOptInfoList.add(projOptInfo);
}
return projOptInfoList;

8
src/main/java/a8k/service/test/fakeproj/FakeProjInfoFactory.java → src/main/java/a8k/a8kproj/fakeproj/FakeProjInfoFactory.java

@ -1,4 +1,4 @@
package a8k.service.test.fakeproj;
package a8k.a8kproj.fakeproj;
import a8k.service.dao.type.ProjInfoCard;
@ -24,15 +24,15 @@ public class FakeProjInfoFactory {
}
static public ProjInfoCard buildIDCardInfo(Class<?> type) {
return newInstance(type).buildA8kIDCardInfo();
return newInstance(type).buildProjCardInfo();
}
static public ProjectInfo buildProjectInfo(Class<?> type) {
return newInstance(type).buildA8kProjectInfo();
return newInstance(type).buildA8kProjInfo();
}
static public List<ProjOptInfo> buildA8kProjOptConfigList(Class<?> type) {
return newInstance(type).buildA8kProjOptConfigList();
return newInstance(type).buildProjOptInfoList();
}
}

216
src/main/java/a8k/a8kproj/fakeprojcontext/FakeProjInfoContextFactory.java

@ -0,0 +1,216 @@
package a8k.a8kproj.fakeprojcontext;
import a8k.a8kproj.opttype.A8kOptX;
import a8k.service.app.appdata.UtilsProjectColorAllocer;
import a8k.service.dao.type.ProjInfoCard;
import a8k.service.dao.type.ProjOptInfo;
import a8k.service.dao.type.ProjectInfo;
import a8k.service.dao.type.a8kidcard.A8kNormalFn;
import a8k.service.dao.type.a8kidcard.A8kOptFnFormula;
import a8k.service.dao.type.a8kidcard.A8kPiecewiseFn;
import a8k.service.dao.type.a8kidcard.A8kResultBuilderFn;
import a8k.service.dao.type.a8kidcard.zenum.A8kFnType;
import a8k.service.dao.type.a8kidcard.zenum.A8kOptType;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;
import a8k.service.dao.type.a8kidcard.zenum.A8kResultUnit;
import a8k.utils.ProjInfoContext;
import a8k.utils.ZDateUtils;
import cn.hutool.core.util.ObjectUtil;
import java.util.ArrayList;
import java.util.List;
public class FakeProjInfoContextFactory {
public static class FakeProjInfoContextCfg {
public String projName;
public String lotId;
public Integer projId;
public Integer updateChipVersion;
public Integer subProjNum;
public String projShortName;
public Integer reactionTemperature;
public String color;
public A8kReactionFlowType reactionFlowType;
public Integer wBloodSampleVolUl;
public Integer serumSampleVolUl;
public Integer shakeTimes;
public Integer bigBufferSampleUl;
public Integer mixLiquidAspirMixingCnt;
public Integer reactionPlateIncubationTimeMin;
public Integer reactionPlateDropletVolUl;
public Boolean expired;
public A8kFnType fnType;
public A8kOptType optType;
public Integer optScanPeakNum;
public Integer optPeakNameAssginRefPeakNum;
}
;
public static FakeProjInfoContextCfg createCfg(String projShortName, Integer projId, A8kReactionFlowType reactionType, Integer subProjNum) {
var val = new FakeProjInfoContextCfg();
val.projName = String.format("%s%04d", projShortName, projId);
val.lotId = String.format("%s001234", projShortName, projId);
val.projId = projId;
val.updateChipVersion = 1;
val.subProjNum = subProjNum;
val.projShortName = projShortName;
val.reactionTemperature = 25;
val.color = UtilsProjectColorAllocer.getProjColor(projId);
val.reactionFlowType = reactionType;
val.wBloodSampleVolUl = 100;
val.serumSampleVolUl = 100;
val.shakeTimes = 2;
val.bigBufferSampleUl = 200;
val.mixLiquidAspirMixingCnt = 1;
val.reactionPlateIncubationTimeMin = 1;
val.reactionPlateDropletVolUl = 50;
val.expired = false;
val.fnType = A8kFnType.NormalFn;
val.optType = A8kOptType.FOPT;
if (projId == 1) {
val.optScanPeakNum = 2;
val.optPeakNameAssginRefPeakNum = 2;
} else {
val.optScanPeakNum = 5;
val.optPeakNameAssginRefPeakNum = 5;
}
return val;
}
/**
* !!! WARNING 这个方法中的数值轻易不要修改后续很多测试代码都是基于这个数值的
*/
private static A8kOptFnFormula buildTestFnFormula(A8kFnType fntyp) {
A8kOptFnFormula formula = new A8kOptFnFormula();
A8kNormalFn a8kNormalFn = new A8kNormalFn();
a8kNormalFn.x = A8kOptX.R;
a8kNormalFn.xMin = 1.0;
a8kNormalFn.xMax = 100.0;
a8kNormalFn.A = 1.0;
a8kNormalFn.B = 1.0;
a8kNormalFn.C = 1.0;
a8kNormalFn.D = 1.0;
a8kNormalFn.lowLimit = 1.0;
a8kNormalFn.upLimit = 100.0;
A8kPiecewiseFn a8kPiecewiseFn = new A8kPiecewiseFn();
a8kPiecewiseFn.judeX = A8kOptX.R;
a8kPiecewiseFn.judeThres = 1.0;
a8kPiecewiseFn.lX = A8kOptX.R;
a8kPiecewiseFn.hX = A8kOptX.R;
a8kPiecewiseFn.xMin = 1.0;
a8kPiecewiseFn.xMax = 100.0;
a8kPiecewiseFn.A0 = 1.0;
a8kPiecewiseFn.B0 = 1.0;
a8kPiecewiseFn.C0 = 1.0;
a8kPiecewiseFn.D0 = 1.0;
a8kPiecewiseFn.A1 = 1.0;
a8kPiecewiseFn.B1 = 1.0;
a8kPiecewiseFn.C1 = 1.0;
a8kPiecewiseFn.D1 = 1.0;
a8kPiecewiseFn.lowLimit = 1.0;
a8kPiecewiseFn.upLimit = 100.0;
A8kResultBuilderFn a8kResultBuilderFn = new A8kResultBuilderFn(); //结果生成函数
a8kResultBuilderFn.ret1Unit = A8kResultUnit.pgPml;
a8kResultBuilderFn.ret2Unit = A8kResultUnit.ngPml;
a8kResultBuilderFn.ret3Unit = A8kResultUnit.ugPml;
a8kResultBuilderFn.toUint2FnA = 2.0;
a8kResultBuilderFn.toUint2FnB = 0.1;
a8kResultBuilderFn.toUint3FnA = 3.0;
a8kResultBuilderFn.toUint3FnB = 0.1;
formula.fnType = fntyp;
//普通函数
if (A8kFnType.NormalFn.equals(fntyp)) {
formula.serumNorFn = a8kNormalFn.clone(); // 血清
formula.bloodNorFn = a8kNormalFn.clone(); // 血浆
}
// 分段函数系数
if (A8kFnType.PiecewiseFn.equals(fntyp)) {
formula.serumPiecewiseFn = a8kPiecewiseFn.clone(); // 血清
formula.bloodPiecewiseFn = a8kPiecewiseFn.clone(); // 血浆
}
//结果
formula.resultBuilderFn = a8kResultBuilderFn.clone(); //结果生成函数
return formula;
}
static public ProjInfoContext build(FakeProjInfoContextCfg cfg) {
//
// ProjectInfo
//
ProjectInfo projInfo = new ProjectInfo();
projInfo.projId = cfg.projId;
projInfo.projName = cfg.projName;
projInfo.projShortName = cfg.projShortName;
projInfo.subProjNum = cfg.subProjNum;
projInfo.reactionTemperature = cfg.reactionTemperature;
projInfo.color = cfg.color;
projInfo.reactionFlowType = cfg.reactionFlowType;
projInfo.wBloodSampleVolUl = cfg.wBloodSampleVolUl;
projInfo.serumSampleVolUl = cfg.serumSampleVolUl;
projInfo.shakeTimes = cfg.shakeTimes;
projInfo.bigBufferSampleUl = cfg.bigBufferSampleUl;
projInfo.reactionPlateIncubationTimeMin = cfg.reactionPlateIncubationTimeMin;
projInfo.reactionPlateDropletVolUl = cfg.reactionPlateDropletVolUl;
//
// ProjInfoCard
//
ProjInfoCard projInfoCard = new ProjInfoCard();
projInfoCard.projName = cfg.projName;
projInfoCard.lotId = cfg.lotId;
if (!cfg.expired) {
projInfoCard.expiryDate = ZDateUtils.nextDay();
} else {
projInfoCard.expiryDate = ZDateUtils.theDayBeforeYesterday();
}
projInfoCard.projId = cfg.projId;
projInfoCard.updateChipVersion = cfg.updateChipVersion;
projInfoCard.subProjNum = cfg.subProjNum;
for (int i = 0; i < cfg.subProjNum; i++) {
var fnFormula = buildTestFnFormula(cfg.fnType);
projInfoCard.setProjFnFormual(i, fnFormula);
}
//
// ProjOptInfo
//
List<ProjOptInfo> projOptInfoList = new ArrayList<>();
for (int i = 0; i < cfg.subProjNum; i++) {
ProjOptInfo projOptInfo = new ProjOptInfo();
projOptInfo.projId = cfg.projId;
projOptInfo.projName = cfg.projName;
projOptInfo.subProjIndex = i;
projOptInfo.subProjName = String.format("SUBPROJ_%d", i);
projOptInfo.subProjShortName = String.format("SP%d", i);
projOptInfo.optType = cfg.optType;
projOptInfo.optScanRange = 250;
projOptInfo.optScanPeakNum = cfg.optScanPeakNum;
projOptInfo.peakNameRefNum = cfg.optPeakNameAssginRefPeakNum;
projOptInfoList.add(projOptInfo);
}
ProjInfoContext projInfoContext = new ProjInfoContext();
projInfoContext.projInfo = projInfo;
projInfoContext.projInfoCard = projInfoCard;
projInfoContext.projOptInfoList = projOptInfoList;
return projInfoContext;
}
}

241
src/main/java/a8k/a8kproj/optalgo/A8kOptAlgo.java

@ -1,241 +0,0 @@
//package a8k.a8kproj.optalgo;
//
//import a8k.a8kproj.optalgo.type.LineProcessContext;
//import a8k.a8kproj.optalgo.type.OptAlgoResult;
//import a8k.a8kproj.optalgo.type.Peak;
//import a8k.a8kproj.optalgo.type.PeakFindState;
//import a8k.a8kproj.optalgo.utils.*;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.util.Assert;
//
//import java.util.ArrayList;
//import java.util.List;
//
//@Slf4j
//public class A8kOptAlgo {
//
//
//
// public static OptAlgoResult processOptData(Integer expectPeakNum, Integer searchStart, double[] data) {
//
// LineProcessContext cxt = new LineProcessContext();
//
// //过采样
// cxt.afSupperVal = SupperSampling.process(data, 5);
// //中值滤波
// cxt.afSupperMedianVal = Filter.medianFiltering(cxt.afSupperVal, 25);
//
// //下采样到1000个点
// cxt.raw1000 = SubSampling.process(cxt.afSupperMedianVal, 6);
// //生成1000个的平滑曲线
// cxt.avg1000 = Filter.smooth(cxt.raw1000, 13);
// //生成1000个的斜率曲线
// cxt.diff1000 = LeastSquare.calculatedSlopeCurve(cxt.avg1000, 13);
// //求数据的均值(巴迪泰A5000算法)
// cxt.avgLine = findAvgLine(cxt.raw1000);
//
// //在曲线开始的位置第10个到15点的斜率
// cxt.baselineSlope = LeastSquare.linearLeastSquares(cxt.avg1000, 10 * 4, 5 * 4).slope;
//
//
// List<Peak> peaks = new ArrayList<>();
// Peak peak = null;
// Peak lastPeak = null;
// for (int i = 0; i < expectPeakNum; i++) {
// if (i == 0) {
// peak = findPeak(cxt, searchStart * 4, 80 * 4);
// } else {
// peak = findPeak(cxt, lastPeak.peakEndPos, 80 * 4);
// }
// peak.off = i;
// peaks.add(peak);
// if (!peak.state.equals(PeakFindState.FIND_PEAK)) {
// break;
// }
// lastPeak = peak;
// }
//
// OptAlgoResult result = new OptAlgoResult();
// result.resultData = SubSampling.process(cxt.avg1000, 4);
// result.ogiginData = data;
// result.peaks = peaks;
// return result;
// }
//
// /**
// * 求数据的均值(巴迪泰A5000算法)
// * @param inputRaw 输入数据
// * @return 均值线
// */
// static double findAvgLine(double[] inputRaw) {
// double base_min = 500;
// double fsum = 0;
// int cnt = 0;
//
// int range = inputRaw.length;
//
// do {
// fsum = cnt = 0;
// for (int i = 1; i < range; i++) {
// if (inputRaw[i] < base_min) {
// fsum += inputRaw[i];
// cnt++;
// }
// }
//
// base_min = base_min + 50;
// } while (cnt < range - 15 * inputRaw.length / 250);
//
// return fsum / cnt;
// }
//
// static Peak findPeak(LineProcessContext cxt, int searchStart, int peakWidth) {
// Peak peak = new Peak();
// /*
// * @brief 查找峰的位置
// *
// * 思路:
// * 搜索所有大于均值的点当点满足其数值大于附近一定数量的点时认为是峰的位置
// */
//
// log.info("findpeak start:{} windth:{}", searchStart, peakWidth);
//
// // judge_win_size
// int judge_win_size = 2 * (cxt.avg1000.length / 250) + 1;
//
// int peakoff = findPeakOff(cxt, searchStart, peakWidth, judge_win_size);
// if (peakoff < 0) {
// peak.state = PeakFindState.NOT_FIND_PEAK;
// return peak;
// }
// peak.peakPos = peakoff;
//
// /*
// * @brief 查找峰的起始位置
// *
// * 思路:
// * 从峰的位置开始向前搜索找到一个点其值小于平均值
// * 然后继续向前搜索找到一个点斜率接近基线斜率
// *
// */
//
// int peak_start_pos = findPeakKneePoint(cxt, peak.peakPos, -1, peakWidth / 2);
// int peak_end_pos = findPeakKneePoint(cxt, peak.peakPos, 1, peakWidth / 2);
//
// if (peak_start_pos < 0) {
// peak.state = PeakFindState.NOT_FIND_PEAK_START;
// return peak;
// }
// if (peak_end_pos < 0) {
// peak.state = PeakFindState.NOT_FIND_PEAK_END;
// return peak;
// }
//
// peak.peakStartPos = peak_start_pos;
// peak.peakEndPos = peak_end_pos;
//
// /*
// * @brief
// * 计算峰的面积
// */
//
// double peak_full_area = 0;
// for (int i = peak_start_pos; i <= peak_end_pos; i++) {
// peak_full_area += cxt.raw1000[i];
// }
//
// double peak_base_line_area;
// peak_base_line_area =
// (cxt.raw1000[peak_start_pos] + cxt.raw1000[peak_end_pos]) * 0.5 * (peak_end_pos - peak_start_pos + 1);
//
// peak.peakFullArea = peak_full_area;
// peak.peakBaseLineArea = peak_base_line_area;
// peak.area = peak_full_area - peak_base_line_area;
// if (peak.area <= 0)
// peak.area = 0.0;
// peak.state = PeakFindState.FIND_PEAK;
//
// return peak;
// }
//
// static public int findPeakOff(LineProcessContext cxt, int start_off, int windos_size, int judge_win_size) {
// double maxv = 0;
// int peakoff = -1;
// boolean findmax = false;
//
// for (int index = 0; index < windos_size; index++) {
// int off = index + start_off;
// // 从窗口的一半大小开始判断
// if (findmax && cxt.avg1000[off] <= cxt.avgLine)
// break;
// if (off < judge_win_size / 2)
// continue;
// // 查找的点要大于基线
// if (cxt.avg1000[off] <= cxt.avgLine)
// continue;
// // 判断的
// if ((off + judge_win_size / 2) > (cxt.avg1000.length - 1))
// break;
// // 找到最大的峰值这里判断用于去除一个波峰中的某个临时的小波峰
// if (maxv > cxt.avg1000[off])
// continue;
//
// /*
// * @brief 检查当前位置的点是否是附近最大的点
// */
// if (BasicAlgo.isMaxvalInWindows(cxt.avg1000, off, judge_win_size)) {
// findmax = true;
// maxv = cxt.avg1000[off];
// peakoff = off;
// }
// }
// return peakoff;
// }
//
// static int findPeakKneePoint(LineProcessContext cxt,
// int search_start, //
// int search_direction, //
// int search_windows) {
// /*
// * @brief
// * 通过波峰的位置查找波峰的起始位置
// *
// * 逻辑:
// * 1. 从波峰的位置开始向前搜索找到一个点其值小于平均值
// * 2. 然后继续向前搜索找到一个点斜率接近基线斜率
// *
// */
//
// int off = -1;
// log.info("find peakend top_pos:{} direction:{} windows:{}", search_start, search_direction, search_windows);
//
// //
// Assert.isTrue(search_windows > 0, "search_windows <= 0");
// Assert.isTrue(search_direction == 1 || search_direction == -1, "search_direction != 1 && search_direction != -1");
// //
// int index_dval = search_direction >= 0 ? 1 : -1;
// int search_end = search_start + search_direction * search_windows;
//
// Assert.isTrue(search_end >= 0, "search_end < 0");
// Assert.isTrue(cxt.avg1000.length > search_end, "cxt.avg1000.size() <= search_start");
//
// for (int i = search_start; i != search_end; i += index_dval) {
// double now = cxt.avg1000[i];
// if (now >= cxt.avgLine)
// continue;
//
// if (search_direction == 1) {
// if (BasicAlgo.feq(cxt.diff1000[i], cxt.baselineSlope, 0.3) || cxt.diff1000[i] >= cxt.baselineSlope) {
// off = i;
// break;
// }
// } else {
// if (BasicAlgo.feq(cxt.diff1000[i], cxt.baselineSlope, 0.3) || cxt.diff1000[i] <= cxt.baselineSlope) {
// off = i;
// break;
// }
// }
// }
// return off;
// }
//}

18
src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeak.java

@ -1,6 +1,6 @@
package a8k.a8kproj.optalgo.type;
import a8k.opttype.PeakName;
import a8k.a8kproj.opttype.PeakName;
public class A8kOptPeak {
public PeakFindState state = PeakFindState.NOT_FIND_PEAK;
@ -12,4 +12,20 @@ public class A8kOptPeak {
public Integer peakEndPos;
public PeakName peakName;
public String toString() {
return String.format("[%s: %s]", peakName, area);
}
public A8kOptPeak deepCopy() {
A8kOptPeak val = new A8kOptPeak();
val.state = state;
val.off = off;
val.area = area;
val.peakPos = peakPos;
val.peakStartPos = peakStartPos;
val.peakEndPos = peakEndPos;
val.peakName = peakName;
return val;
}
}

10
src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeakArea.java

@ -1,10 +0,0 @@
package a8k.a8kproj.optalgo.type;
import a8k.opttype.PeakName;
import java.util.List;
public class A8kOptPeakArea {
public PeakName peakName;
public Double area;
}

14
src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeakAreas.java

@ -1,14 +0,0 @@
package a8k.a8kproj.optalgo.type;
import a8k.opttype.PeakName;
import java.util.ArrayList;
import java.util.List;
public class A8kOptPeakAreas {
List<A8kOptPeakArea> areas = new ArrayList<>();
// public Double getArea(PeakName peakName) {
// }
}

19
src/main/java/a8k/a8kproj/optalgo/type/A8kOptPeaks.java

@ -1,6 +1,7 @@
package a8k.a8kproj.optalgo.type;
import a8k.opttype.PeakName;
import a8k.a8kproj.opttype.PeakName;
import org.springframework.util.Assert;
public class A8kOptPeaks {
public A8kOptPeak P040 = new A8kOptPeak();
@ -10,21 +11,27 @@ public class A8kOptPeaks {
public A8kOptPeak P200 = new A8kOptPeak();
public A8kOptPeak findPeak(PeakName peakName) {
if (P040.peakName.equals(peakName)) {
Assert.notNull(peakName, "peakName must not be null");
if (peakName.equals(P040.peakName)) {
return P040;
}
if (P080.peakName.equals(peakName)) {
if (peakName.equals(P080.peakName)) {
return P080;
}
if (P120.peakName.equals(peakName)) {
if (peakName.equals(P120.peakName)) {
return P120;
}
if (P160.peakName.equals(peakName)) {
if (peakName.equals(P160.peakName)) {
return P160;
}
if (P200.peakName.equals(peakName)) {
if (peakName.equals(P200.peakName)) {
return P200;
}
return null;
}
public String toString() {
return String.format("P040: %s, P080: %s, P120: %s, P160: %s, P200: %s", P040, P080, P120, P160, P200);
}
}

6
src/main/java/a8k/a8kproj/optanalyzer/A8kOptXGetter.java

@ -3,9 +3,9 @@ package a8k.a8kproj.optanalyzer;
import a8k.a8kproj.optalgo.type.A8kOptPeak;
import a8k.a8kproj.optalgo.type.A8kOptPeaks;
import a8k.a8kproj.optanalyzer.exception.A8kOptProcessException;
import a8k.opttype.A8kOptX;
import a8k.opttype.PeakDivision;
import a8k.opttype.PeakName;
import a8k.a8kproj.opttype.A8kOptX;
import a8k.a8kproj.opttype.PeakDivision;
import a8k.a8kproj.opttype.PeakName;
import a8k.service.dao.type.ProjOptInfo;
import a8k.type.reaction_result_type.ReactionResultStatus;
import org.slf4j.Logger;

3
src/main/java/a8k/a8kproj/optanalyzer/OptChecker.java

@ -2,9 +2,8 @@ package a8k.a8kproj.optanalyzer;
import a8k.a8kproj.optalgo.type.A8kOptPeak;
import a8k.a8kproj.optalgo.type.PeakFindState;
import a8k.a8kproj.optanalyzer.context.OptAnalyzeContext;
import a8k.a8kproj.optanalyzer.exception.A8kOptProcessException;
import a8k.opttype.PeakName;
import a8k.a8kproj.opttype.PeakName;
import a8k.type.reaction_result_type.ReactionResultStatus;
public class OptChecker {

68
src/main/java/a8k/a8kproj/optanalyzer/PeakNameAssigner.java

@ -1,46 +1,52 @@
package a8k.a8kproj.optanalyzer;
import a8k.a8kproj.optalgo.type.A8kOptPeaks;
import a8k.opttype.PeakName;
import a8k.a8kproj.opttype.PeakName;
import a8k.service.dao.type.ProjOptInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
@Slf4j
public class PeakNameAssigner {
public static void assignPeakName(ProjOptInfo optcfg, A8kOptPeaks peaks) {
public static void assignPeakName(Integer projId, Integer peakNameRefNum, A8kOptPeaks peaks) {
//项目ID==1时峰的命名是特殊的
if (optcfg.projId == 1) {
if (projId == 1) {
peaks.P080.peakName = PeakName.C;
peaks.P120.peakName = PeakName.T;
return;
}
} else {
//
switch (optcfg.optPeakNameAssginRefPeakNum) {
case 2 -> {
peaks.P080.peakName = PeakName.T;
peaks.P120.peakName = PeakName.C;
}
case 3 -> {
peaks.P040.peakName = PeakName.H;
peaks.P080.peakName = PeakName.T;
peaks.P120.peakName = PeakName.C;
}
case 4 -> {
peaks.P040.peakName = PeakName.R;
peaks.P080.peakName = PeakName.H;
peaks.P120.peakName = PeakName.T;
peaks.P160.peakName = PeakName.C;
}
case 5 -> {
peaks.P040.peakName = PeakName.T4;
peaks.P080.peakName = PeakName.R;
peaks.P120.peakName = PeakName.H;
peaks.P160.peakName = PeakName.T;
peaks.P200.peakName = PeakName.C;
}
default -> {
//
switch (peakNameRefNum) {
case 2 -> {
peaks.P080.peakName = PeakName.T;
peaks.P120.peakName = PeakName.C;
}
case 3 -> {
peaks.P040.peakName = PeakName.H;
peaks.P080.peakName = PeakName.T;
peaks.P120.peakName = PeakName.C;
}
case 4 -> {
peaks.P040.peakName = PeakName.R;
peaks.P080.peakName = PeakName.H;
peaks.P120.peakName = PeakName.T;
peaks.P160.peakName = PeakName.C;
}
case 5 -> {
peaks.P040.peakName = PeakName.T4;
peaks.P080.peakName = PeakName.R;
peaks.P120.peakName = PeakName.H;
peaks.P160.peakName = PeakName.T;
peaks.P200.peakName = PeakName.C;
}
default -> {
}
}
}
}
}

2
src/main/java/a8k/a8kproj/optanalyzer/context/OptAnalyzeContext.java

@ -21,7 +21,7 @@ public class OptAnalyzeContext {
}
public String getProjName() {
return projInfoCxt.projectInfo.projName;
return projInfoCxt.projInfo.projName;
}

2
src/main/java/a8k/opttype/A8kOptX.java → src/main/java/a8k/a8kproj/opttype/A8kOptX.java

@ -1,4 +1,4 @@
package a8k.opttype;
package a8k.a8kproj.opttype;
public enum A8kOptX {
USUPPORT,

2
src/main/java/a8k/opttype/PeakDivision.java → src/main/java/a8k/a8kproj/opttype/PeakDivision.java

@ -1,4 +1,4 @@
package a8k.opttype;
package a8k.a8kproj.opttype;
public enum PeakDivision {
R(PeakName.T, PeakName.C), //T/C

2
src/main/java/a8k/opttype/PeakName.java → src/main/java/a8k/a8kproj/opttype/PeakName.java

@ -1,4 +1,4 @@
package a8k.opttype;
package a8k.a8kproj.opttype;
public enum PeakName {
T4,

14
src/main/java/a8k/service/app/appctrl/AppConsumablesScanService.java

@ -87,17 +87,17 @@ public class AppConsumablesScanService {
return ret;
}
if (projCfg.projectInfo == null) {
if (projCfg.projInfo == null) {
logger.warn("不支持的项目,LotID:{}", rp2dcode.lotId);
ret.report = ConsumablesScanReportErrorType.UN_SUPPORT_PROJ;
return ret;
}
Assert.isTrue(projCfg.projectInfo.reactionFlowType != null, "reactionType != null");
Assert.isTrue(projCfg.projInfo.reactionFlowType != null, "reactionType != null");
Integer projId = projCfg.projInfoCard.projId;
A8kReactionFlowType reactionType = projCfg.projectInfo.reactionFlowType;
A8kReactionFlowType reactionType = projCfg.projInfo.reactionFlowType;
if (reactionType.equals(A8kReactionFlowType.FlowType1)) {
//校验小瓶缓冲液,小瓶缓冲液+样本
if (ZStringUtils.isNullOrEmpty(rawResult.littBSScanResult)) {
@ -144,13 +144,13 @@ public class AppConsumablesScanService {
Assert.isTrue(ch.equals(result.chNum), "ch.equals(result.chNum)");
Assert.isTrue(projCfg != null, "projCfg != null");
Assert.isTrue(projCfg.projectInfo != null, "a8kIdCardInfo != null");
Assert.isTrue(projCfg.projectInfo.reactionFlowType != null, "reactionType != null");
Assert.isTrue(projCfg.projInfo != null, "a8kIdCardInfo != null");
Assert.isTrue(projCfg.projInfo.reactionFlowType != null, "reactionType != null");
Assert.isTrue(projCfg.projInfoCard != null, "projInfo != null");
var a8kIdCardInfo = projCfg.projInfoCard;
var reactionType = projCfg.projectInfo.reactionFlowType;
var projInfo = projCfg.projectInfo;
var reactionType = projCfg.projInfo.reactionFlowType;
var projInfo = projCfg.projInfo;
cState.reactionPlateGroup[ch] = new ReactionPlateGroup(result.projId, a8kIdCardInfo.projName, projInfo.projShortName, result.lotId, a8kIdCardInfo.color, AppConstant.CONSUMABLE_NUM);
if (reactionType.equals(A8kReactionFlowType.FlowType1)) {

4
src/main/java/a8k/service/app/appctrl/mainflowctrl/action/PLATE_OPT_SCAN.java

@ -88,7 +88,7 @@ public class PLATE_OPT_SCAN extends A8kStepAction {
return reactionResults;
}
Integer subProjNum = cxt.projInfoContext.projectInfo.subProjNum;
Integer subProjNum = cxt.projInfoContext.projInfo.subProjNum;
for (int i = 0; i < subProjNum; i++) {
A8kOptType optType = cxt.projInfoContext.getOptType(i);
OptScanResult optScanResult = cxt.getfOptScanResult(optType);
@ -97,7 +97,7 @@ public class PLATE_OPT_SCAN extends A8kStepAction {
cxt.setOptScanResult(optType, optScanResult);
}
ReactionResult result = A8kOptScanResultAnalyzer.analyze(cxt.sampleInfo, cxt.projInfoContext, i, optScanResult);
ReactionResult result = A8kOptScanResultAnalyzer.analyze(cxt.sampleInfo, cxt.projInfoContext, i, optScanResult.peaks);
reactionResults.add(result);
}

2
src/main/java/a8k/service/app/appctrl/mainflowctrl/action/SEQ5_PROCESS.java

@ -71,7 +71,7 @@ public class SEQ5_PROCESS extends A8kStepAction {
var tube = gstate.getCurProcessingTube();
Integer projProcessOff = tube.getProjProcessOff();
ProjProcessContext cxt = projectProcessContextMgrService.getProjProcessContext(tube.getSampleId(), tube.getProjIds().get(projProcessOff));
A8kReactionFlowType type = cxt.projInfoContext.projectInfo.reactionFlowType;
A8kReactionFlowType type = cxt.projInfoContext.projInfo.reactionFlowType;
if (virtualDevice.isEnable()) {
virtualDevice.doVirtualThings("处理样本(准备反应板,取tip,摇匀,脱帽)", 5);

6
src/main/java/a8k/service/app/appdata/ProjCfgMgrService.java

@ -31,7 +31,7 @@ public class ProjCfgMgrService {
if(projCfg.projInfoCard == null){
return projCfg;
}
projCfg.projectInfo = a8KProjInfoDao.findByProjId(projCfg.projInfoCard.projId);
projCfg.projInfo = a8KProjInfoDao.findByProjId(projCfg.projInfoCard.projId);
projCfg.projOptInfoList = a8KProjOptConfigDao.findByProjIndex(projCfg.projInfoCard.projId);
return projCfg;
}
@ -40,8 +40,8 @@ public class ProjCfgMgrService {
ProjInfoContext projCfg = new ProjInfoContext();
projCfg.projInfoCard = a8KProjIdCardDao.getByLotId(lotid);
Assert.isTrue(projCfg.projInfoCard != null, "ID卡信息不存在");
projCfg.projectInfo = a8KProjInfoDao.findByProjId(projCfg.projInfoCard.projId);
Assert.isTrue(projCfg.projectInfo != null, "项目信息不存在");
projCfg.projInfo = a8KProjInfoDao.findByProjId(projCfg.projInfoCard.projId);
Assert.isTrue(projCfg.projInfo != null, "项目信息不存在");
projCfg.projOptInfoList = a8KProjOptConfigDao.findByProjIndex(projCfg.projInfoCard.projId);
Assert.isTrue(projCfg.projOptInfoList != null, "项目配置信息不存在");
return projCfg;

4
src/main/java/a8k/service/app/appdata/ReactionRecordMgrService.java

@ -50,12 +50,12 @@ public class ReactionRecordMgrService {
record.sampleBarcode = projContext.sampleInfo.sampleBarcode;
record.sampleUserid = projContext.sampleInfo.userid;
record.sampleId = projContext.sampleInfo.sampleId;
record.projName = projContext.projInfoContext.projectInfo.projName;
record.projName = projContext.projInfoContext.projInfo.projName;
record.lotId = projContext.projInfoContext.projInfoCard.lotId;
record.projId = projContext.projInfoContext.projInfoCard.projId;
record.setExpiryDate(projContext.projInfoContext.projInfoCard.expiryDate);
record.operator = operator;
record.projShortName = projContext.projInfoContext.projectInfo.projShortName;
record.projShortName = projContext.projInfoContext.projInfo.projShortName;
record.appVersion = gstate.getAppVersion();
record.mcuVersion = gstate.getMcuVersion();
record.sn = gstate.getSn();

4
src/main/java/a8k/service/app/appdata/UtilsProjectColorAllocer.java

@ -5,7 +5,7 @@ import org.springframework.stereotype.Component;
@Component
public class UtilsProjectColorAllocer {
// https://blog.csdn.net/weixin_44878336/article/details/135003274
String[] colors = {
final static String[] colors = {
"#FFB6C1", // 1:浅粉红
"#FFC0CB", // 2:粉红
"#DC143C", // 3:猩红
@ -131,7 +131,7 @@ public class UtilsProjectColorAllocer {
"#FF0000", // 纯红
};
public String getProjColor(Integer projId) {
static public String getProjColor(Integer projId) {
return colors[projId % colors.length];
}
}

2
src/main/java/a8k/service/app/appstate/TubeStateMgrService.java

@ -1,2 +0,0 @@
package a8k.service.app.appstate;

4
src/main/java/a8k/service/app/appstate/type/SampleInfo.java

@ -4,8 +4,8 @@ import a8k.type.type.A8kTubeHolderType;
import a8k.type.type.BloodType;
public class SampleInfo {
public String sampleId; //样本ID-系统生成-唯一标识一个样本
public Integer projId;
public String sampleId = ""; //样本ID-系统生成-唯一标识一个样本
public Integer projId = 0;
public A8kTubeHolderType tubeHolderType;
public Boolean isHighTube = false;

21
src/main/java/a8k/service/app/appstate/type/TubeProcessContext.java

@ -1,21 +0,0 @@
package a8k.service.app.appstate.type;
import a8k.type.type.BloodType;
import java.util.ArrayList;
import java.util.List;
//public class TubeProcessContext {
// public String sampleid; //样本ID-系统生成-唯一标识一个样本
//
// public Boolean isHighTube = false;
// public Boolean isEmergency = false;
//
// public BloodType bloodType = BloodType.WHOLE_BLOOD; //血液类型
// public String sampleBarcode = ""; //用于请求用户信息的条码ID
// public String userid = ""; //用户输入的样本ID不做逻辑只做展示
// public List<Integer> projId = new ArrayList<>(); //项目代码
//
// public List<ProjProcessContext> projProcessContext;
//
//}

2
src/main/java/a8k/service/app/devicectrl/ctrlservice/OptScanModuleCtrlService.java

@ -150,7 +150,7 @@ public class OptScanModuleCtrlService {
Integer[] optdata = doOptScan(projOptInfo);
OptScanResult optResult = A8kOptAlgoV2.processOptData(optdata);
PeakNameAssigner.assignPeakName(projOptInfo, optResult.peaks);
PeakNameAssigner.assignPeakName(projOptInfo.projId, projOptInfo.peakNameRefNum, optResult.peaks);
return optResult;
}

4
src/main/java/a8k/service/app/devicectrl/script/DeviceCtrlScripter.java

@ -144,7 +144,7 @@ public class DeviceCtrlScripter {
public void doSampleProcessPrepare(ProjProcessContext ctx) throws AppException {
A8kReactionFlowType type = ctx.projInfoContext.projectInfo.reactionFlowType;
A8kReactionFlowType type = ctx.projInfoContext.projInfo.reactionFlowType;
if (type.equals(A8kReactionFlowType.FlowType1)) {
log.info("样本预处理,刺破小瓶缓冲液");
/*
@ -212,7 +212,7 @@ public class DeviceCtrlScripter {
Integer sampleul = ProjProcessContextUtils.getSampleVol(ctx);
Integer reactionul = ProjProcessContextUtils.getReactionPlateDropletVolUl(ctx);
A8kReactionFlowType type = ctx.projInfoContext.projectInfo.reactionFlowType;
A8kReactionFlowType type = ctx.projInfoContext.projInfo.reactionFlowType;
if (type.equals(A8kReactionFlowType.FlowType1)) {
// hbotCtrlService.takeTip(ctx.takeTip());
} else {

96
src/main/java/a8k/service/app/devicectrl/test/OptAlgoTest.java

@ -1,96 +0,0 @@
package a8k.service.app.devicectrl.test;
import a8k.a8kproj.optalgo.type.A8kOptPeakAreas;
import a8k.a8kproj.optalgo.type.A8kOptPeaks;
import a8k.service.dao.type.a8kidcard.A8kOptFnFormula;
import a8k.type.ReactionResult;
import a8k.type.type.BloodType;
public class OptAlgoTest {
//输入
// 峰面积峰面积峰面积峰面积峰面积
// ID卡
// 虚拟ID卡
//
//输出
// 峰比例数值
// 计算结果1单位123
// 计算结果2单位123
// 计算结果3单位123
// void computeResult(){}
//
// 方法的设备
// 光学配置+峰集合
A8kOptPeaks peaks;
// ReactionResult testComputeReactionResult() {
// }
// static private ReactionResult doNormalFn(A8kIdCardFn idCardFn, int subProjIndex) throws A8kOptProcessException {
// A8kFnFormula fn = switch (optcxt.bloodType) {
// case WHOLE_BLOOD -> idCardFn.norSerumFn;
// case SERUM_OR_PLASMA -> idCardFn.norBloodFn;
// };
// OptChecker.checkNotNull(optcxt, fn, "norSerumFn == null");
// OptChecker.checkNotNull(optcxt, idCardFn, "idCardFn == null");
// OptChecker.checkNotNull(optcxt, optcfg, "optcfg == null");
//
// A8kOptPeaks tpeaks = null, fpeaks = null;
// if (optcxt.foptResult != null) {
// fpeaks = optcxt.foptResult.peaks;
// }
// if (optcxt.toptResult != null) {
// tpeaks = optcxt.toptResult.peaks;
// }
//
//
// Double X = A8kOptXGetter.getX(idCardFn.norFnX, optcfg, fpeaks, tpeaks);
// OptChecker.checkX(X, idCardFn.norFnXMin, idCardFn.norFnXMax);
//
// Double result1 = fn.A * X * X + fn.B * X + fn.C;
// OptChecker.checkResult1(result1, fn.lowLimit, fn.upLimit);
//
// return buildResult(optcxt, subProjIndex, result1);
// }
//
// static private ReactionResult doPwFn(A8kIdCardFn idCardFn, int subProjIndex) throws A8kOptProcessException {
//
// A8kPiecewiseFnFormula piecfn = switch (optcxt.bloodType) {
// case WHOLE_BLOOD -> fnparam.bloodPiecewiseFn;
// case SERUM_OR_PLASMA -> fnparam.serumPiecewiseFn;
// };
//
// Double pwFnJudeX = A8kOptXGetter.getX(fnparam.pwFnJudeX, optcfg, optcxt.foptResult.peaks, optcxt.toptResult.peaks);
// Double X = null;
// Double result1 = null;
// if (pwFnJudeX < fnparam.pwFnJudeThres) {
// X = A8kOptXGetter.getX(fnparam.pwFnLCX, optcfg, optcxt.foptResult.peaks, optcxt.toptResult.peaks);
// result1 = piecfn.A0 * X * X + piecfn.B0 * X + piecfn.C0;
// } else {
// X = A8kOptXGetter.getX(fnparam.pwFnHCX, optcfg, optcxt.foptResult.peaks, optcxt.toptResult.peaks);
// result1 = piecfn.A1 * X * X + piecfn.B1 * X + piecfn.C1;
// }
// OptChecker.checkX(X, fnparam.pwFnXMin, fnparam.pwFnXMax);
// OptChecker.checkResult1(result1, piecfn.lowLimit, piecfn.upLimit);
//
// return buildResult(optcxt, subProjIndex, result1);
// }
ReactionResult analyzeOptPeaks(A8kOptFnFormula projOptConfig, BloodType bloodType, A8kOptPeakAreas areas) {
return null;
}
// 计算结果1
// 计算结果2
// 计算结果3
}

16
src/main/java/a8k/service/dao/type/ProjInfoCard.java

@ -46,9 +46,9 @@ public class ProjInfoCard {
public Integer subProjNum = 1; // 当前项目是几联卡项目,val = 1,2,3 0x0100
public A8kOptFnFormula pj1FnInfo;
public A8kOptFnFormula pj2FnInfo;
public A8kOptFnFormula pj3FnInfo;
public A8kOptFnFormula projFnFormual1;
public A8kOptFnFormula projFnFormual2;
public A8kOptFnFormula projFnFormual3;
public String toString() {
ObjectMapper mapper = new ObjectMapper();
@ -59,6 +59,16 @@ public class ProjInfoCard {
}
}
public void setProjFnFormual(Integer subProjIndex, A8kOptFnFormula projFnFormual) {
switch (subProjIndex) {
case 0 -> this.projFnFormual1 = projFnFormual;
case 1 -> this.projFnFormual2 = projFnFormual;
case 2 -> this.projFnFormual3 = projFnFormual;
default -> {
}
}
}
public A8kProjInfoCardBreif toBreif() {
A8kProjInfoCardBreif breif = new A8kProjInfoCardBreif();

6
src/main/java/a8k/service/dao/type/ProjOptInfo.java

@ -3,7 +3,7 @@ package a8k.service.dao.type;
import a8k.service.dao.type.a8kidcard.zenum.A8kOptType;
public class ProjOptInfo {
public int id;
public int id = 0;
public Integer projId; //项目INDEX
public String projName; //项目名称
public Integer subProjIndex;//子项目INDEX
@ -15,6 +15,6 @@ public class ProjOptInfo {
public A8kOptType optType; //子项目 光学类型 necessity
public Integer optScanRange; //子项目 扫描范围 扫描范围
public Integer optScanPeakNum; //子项目 实际扫描到的峰的数量
public Integer optPeakNameAssginRefPeakNum; //子项目 峰的数量
public Integer optScanPeakNum; //子项目 实际扫描到的峰的数量
public Integer peakNameRefNum; //子项目 峰的数量
}

12
src/main/java/a8k/service/dao/type/a8kidcard/A8kNormalFn.java

@ -1,8 +1,8 @@
package a8k.service.dao.type.a8kidcard;
import a8k.opttype.A8kOptX;
import a8k.a8kproj.opttype.A8kOptX;
public class A8kNormalFn {
public class A8kNormalFn implements Cloneable {
// 非分段函数
public A8kOptX x = A8kOptX.R; // 函数未知数是 0150
public Double xMin = 0.0; // 函数未知数下限闻值 0155
@ -15,6 +15,14 @@ public class A8kNormalFn {
public Double lowLimit = 0.0;//0173
public Double upLimit = 999999.0;//0178
public A8kNormalFn clone() {
try {
return (A8kNormalFn) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public A8kNormalFn() {
}

13
src/main/java/a8k/service/dao/type/a8kidcard/A8kPiecewiseFn.java

@ -1,8 +1,8 @@
package a8k.service.dao.type.a8kidcard;
import a8k.opttype.A8kOptX;
import a8k.a8kproj.opttype.A8kOptX;
public class A8kPiecewiseFn {
public class A8kPiecewiseFn implements Cloneable{
// 分段函数
public A8kOptX judeX; // 分界判断数据来源 01F0
public Double judeThres; // 分界判断数据值 01F5
@ -62,4 +62,13 @@ public class A8kPiecewiseFn {
this.lowLimit = lowLimit;
this.upLimit = upLimit;
}
public A8kPiecewiseFn clone() {
try {
return (A8kPiecewiseFn) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}

13
src/main/java/a8k/service/dao/type/a8kidcard/A8kResultBuilderFn.java

@ -2,7 +2,7 @@ package a8k.service.dao.type.a8kidcard;
import a8k.service.dao.type.a8kidcard.zenum.A8kResultUnit;
public class A8kResultBuilderFn {
public class A8kResultBuilderFn implements Cloneable{
// 结果
public A8kResultUnit ret1Unit; // 单位 02E0
public A8kResultUnit ret2Unit; // 单位 02E5
@ -24,4 +24,15 @@ public class A8kResultBuilderFn {
this.toUint3FnA = toUint3FnA;
this.toUint3FnB = toUint3FnB;
}
public A8kResultBuilderFn() {
}
public A8kResultBuilderFn clone() {
try {
return (A8kResultBuilderFn) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}

2
src/main/java/a8k/service/test/MainflowCtrlTestService.java

@ -1,6 +1,7 @@
package a8k.service.test;
import a8k.OS;
import a8k.a8kproj.fakeproj.*;
import a8k.constant.AppConstant;
import a8k.extapi_controler.utils.ExtApiFn;
import a8k.extapi_controler.utils.ExtApiTab;
@ -20,7 +21,6 @@ import a8k.service.app.devicectrl.exdriver.MotorEnableExDriver;
import a8k.service.dao.A8kProjIdCardDao;
import a8k.service.dao.A8kProjInfoDao;
import a8k.service.dao.A8kProjOptConfigDao;
import a8k.service.test.fakeproj.*;
import a8k.service.test.state.TestModeState;
import a8k.service.test.state.VirtualDevice;
import a8k.type.*;

2
src/main/java/a8k/service/test/TestStateMgrService.java

@ -4,7 +4,7 @@ package a8k.service.test;
import a8k.service.dao.A8kProjIdCardDao;
import a8k.service.dao.A8kProjInfoDao;
import a8k.service.dao.A8kProjOptConfigDao;
import a8k.service.test.fakeproj.FakeProjInfoFactory;
import a8k.a8kproj.fakeproj.FakeProjInfoFactory;
import a8k.service.test.state.TestModeState;
import a8k.service.test.state.VirtualDevice;
import a8k.type.ConsumableOneChRawResult;

4
src/main/java/a8k/service/test/VirtualDeviceSimulationTest.java

@ -1,6 +1,7 @@
package a8k.service.test;
import a8k.SpringBootBeanUtil;
import a8k.a8kproj.fakeproj.*;
import a8k.extapi_controler.utils.ExtApiFn;
import a8k.extapi_controler.utils.ExtApiTab;
import a8k.hardware.type.a8kcanprotocol.A8kEcode;
@ -17,7 +18,6 @@ import a8k.service.dao.ReactionRecordDao;
import a8k.service.dao.type.ProjInfoCard;
import a8k.service.dao.type.ReactionResultRecord;
import a8k.service.dao.type.a8kidcard.zenum.A8kResultUnit;
import a8k.service.test.fakeproj.*;
import a8k.service.test.state.VirtualDevice;
import a8k.type.ConsumableOneChRawResult;
import a8k.type.ReactionResult;
@ -69,7 +69,7 @@ public class VirtualDeviceSimulationTest {
@ExtApiFn(name = "模拟插入一张虚拟ID卡", group = "虚拟操作", order = 200)
public void insertVirtualIdCard() {
ProjInfoCard idCardInfo = new FAKE_PROJ_01_FLOW1().buildA8kIDCardInfo();
ProjInfoCard idCardInfo = new FAKE_PROJ_01_FLOW1().buildProjCardInfo();
virtualDevice.setMountIdCard(idCardInfo);
eventBus.pushEvent(new A8kHardwareReport(A8kPacketBuilder.build_event_a8000_idcard_online()));
}

53
src/main/java/a8k/test/TestOptAnalyzer.java

@ -0,0 +1,53 @@
package a8k.test;
import a8k.a8kproj.A8kOptScanResultAnalyzer;
import a8k.a8kproj.fakeoptpeak.FakeOptPeakFactory;
import a8k.a8kproj.fakeprojcontext.FakeProjInfoContextFactory;
import a8k.a8kproj.optalgo.type.OptScanResult;
import a8k.service.app.appstate.type.SampleInfo;
import a8k.a8kproj.fakeproj.FAKE_PROJ_01_FLOW1;
import a8k.service.dao.type.a8kidcard.zenum.A8kReactionFlowType;
import a8k.type.ReactionResult;
import a8k.utils.ProjInfoContext;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class TestOptAnalyzer {
@FunctionalInterface
public interface TEST {
Boolean test();
}
Boolean TEST_OPT_RESULT_PARSE_01() {
var cfg = FakeProjInfoContextFactory.createCfg("TEST_PROJ", 2, A8kReactionFlowType.FlowType1, 3);
ProjInfoContext projInfoContext = FakeProjInfoContextFactory.build(cfg);
var peaks = FakeOptPeakFactory.build(cfg.projId, 4, 100.0);
SampleInfo sampleInfo = new SampleInfo();
sampleInfo.projId = cfg.projId;
ReactionResult result = A8kOptScanResultAnalyzer.analyze(sampleInfo, projInfoContext, 0, peaks);
log.info("result: {}", result);
return true;
}
void test(String mark, TEST test) {
Boolean suc = test.test();
if (suc) {
log.info("TEST: {} -> SUCCESS", mark);
} else {
log.error("TEST: {} -> FAILED", mark);
}
}
@PostConstruct
void init() {
// test("TEST_OPT_RESULT_PARSE_01", this::TEST_OPT_RESULT_PARSE_01);
}
}

5
src/main/java/a8k/type/ReactionResult.java

@ -2,6 +2,7 @@ package a8k.type;
import a8k.service.dao.type.a8kidcard.zenum.A8kResultUnit;
import a8k.type.reaction_result_type.ReactionResultStatus;
import a8k.utils.ZJsonHelper;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
@ -62,4 +63,8 @@ public class ReactionResult {
status = error;
this.errorInfo = errorInfo;
}
public String toString() {
return ZJsonHelper.objectToJson(this);
}
}

16
src/main/java/a8k/utils/ProjInfoContext.java

@ -9,23 +9,23 @@ import a8k.service.dao.type.a8kidcard.zenum.A8kOptType;
import java.util.List;
public class ProjInfoContext {
public ProjectInfo projectInfo;
public ProjInfoCard projInfoCard;
public ProjectInfo projInfo;
public ProjInfoCard projInfoCard;
public List<ProjOptInfo> projOptInfoList;
public ProjBriefInfo getProjBriefInfo() {
return new ProjBriefInfo(projectInfo.projId, projectInfo.projName, projectInfo.projShortName, projectInfo.color);
return new ProjBriefInfo(projInfo.projId, projInfo.projName, projInfo.projShortName, projInfo.color);
}
public Integer getReactionPlateIncubationTimeMin() {
if (projInfoCard.reactionPlateReactionTime > 0) {
return projInfoCard.reactionPlateReactionTime;
}
return projectInfo.reactionPlateIncubationTimeMin;
return projInfo.reactionPlateIncubationTimeMin;
}
public Integer getProjId() {
return projectInfo.projId;
return projInfo.projId;
}
public A8kOptType getOptType(Integer subProjIndex) {
@ -39,9 +39,9 @@ public class ProjInfoContext {
public A8kOptFnFormula getA8kOptFnFormula(Integer subProjIndex) {
return switch (subProjIndex) {
case 0 -> projInfoCard.pj1FnInfo;
case 1 -> projInfoCard.pj2FnInfo;
case 2 -> projInfoCard.pj3FnInfo;
case 0 -> projInfoCard.projFnFormual1;
case 1 -> projInfoCard.projFnFormual2;
case 2 -> projInfoCard.projFnFormual3;
default -> null;
};
}

20
src/main/java/a8k/utils/ProjProcessContextUtils.java

@ -21,11 +21,11 @@ public class ProjProcessContextUtils {
for (var cxt : cxts) {
ProjInfoContext projCfg = cxt.projInfoContext;
if (projCfg != null) {
if (projCfg.projectInfo.shakeTimes == null) {
if (projCfg.projInfo.shakeTimes == null) {
continue;
}
if (projCfg.projectInfo.shakeTimes > shakeTimes) {
shakeTimes = projCfg.projectInfo.shakeTimes;
if (projCfg.projInfo.shakeTimes > shakeTimes) {
shakeTimes = projCfg.projInfo.shakeTimes;
}
}
}
@ -37,7 +37,7 @@ public class ProjProcessContextUtils {
public static Integer getTakeLargeBSVolume(ProjProcessContext ctx) {
return ctx.projInfoContext.projectInfo.bigBufferSampleUl;
return ctx.projInfoContext.projInfo.bigBufferSampleUl;
}
public static Boolean isDoMixTubeSample(ProjProcessContext ctx) {
@ -69,7 +69,7 @@ public class ProjProcessContextUtils {
public static Integer getTubeMixingCount(ProjProcessContext ctx) {
var projCfg = ctx.projInfoContext;
var idcard = projCfg.projInfoCard;
var defaultVal = projCfg.projectInfo;
var defaultVal = projCfg.projInfo;
if (isEffectiveValue(idcard.tubeMixingCount)) {
return idcard.tubeMixingCount;
}
@ -83,7 +83,7 @@ public class ProjProcessContextUtils {
public static Integer getBSMixingCnt(ProjProcessContext ctx) {
var projCfg = ctx.projInfoContext;
var idcard = projCfg.projInfoCard;
var defaultVal = projCfg.projectInfo;
var defaultVal = projCfg.projInfo;
if (isEffectiveValue(idcard.bufferSolutionMixingCnt)) {
return idcard.bufferSolutionMixingCnt;
}
@ -97,11 +97,11 @@ public class ProjProcessContextUtils {
public static Integer getReactionPlateDropletVolUl(ProjProcessContext ctx) {
var projCfg = ctx.projInfoContext;
var idcard = projCfg.projInfoCard;
var defaultVal = projCfg.projectInfo;
var defaultVal = projCfg.projInfo;
if (isEffectiveValue(idcard.reactionPlateDropletVolUl)) {
return idcard.reactionPlateDropletVolUl;
}
return ctx.projInfoContext.projectInfo.reactionPlateDropletVolUl;
return ctx.projInfoContext.projInfo.reactionPlateDropletVolUl;
}
@ -111,7 +111,7 @@ public class ProjProcessContextUtils {
public static Integer getSampleVol(ProjProcessContext ctx) {
var projCfg = ctx.projInfoContext;
var idcard = projCfg.projInfoCard;
var defaultVal = projCfg.projectInfo;
var defaultVal = projCfg.projInfo;
var bloodType = ctx.sampleInfo.bloodType;
if (bloodType.equals(BloodType.WHOLE_BLOOD)) {
@ -175,7 +175,7 @@ public class ProjProcessContextUtils {
static public Pos3d getReactionEndPos(ProjProcessContext ctx) {
HbotConsumableParamMgr hbotConsumableParamMgr = SpringBootBeanUtil.getBean(HbotConsumableParamMgr.class);
A8kReactionFlowType type = ctx.projInfoContext.projectInfo.reactionFlowType;
A8kReactionFlowType type = ctx.projInfoContext.projInfo.reactionFlowType;
return switch (type) {
case FlowType1 -> hbotConsumableParamMgr.getLittleBufferSamplePosEnd(ctx.consumable.getGroup(), ctx.consumable.getPos());
case FlowType2 -> hbotConsumableParamMgr.getProbeSubstanceSamplePosEnd(ctx.consumable.getGroup(), ctx.consumable.getPos());

6
src/main/java/a8k/utils/ZObjectUtils.java

@ -0,0 +1,6 @@
package a8k.utils;
public class ZObjectUtils {
}
Loading…
Cancel
Save