TaskService.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. using DevExpress.XtraLayout;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Configuration;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using XdCxRhDW.Dto;
  12. namespace X1LeoTaskServer54.Service
  13. {
  14. //业务逻辑处理类
  15. public class TaskService
  16. {
  17. private readonly string baseUrl;
  18. CancellationTokenSource cts;
  19. string CapDir;
  20. string PosResDir;
  21. string StateDir;
  22. int MainSatCode;
  23. double[] Time1XYZ, Time2XYZ, Time3XYZ;
  24. int PosDtoFactor;
  25. bool useGpuCg = false;
  26. double DfoErrHz;
  27. double EphPosErrM;
  28. double EphVelErr;
  29. public TaskService()
  30. {
  31. Directory.CreateDirectory("tmp");
  32. var posPlatformAddr = ConfigurationManager.AppSettings["PosPlatformAddr"].Trim();//like http://127.0.0.1:8091 or http://127.0.0.1:8091/
  33. if (posPlatformAddr.EndsWith("/"))
  34. this.baseUrl = posPlatformAddr + "api/";
  35. else
  36. this.baseUrl = posPlatformAddr + "/api/";
  37. CapDir = ConfigurationManager.AppSettings["CapDir"].Trim();
  38. PosResDir = ConfigurationManager.AppSettings["PosResDir"].Trim();
  39. StateDir = ConfigurationManager.AppSettings["StateRptDir"].Trim();
  40. var PosDtoFactorstr = ConfigurationManager.AppSettings["PosDtoFactor"].Trim();
  41. int.TryParse(PosDtoFactorstr, out PosDtoFactor);
  42. if (PosDtoFactor == 0) PosDtoFactor = 1;
  43. var DfoErrusstr = ConfigurationManager.AppSettings["DfoErr"].Trim();
  44. double.TryParse(DfoErrusstr, out DfoErrHz);
  45. var EphPosErrstr = ConfigurationManager.AppSettings["EphPosErr"].Trim();
  46. double.TryParse(EphPosErrstr, out EphPosErrM);
  47. var EphVelErrstr = ConfigurationManager.AppSettings["EphVelErr"].Trim();
  48. double.TryParse(EphVelErrstr, out EphVelErr);
  49. string useGpuStr = ConfigurationManager.AppSettings["UseGpuCg"];
  50. if (useGpuStr != null && useGpuStr.Trim() == "1")
  51. useGpuCg = true;
  52. }
  53. /// <summary>
  54. /// 扫描 检测 参估 定位
  55. /// </summary>
  56. /// <param name="dto"></param>
  57. public void StartAsync(LeoSat1TaskHandleDto dto)
  58. {
  59. cts = new CancellationTokenSource();
  60. Task.Run(async () =>
  61. {
  62. LogHelper.Info($"【任务{dto.ID}】开始执行...");
  63. LogHelper.Info($"【任务{dto.ID}】AD采集目录[{CapDir}]");
  64. LogHelper.Info($"【任务{dto.ID}】状态上报输出目录[{StateDir}]");
  65. //点击定位平台右上角查看接口可以在浏览器中查看平台提供的所有接口详细信息
  66. while (!cts.IsCancellationRequested)
  67. {
  68. try
  69. {
  70. #region 第1步,读取需要的配置信息
  71. if (!Directory.Exists(CapDir))
  72. {
  73. await StopTask(dto.ID, EnumTaskStopType.Error, $"AD采集目录[{CapDir}]不存在");
  74. return;
  75. }
  76. Directory.CreateDirectory(PosResDir);
  77. try
  78. {
  79. var mainInfo = ConfigurationManager.AppSettings["Time1SatInfo"].Replace(",", ",").Trim();
  80. var adja1Info = ConfigurationManager.AppSettings["Time2SatInfo"].Replace(",", ",").Trim();
  81. var adja2Info = ConfigurationManager.AppSettings["Time2SatInfo"].Replace(",", ",").Trim();
  82. var arr1 = mainInfo.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
  83. var arr2 = adja1Info.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
  84. var arr3 = adja2Info.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
  85. MainSatCode = Convert.ToInt32(arr1[0]);
  86. Time1XYZ = GetEph(arr1);
  87. Time2XYZ = GetEph(arr2);
  88. Time3XYZ = GetEph(arr3);
  89. }
  90. catch
  91. {
  92. await StopTask(dto.ID, EnumTaskStopType.Error, $"任务处理服务配置文件卫星信息解析出错");
  93. return;
  94. }
  95. #endregion
  96. #region 第2步,扫描检测结果目录
  97. //同一个AD文件得到的不同频点的检测文件FlagNo相同
  98. var groupFiles = Directory.EnumerateFiles(CapDir, "*.dat", SearchOption.TopDirectoryOnly).Select(p => StringToAdFile(p))
  99. .GroupBy(m => m.XDNo).OrderBy(m => m.Key);
  100. if (!groupFiles.Any())
  101. {
  102. LogHelper.Info($"【任务{dto.ID}】等待扫描文件...");
  103. await Task.Delay(10000);
  104. }
  105. var listTask = new List<Task>();
  106. foreach (var groupFile in groupFiles)//每一组文件代表同一组可定位的三个不同时刻的采集文件
  107. {
  108. if (cts.IsCancellationRequested) break;
  109. var first = groupFile.First();
  110. LogHelper.Info($"【任务{dto.ID}】正在执行第{first.XDNo}组的采集文件");
  111. var group = groupFile.OrderBy(g => g.AdTime).ToArray();
  112. if (group.Count() != 3)
  113. {
  114. LogHelper.Warning($"【任务{dto.ID}】第{first.XDNo}组{first.AdTime:yyyyMMddHHmmss}时刻-信号{first.FreqDownMHz}MHz-未找到三个时刻的信号文件,跳过此组数据");
  115. return;
  116. }
  117. //group:同一组不同时刻的文件
  118. var task = Task.Run(async () =>
  119. {
  120. DateTime adTime = groupFile.First().AdTime;
  121. double freq = groupFile.First().FreqDownMHz;
  122. int No = groupFile.First().XDNo;
  123. var ch0File = group[0];
  124. var ch1File = group[1];
  125. var ch2File = group[2];
  126. if (cts.IsCancellationRequested) return;
  127. Stopwatch sw = new Stopwatch();
  128. sw.Start();
  129. string mainFile = await HttpHelper.UploadFileAsync(ch0File.File, baseUrl, token: cts.Token);//主星文件
  130. string adja1File = await HttpHelper.UploadFileAsync(ch1File.File, baseUrl, token: cts.Token);//邻1星文件
  131. string adja2File = await HttpHelper.UploadFileAsync(ch2File.File, baseUrl, token: cts.Token);//邻2星文件
  132. DetectDto detectDto = new DetectDto()
  133. {
  134. file1 = mainFile,
  135. dmcType = EnumSigCheckTypeDto.Ky5758,
  136. fsHz = ch0File.Fs,
  137. mergeRes = true,
  138. SigProc = true,
  139. };
  140. var deteResp = await HttpHelper.PostRequestAsync<List<DetectResDto>>(baseUrl + "DetectCg/DetectCalc", detectDto, token: cts.Token);
  141. if (deteResp.code != 200)
  142. {
  143. LogHelper.Error($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz信号检测出错.{deteResp.msg}");
  144. return;
  145. }
  146. var smps = deteResp.data.Select(m => new SmpPosition(m.Start, m.Length)).ToList();//怎么补0?
  147. LogHelper.Info($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz-CPU参估开始,共{smps.Count}个突发...");
  148. var cgDto = new CpuCgMultiDto()
  149. {
  150. dtCenter = 0,
  151. dtRange = 40000,
  152. file1 = mainFile,
  153. file2 = adja1File,
  154. samplingRate = ch0File.Fs,
  155. smpPositions = smps,
  156. snrThreshold = 15,
  157. };
  158. var result1 = await HttpHelper.PostRequestAsync<List<CpuCgResDto>>(baseUrl + "DetectCg/CpuCgMultiCalc", cgDto, token: cts.Token);
  159. if (result1.code != 200)
  160. {
  161. LogHelper.Error($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz-主星邻1星CPU参估出错.{result1.msg}");
  162. return;
  163. }
  164. cgDto = new CpuCgMultiDto()
  165. {
  166. dtCenter = 0,
  167. dtRange = 40000,
  168. file1 = mainFile,
  169. file2 = adja2File,
  170. samplingRate = ch0File.Fs,
  171. smpPositions = smps,
  172. snrThreshold = 15,
  173. };
  174. var result2 = await HttpHelper.PostRequestAsync<List<CpuCgResDto>>(baseUrl + "DetectCg/CpuCgMultiCalc", cgDto, token: cts.Token);
  175. sw.Stop();
  176. if (result2.code != 200)
  177. {
  178. LogHelper.Error($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz-主星邻2星CPU参估出错.{result2.msg}");
  179. return;
  180. }
  181. LogHelper.Info($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz-CPU参估完成,耗时{sw.ElapsedMilliseconds}ms");
  182. var data1 = result1.data;
  183. var data2 = result2.data;
  184. if (data1.Count != data2.Count || data1.Count != cgDto.smpPositions.Count)
  185. {
  186. LogHelper.Error($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz-参估结果个数和检测结果个数不匹配");
  187. return;
  188. }
  189. sw.Start();
  190. for (int i = 0; i < data1.Count; i++)
  191. {
  192. try
  193. {
  194. if (cts.IsCancellationRequested) break;
  195. LeoX1ParPosDto leoX1 = new LeoX1ParPosDto()
  196. {
  197. TaskID = dto.ID,
  198. SigTime = adTime.AddSeconds(data1[i].TimeSeconds),
  199. MainCode = MainSatCode,
  200. Adja1Code = MainSatCode,
  201. Adja2Code = MainSatCode,
  202. MainX = Time1XYZ[0],
  203. MainY = Time1XYZ[1],
  204. MainZ = Time1XYZ[2],
  205. MainVX = Time1XYZ[3],
  206. MainVY = Time1XYZ[4],
  207. MainVZ = Time1XYZ[5],
  208. Adja1X = Time2XYZ[0],
  209. Adja1Y = Time2XYZ[1],
  210. Adja1Z = Time2XYZ[2],
  211. Adja1VX = Time2XYZ[3],
  212. Adja1VY = Time2XYZ[4],
  213. Adja1VZ = Time2XYZ[5],
  214. Adja2X = Time3XYZ[0],
  215. Adja2Y = Time3XYZ[1],
  216. Adja2Z = Time3XYZ[2],
  217. Adja2VX = Time3XYZ[3],
  218. Adja2VY = Time3XYZ[4],
  219. Adja2VZ = Time3XYZ[5],
  220. Dto1 = PosDtoFactor * data1[i].Dt,
  221. Dfo1 = data1[i].Df,
  222. Snr1 = data1[i].Snr,
  223. Dto2 = PosDtoFactor * data2[i].Dt,
  224. Dfo2 = data2[i].Df,
  225. Snr2 = data2[i].Snr,
  226. FreqUp = (ch0File.FreqDownMHz + 44) * 1e6,
  227. SatTxLon = dto.CapLon,
  228. SatTxLat = dto.CapLat,
  229. FreqDown = ch0File.FreqDownMHz * 1e6,
  230. CheckRes = new CheckResDto()
  231. {
  232. FileName = Path.GetFileName(ch0File.File),
  233. SmpStart = cgDto.smpPositions[i].smpStart,
  234. SmpCount = cgDto.smpPositions[i].smpCount,
  235. PosCheckType = EnumPosCheckTypeDto.Ky5758,
  236. }
  237. };
  238. var result = await HttpHelper.PostRequestAsync<PosResDto>(baseUrl + "Pos/PosLeX1ParAsync", leoX1);
  239. if (result.code != 200)
  240. {
  241. LogHelper.Error($"【任务{dto.ID}】第{No}组-{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz 第{i + 1}个突发定位异常.{result.msg}");
  242. }
  243. else
  244. {
  245. var posRes = result.data;
  246. double posLon = posRes.PosLon;
  247. double posLat = posRes.PosLat;
  248. if (leoX1.Snr1 == 0 || leoX1.Snr2 == 0)
  249. {
  250. posLon = 0;
  251. posLat = 0;
  252. }
  253. ErrorEllipseLeoX1Dto errdto = new ErrorEllipseLeoX1Dto()
  254. {
  255. MsEph = Time1XYZ,
  256. NsEph1 = Time2XYZ,
  257. NsEph2 = Time3XYZ,
  258. SelectPoint = new double[3] { posLon, posLat,0 },
  259. DfoErr=DfoErrHz,
  260. EphPosErr=EphPosErrM,
  261. EphVelErr=EphVelErr,
  262. fu= leoX1.FreqUp,
  263. Pe=0.5,
  264. OutputErrPoint=false
  265. };
  266. var errRes =await GetErrEllipseResDto(errdto, posLon,posLat);
  267. StringBuilder sb = new StringBuilder();
  268. sb.Append($"{leoX1.SigTime:yyyy}\t");
  269. sb.Append($"{leoX1.SigTime:MM}\t");
  270. sb.Append($"{leoX1.SigTime:dd}\t");
  271. sb.Append($"{leoX1.SigTime:HH}\t");
  272. sb.Append($"{leoX1.SigTime:mm}\t");
  273. sb.Append($"{leoX1.SigTime:ss}\t");
  274. sb.Append($"{leoX1.SigTime:fff}\t");
  275. sb.Append($"{leoX1.CheckRes.SmpCount * 1000 / ch0File.Fs:D4}\t");//信号持续时间ms
  276. sb.Append($"{Convert.ToInt64(group.First().FreqDownMHz * 1e6):D12}\t");//下行频点
  277. sb.Append($"{Convert.ToInt64((group.First().FreqDownMHz + 44) * 1e6):D12}\t");//上行频点
  278. sb.Append($"{GetSignalType(deteResp.data[i].ModType)}\t");//信号样式(暂定有这些1:CPM,2:BPSK,4:QPSK,9:其它),
  279. sb.Append($"{0:D4}\t");//目标序号
  280. sb.Append($"res\t");
  281. sb.Append($"{Convert.ToInt64(posLon * 1e6):D10}\t");
  282. sb.Append($"{Convert.ToInt64(posLat * 1e6):D10}\t");
  283. sb.Append($"{Convert.ToInt64(0 * 1e3):D8}\t");//定位误差km
  284. sb.Append($"{Convert.ToInt64(leoX1.Dto1 * 1e2):D10}\t");
  285. sb.Append($"{Convert.ToInt64(leoX1.Dfo1 * 1e2):D10}\t");
  286. sb.Append($"{Convert.ToInt64(leoX1.Snr1 * 1e2):D6}\t");
  287. sb.Append($"{Convert.ToInt64(leoX1.Dto2 * 1e2):D10}\t");
  288. sb.Append($"{Convert.ToInt64(leoX1.Dfo2 * 1e2):D10}\t");
  289. sb.Append($"{Convert.ToInt64(leoX1.Snr2 * 1e2):D6}\t");
  290. sb.Append($"{Convert.ToInt64(0 * 1e2):D10}\t");
  291. sb.Append($"{Convert.ToInt64(0 * 1e2):D10}\t");
  292. sb.Append($"{Convert.ToInt64(0 * 1e2):D6}\t");
  293. sb.Append($"{(long)errRes.LongRadius:D8}\t");//长轴m
  294. sb.Append($"{(long)errRes.ShortRadius:D8}\t");//短轴m
  295. sb.Append($"{(long)errRes.DipAngle:D7}\t");//倾角°
  296. sb.Append($"{data1.Count:D2}\t");//时隙属性
  297. sb.Append($"{1}\t");//所属卫星
  298. sb.Append($"{100:D3}\t");//置信度
  299. sb.Append($"{4}\t");//定位体制(星地=3)
  300. sb.Append($"{(long)deteResp.data[i].ModRate.Value:D12}");//符号速率bps 12个
  301. sb.Append("\r\n");
  302. string resFile = Path.Combine(PosResDir, $"低轨单星定位结果_{posRes.SigTime:yyyyMMdd}.txt");
  303. File.AppendAllText(resFile, sb.ToString());
  304. }
  305. }
  306. catch (Exception ex)
  307. {
  308. LogHelper.Error($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz-时隙位置{data1[i].Smpstart}定位异常", ex);
  309. }
  310. }
  311. sw.Stop();
  312. LogHelper.Info($"【任务{dto.ID}】第{No}组{adTime:yyyyMMddHHmmss}时刻-信号{freq}MHz-定位完成,耗时{sw.ElapsedMilliseconds}ms");
  313. /* File.Delete(ch0File.File);
  314. File.Delete(ch1File.File);
  315. File.Delete(ch2File.File);*/
  316. }, cts.Token);
  317. listTask.Add(task);
  318. await Task.WhenAll(listTask);
  319. }
  320. #endregion
  321. }
  322. catch (TaskCanceledException ex)
  323. {
  324. LogHelper.Warning($"【任务{dto.ID}】处理结束,用户手动终止", ex.InnerException);
  325. }
  326. catch (Exception ex)
  327. {
  328. if (ex.InnerException != null && ex.InnerException.GetType() == typeof(TaskCanceledException))
  329. LogHelper.Warning($"【任务{dto.ID}】处理结束,用户手动终止", ex.InnerException);
  330. else
  331. LogHelper.Error($"【任务{dto.ID}】任务执行出错", ex);
  332. continue;
  333. }
  334. }
  335. }, cts.Token);
  336. }
  337. private double[] GetEph(string[] strs)
  338. {
  339. var TimeXYZ = new double[6] { Convert.ToDouble(strs[1]),
  340. Convert.ToDouble(strs[2]),
  341. Convert.ToDouble(strs[3]),
  342. Convert.ToDouble(strs[4]),
  343. Convert.ToDouble(strs[5]),
  344. Convert.ToDouble(strs[6]),
  345. };
  346. return TimeXYZ;
  347. }
  348. private int GetSignalType(string modTypestr)
  349. {
  350. EnumSignalTypeDto modType = modTypestr.GetEnumByDisplayName<EnumSignalTypeDto>();
  351. #warning 没有CPM调制方式
  352. //1:CPM,2:BPSK,4:QPSK,9:其他
  353. int signalType = 9;
  354. if (modType == EnumSignalTypeDto.BPSK)
  355. {
  356. signalType = 2;
  357. }
  358. else if (modType == EnumSignalTypeDto.QPSK)
  359. {
  360. signalType = 4;
  361. }
  362. return signalType;
  363. }
  364. private async Task<ErrEllipseResDto> GetErrEllipseResDto(ErrorEllipseLeoX1Dto dto,double posLon,double posLat)
  365. {
  366. ErrEllipseResDto errRes = new ErrEllipseResDto();
  367. if (posLon != 0 && posLat != 0 && posLon != 999 && posLat != 999)
  368. {
  369. var errResRsp = await HttpHelper.PostRequestAsync<ErrEllipseResDto>(baseUrl + "DetectCg/ErrorEllipseX1Leo", dto);
  370. errRes = errResRsp.data;
  371. }
  372. return errRes;
  373. }
  374. public void Stop()
  375. {
  376. cts?.Cancel();
  377. }
  378. private async Task StopTask(int taskID, EnumTaskStopType type, string stopReason)
  379. {
  380. await Task.Delay(2000);
  381. if (type == EnumTaskStopType.Properly)
  382. {
  383. LogHelper.Info($"【任务{taskID}】{stopReason}");
  384. }
  385. else
  386. {
  387. LogHelper.Error($"【任务{taskID}】{stopReason}");
  388. }
  389. TaskStopHandleDto stopDto = new TaskStopHandleDto() { ID = taskID, StopType = type, StopReason = stopReason };
  390. var stopResp = await HttpHelper.PostRequestAsync(baseUrl + "Task/StopTask", stopDto);
  391. if (stopResp.code != 200)
  392. {
  393. LogHelper.Error($"【任务{taskID}】停止异常.{stopResp.msg}");
  394. }
  395. }
  396. private AdFile StringToAdFile(string file)
  397. {
  398. //20240409094240_ADC_ch02.dat
  399. var name = Path.GetFileNameWithoutExtension(file).ToUpper();
  400. var arr = name.Split(new string[] { "_", "CH", "C", "XD" }, StringSplitOptions.RemoveEmptyEntries);
  401. var time = DateTime.ParseExact(arr[0], "yyyyMMddHHmmss", null);
  402. AdFile adFile = new AdFile()
  403. {
  404. File = file,
  405. AdTime = time,
  406. FreqDownMHz = Convert.ToDouble(arr[1]),
  407. Fs = Convert.ToInt32(arr[2]),
  408. XDNo = Convert.ToInt32(arr[4]),
  409. };
  410. return adFile;
  411. }
  412. }
  413. }