Browse Source

----

master
sige 1 year ago
parent
commit
4c6613faeb
  1. 6
      pom.xml
  2. 228
      src/main/java/com/dreamworks/boditech/MyApplication.java
  3. 1
      src/main/java/com/dreamworks/boditech/driver/DeviceCommand.java
  4. 32
      src/main/java/com/dreamworks/boditech/driver/actuator/ActuatorBase.java
  5. 203
      src/main/java/com/dreamworks/boditech/driver/task/step/StepAnalysis.java
  6. 39
      src/main/java/com/dreamworks/boditech/model/MdbIdChip.java
  7. 81
      src/main/java/com/dreamworks/boditech/model/MyActiveRecord.java
  8. 46
      src/main/java/com/dreamworks/boditech/model/MyActiveRecordCriteria.java
  9. 10
      src/main/java/com/dreamworks/boditech/model/MyActiveRecordField.java
  10. 47
      src/main/java/com/dreamworks/boditech/model/MyActiveRecordMapper.java
  11. 11
      src/main/java/com/dreamworks/boditech/utils/MyCommon.java
  12. BIN
      src/main/java/com/dreamworks/boditech/utils/MyOptAlgo$AlgoResult.class
  13. 24
      src/main/java/com/dreamworks/boditech/utils/MyOptAlgo.java

6
pom.xml

@ -55,6 +55,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

228
src/main/java/com/dreamworks/boditech/MyApplication.java

