You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
6.9 KiB

  1. package com.iflytop.a800.utils;
  2. import com.fasterxml.jackson.databind.JsonNode;
  3. import com.iflytop.a800.model.MdbIdChip;
  4. import com.iflytop.uf.util.UfJsonHelper;
  5. import java.util.*;
  6. public class ScanResultAnalyser {
  7. // id chip
  8. private final MdbIdChip idChip;
  9. // constructor
  10. public ScanResultAnalyser( MdbIdChip idChip ) {
  11. this.idChip = idChip;
  12. }
  13. // analyse
  14. public List<ScanResultAnalyseResultItem> analyse( String sampleType, float[] scanResult ) {
  15. var algo = new ScanResultAnalysisAlgo();
  16. var algoResult = algo.calculate(scanResult, this.idChip.peakCount);
  17. // 处理
  18. List<ScanResultAnalyseResultItem> results = new ArrayList<>();
  19. var projects = UfJsonHelper.jsonToNode(idChip.items);
  20. for ( var i=0; i< idChip.itemCount; i++ ) {
  21. double valueX = 0;
  22. JsonNode funcInfo = null;
  23. var project = projects.get(i);
  24. var itemName = project.get("item").asText();
  25. var isPiecewiseFunction = project.get("isPiecewiseFunction").asBoolean();
  26. if ( !isPiecewiseFunction ) { // 非分段函数
  27. var func = project.get("nonPiecewiseFunction");
  28. var xValueSource = func.get("xValueSource").asInt();
  29. valueX = this.calculateRatio(algoResult, xValueSource, itemName);
  30. funcInfo = func.get("serum");
  31. if ("WB".equals(sampleType)) {
  32. funcInfo = func.get("wb");
  33. }
  34. } else { // 分段函数
  35. var func = project.get("piecewiseFunction");
  36. var piecewiseValueSrc = func.get("piecewiseValueSrc").asInt();
  37. var piecewiseValueSrcValue = this.calculateRatio(algoResult, piecewiseValueSrc, itemName);
  38. var piecewiseValue = func.get("piecewiseValue").asDouble();
  39. if ( piecewiseValueSrcValue > piecewiseValue ) { // 高浓度
  40. var highXValueSource = func.get("highXValueSource").asInt();
  41. valueX = this.calculateRatio(algoResult, highXValueSource, itemName);
  42. funcInfo = func.get("serumHigh");
  43. if ("WB".equals(sampleType)) {
  44. funcInfo = func.get("wbHigh");
  45. }
  46. } else { // 低浓度
  47. var lowXValueSource = func.get("lowXValueSource").asInt();
  48. valueX = this.calculateRatio(algoResult, lowXValueSource, itemName);
  49. funcInfo = func.get("serumLow");
  50. if ("WB".equals(sampleType)) {
  51. funcInfo = func.get("wbLow");
  52. }
  53. }
  54. }
  55. double valueD = funcInfo.get("d").asDouble();
  56. double valueB = funcInfo.get("b").asDouble();
  57. double valueC = funcInfo.get("c").asDouble();
  58. double valueA = funcInfo.get("a").asDouble();
  59. double value = valueA * Math.pow(valueX,3) + valueB * Math.pow(valueX,2) + valueC * valueX + valueD;
  60. // @TODO : 单位也要从配置中读取
  61. var result = new ScanResultAnalyseResultItem();
  62. result.name = itemName;
  63. result.value = value;
  64. result.unit = "xx/xx";
  65. results.add(result);
  66. }
  67. return results;
  68. }
  69. /**
  70. * @link https://iflytop1.feishu.cn/docx/UnRtdSG4qouMTaxzRb2cjiTTnZe
  71. * @link https://iflytop1.feishu.cn/docx/A0CHdQL6OoTTCSx8MB7cQKEjnSc
  72. * @param result - algo result
  73. * @param xSource - x source
  74. * @return double - value of ratio
  75. */
  76. private double calculateRatio(ScanResultAnalysisAlgo.AlgoResult result, int xSource, String itenName) {
  77. // 计算 ratio
  78. Map<String, Float> ratios = new HashMap<>();
  79. if ( 5 == idChip.scanPeakCount ) {
  80. var peaks = result.peakInfos;
  81. ratios.put("ratio", peaks[3].area / peaks[4].area); // T/C
  82. ratios.put("antiRatio", peaks[3].area / peaks[4].area); // H/C
  83. ratios.put("antiTestRatio", peaks[3].area / peaks[2].area); // T/H
  84. ratios.put("rfRatio", peaks[1].area / peaks[4].area); // R/C
  85. ratios.put("rtRatio", peaks[3].area / peaks[1].area); // T/R
  86. ratios.put("t4Ratio", peaks[0].area / peaks[4].area); // T4/C
  87. ratios.put("t4t3Ratio", peaks[1].area / peaks[0].area); // R/T4
  88. } else if ( 4 == idChip.scanPeakCount && Objects.equals(idChip.scanType, 1) ) { // F 光学
  89. var peaks = result.peakInfos; // H T C
  90. ratios.put("ratio", peaks[1].area / peaks[2].area); // T/C
  91. ratios.put("antiRatio", peaks[0].area / peaks[2].area); // H/C
  92. ratios.put("antiTestRatio", peaks[1].area / peaks[0].area); // T/H
  93. ratios.put("rfRatio", peaks[0].area / peaks[2].area); // R/C @TODO : 待定, 三联卡F光学没有R
  94. ratios.put("rtRatio", peaks[1].area / peaks[0].area); // T/R @TODO : 待定, 三联卡F光学没有R
  95. } else if ( 4 == idChip.scanPeakCount && Objects.equals(idChip.scanType, 2) ) { // T 光学
  96. var peaks = result.peakInfos; // R H T C
  97. ratios.put("ratio", peaks[2].area / peaks[3].area); // T/C
  98. ratios.put("antiRatio", peaks[1].area / peaks[3].area); // H/C
  99. ratios.put("antiTestRatio", peaks[2].area / peaks[1].area); // T/H
  100. ratios.put("rfRatio", peaks[0].area / peaks[3].area); // R/C
  101. ratios.put("rtRatio", peaks[2].area / peaks[0].area); // T/R
  102. } else if ( 3 == idChip.scanPeakCount ) {
  103. var peaks = result.peakInfos; // H T C
  104. ratios.put("ratio", peaks[1].area / peaks[2].area); // T/C
  105. ratios.put("antiRatio", peaks[0].area / peaks[2].area); // H/C
  106. ratios.put("antiTestRatio", peaks[1].area / peaks[0].area); // T/H
  107. } else if ("PCT".equals(itenName)) {
  108. var peaks = result.peakInfos; // C T
  109. ratios.put("ratio", peaks[1].area / peaks[0].area); // T/C
  110. } else if ( 2 == idChip.scanPeakCount ) {
  111. var peaks = result.peakInfos; // T C
  112. ratios.put("ratio", peaks[0].area / peaks[1].area); // T/C
  113. } else {
  114. throw new RuntimeException("unknown scan peak count" + idChip.scanPeakCount);
  115. }
  116. // calculate ratio by x source
  117. if ( 1 == xSource ) {
  118. return ratios.get("ratio");
  119. } else if ( 2 == xSource ) {
  120. return ratios.get("antiTestRatio");
  121. } else if ( 3 == xSource ) {
  122. return ratios.get("antiRatio");
  123. } else if ( 4 == xSource ) {
  124. return ratios.get("ratio") + ratios.get("antiTestRatio");
  125. } else if ( 5 == xSource ) {
  126. // @TODO : 这里 R-ratio 不知道是啥
  127. throw new RuntimeException("不知道 R-Ratio 是啥");
  128. } else if ( 6 == xSource ) {
  129. return ratios.get("t4Ratio");
  130. } else {
  131. throw new RuntimeException("unknown x source" + xSource);
  132. }
  133. }
  134. }