Browse Source

结果扫描

tags/v0
sige 1 year ago
parent
commit
0f1d6e78e8
  1. BIN
      app.db
  2. 2
      pom.xml
  3. 18
      src/main/java/com/iflytop/a800/controller/DemoController.java
  4. 7
      src/main/java/com/iflytop/a800/device/Device.java
  5. 4
      src/main/java/com/iflytop/a800/device/Feeder.java
  6. 15
      src/main/java/com/iflytop/a800/device/Incubator.java
  7. 90
      src/main/java/com/iflytop/a800/device/Pipette.java
  8. 55
      src/main/java/com/iflytop/a800/device/Scanner.java
  9. 8
      src/main/java/com/iflytop/a800/model/MdbIdChip.java
  10. 15
      src/main/java/com/iflytop/a800/model/MdbProject.java
  11. 4
      src/main/java/com/iflytop/a800/resource/TestCard.java
  12. 8
      src/main/java/com/iflytop/a800/resource/TestCardManager.java
  13. 4
      src/main/java/com/iflytop/a800/resource/TestTube.java
  14. 2
      src/main/java/com/iflytop/a800/resource/TestTubeRack.java
  15. 4
      src/main/java/com/iflytop/a800/task/TubeRackTask.java
  16. 287
      src/main/java/com/iflytop/a800/task/TubeTestTask.java
  17. 29
      src/main/java/com/iflytop/a800/utils/ScanResultAnalysisAlgo.java

BIN
app.db

2
pom.xml

@ -20,7 +20,7 @@
<dependency>
<groupId>com.iflytop</groupId>
<artifactId>uf</artifactId>
<version>0.0.21</version>
<version>0.0.24</version>
</dependency>
</dependencies>

18
src/main/java/com/iflytop/a800/controller/DemoController.java

@ -1,6 +1,11 @@
package com.iflytop.a800.controller;
import com.iflytop.a800.TaskManager;
import com.iflytop.a800.device.Device;
import com.iflytop.a800.model.MdbProject;
import com.iflytop.a800.resource.BufferTube;
import com.iflytop.a800.resource.TestTube;
import com.iflytop.a800.task.TubeTestTask;
import com.iflytop.uf.UfActiveRecord;
import com.iflytop.uf.UfActuatorCmdExecutor;
import com.iflytop.uf.controller.UfApiControllerBase;
import com.iflytop.uf.controller.UfApiResponse;
@ -75,4 +80,17 @@ public class DemoController extends UfApiControllerBase {
}
return this.success();
}
@PostMapping("/api/demo/tube-test-task-start")
@ResponseBody
public UfApiResponse tubeTestTaskStart() {
var task = new TubeTestTask();
task.project = UfActiveRecord.findOne(MdbProject.class, "1");
task.tube = new TestTube();
task.tube.type = "EmergencyTube";
task.tube.index = 0;
var taskMan = TaskManager.getInstance();
taskMan.append(task);
return this.success();
}
}

7
src/main/java/com/iflytop/a800/device/Device.java