@ -0,0 +1,228 @@
package com.dreamworks.boditech;
import com.dreamworks.boditech.driver.Device;
import com.dreamworks.boditech.driver.actuator.ActAnalysisScanner;
import com.dreamworks.boditech.driver.actuator.ActMotor;
import com.dreamworks.boditech.driver.actuator.ActuatorModule;
import com.dreamworks.boditech.model.MdbIdChip;
import com.dreamworks.boditech.model.MyActiveRecord;
import com.dreamworks.boditech.utils.MyCommon;
import com.dreamworks.boditech.utils.MyOptAlgo;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.annotation.Resource;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.nio.ByteOrder;
import java.util.*;
@Order(1)
@Component
public class MyApplication implements ApplicationRunner, ApplicationContextAware {
// application context
private static ApplicationContext context;
// get application context
public static ApplicationContext getContext() {
return MyApplication.context;
}
// get bean
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
@Override
public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
MyApplication.context = applicationContext;
}
@Resource
public Device device;
@Override
public void run(ApplicationArguments args) throws Exception {
var analysisScanMotor = (ActMotor)device.getActuator(ActuatorModule.ANALYSIS_SCAN_MOTOR);
// analysisScanMotor.reset();
this.analysis();
}
private void analysis() {
var scanner = (ActAnalysisScanner)device.getActuator(ActuatorModule.ANALYSIS_SCAN_SCANNER);
var sampleType = "wb";
var idChip = MyActiveRecord.findById(MdbIdChip.class, 2);
assert idChip != null;
// 配置相机
if (Objects.equals(idChip.scanType, MdbIdChip.SCAN_TYPE_F)) { // F 光学扫描
scanner.setRegister(4200, 0); // 设置扫描类型
scanner.setRegister(4201, 2860); // 设置扫描开始坐标
scanner.setRegister(4202, -1); // 设置扫描方向
scanner.setRegister(4203, 1); // 设置扫描间隔
scanner.setRegister(4204, 1200); // 设置扫描点数
scanner.setRegister(4205, 1); // 选通通道
scanner.setRegister(4206, 0); // 激光增益
scanner.setRegister(4207, 0); // 扫描器增益
scanner.setRegister(40, 7); // 刷新激光器增益到mcp41xxx
scanner.setRegister(40, 8); // 刷新设置扫描器增益到mcp41xxx
scanner.setRegister(40, 1); // 选通通道
} else if (Objects.equals(idChip.scanType, MdbIdChip.SCAN_TYPE_T)) { // T 光学扫描
scanner.setRegister(4200, 1); // 设置扫描类型
scanner.setRegister(4201, 4005); // 设置扫描开始坐标
scanner.setRegister(4202, -1); // 设置扫描方向
scanner.setRegister(4203, 1); // 设置扫描间隔
scanner.setRegister(4204, 1200); // 设置扫描点数
scanner.setRegister(4205, 1); // 选通通道
scanner.setRegister(4206, 0); // 激光增益
scanner.setRegister(4207, 0); // 扫描器增益
scanner.setRegister(40, 7); // 刷新激光器增益到mcp41xxx
scanner.setRegister(40, 8); // 刷新设置扫描器增益到mcp41xxx
scanner.setRegister(40, 1); // 选通通道
} else {
throw new RuntimeException("unknown scan type" + idChip.scanType);
}
// 开始扫描
scanner.start();
MyCommon.easySleep(20000); // 延时10s @TODO : 这里要根据不同的扫描类型进行延时
// 读取扫描数据
var buffer = scanner.readRaw();
buffer.order(ByteOrder.LITTLE_ENDIAN);
float[] data = new float[buffer.capacity() / 2];
for (int i = 0; i < data.length; i++) {
data[i] = buffer.getShort();
}
// 分析数据
var algo = new MyOptAlgo();
var result = algo.calculate(data, idChip.scanPeakCount);
// 结算结果
List<Double> values = new ArrayList<>();
var projects = MyCommon.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(result, xValueSource, idChip, itemName);
funcInfo = func.get("wb");
if ("serum".equals(sampleType)) {
funcInfo = project.get("serum");
}
} else { // 分段函数
var func = project.get("piecewiseFunction");
var piecewiseValueSrc = func.get("piecewiseValueSrc").asInt();
var piecewiseValueSrcValue = this.calculateRatio(result, piecewiseValueSrc, idChip, itemName);
var piecewiseValue = func.get("piecewiseValue").asDouble();
if ( piecewiseValueSrcValue > piecewiseValue ) { // 高浓度
var highXValueSource = func.get("highXValueSource").asInt();
valueX = this.calculateRatio(result, highXValueSource, idChip, itemName);
funcInfo = func.get("wbHigh");
if ("serum".equals(sampleType)) {
funcInfo = project.get("serumHigh");
}
} else { // 低浓度
var lowXValueSource = func.get("lowXValueSource").asInt();
valueX = this.calculateRatio(result, lowXValueSource, idChip, itemName);
funcInfo = func.get("wbLow");
if ("serum".equals(sampleType)) {
funcInfo = project.get("serumLow");
}
}
}
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;
values.add(value);
System.out.println("扫描完成 : " + value);
}
System.out.println("扫描完成 : " + values.size());
}
/**
* @link https://iflytop1.feishu.cn/docx/UnRtdSG4qouMTaxzRb2cjiTTnZe
* @link https://iflytop1.feishu.cn/docx/A0CHdQL6OoTTCSx8MB7cQKEjnSc
* @param result
* @param xSource
* @return
*/
private double calculateRatio(MyOptAlgo.AlgoResult result, int xSource, MdbIdChip idChip, 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, MdbIdChip.SCAN_TYPE_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, MdbIdChip.SCAN_TYPE_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);
}
}
}

1
src/main/java/com/dreamworks/boditech/driver/DeviceCommand.java

