diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DateConstant.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DateConstant.java index eb04f2cc..60891dfd 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DateConstant.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DateConstant.java @@ -6,6 +6,8 @@ public interface DateConstant { String TIME = "HH:mm:ss"; + String TIME_MS = "HH:mm:ss.S"; + String DATE_TIME = "yyyy-MM-dd HH:mm:ss"; String DATE_TIME_S = "yyyy/MM/dd-HH:mm:ss"; @@ -14,6 +16,8 @@ public interface DateConstant { String DATE_BIAS_TIME = "yyyy/MM/dd HH:mm:ss"; + String DATE_BIAS_TIME_MS = "yyyy/MM/dd HH:mm:ss.S"; + String TIME_START = " 00:00:00"; String TIME_END = " 23:59:59"; diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/entity/SpcHead1.java b/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/entity/SpcHead1.java new file mode 100644 index 00000000..575f148d --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/entity/SpcHead1.java @@ -0,0 +1,91 @@ +package org.jeecg.modules.base.entity; + +import lombok.Data; + +@Data +public class SpcHead1 { + + public SpcHead1() { + // 需根据谱改变 + EngPrNum = 3; + EffNum = 0; + SpcRecNum = 0; + SpcChnNum = 0; + + // 重要指针 + AcqInfRP = 2; + CalRP1 = 5; + CalRP2 = 7; + EffRP = 14; + EngPrRP = 11; + SpcFirstRP = 68; + + Inftyp = 1; + Filtyp = 1; + Reserved1 = 1; + Reserved2 = 0; + SamDesRP = 3; + DetDesRP = 4; + EbrDesRP = 0; + AnaRP1 = 31; + AnaRP2 = 37; + AnaRP3 = 46; + AnaRP4 = 56; + SrpDesRP = 0; + IeqDesRP = 0; + GeoDesRP = 0; + MpcDesRP = 0; + CalDesRP = 10; + ROI1 = 65; + Reserved3 = 0; + DDP = 0; + ActUnit = 0; + LabPerRP = 55; + MaxNumE = 323; + MaxNumU = 323; + Abstch = 0; + AcqTime = 12631.7f; + AcqTime8 = 12631.7; + } + + public short Inftyp; //1:整形SPC文件的标志 必须为“1” + public short Filtyp; //2:整形SPC文件的标志 必须为“1” + public short Reserved1; //3:Reserved + public short Reserved2; //4:Reserved + public short AcqInfRP; //5:Acquisition Information Record pointer + public short SamDesRP; //6:Sample Description Record pointer + public short DetDesRP; //7:Detector Description Record pointer + public short EbrDesRP; //8:EBAR Description Record + + public short AnaRP1; //9:First Analysis Parameters Record pointer + public short AnaRP2; //10:Second Analysis Parameters Record pointer + public short AnaRP3; //11:Third Analysis Parameters Record pointer + public short AnaRP4; //12:Fourth Analysis Parameters Record pointer + public short SrpDesRP; //13:Absorption Correction Description Record pointer + public short IeqDesRP; //14:IEQ Description Record pointer + public short GeoDesRP; //15:Geometry Correction Description Record pointer + public short MpcDesRP; //16:MPC Description Record pointer + + public short CalDesRP; //17:Calibration Description Record pointer + public short CalRP1; //18:First Calibration Data Record pointer + public short CalRP2; //19:Second Calibration Data Record pointer + public short EffRP; //20:Efficiency Pairs Record pointer(first record) + public short ROI1; //21:Record Number of the first of the two ROI records + public short EngPrRP; //22:Energe pairs record pointer + public short EngPrNum; //23:Number of energy pair records + public short Reserved3; //24:Reserved + + public short DDP; //25:Disable deconvolution of unknown peaks + public short ActUnit; //26:True=microCuries,false=becquerels + public short LabPerRP; //27:Laboratory and operator name record pointer + public short MaxNumE; //28:Maximum Record Number Ever Used + public short MaxNumU; //29:Maximum Record Number In Use + public short EffNum; //30:Number of Efficiency Pairs Records(See public short 20) + public short SpcFirstRP; //31:Spectrum Record pointer (pointer to first record) + public short SpcRecNum; //32:Number of records in the spectrum + + public short SpcChnNum; //33:Number of channels in spectrum + public short Abstch; //34:Physical start channel for data + public float AcqTime; //35,36:Date and Time of acquisition start in DECDAY format + public double AcqTime8; //37,40:Date and Time as double precision DECDAY +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/entity/SpcHead2.java b/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/entity/SpcHead2.java new file mode 100644 index 00000000..86bba32c --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/entity/SpcHead2.java @@ -0,0 +1,30 @@ +package org.jeecg.modules.base.entity; + +import lombok.Data; + +@Data +public class SpcHead2 { + + public SpcHead2() { + // 需根据谱改变 + Chnsrt = 0; + RealTime = 0.0f; + LiveTime = 0.0f; + + Seqnum = 0; + Mcanu = 1; + Segnum = 1; + Mcadvt = 0; + } + + public short AddRAM; //40:用于补足内存 + public short Seqnum; //41:Sequence number + public short Mcanu; //42:MCA number as two ASCII characters(old) or Detector + // number as integer for systems with Connections + public short Segnum; //43:Segment number as two ASCII characters(old) + // or as integer value 1 for systems with Connections + public short Mcadvt; //44:MCA device type + public short Chnsrt; //45:Start channel number + public float RealTime; //46,47:Real Time in seconds + public float LiveTime; //48,49:Live time in seconds +} diff --git a/jeecg-module-beta-gamma-analyser/src/main/java/org/jeecg/modules/entity/vo/FileData.java b/jeecg-module-beta-gamma-analyser/src/main/java/org/jeecg/modules/entity/vo/FileData.java index 7a845bda..949f574e 100644 --- a/jeecg-module-beta-gamma-analyser/src/main/java/org/jeecg/modules/entity/vo/FileData.java +++ b/jeecg-module-beta-gamma-analyser/src/main/java/org/jeecg/modules/entity/vo/FileData.java @@ -1,11 +1,12 @@ package org.jeecg.modules.entity.vo; import com.google.common.collect.Lists; +import lombok.Data; import java.io.Serializable; import java.util.LinkedList; import java.util.List; - +@Data public class FileData implements Serializable { diff --git a/jeecg-module-spectrum-analysis/src/main/java/org/jeecg/modules/controller/Demo.java b/jeecg-module-spectrum-analysis/src/main/java/org/jeecg/modules/controller/Demo.java new file mode 100644 index 00000000..fcbb39bd --- /dev/null +++ b/jeecg-module-spectrum-analysis/src/main/java/org/jeecg/modules/controller/Demo.java @@ -0,0 +1,343 @@ +package org.jeecg.modules.controller; + +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.CharsetUtil; +import org.jeecg.common.constant.DateConstant; +import org.jeecg.modules.base.entity.SpcHead1; +import org.jeecg.modules.base.entity.SpcHead2; +import org.jeecg.modules.entity.vo.FileData; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +import static java.lang.Math.pow; + +public class Demo { + + public static void main(String[] args) throws IOException { + FileData fileData = new FileData(); + String filePath = "C:\\\\Users\\\\a\\\\Desktop\\\\shift\\\\standard.SPC"; + // r:只读 rw:读写 + RandomAccessFile SpcFile = new RandomAccessFile(filePath, "r"); + short Inftyp; + short Filtyp; + byte[] buffer = new byte[2]; + SpcFile.read(buffer); + ByteBuffer byteBuffer = ByteBuffer.wrap(buffer); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + Inftyp = byteBuffer.getShort(); + SpcFile.read(buffer); + byteBuffer = ByteBuffer.wrap(buffer); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + Filtyp = byteBuffer.getShort(); + if (Inftyp != 1 || Filtyp != 1) return; + // 读入整形spc文件的头记录(第一个记录)-128字节 + SpcHead1 head1 = new SpcHead1(); + SpcHead2 head2 = new SpcHead2(); + SpcFile.seek(0); + + // Acquisition + // 从intspc能谱中读取能谱开测时间 + int AcqY, AcqM, AcqD, AcqH, AcqMin; + float AcqS, AcqRT, AcqLT; + byte[] temByte = new byte[200 * 2]; + int lOffset; + lOffset = (head1.AcqInfRP - 1) * 128; + SpcFile.seek((lOffset + 16) * 2); + SpcFile.read(temByte, 0, 12 * 2); + char[] temchar = byteToChar(temByte); + char char1, char2; + char1 = temchar[7]; + char2 = temchar[8]; + if (temchar[9] == '0') { + temchar[7] = '1'; + temchar[8] = '9'; + } else { + temchar[7] = '2'; + temchar[8] = '0'; + } + temchar[9] = char1; + temchar[10] = char2; + temchar[11] = '\0'; + + AcqY = 0; + for (int i = 7; i < 11; i++) { + temchar[i] = (char) (temchar[i] - 48); + AcqY = (int) (AcqY + temchar[i] * pow(10, 10 - i)); + } + + if (temchar[3] == 'J' && temchar[4] == 'a' && temchar[5] == 'n') AcqM = 1; + if (temchar[3] == 'F' && temchar[4] == 'e' && temchar[5] == 'b') AcqM = 2; + if (temchar[3] == 'M' && temchar[4] == 'a' && temchar[5] == 'r') AcqM = 3; + if (temchar[3] == 'A' && temchar[4] == 'p' && temchar[5] == 'r') AcqM = 4; + if (temchar[3] == 'M' && temchar[4] == 'a' && temchar[5] == 'y') AcqM = 5; + if (temchar[3] == 'J' && temchar[4] == 'u' && temchar[5] == 'n') AcqM = 6; + if (temchar[3] == 'J' && temchar[4] == 'u' && temchar[5] == 'l') AcqM = 7; + if (temchar[3] == 'A' && temchar[4] == 'u' && temchar[5] == 'g') AcqM = 8; + if (temchar[3] == 'S' && temchar[4] == 'e' && temchar[5] == 'p') AcqM = 9; + if (temchar[3] == 'O' && temchar[4] == 'c' && temchar[5] == 't') AcqM = 10; + if (temchar[3] == 'N' && temchar[4] == 'o' && temchar[5] == 'v') AcqM = 11; + if (temchar[3] == 'D' && temchar[4] == 'e' && temchar[5] == 'c') AcqM = 12; + + AcqD = 0; + for (int i = 0; i < 2; i++) { + temchar[i] = (char) (temchar[i] - 48); + AcqD = (int) (AcqD + temchar[i] * pow(10, 1 - i)); + } + + SpcFile.read(temByte, 0 ,10 * 2); + temchar = byteToChar(temByte); + temchar[9] = '\0'; + + AcqH = 0; + for (int i = 0; i < 2; i++) { + temchar[i] = (char) (temchar[i] - 48); + AcqH = (int) (AcqH + temchar[i] * pow(10, 1 - i)); + } + AcqMin = 0; + for (int i = 3; i < 5; i++) { + temchar[i] = (char) (temchar[i] - 48); + AcqMin = (int) (AcqMin + temchar[i] * pow(10, 4 - i)); + } + AcqS = 0; + for (int i = 6; i < 8; i++) { + temchar[i] = (char) (temchar[i] - 48); + AcqS = (float) (AcqS + temchar[i] * pow(10, 7 - i)); + } + AcqLT = 0; + SpcFile.read(temByte, 0, 10 * 2); + temchar = byteToChar(temByte); + for (int i = 0; i < 10; i++) { + if (temchar[i] == 32) { + temchar[i] = 0; + } else { + temchar[i] = (char) (temchar[i] - 48); + } + AcqLT = (float) (AcqLT + temchar[i] * pow(10, 9 - i)); + } + + AcqRT = 0; + SpcFile.read(temByte, 0, 10 * 2); + temchar = byteToChar(temByte); + for (int i = 0; i < 10; i++) { + if (temchar[i] == 32) + temchar[i] = 0; + else + temchar[i] = (char) (temchar[i] - 48); + AcqRT = (float) (AcqRT + temchar[i] * pow(10, 9 - i)); + } + + int seconds = (int) AcqS; + int ms = (int) ((AcqS - seconds) * 10); + String acq_date = LocalDate.of(AcqY, AcqM, AcqD). + format(DateTimeFormatter.ofPattern(DateConstant.DATE_BIAS)); + fileData.setAcq_date(acq_date); + String acq_time = LocalTime.of(AcqH, AcqMin, seconds, ms) + .format(DateTimeFormatter.ofPattern(DateConstant.TIME_MS)); + fileData.setAcq_time(acq_time); + fileData.setAcq_real((double) head2.RealTime); + fileData.setAcq_live((double) head2.LiveTime); + + // Calibration + // 从intspc能谱中读取能谱刻度时间 + int CalY, CalM, CalD, CalH, CalMin; + float CalS; + + lOffset = (head1.CalRP2 - 1) * 128; + SpcFile.seek((lOffset + 32) * 2); + SpcFile.read(temByte, 0, 10 * 2); + temchar = byteToChar(temByte); + char1 = temchar[7]; + char2 = temchar[8]; + if (temchar[9] == '0') { + temchar[7] = '1'; + temchar[8] = '9'; + } else { + temchar[7] = '2'; + temchar[8] = '0'; + } + temchar[9] = char1; + temchar[10] = char2; + temchar[11] = '\0'; + + CalY = 0; + for (int i = 7; i < 11; i++) { + temchar[i] = (char) (temchar[i] - 48); + CalY = (int) (CalY + temchar[i] * pow(10, 10 - i)); + } + + if (temchar[3] == 'J' && temchar[4] == 'a' && temchar[5] == 'n') CalM = 1; + if (temchar[3] == 'F' && temchar[4] == 'e' && temchar[5] == 'b') CalM = 2; + if (temchar[3] == 'M' && temchar[4] == 'a' && temchar[5] == 'r') CalM = 3; + if (temchar[3] == 'A' && temchar[4] == 'p' && temchar[5] == 'r') CalM = 4; + if (temchar[3] == 'M' && temchar[4] == 'a' && temchar[5] == 'y') CalM = 5; + if (temchar[3] == 'J' && temchar[4] == 'u' && temchar[5] == 'n') CalM = 6; + if (temchar[3] == 'J' && temchar[4] == 'u' && temchar[5] == 'l') CalM = 7; + if (temchar[3] == 'A' && temchar[4] == 'u' && temchar[5] == 'g') CalM = 8; + if (temchar[3] == 'S' && temchar[4] == 'e' && temchar[5] == 'p') CalM = 9; + if (temchar[3] == 'O' && temchar[4] == 'c' && temchar[5] == 't') CalM = 10; + if (temchar[3] == 'N' && temchar[4] == 'o' && temchar[5] == 'v') CalM = 11; + if (temchar[3] == 'D' && temchar[4] == 'e' && temchar[5] == 'c') CalM = 12; + + CalD = 0; + for (int i = 0; i < 2; i++) { + temchar[i] = (char) (temchar[i] - 48); + CalD = (int) (CalD + temchar[i] * pow(10, 1 - i)); + } + + SpcFile.read(temByte, 0, 10 * 2); + temchar = byteToChar(temByte); + temchar[9] = '\0'; + + CalH = 0; + for (int i = 0; i < 2; i++) { + temchar[i] = (char) (temchar[i] - 48); + CalH = (int) (CalH + temchar[i] * pow(10, 1 - i)); + } + CalMin = 0; + for (int i = 3; i < 5; i++) { + temchar[i] = (char) (temchar[i] - 48); + CalMin = (int) (CalMin + temchar[i] * pow(10, 4 - i)); + } + CalS = 0; + for (int i = 6; i < 8; i++) { + temchar[i] = (char) (temchar[i] - 48); + CalS = (float) (CalS + temchar[i] * pow(10, 7 - i)); + } + + int cal_s = (int) CalS; + int cal_ms = (int) ((CalS - cal_s) * 10); + String calibra_time = LocalDateTime.of(CalY, CalM, CalD, CalH, CalMin, cal_s, cal_ms) + .format(DateTimeFormatter.ofPattern(DateConstant.DATE_BIAS_TIME_MS)); + fileData.setCalibra_time(calibra_time); + + // g_Energy g_Resolution + if (head1.EngPrRP > 0) // 存在能量刻度 + { + // 从intspc能谱中读取能谱刻度信息 + byte[] cerByte = new byte[32 * 4]; + byte[] engByte = new byte[32 * 4]; + byte[] fWHMByte = new byte[32 * 4]; + + lOffset = (head1.EngPrRP - 1) * 128; + SpcFile.seek(lOffset * 2); + SpcFile.read(cerByte, 0, 128 * 2); + float Cer[] = byteToFloat(cerByte); + SpcFile.read(engByte, 0, 128 * 2); + float Eng[] = byteToFloat(engByte); + SpcFile.read(fWHMByte, 0, 128 * 2); + float FWHM[] = byteToFloat(fWHMByte); + + short EngNum; + byte[] engNumByte = new byte[4]; + lOffset = (head1.CalRP1 - 1) * 128; + SpcFile.seek((lOffset + 74) * 2); + SpcFile.read(engNumByte, 0, 2 * 2); + EngNum = byteToShort(engNumByte); + + float CerUnc = 0.5F; + for (int i = 0; i < EngNum; i++) { + fileData.getVvEner().get(0).add((double) Eng[i]); + fileData.getVvEner().get(1).add((double) Cer[i]); + fileData.getVvEner().get(2).add((double) CerUnc); + } + if (EngNum > 1) { + int i1 = 1, i2 = EngNum - 2; + if (EngNum < 4) { + i1 = 0; + i2 = EngNum - 1; + } + fileData.setEner_slope((double) ((Eng[i2] - Eng[i1]) / (Cer[i2] - Cer[i1]))); + double v1 = fileData.getVvEner().get(0).get(i1) * fileData.getVvEner().get(1).get(i2); + double v2 = fileData.getVvEner().get(0).get(i2) * fileData.getVvEner().get(1).get(i1); + double v3 = fileData.getVvEner().get(1).get(i2) - fileData.getVvEner().get(1).get(i1); + fileData.setEner_intercept((v1 - v2) / v3); + } + + for (int i = 0; i < EngNum; i++) { + fileData.getVvReso().get(0).add((double) Eng[i]); + fileData.getVvReso().get(1).add(FWHM[i] * fileData.getEner_slope()); + fileData.getVvReso().get(2).add((double) CerUnc); + } + } + + // g_Efficiency + if (head1.EffRP > 0) { // 存在效率刻度 + byte[] effNumByte = new byte[4]; + lOffset = (head1.CalRP1 - 1) * 128; + SpcFile.seek((lOffset + 4) * 2); + SpcFile.read(effNumByte,0,2); + short EffNum = byteToShort(effNumByte); + + // 0,2,4等偶数存放能量,1,3,5等奇数存放效率 + byte[] effByte = new byte[32 * 4]; + float EffUnc = 0.5F; + + lOffset = (head1.EffRP - 1) * 128; + SpcFile.seek(lOffset * 2); + SpcFile.read(effByte, 0, 128 * 2); + float Eff[] = byteToFloat(effByte); + + for (int i = 0; i < EffNum; i++) { + fileData.getVvEffi().get(0).add((double) Eff[i * 2]); + fileData.getVvEffi().get(1).add((double) Eff[i * 2 + 1]); + fileData.getVvEffi().get(2).add((double) EffUnc); + } + } + + // Spectrum + int[] SpcData = new int[100000]; + + fileData.setNum_count(head1.SpcChnNum); + fileData.setStart_chan(head2.Chnsrt); + + float EngA, EngB, EngC; + lOffset = (head1.CalRP1 - 1) * 128; + SpcFile.seek(lOffset + 20); + SpcFile.read(( char*)&EngA, 4); + SpcFile.read(( char*)&EngB, 4); + SpcFile.read(( char*)&EngC, 4); + fileData.max_energy = EngA + EngB * fileData.num_count + EngC * pow(fileData.num_count, 2); + + lOffset = (head1.SpcFirstRP - 1) * 128; + SpcFile.seek(lOffset); + SpcFile.read(( char*)SpcData, fileData.num_count * 4); + + for (int i = 0; i < fileData.num_count; i++) { + fileData.vCounts.push_back(SpcData[i]); + } + + SpcFile.close(); + } + + public static char[] byteToChar(byte[] data) { + return new String(data, StandardCharsets.UTF_8).toCharArray(); + } + + public static float[] byteToFloat(byte[] data) { + // 每个浮点数占用4个字节 + int floatCount = data.length / 4; + float[] floatArray = new float[floatCount]; + + ByteBuffer buffer = ByteBuffer.wrap(data); + for (int i = 0; i < floatCount; i++) { + floatArray[i] = buffer.getFloat(); + } + + return floatArray; + } + + public static short byteToShort(byte[] byteData) { + ByteBuffer buffer = ByteBuffer.wrap(byteData); + buffer.order(ByteOrder.LITTLE_ENDIAN); + return buffer.getShort(); + } +}