@ -2,6 +2,7 @@ package com.iflytop.a800.device;
import com.iflytop.a800.resource.BufferTubeManager;
import com.iflytop.a800.resource.LargeBufferTubeManager;
import com.iflytop.a800.resource.TestCardManager;
public class Device {
// singleton instance
@ -10,10 +11,16 @@ public class Device {
public final Feeder feeder = new Feeder();
// pipette
public final Pipette pipette = new Pipette();
// incubator
public final Incubator incubator = new Incubator();
// scanner
public final Scanner scanner = new Scanner();
// buffer tube manager
public final BufferTubeManager bufferTube = new BufferTubeManager();
// large buffer tube manager
public final LargeBufferTubeManager largeBufferTube = new LargeBufferTubeManager();
// test card manager
public final TestCardManager testCard = new TestCardManager();
// get instance
public static Device getInstance() {

4
src/main/java/com/iflytop/a800/device/Feeder.java

@ -12,9 +12,9 @@ public class Feeder {
}
// 读取试管架类型
public Number readTubeRackType() {
public String readTubeRackType() {
UfCmdSnippetExecutor.execute("FeedTubeRackTypeReadPrepare");
return 1;
return "wb";
}
// 读取试管是否存在

15
src/main/java/com/iflytop/a800/device/Incubator.java

@ -1,4 +1,17 @@
package com.iflytop.a800.device;
import com.iflytop.uf.UfCmdSnippetExecutor;
import com.iflytop.uf.model.UfMdbOption;
import java.util.Map;
public class Incubator {
// 推送新卡片
public void pushNewCard( Integer boxIndex ) {
Integer boxPos = UfMdbOption.getInteger(String.format("TestCardWarehouseBox.%d", boxIndex));
Map<String,Object> params = Map.of("box", boxPos);
UfCmdSnippetExecutor.execute("IncubatorTestCardPushIn", params);
}
// 退出到扫描
public void exitToScanner() {
UfCmdSnippetExecutor.execute("IncubatorTestCardExitToScanner");
}
}

90
src/main/java/com/iflytop/a800/device/Pipette.java

@ -60,20 +60,20 @@ public class Pipette {
Integer x = zoneStartX + indexX * distanceX;
Integer y = zoneStartY + indexY * distanceY;
Boolean tipStatusCheckEnable = UfMdbOption.getBoolean("PipetteTipStatusCheckEnable");
Map<String,Object> pickUpParams = Map.of("tipX", x, "tipY", y, "tipZ", zoneZ);
// 尝试三次拾取枪头
for ( int i=0; i<3; i++ ) {
LOG.info("[Pipette] Pick up tip at [{},{}](x={}, y={}, z={})", indexX, indexY, x, y, zoneZ);
UfCmdSnippetExecutor.execute("PipetteTipPickUp", pickUpParams);
String tipState = UfActuatorCmdExecutor.execute("Pipette", "read_pipette_tip_state");
if ("1".equals(tipState)) {
if ( "1".equals(tipState) || !tipStatusCheckEnable ) {
break ;
}
}
String tipState = UfActuatorCmdExecutor.execute("Pipette", "read_pipette_tip_state");
if ("0".equals(tipState)) {
if ("0".equals(tipState) && tipStatusCheckEnable ) {
this.tipPickUp();
return ; // 如果拾取失败则跳过这个TIP取下一个
}
@ -139,6 +139,75 @@ public class Pipette {
UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
}
// 混匀
public void mix( BufferTube tube, Integer count, Integer volume ) {
if ( 0 == count ) {
return ;
}
Integer startX = UfMdbOption.getInteger(String.format("%sZoneStartX.%d", tube.type, tube.zoneIndex));
Integer startY = UfMdbOption.getInteger(String.format("%sZoneStartY.%d", tube.type, tube.zoneIndex));
Integer distanceX = UfMdbOption.getInteger(String.format("%sDistanceX", tube.type));
Integer distanceY = UfMdbOption.getInteger(String.format("%sDistanceY", tube.type));
Integer indexX = tube.tubeIndex % 5;
Integer indexY = tube.tubeIndex / 5;
Integer tubeX = startX + indexX * distanceX;
Integer tubeY = startY + indexY * distanceY;
Map<String,Object> dispenseParams = Map.of("tubeX", tubeX, "tubeY", tubeY);
String snippetKey = "SampleMixingAtDetectionTubePrepare";
if ( "BufferTube".equals(tube.type) ) {
snippetKey = "SampleMixingAtBufferTubePrepare";
}
UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
String volumeStr = Integer.toString(volume);
for ( int i=0; i<count; i++ ) {
UfActuatorCmdExecutor.execute("Pipette", "pipette_ctrl_move_to_ul", volumeStr);
UfActuatorCmdExecutor.execute("Pipette", "pipette_ctrl_move_to_ul", "0");
}
UfCmdSnippetExecutor.execute("ArmResetZ");
}
// 穿孔
public void puncture( BufferTube tube ) {
Integer startX = UfMdbOption.getInteger(String.format("%sZoneStartX.%d", tube.type, tube.zoneIndex));
Integer startY = UfMdbOption.getInteger(String.format("%sZoneStartY.%d", tube.type, tube.zoneIndex));
Integer distanceX = UfMdbOption.getInteger(String.format("%sDistanceX", tube.type));
Integer distanceY = UfMdbOption.getInteger(String.format("%sDistanceY", tube.type));
Integer indexX = tube.tubeIndex % 5;
Integer indexY = tube.tubeIndex / 5;
Integer tubeX = startX + indexX * distanceX;
Integer tubeY = startY + indexY * distanceY;
Map<String,Object> dispenseParams = Map.of("tubeX", tubeX, "tubeY", tubeY);
String snippetKey = "PunctureAtDetectionTube";
if ( "BufferTube".equals(tube.type) ) {
snippetKey = "PunctureAtBufferTube";
}
UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
}
// 从缓冲液管吸液并吐液到检测板
public void aspirateFromBufferTubeAndDispenseToTestCard( BufferTube tube, Integer volume ) {
Integer startX = UfMdbOption.getInteger(String.format("%sZoneStartX.%d", tube.type, tube.zoneIndex));
Integer startY = UfMdbOption.getInteger(String.format("%sZoneStartY.%d", tube.type, tube.zoneIndex));
Integer distanceX = UfMdbOption.getInteger(String.format("%sDistanceX", tube.type));
Integer distanceY = UfMdbOption.getInteger(String.format("%sDistanceY", tube.type));
Integer indexX = tube.tubeIndex % 5;
Integer indexY = tube.tubeIndex / 5;
Integer tubeX = startX + indexX * distanceX;
Integer tubeY = startY + indexY * distanceY;
Map<String,Object> dispenseParams = Map.of("tubeX", tubeX, "tubeY", tubeY, "volume", volume);
String snippetKey = "AspirateFromDetectionTubeAndDispenseToTestCard";
if ( "BufferTube".equals(tube.type) ) {
snippetKey = "AspirateFromBufferTubeAndDispenseToTestCard";
}
UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
}
// 从大缓冲液管吸液
public void aspirateFromLargeBufferTube(LargeBufferTube tube, Integer volume) {
Integer startX = UfMdbOption.getInteger("LargeBufferTubeZoneStartX");
@ -208,8 +277,23 @@ public class Pipette {
this.aspirateWithLiquidLevelFollow(volume, depth);
}
// 从全血5ml吸液
public void aspirateFromWholeBlood5ml(Integer index, Integer volume) {
throw new RuntimeException("摇匀没接,暂时无法测试");
}
// 从全血3ml吸液
public void aspirateFromWholeBlood3ml(Integer index, Integer volume) {
throw new RuntimeException("摇匀没接,暂时无法测试");
}
// 移动到液面
private void moveToLiquidLevel( Integer maxDepth, Integer threshold ) {
Boolean liquidLevelDetectEnable = UfMdbOption.getBoolean("PipetteLiquidLevelDetectEnable");
if ( !liquidLevelDetectEnable ) {
return ;
}
int stepDepth = 10;
int depth = 0;
do {

55
src/main/java/com/iflytop/a800/device/Scanner.java

@ -1,4 +1,59 @@
package com.iflytop.a800.device;
import com.iflytop.uf.UfActuatorCmdExecutor;
import com.iflytop.uf.UfCmdSnippetExecutor;
import com.iflytop.uf.util.UfCommon;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
public class Scanner {
// 扫描类型F
public void scanTypeF() {
UfCmdSnippetExecutor.execute("SampleResultAnalysisTypeF");
UfCommon.delay(20 * 1000);
}
// 扫描类型T
public void scanTypeT() {
UfCmdSnippetExecutor.execute("SampleResultAnalysisTypeT");
UfCommon.delay(20 * 1000);
}
// 读取结果
public float[] readResult() {
String sizeStr = UfActuatorCmdExecutor.execute("Scanner","module_get_reg", "10");
String countStr = UfActuatorCmdExecutor.execute("Scanner","module_get_reg", "11");
int size = Integer.parseInt(sizeStr);
int count = Integer.parseInt(countStr);
List<Byte> data = new ArrayList<>();
for ( int i = 0; i < count; i++ ) {
String readParam = Integer.toString(i);
String response = UfActuatorCmdExecutor.execute("Scanner","module_read_raw", readParam);
Base64.Decoder decoder = Base64.getDecoder();
byte[] bytes = decoder.decode(response);
for (byte aByte : bytes) {
data.add(aByte);
}
UfCommon.delay(100);
}
byte[] result = new byte[data.size()];
for ( int i = 0; i < data.size(); i++ ) {
result[i] = data.get(i);
}
var buffer = ByteBuffer.wrap(result);
buffer.order(ByteOrder.LITTLE_ENDIAN);
float[] scanRawData = new float[buffer.capacity() / 2];
for (int i = 0; i < scanRawData.length; i++) {
scanRawData[i] = buffer.getShort();
}
return scanRawData;
}
// 丢弃卡片
public void dropCard() {
UfCmdSnippetExecutor.execute("SampleResultAnalysisDropCard");
}
}

8
src/main/java/com/iflytop/a800/model/MdbIdChip.java

@ -0,0 +1,8 @@
package com.iflytop.a800.model;
public class MdbIdChip {
public Integer peakCount;
public Integer itemCount;
public String items;
public Integer scanPeakCount;
public Integer scanType;
}

15
src/main/java/com/iflytop/a800/model/MdbProject.java

@ -0,0 +1,15 @@
package com.iflytop.a800.model;
import com.iflytop.uf.UfActiveRecord;
import com.iflytop.uf.UfActiveRecordField;
public class MdbProject extends UfActiveRecord {
@UfActiveRecordField
public String name;
@UfActiveRecordField
public String steps;
// get table name
public static String getTableName() {
return "app_projects";
}
}

4
src/main/java/com/iflytop/a800/resource/TestCard.java

@ -0,0 +1,4 @@
package com.iflytop.a800.resource;
public class TestCard {
public Integer boxIndex;
}

8
src/main/java/com/iflytop/a800/resource/TestCardManager.java

@ -0,0 +1,8 @@
package com.iflytop.a800.resource;
public class TestCardManager {
public TestCard alloc() {
var card = new TestCard();
card.boxIndex = 0;
return card;
}
}

4
src/main/java/com/iflytop/a800/resource/TestTube.java

@ -4,7 +4,9 @@ public class TestTube {
// is tube existed
public Boolean isExisted = false;
// tube type
public Number type;
public String type;
// tube bar code
public String barCode;
// tube index
public Integer index;
}

2
src/main/java/com/iflytop/a800/resource/TestTubeRack.java

@ -2,7 +2,7 @@ package com.iflytop.a800.resource;
import java.util.List;
public class TestTubeRack {
// tube rack type
public Number type;
public String type;
// list of test tubes
public List<TestTube> tubes;
}

4
src/main/java/com/iflytop/a800/task/TubeRackTask.java

@ -34,13 +34,13 @@ public class TubeRackTask extends TaskBase {
this.samplingTubes.add(tube);
tube.type = tubeRack.type;
if ( !tube.type.equals(1) ) {
if ( !tube.type.equals("wb") ) {
continue;
}
Boolean isWb5ml = feeder.readIsWb5ml(i);
if ( isWb5ml ) {
tube.type = 2;
tube.type = "wb5ml";
}
tube.barCode = feeder.readBarCode(i);

287
src/main/java/com/iflytop/a800/task/TubeTestTask.java

@ -1,25 +1,89 @@
package com.iflytop.a800.task;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iflytop.a800.TaskBase;
import com.iflytop.a800.resource.TestTube;
import com.iflytop.a800.resource.TestTubeRack;
import com.iflytop.a800.device.Device;
import com.iflytop.a800.model.MdbIdChip;
import com.iflytop.a800.model.MdbProject;
import com.iflytop.a800.resource.*;
import com.iflytop.a800.utils.ScanResultAnalysisAlgo;
import com.iflytop.uf.UfCmdSnippetExecutor;
import com.iflytop.uf.util.UfCommon;
import com.iflytop.uf.util.UfJsonHelper;
import java.util.*;
public class TubeTestTask extends TaskBase {
// 测试项目
public MdbProject project;
public TestTubeRack tubeRack;
public TestTube tube;
public String status;
// 缓冲液试管
private BufferTube bufferTube;
// 大容量缓冲液试管
private LargeBufferTube largeBufferTube;
// 测试卡
private TestCard testCard;
// id chip
private MdbIdChip idChip;
// 任务准备
public void prepare() {
var device = Device.getInstance();
this.bufferTube = device.bufferTube.alloc();
this.largeBufferTube = device.largeBufferTube.getTube();
this.testCard = device.testCard.alloc();
this.idChip = new MdbIdChip();
this.idChip.peakCount = 3;
this.idChip.itemCount = 1;
this.idChip.scanPeakCount = 3;
this.idChip.items = UfJsonHelper.objectToJson(List.of(Map.of(
"item", "hsCRP",
"isPiecewiseFunction", false,
"nonPiecewiseFunction", Map.of(
"xValueSource", 1,
"serum", Map.of("a", 1.0, "b", 2.0, "c", 3.0, "d", 4.0),
"wb", Map.of("a", 1.0, "b", 2.0, "c", 3.0, "d", 4.0)
)
)));
}
@Override
public void run() {
this.shake();
this.uncap();
this.sampling();
this.cap();
this.incubate();
this.scan();
this.prepare();
ObjectMapper jsonMapper = new ObjectMapper();
JsonNode stepsJsonTree = null;
try {
stepsJsonTree = jsonMapper.readTree(this.project.steps);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
for ( JsonNode stepNode : stepsJsonTree ) {
var stepEnable = stepNode.get("enable").asBoolean();
if ( !stepEnable ) {
continue;
}
var stepAction = stepNode.get("action").asText();
switch ( stepAction ) {
// case "shaking" : this.shake(stepNode); break;
case "puncture" : this.executeStepPuncture(stepNode); break;
case "aspirate" : this.executeStepAspirate(stepNode); break;
case "mixing" : this.executeStepMixing(stepNode); break;
case "drop-tip" : this.executeStepDropTip(stepNode); break;
case "incubate" : this.executeStepIncubate(stepNode); break;
case "analysis" : this.executeStepAnalysis(stepNode); break;
}
}
}
// 摇匀
private void shake() {
private void shake( JsonNode stepNode ) {
UfCmdSnippetExecutor.execute("SampleTestShake");
}
@ -28,25 +92,206 @@ public class TubeTestTask extends TaskBase {
UfCmdSnippetExecutor.execute("SampleTestUnCap");
}
// 取样
private void sampling() {
UfCmdSnippetExecutor.execute("SampleTestSamplingFromWb5ml");
UfCmdSnippetExecutor.execute("SampleTestSamplingFromBufferTube");
UfCmdSnippetExecutor.execute("SampleTestSamplingFromBufferTube");
// 穿孔
private void executeStepPuncture( JsonNode stepNode ) {
Device device = Device.getInstance();
var pipette = device.pipette;
pipette.tipPickUp();
pipette.puncture(this.bufferTube);
}
// 吸液
private void executeStepAspirate( JsonNode stepNode ) {
Device device = Device.getInstance();
var pipette = device.pipette;
pipette.tipPickUp();
String source = stepNode.get("source").asText();
Integer volume = stepNode.get("volume").asInt();
if ( "LargeBufferTube".equals(source) ) {
pipette.aspirateFromLargeBufferTube(this.largeBufferTube, volume);
} else if ( "Sample".equals(source) && "EmergencyTube".equals(this.tube.type) ) {
pipette.aspirateFromEmergencyTube(this.tube.index, volume);
} else if ( "Sample".equals(source) && "SampleEpp0_5Tube".equals(this.tube.type) ) {
pipette.aspirateFromSampleEpp0_5(this.tube.index, volume);
} else if ( "Sample".equals(source) && "SampleEpp1_5Tube".equals(this.tube.type) ) {
pipette.aspirateFromSampleEpp1_5(this.tube.index, volume);
} else if ( "Sample".equals(source) && "SampleWholeBlood5mlTube".equals(this.tube.type) ) {
pipette.aspirateFromWholeBlood5ml(this.tube.index, volume);
} else if ( "Sample".equals(source) && "SampleWholeBlood3mlTube".equals(this.tube.type) ) {
pipette.aspirateFromWholeBlood3ml(this.tube.index, volume);
} else {
throw new RuntimeException(String.format("无效的取样源 : %s/%s",source,this.tube.type));
}
pipette.dispense(this.bufferTube);
}
// 混匀
private void executeStepMixing( JsonNode stepNode ) {
Device device = Device.getInstance();
var pipette = device.pipette;
var mixCount = stepNode.get("count").asInt();
var mixVolume = stepNode.get("volume").asInt();
pipette.mix(this.bufferTube, mixCount, mixVolume);
}
// 盖回
private void cap() {
UfCmdSnippetExecutor.execute("SampleTestCap");
// 丢弃吸头
private void executeStepDropTip( JsonNode stepNode ) {
Device device = Device.getInstance();
var pipette = device.pipette;
pipette.tipDrop();
}
// 孵育
private void incubate() {
UfCmdSnippetExecutor.execute("SampleTestIncubate");
private void executeStepIncubate( JsonNode stepNode ) {
Device device = Device.getInstance();
device.incubator.pushNewCard(this.testCard.boxIndex);
var pipette = device.pipette;
pipette.tipPickUp();
Integer volume = stepNode.get("volume").asInt();
pipette.aspirateFromBufferTubeAndDispenseToTestCard(this.bufferTube, volume);
pipette.tipDrop();
Integer duration = stepNode.get("duration").asInt();
UfCommon.delay(duration);
}
// 扫描
private void scan() {
UfCmdSnippetExecutor.execute("SampleTestScanResult");
private void executeStepAnalysis( JsonNode stepNode ) {
// 扫描
Device device = Device.getInstance();
// device.incubator.exitToScanner();
var scanner = device.scanner;
scanner.scanTypeF();
var scanResult = scanner.readResult();
scanner.dropCard();
// 计算
var algo = new ScanResultAnalysisAlgo();
var algoResult = algo.calculate(scanResult, this.idChip.peakCount);
// 处理
String sampleType = "WB"; // @TODO : 这里要从样本中取 ~~~~
List<Map<String, Object>> results = new ArrayList<>();
var projects = UfJsonHelper.jsonToNode(idChip.items);
for ( var i=0; i< idChip.itemCount; i++ ) {
double valueX = 0;
JsonNode funcInfo = null;
var project = projects.get(i);
var itemName = project.get("item").asText();
var isPiecewiseFunction = project.get("isPiecewiseFunction").asBoolean();
if ( !isPiecewiseFunction ) { // 非分段函数
var func = project.get("nonPiecewiseFunction");
var xValueSource = func.get("xValueSource").asInt();
valueX = this.calculateRatio(algoResult, xValueSource, itemName);
funcInfo = func.get("serum");
if ("WB".equals(sampleType)) {
funcInfo = func.get("wb");
}
} else { // 分段函数
var func = project.get("piecewiseFunction");
var piecewiseValueSrc = func.get("piecewiseValueSrc").asInt();
var piecewiseValueSrcValue = this.calculateRatio(algoResult, piecewiseValueSrc, itemName);
var piecewiseValue = func.get("piecewiseValue").asDouble();
if ( piecewiseValueSrcValue > piecewiseValue ) { // 高浓度
var highXValueSource = func.get("highXValueSource").asInt();
valueX = this.calculateRatio(algoResult, highXValueSource, itemName);
funcInfo = func.get("serumHigh");
if ("WB".equals(sampleType)) {
funcInfo = func.get("wbHigh");
}
} else { // 低浓度
var lowXValueSource = func.get("lowXValueSource").asInt();
valueX = this.calculateRatio(algoResult, lowXValueSource, itemName);
funcInfo = func.get("serumLow");
if ("WB".equals(sampleType)) {
funcInfo = func.get("wbLow");
}
}
}
double valueD = funcInfo.get("d").asDouble();
double valueB = funcInfo.get("b").asDouble();
double valueC = funcInfo.get("c").asDouble();
double valueA = funcInfo.get("a").asDouble();
double value = valueA * Math.pow(valueX,3) + valueB * Math.pow(valueX,2) + valueC * valueX + valueD;
// @TODO : 单位也要从配置中读取
results.add(Map.of("name",itemName,"value",value,"unit","xx/xx"));
}
String testResult = UfJsonHelper.objectToJson(results);
System.out.println(testResult);
}
/**
* @link https://iflytop1.feishu.cn/docx/UnRtdSG4qouMTaxzRb2cjiTTnZe
* @link https://iflytop1.feishu.cn/docx/A0CHdQL6OoTTCSx8MB7cQKEjnSc
* @param result - algo result
* @param xSource - x source
* @return double - value of ratio
*/
private double calculateRatio(ScanResultAnalysisAlgo.AlgoResult result, int xSource, String itenName) {
// 计算 ratio
Map<String, Float> ratios = new HashMap<>();
if ( 5 == idChip.scanPeakCount ) {
var peaks = result.peakInfos;
ratios.put("ratio", peaks[3].area / peaks[4].area); // T/C
ratios.put("antiRatio", peaks[3].area / peaks[4].area); // H/C
ratios.put("antiTestRatio", peaks[3].area / peaks[2].area); // T/H
ratios.put("rfRatio", peaks[1].area / peaks[4].area); // R/C
ratios.put("rtRatio", peaks[3].area / peaks[1].area); // T/R
ratios.put("t4Ratio", peaks[0].area / peaks[4].area); // T4/C
ratios.put("t4t3Ratio", peaks[1].area / peaks[0].area); // R/T4
} else if ( 4 == idChip.scanPeakCount && Objects.equals(idChip.scanType, 1) ) { // F 光学
var peaks = result.peakInfos; // H T C
ratios.put("ratio", peaks[1].area / peaks[2].area); // T/C
ratios.put("antiRatio", peaks[0].area / peaks[2].area); // H/C
ratios.put("antiTestRatio", peaks[1].area / peaks[0].area); // T/H
ratios.put("rfRatio", peaks[0].area / peaks[2].area); // R/C @TODO : 待定 三联卡F光学没有R
ratios.put("rtRatio", peaks[1].area / peaks[0].area); // T/R @TODO : 待定 三联卡F光学没有R
} else if ( 4 == idChip.scanPeakCount && Objects.equals(idChip.scanType, 2) ) { // T 光学
var peaks = result.peakInfos; // R H T C
ratios.put("ratio", peaks[2].area / peaks[3].area); // T/C
ratios.put("antiRatio", peaks[1].area / peaks[3].area); // H/C
ratios.put("antiTestRatio", peaks[2].area / peaks[1].area); // T/H
ratios.put("rfRatio", peaks[0].area / peaks[3].area); // R/C
ratios.put("rtRatio", peaks[2].area / peaks[0].area); // T/R
} else if ( 3 == idChip.scanPeakCount ) {
var peaks = result.peakInfos; // H T C
ratios.put("ratio", peaks[1].area / peaks[2].area); // T/C
ratios.put("antiRatio", peaks[0].area / peaks[2].area); // H/C
ratios.put("antiTestRatio", peaks[1].area / peaks[0].area); // T/H
} else if ("PCT".equals(itenName)) {
var peaks = result.peakInfos; // C T
ratios.put("ratio", peaks[1].area / peaks[0].area); // T/C
} else if ( 2 == idChip.scanPeakCount ) {
var peaks = result.peakInfos; // T C
ratios.put("ratio", peaks[0].area / peaks[1].area); // T/C
} else {
throw new RuntimeException("unknown scan peak count" + idChip.scanPeakCount);
}
// calculate ratio by x source
if ( 1 == xSource ) {
return ratios.get("ratio");
} else if ( 2 == xSource ) {
return ratios.get("antiTestRatio");
} else if ( 3 == xSource ) {
return ratios.get("antiRatio");
} else if ( 4 == xSource ) {
return ratios.get("ratio") + ratios.get("antiTestRatio");
} else if ( 5 == xSource ) {
// @TODO : 这里 R-ratio 不知道是啥
throw new RuntimeException("不知道 R-Ratio 是啥");
} else if ( 6 == xSource ) {
return ratios.get("t4Ratio");
} else {
throw new RuntimeException("unknown x source" + xSource);
}
}
}

29
src/main/java/com/iflytop/a800/utils/ScanResultAnalysisAlgo.java

@ -0,0 +1,29 @@
package com.iflytop.a800.utils;
public class ScanResultAnalysisAlgo {
public static class AlgoResult {
public static class PeakInfo {
public boolean findPeak;
public float peakFullArea;
public float peakBaseLineArea;
public float area;
public int peakPos;
public int peakStartPos;
public int peakEndPos;
}
public int peakNum;
public float[] lineAvg250;
public PeakInfo[] peakInfos;
}
static {
String osName = System.getProperty("os.name").toLowerCase();
if ( osName.contains("win") ) {
System.load("D:/Sige5193/boditech-a800/lib-algo/x64/Debug/boditech-opt-algo-java-lib.dll");
} else {
System.load("/app-java/algo/libalgo.so");
}
}
public native AlgoResult calculate(float[] data, int peakCount);
}
Loading…
Cancel
Save