@ -3,6 +3,7 @@ public class DeviceCommand {
// command constants
public static final Integer CMD_MODULE_STOP = 0x0101;
public static final Integer CMD_MODULE_GET_STATUS = 0x0104;
public static final Integer CMD_MODULE_SET_REG = 0x0105;
public static final Integer CMD_MODULE_GET_REG = 0x0106;
public static final Integer CMD_MODULE_READ_IO = 0x0107;
public static final Integer CMD_MODULE_READ_RAW = 0x0113;

32
src/main/java/com/dreamworks/boditech/driver/actuator/ActuatorBase.java

@ -6,6 +6,8 @@ import com.dreamworks.boditech.utils.MyCommon;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class ActuatorBase implements Actuator {
// device
@ -40,7 +42,7 @@ public class ActuatorBase implements Actuator {
}
// wait for finish
protected void waitForFinish() {
public void waitForFinish() {
Integer status = ActuatorModule.MODULE_STATUS_BUSY;
do {
try {
@ -87,6 +89,29 @@ public class ActuatorBase implements Actuator {
return rawText.trim();
}
// read raw
// @TODO : 数据过大时需要分批读取 但是仍然会出现响应分批到达导致解析失败的问题 ~~~
public ByteBuffer readRaw() {
Integer size = this.getRegister(10);
Integer count = this.getRegister(11);
List<Byte> data = new ArrayList<>();
for ( int i = 0; i < count; i++ ) {
ByteBuffer response = this.call(DeviceCommand.CMD_MODULE_READ_RAW, i);
var bytes = response.array();
for ( int j = 8; j < bytes.length; j++ ) {
data.add(bytes[j]);
}
MyCommon.easySleep(100);
}
byte[] result = new byte[data.size()];
for ( int i = 0; i < data.size(); i++ ) {
result[i] = data.get(i);
}
return ByteBuffer.wrap(result);
}
// get register
public Integer getRegister( Integer index ) {
ByteBuffer response = this.call(DeviceCommand.CMD_MODULE_GET_REG, index);
@ -94,6 +119,11 @@ public class ActuatorBase implements Actuator {
return value;
}
// set register
public void setRegister( Integer index, Integer value ) {
this.call(DeviceCommand.CMD_MODULE_SET_REG, index, value);
}
// get integer from response
protected Integer getIntegerFromResponse(ByteBuffer response, Integer index ) {
response.order(ByteOrder.LITTLE_ENDIAN);

203
src/main/java/com/dreamworks/boditech/driver/task/step/StepAnalysis.java

@ -8,12 +8,13 @@ import com.dreamworks.boditech.driver.actuator.ActMotor;
import com.dreamworks.boditech.driver.actuator.ActuatorModule;
import com.dreamworks.boditech.driver.entity.IncubatorSlot;
import com.dreamworks.boditech.driver.task.TaskTest;
import com.dreamworks.boditech.model.MdbIdChip;
import com.dreamworks.boditech.model.MyActiveRecord;
import com.dreamworks.boditech.utils.MyCommon;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.dreamworks.boditech.utils.MyOptAlgo;
import com.fasterxml.jackson.databind.JsonNode;
import java.nio.ByteOrder;
import java.util.*;
public class StepAnalysis extends StepBase {
// task test
private TaskTest taskTest;
@ -29,23 +30,15 @@ public class StepAnalysis extends StepBase {
ActAnalysisScanner scanner = (ActAnalysisScanner)device.getActuator(ActuatorModule.ANALYSIS_SCAN_SCANNER);
// 01. 获取卡位
IncubatorSlot incubatorSlot = this.taskTest.getIncubatorSlot();
incubator.moveTo(incubatorSlot.getExitLocation());
// IncubatorSlot incubatorSlot = this.taskTest.getIncubatorSlot();
// incubator.moveTo(incubatorSlot.getExitLocation());
// 02. 推出测试卡
pushMotor.moveTo("analysisPushMotorScanStart");
pushMotor.moveTo("analysisPushMotorStandby");
// 03. 扫描测试卡
scanner.start();
try { // @TODO : wait for scan finish
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
scanner.stop();
this.calculateScanResult();
// @TODO : read raw from scanner and parse it later
// 03. 分析
this.analysis(executor);
// 04. 丢弃测试卡
scanMotor.moveTo("analysisScanMotorDropCard");
@ -54,8 +47,8 @@ public class StepAnalysis extends StepBase {
// @TODO : process raw data from scanner
// unlock incubator slot
incubator.unlockSlot(incubatorSlot.getIndex());
executor.incubatorSlotAvailable();
// incubator.unlockSlot(incubatorSlot.getIndex());
// executor.incubatorSlotAvailable();
}
// calculate result
@ -65,4 +58,176 @@ public class StepAnalysis extends StepBase {
results.add(Map.of("name", "HbA1c", "value", 5.6, "unit","g/ml"));
this.taskTest.setTestResult(MyCommon.objectToJson(results));
}
private void analysis(Executor executor) {
Device device = executor.getDevice();
var scanner = (ActAnalysisScanner)device.getActuator(ActuatorModule.ANALYSIS_SCAN_SCANNER);
var sampleType = "wb";
var idChip = MyActiveRecord.findById(MdbIdChip.class, 2);
assert idChip != null;
// 配置相机
if (Objects.equals(idChip.scanType, MdbIdChip.SCAN_TYPE_F)) { // F 光学扫描
scanner.setRegister(4200, 0); // 设置扫描类型
scanner.setRegister(4201, 2860); // 设置扫描开始坐标
scanner.setRegister(4202, -1); // 设置扫描方向
scanner.setRegister(4203, 1); // 设置扫描间隔
scanner.setRegister(4204, 1200); // 设置扫描点数
scanner.setRegister(4205, 1); // 选通通道
scanner.setRegister(4206, 0); // 激光增益
scanner.setRegister(4207, 0); // 扫描器增益
scanner.setRegister(40, 7); // 刷新激光器增益到mcp41xxx
scanner.setRegister(40, 8); // 刷新设置扫描器增益到mcp41xxx
scanner.setRegister(40, 1); // 选通通道
} else if (Objects.equals(idChip.scanType, MdbIdChip.SCAN_TYPE_T)) { // T 光学扫描
scanner.setRegister(4200, 1); // 设置扫描类型
scanner.setRegister(4201, 4005); // 设置扫描开始坐标
scanner.setRegister(4202, -1); // 设置扫描方向
scanner.setRegister(4203, 1); // 设置扫描间隔
scanner.setRegister(4204, 1200); // 设置扫描点数
scanner.setRegister(4205, 1); // 选通通道
scanner.setRegister(4206, 0); // 激光增益
scanner.setRegister(4207, 0); // 扫描器增益
scanner.setRegister(40, 7); // 刷新激光器增益到mcp41xxx
scanner.setRegister(40, 8); // 刷新设置扫描器增益到mcp41xxx
scanner.setRegister(40, 1); // 选通通道
} else {
throw new RuntimeException("unknown scan type" + idChip.scanType);
}
// 开始扫描
scanner.start();
MyCommon.easySleep(20000); // 延时10s @TODO : 这里要根据不同的扫描类型进行延时
// 读取扫描数据
var buffer = scanner.readRaw();
buffer.order(ByteOrder.LITTLE_ENDIAN);
float[] data = new float[buffer.capacity() / 2];
for (int i = 0; i < data.length; i++) {
data[i] = buffer.getShort();
}
// 分析数据
var algo = new MyOptAlgo();
var result = algo.calculate(data, idChip.scanPeakCount);
// 结算结果
List<Double> values = new ArrayList<>();
var projects = MyCommon.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(result, xValueSource, idChip, itemName);
funcInfo = func.get("wb");
if ("serum".equals(sampleType)) {
funcInfo = project.get("serum");
}
} else { // 分段函数
var func = project.get("piecewiseFunction");
var piecewiseValueSrc = func.get("piecewiseValueSrc").asInt();
var piecewiseValueSrcValue = this.calculateRatio(result, piecewiseValueSrc, idChip, itemName);
var piecewiseValue = func.get("piecewiseValue").asDouble();
if ( piecewiseValueSrcValue > piecewiseValue ) { // 高浓度
var highXValueSource = func.get("highXValueSource").asInt();
valueX = this.calculateRatio(result, highXValueSource, idChip, itemName);
funcInfo = func.get("wbHigh");
if ("serum".equals(sampleType)) {
funcInfo = project.get("serumHigh");
}
} else { // 低浓度
var lowXValueSource = func.get("lowXValueSource").asInt();
valueX = this.calculateRatio(result, lowXValueSource, idChip, itemName);
funcInfo = func.get("wbLow");
if ("serum".equals(sampleType)) {
funcInfo = project.get("serumLow");
}
}
}
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;
values.add(value);
System.out.println("扫描完成 : " + value);
}
System.out.println("扫描完成 : " + values.size());
}
/**
* @link https://iflytop1.feishu.cn/docx/UnRtdSG4qouMTaxzRb2cjiTTnZe
* @link https://iflytop1.feishu.cn/docx/A0CHdQL6OoTTCSx8MB7cQKEjnSc
* @param result
* @param xSource
* @return
*/
private double calculateRatio(MyOptAlgo.AlgoResult result, int xSource, MdbIdChip idChip, 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, MdbIdChip.SCAN_TYPE_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, MdbIdChip.SCAN_TYPE_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);
}
}
}

39
src/main/java/com/dreamworks/boditech/model/MdbIdChip.java

@ -0,0 +1,39 @@
package com.dreamworks.boditech.model;
public class MdbIdChip extends MyActiveRecord {
public static final Integer SCAN_TYPE_AUTO = 0;
public static final Integer SCAN_TYPE_F = 1;
public static final Integer SCAN_TYPE_T = 2;
public static final Integer SCAN_TYPE_F_T = 3;
@MyActiveRecordField
public Long id;
@MyActiveRecordField
public String item;
@MyActiveRecordField
public Integer itemCount;
@MyActiveRecordField
public String lotCode;
@MyActiveRecordField
public Integer expiredDate;
@MyActiveRecordField
public Integer version;
@MyActiveRecordField
public Integer scanType;
@MyActiveRecordField
public Integer scanPeakCount;
@MyActiveRecordField
public String items;
// get table name
public static String getTableName() {
return "bdt_id_chips";
}
}

81
src/main/java/com/dreamworks/boditech/model/MyActiveRecord.java

@ -0,0 +1,81 @@
package com.dreamworks.boditech.model;
import com.dreamworks.boditech.MyApplication;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
public class MyActiveRecord {
// find model by given id
public static <T extends MyActiveRecord> T findById(Class<T> clazz , int id ) {
var mapper = MyApplication.getBean(MyActiveRecordMapper.class);
var criteria = new MyActiveRecordCriteria();
criteria.tableName = MyActiveRecord.getTableNameFromModelClass(clazz);
criteria.limit = 1;
criteria.whereIs("id", id);
var rows = mapper.find(criteria);
if (rows.isEmpty()) {
return null;
}
return MyActiveRecord.fillModel(clazz, rows.get(0));
}
// get table name from model class
private static <T> String getTableNameFromModelClass(Class<T> modelClass) {
Method tableNameGetter = null;
try {
tableNameGetter = modelClass.getMethod("getTableName");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
String tableName = null;
try {
tableName = (String)tableNameGetter.invoke(null);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return tableName;
}
// fill model
private static <T> T fillModel(Class<T> modelClass, Map<String,Object> data) {
Constructor<?> modelConstructor = null;
try {
modelConstructor = modelClass.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
T model = null;
try {
model = modelClass.cast(modelConstructor.newInstance());
} catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
for ( Map.Entry<String,Object> entry : data.entrySet() ) {
String key = entry.getKey();
Field field = null;
try {
field = model.getClass().getDeclaredField(key);
} catch (NoSuchFieldException e) {
continue ;
}
Class<?> fieldType = field.getType();
if ( !fieldType.isAssignableFrom(entry.getValue().getClass()) ) {
throw new RuntimeException("Attribute type mismatch: " + key);
}
field.setAccessible(true);
try {
field.set(model, entry.getValue());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return model;
}
}

46
src/main/java/com/dreamworks/boditech/model/MyActiveRecordCriteria.java

@ -0,0 +1,46 @@
package com.dreamworks.boditech.model;
import java.util.ArrayList;
import java.util.List;
public class MyActiveRecordCriteria {
// condition
public static class Condition {
public String name;
public String operator;
public Object value;
}
// table name
public String tableName;
// conditions
public List<Condition> conditions;
// limit
public Integer limit;
// offset
public Integer offset;
// where is
public void whereIs(String key, Object value) {
var condition = new Condition();
condition.name = key;
condition.operator = "=";
condition.value = value;
this.appendCondition(condition);
}
// where is not
public void whereIsNot(String key, Object value) {
var condition = new Condition();
condition.name = key;
condition.operator = "!=";
condition.value = value;
this.appendCondition(condition);
}
// append condition
private void appendCondition( Condition condition ) {
if ( this.conditions == null ) {
this.conditions = new ArrayList<>();
}
this.conditions.add(condition);
}
}

10
src/main/java/com/dreamworks/boditech/model/MyActiveRecordField.java

@ -0,0 +1,10 @@
package com.dreamworks.boditech.model;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface MyActiveRecordField {
}

47
src/main/java/com/dreamworks/boditech/model/MyActiveRecordMapper.java

@ -0,0 +1,47 @@
package com.dreamworks.boditech.model;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
@Mapper
public interface MyActiveRecordMapper {
@Select(
"<script>" +
"SELECT * FROM ${tableName} " +
"<if test='conditions != null'>" +
"WHERE " +
"<foreach collection='conditions' item='value' separator=' AND '>" +
"<if test='value.operator == \"=\"'>${value.name} = #{value.value}</if>" +
"<if test='value.operator == \"!=\"'>${value.name} != #{value.value}</if>" +
"<if test='value.operator == \"&lt;\"'>${value.name} &lt; #{value.value}</if>" +
"<if test='value.operator == \"&lt;=\"'>${value.name} &lt;= #{value.value}</if>" +
"<if test='value.operator == \"&gt;\"'>${value.name} &gt; #{value.value}</if>" +
"<if test='value.operator == \"&gt;=\"'>${value.name} &gt;= #{value.value}</if>" +
"<if test='value.operator == \"LIKE\"'>${value.name} LIKE #{value.value}</if>" +
"<if test='value.operator == \"IN\"'>${value.name} IN " +
"<foreach collection='value.value' item='v' open='(' separator=',' close=')'>#{v}</foreach>" +
"</if>" +
"<if test='value.operator == \"NOT IN\"'>${value.name} NOT IN " +
"<foreach collection='value.value' item='v' open='(' separator=',' close=')'>#{v}</foreach>" +
"</if>" +
"<if test='value.operator == \"IS NULL\"'>${value.name} IS NULL</if>" +
"<if test='value.operator == \"IS NOT NULL\"'>${value.name} IS NOT NULL</if>" +
"<if test='value.operator == \"BETWEEN\"'>${value.name} BETWEEN #{value.value[0]} AND #{value.value[1]}</if>" +
"<if test='value.operator == \"NOT BETWEEN\"'>${value.name} NOT BETWEEN #{value.value[0]} AND #{value.value[1]}</if>" +
"</foreach>" +
"</if> " +
"ORDER BY id DESC " +
"<if test='limit != null'>LIMIT #{limit}</if> " +
"<if test='offset != null'>OFFSET #{offset}</if>" +
"</script>"
)
List<Map<String,Object>> find(MyActiveRecordCriteria criteria);
void insert();
void update();
void delete();
void findOne();
void find();
void batchUpdate();
void batchDelete();
}

11
src/main/java/com/dreamworks/boditech/utils/MyCommon.java

@ -1,5 +1,6 @@
package com.dreamworks.boditech.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cglib.beans.BeanMap;
@ -47,4 +48,14 @@ public class MyCommon {
throw new RuntimeException(e);
}
}
// json to node
public static JsonNode jsonToNode(String json) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readTree(json);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

BIN
src/main/java/com/dreamworks/boditech/utils/MyOptAlgo$AlgoResult.class

24
src/main/java/com/dreamworks/boditech/utils/MyOptAlgo.java

@ -0,0 +1,24 @@
package com.dreamworks.boditech.utils;
public class MyOptAlgo {
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 {
System.load("D:/Sige5193/boditech-opt-algo-java-lib/x64/Debug/boditech-opt-algo-java-lib.dll");
}
public native AlgoResult calculate(float[] data, int peakCount);
}
Loading…
Cancel
Save