Browse Source

update

tags/v0
zhaohe 10 months ago
parent
commit
143f1a4095
  1. 44
      README.md
  2. 295
      src/main/java/a8k/optalgo/OptAlgo.java
  3. 6
      src/main/java/a8k/optalgo/type/LinearResult.java
  4. 6
      src/main/java/a8k/optalgo/type/LinearResultSeq.java
  5. 14
      src/main/java/a8k/optalgo/type/OptAlgoResult.java
  6. 5
      src/main/java/a8k/optalgo/type/OptCfg.java
  7. 4
      src/main/java/a8k/optalgo/type/OptProcessContext.java
  8. 2
      src/main/java/a8k/optalgo/type/Peak.java
  9. 1
      src/main/java/a8k/service/appdata/AppReactionResultMgrService.java
  10. 105
      src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java
  11. 2
      src/main/java/a8k/service/appsetting/AppSettingsMgr.java

44
README.md

@ -200,10 +200,48 @@ TODO:
TODO:
1. 如果当前板夹仓对应位置的耗材批次码没有发生变化,则耗材量不重新初始化。
2. tip头只有在第一次扫描时,才会初始化其数量是满的。
```
```
TODO:
1. 软件启动后读取所有单片机版本号。
2. 添加温度控制服务。(不用向前台提供接口)
3. 扫描耗材时,检查ID卡,同时检查温度是否一致。
4. MainFlowCtrl监听,温度控制异常事件,当发生异常时,主动暂停MainFlowCtrl
5. 打印结果
6. 支持扫码枪
添加DEBUG模式,
需要模拟硬件行为的地方。
1. 耗材扫描
2. 初始化
3. 工作流中的所有动作
需要产生的虚假行为
1. 触发.提供插入一个假的ID卡配置的事件
2. 触发.提供假的耗材配置
3. 触发.提供假的样本
4. 触发.添加一个假的急诊
为前台提供的接口:
设备控制
主流程控制
扫描耗材
添加急诊
开关机
配置:
xxx
xxx
xxx
数据
项目管理
用户接口
事件
...
错误码
...
```

295
src/main/java/a8k/optalgo/OptAlgo.java

@ -1,7 +1,302 @@
package a8k.optalgo;
import a8k.optalgo.type.LinearResult;
import a8k.optalgo.type.OptAlgoResult;
public class OptAlgo {
OptAlgoResult processOptData(Integer expectPeakNum, Float[] data) {
return null;
}
Boolean feq(double a, double b, double epsilon) {
double dv = a - b;
if (dv < 0)
dv = -dv;
return dv <= epsilon;
}
Float[] super_sampling(Float[] inputRaw, Integer nInputLength, Integer nUpSampleRate) {
/*
* @brief
*
*/
int nOutputLength = nInputLength * nUpSampleRate;
Float[] upSamplingRaw = new Float[nOutputLength];
for (int si = 0, di = 0; si < nInputLength - 1; di++) {
float a = upSamplingRaw[di * nUpSampleRate] = (float) inputRaw[si];
float b = upSamplingRaw[(di + 1) * nUpSampleRate] = (float) inputRaw[++si];
float nSlope = (b - a) / nUpSampleRate;
for (int i = 0; i < nUpSampleRate - 1; i++) {
int baseIndex = (di * nUpSampleRate) + i;
upSamplingRaw[baseIndex + 1] = upSamplingRaw[baseIndex] + nSlope;
}
}
return upSamplingRaw;
}
Float[] sub_sampling(Float[] inputRaw, int nSubSampleRate) {
int nSum = 0;
float fAvg = 0;
int subIndex = 0;
int nOutputLength = inputRaw.length / nSubSampleRate;
Float[] subSampledRaw = new Float[nOutputLength];
for (int index = 0; index < inputRaw.length; index++) {
if (index % nSubSampleRate == 0 && index > 0) {
fAvg = nSum * 1.0f / nSubSampleRate;
if (subIndex < subSampledRaw.length) {
subSampledRaw[subIndex++] = fAvg;
} else {
int empty = 0;
}
nSum = 0;
}
nSum += inputRaw[index];
}
subSampledRaw[subSampledRaw.length - 1] = subSampledRaw[subSampledRaw.length - 2];
return subSampledRaw;
}
Float[] smooth_windows(Float[] inputRaw, int windows_size) {
Float[] smoothRaw = new Float[inputRaw.length];
int windows_size_half = (windows_size - 1) / 2;
for (int index = windows_size_half; index < inputRaw.length - windows_size_half; index++) {
float sum = 0;
for (int i = index - windows_size_half; i <= index + windows_size_half; i++) {
sum += inputRaw[i];
}
smoothRaw[index] = sum / windows_size;
}
for (int i = 0; i < windows_size_half; i++) {
smoothRaw[i] = smoothRaw[windows_size_half];
}
for (int i = inputRaw.length - windows_size_half; i < inputRaw.length; i++) {
smoothRaw[i] = smoothRaw[inputRaw.length - windows_size_half - 1];
}
return smoothRaw;
}
Float[] median_filtering(Float[] inputRaw, int windows_size) {
Float[] medianRaw = new Float[inputRaw.length];
Float[] windows = new Float[windows_size];
int windows_size_half = (windows_size - 1) / 2;
for (int index = windows_size_half; index < inputRaw.length - windows_size_half; index++) {
for (int i = 0; i < windows_size; i++) {
windows[i] = inputRaw[index + i - windows_size_half];
}
sort_vector(windows); // 从小到大顺序排序
medianRaw[index] = windows[windows_size_half + 1];
}
for (int i = 0; i < windows_size_half; i++) {
medianRaw[i] = medianRaw[windows_size_half];
}
for (int i = inputRaw.length - windows_size_half; i < inputRaw.length; i++) {
medianRaw[i] = medianRaw[inputRaw.length - windows_size_half - 1];
}
return medianRaw;
}
/**
* @brief 求数据的均值
*
* @param inputRaw
* @return float
*/
float find_avg_line(Float[] inputRaw) {
float base_min = 500;
float 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);
float fbase = fsum / cnt;
return fbase;
}
Float[] differentiate(Float[] inputRaw) {
/**
* @brief
* 巴迪泰源码对原始数据添加了一些微小的值原因未知
*/
for (int i = 0; i <= inputRaw.length - 8; i += 8) {
inputRaw[i + 1] = inputRaw[i + 1] + 0.001f;
inputRaw[i + 2] = inputRaw[i + 2] + 0.002f;
inputRaw[i + 3] = inputRaw[i + 3] + 0.003f;
inputRaw[i + 4] = inputRaw[i + 4] + 0.004f;
inputRaw[i + 5] = inputRaw[i + 5] + 0.005f;
inputRaw[i + 6] = inputRaw[i + 6] + 0.004f;
inputRaw[i + 7] = inputRaw[i + 7] + 0.003f;
inputRaw[i + 8] = inputRaw[i + 8] + 0.002f;
}
/**
* @brief
* @Warning: 此处求导和巴迪泰的存在差异
* 巴迪泰的是当前数值减去下一个数值
* 而此处是当前数值减去上一个数值
*/
Float[] differentiateRaw = new Float[inputRaw.length];
for (int i = 1; i < differentiateRaw.length; i++) {
differentiateRaw[i] = inputRaw[i] - inputRaw[i - 1];
}
differentiateRaw[0] = differentiateRaw[1];
return differentiateRaw;
}
Float[] least_square_method_differentiate(Float[] inputRaw, int windows_size) {
assert (windows_size > 0);
assert (windows_size % 2 == 1);
Float[] differentiateRaw = new Float[inputRaw.length];
Float[] windowsRaw = new Float[windows_size];
int windows_size_half = (windows_size - 1) / 2;
for (int index = windows_size_half; index < inputRaw.length - windows_size_half; index++) {
windowsRaw = getwindowspoint(inputRaw, index, windows_size);
float intercept = 0;
// linear_least_squares(windowsRaw, windows_size, differentiateRaw[index], intercept);
}
for (int i = 0; i < windows_size_half; i++) {
differentiateRaw[i] = differentiateRaw[windows_size_half];
}
for (int i = inputRaw.length - windows_size_half; i < inputRaw.length; i++) {
differentiateRaw[i] = differentiateRaw[inputRaw.length - windows_size_half - 1];
}
return differentiateRaw;
}
Boolean is_maxval_in_windows(Float[] data, int pos, int windows_size) {
assert (windows_size > 0);
assert (windows_size % 2 == 1);
boolean ret = true;
int startPos = pos - windows_size / 2;
Float val = data[pos];
for (int i = 0; i < windows_size; i++) {
if (startPos + i == pos)
continue;
if (data[startPos + i] > val) {
ret = false;
break;
}
}
return ret;
}
LinearResult linear_least_squares(double[] x, double[] y) {
LinearResult result = new LinearResult();
int n = x.length;
double sumX = 0.0, sumY = 0.0, sumXY = 0.0, sumXX = 0.0;
for (int i = 0; i < n; ++i) {
sumX += x[i];
sumY += y[i];
sumXY += x[i] * y[i];
sumXX += x[i] * x[i];
}
double xMean = sumX / n;
double yMean = sumY / n;
assert (!feq((sumXX - n * xMean * xMean), 0, 0.0001));
result.slope = (sumXY - n * xMean * yMean) / (sumXX - n * xMean * xMean);
result.intercept = yMean - result.slope * xMean;
return result;
}
//
LinearResult linear_least_squares(double[] y, int size) {
double[] xpoint = new double[size];
double[] ypoint = new double[size];
for (int i = 0; i < size; i++) {
xpoint[i] = i;
ypoint[i] = y[i];
}
return linear_least_squares(xpoint, ypoint);
}
LinearResult linear_least_squares_muti_windos(int[] startx, int windows, float[] y) {
double[] xpoint = new double[windows * startx.length];
double[] ypoint = new double[windows * startx.length];
int j = 0;
for (int xstart : startx) {
for (int xindex = xstart; xindex < (xstart + windows); xindex++) {
xpoint[j] = xindex;
ypoint[j] = y[xindex];
j++;
}
}
return linear_least_squares(xpoint, ypoint);
}
float get_avg_in_windows(double[] src, int off, int windows) {
float sum = 0;
assert (windows % 2 == 1);
for (int i = off - windows / 2; i <= off + windows / 2; i++) {
sum += (float) src[i];
}
return sum / windows;
}
void sort_vector(Float[] src) {
// 实现冒泡排序
for (int i = 0; i < src.length; i++) {
for (int j = 0; j < src.length - i - 1; j++) {
if (src[j] > src[j + 1]) {
float temp = src[j];
src[j] = src[j + 1];
src[j + 1] = temp;
}
}
}
}
double[] getwindowspoint(double[] src, int off, int windows) {
double[] ret = new double[windows];
int retindex = 0;
for (int i = off - windows / 2; i <= off + windows / 2; i++) {
ret[retindex] = src[i];
retindex++;
}
return ret;
}
}

6
src/main/java/a8k/optalgo/type/LinearResult.java

@ -0,0 +1,6 @@
package a8k.optalgo.type;
public class LinearResult {
public double slope;
public double intercept;
}

6
src/main/java/a8k/optalgo/type/LinearResultSeq.java

@ -0,0 +1,6 @@
package a8k.optalgo.type;
public class LinearResultSeq {
public Float[] slope;
public Float intercept;
}

14
src/main/java/a8k/optalgo/type/OptAlgoResult.java

@ -1,14 +1,12 @@
package a8k.optalgo.type;
import java.util.ArrayList;
import java.util.List;
public class OptAlgoResult {
// vector<float> ogigin_val; // 1200
// vector<float> supper_val; // 原始数据线性填充1200*5=6000
// vector<float> supper_median_val; // supper_val 窗口平滑滤波6000
// vector<float> supper_smooth_sub_val; // supper_smooth_val 均值压缩6000/6=1000
public Float[] ogiginVal;
public Float[] supperVal;
public Float[] supperMedianVal;
public Float[] supperSmoothSubVal;
public Float[] ogigin_val; // 1200 POINT
public Float[] result_val; // 250 POINT
public List<Peak> peaks = new ArrayList<>();
}

5
src/main/java/a8k/optalgo/type/OptCfg.java

@ -0,0 +1,5 @@
package a8k.optalgo.type;
public class OptCfg {
public Integer peakNum;
}

4
src/main/java/a8k/optalgo/type/OptProcessContext.java

@ -0,0 +1,4 @@
package a8k.optalgo.type;
public class OptProcessContext {
}

2
src/main/java/a8k/optalgo/type/PeakInfo.java → src/main/java/a8k/optalgo/type/Peak.java

@ -1,6 +1,6 @@
package a8k.optalgo.type;
public class PeakInfo {
public class Peak {
public Boolean findPeak;
public Float peakFullArea;
public Float peakBaseLineArea;

1
src/main/java/a8k/service/appdata/AppReactionResultMgrService.java

@ -96,4 +96,5 @@ public class AppReactionResultMgrService {
}
}
}

105
src/main/java/a8k/service/appdata/AppSampleRecordMgrService.java

@ -1,105 +0,0 @@
package a8k.service.appdata;
import a8k.controler.extapi.pagecontrol.ExtApiTabConfig;
import a8k.controler.extapi.utils.ExtApiFn;
import a8k.controler.extapi.utils.ExtApiTab;
import a8k.dbservice.SampleRecordDBService;
import a8k.dbservice.type.SampleRecord;
import a8k.service.appstate.type.Tube;
import a8k.service.appstate.type.state.TubeState;
import a8k.type.type.BloodType;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@Component
@ExtApiTab(cfg = ExtApiTabConfig.AppSampleMgrService)
public class AppSampleRecordMgrService {
@Resource
SampleRecordDBService sampleRecordDBService;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@PostConstruct
public void init() {
}
// String generateSampleId(Date date, Integer tubePos) {
// String sampleid = "";
// SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd_HHmmss");
// sampleid = String.format("%s_%s", sdf.format(date), tubePos + 1);
// if (tubePos == -1) {
// sampleid = String.format("%s_%s", sdf.format(date), "E");
// }
// return sampleid;
// }
//
// @ExtApiFn(name = "addSampleRecordExtApi")
// public SampleRecord addSampleRecordExtApi(Integer tuebPos, BloodType bloodType, String sampleBarcode, String userid, String projIndex) {
// return addSampleRecord(new Date(), tuebPos, bloodType, sampleBarcode, userid, projIndex);
// }
//
// @ExtApiFn(name = "getAllSampleRecordsExtApi")
// public List<SampleRecord> getAllSampleRecords() {
// return sampleRecordDBService.getAll();
// }
//
// public SampleRecord addSampleRecord(Date intertime, Integer tuebPos, BloodType bloodType, String sampleBarcode, String userid, String projIndex) {
// SampleRecord record = new SampleRecord();
// record.bloodType = bloodType;
// record.sampleBarcode = sampleBarcode;
// record.userid = userid;
// record.date = intertime;
// record.sampleid = generateSampleId(intertime, tuebPos);
// for (String s : projIndex.split(",")) {
// record.projIndex.add(Integer.parseInt(s));
// }
// sampleRecordDBService.add(record);
// return record;
// }
//
// public void addSampleRecord(Tube[] state) {
// Date intertime = new Date();
// for (int i = 0; i < state.length; i++) {
// if (state[i] == null) {
// continue;
// }
// if (state[i].state.equals(TubeState.EMPTY)) {
// continue;
// }
// SampleRecord record = new SampleRecord();
// record.bloodType = state[i].bloodType;
// record.sampleBarcode = state[i].sampleBarcode;
// record.userid = state[i].userid;
// record.date = intertime;
// record.isEmergency = state[i].isEmergency;
// record.sampleid = generateSampleId(intertime, i);
// record.projIndex = state[i].projIndex;
// state[i].sampleid = record.sampleid;
// sampleRecordDBService.add(record);
// }
// }
//
// public void addEmergencySampleRecord(Tube state) {
// Date intertime = new Date();
// SampleRecord record = new SampleRecord();
// state.isEmergency = true;
//
// record.bloodType = state.bloodType;
// record.sampleBarcode = state.sampleBarcode;
// record.userid = state.userid;
// record.date = intertime;
// record.isEmergency = true;
// record.sampleid = generateSampleId(intertime, -1);
// record.projIndex = state.projIndex;
// state.sampleid = record.sampleid;
// sampleRecordDBService.add(record);
// }
//
}

2
src/main/java/a8k/service/appdata/AppSettingsMgr.java → src/main/java/a8k/service/appsetting/AppSettingsMgr.java

@ -1,4 +1,4 @@
package a8k.service.appdata;
package a8k.service.appsetting;
import a8k.dbservice.AppSettingDBService;
import a8k.dbservice.type.AppSetting;
Loading…
Cancel
Save