BaseDataReviewItemViewModel.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. using Avalonia.Collections;
  2. using Avalonia.Controls;
  3. using OxyPlot;
  4. using OxyPlot.Series;
  5. using Shaker.Models;
  6. using ShakerApp.Tools;
  7. using System;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using System.Data;
  11. using System.Diagnostics;
  12. using System.Diagnostics.CodeAnalysis;
  13. using System.Linq;
  14. using System.Text;
  15. namespace ShakerApp.ViewModels
  16. {
  17. public abstract class BaseDataReviewItemViewModel:DisplayViewModelBase<IModel>,IDataReviewItem
  18. {
  19. public BaseDataReviewItemViewModel()
  20. {
  21. TimeDomainReview = new TimeDomainReviewViewModel(this);
  22. THDReview = new THDReviewViewModel(this);
  23. ButtonVisibily = false;
  24. }
  25. private protected ShakerConfigModel ShakerConfig = new ShakerConfigModel();
  26. private protected ShakerControlModel ShakerControl = new ShakerControlModel();
  27. private protected DeviceInfoModel DeviceInfo = new DeviceInfoModel();
  28. private protected bool isopen = false;
  29. public bool IsOpen => isopen;
  30. public abstract MainPageType PageType { get; }
  31. public string File { get; } = string.Empty;
  32. [AllowNull]
  33. private protected TDMS.ITDMSFile tdmsfile;
  34. [AllowNull]
  35. public TimeDomainReviewViewModel TimeDomainReview { get; }
  36. [AllowNull]
  37. public THDReviewViewModel THDReview { get; }
  38. public virtual void OpenFile(string path)
  39. {
  40. tdmsfile?.Close();
  41. tdmsfile?.Dispose();
  42. tdmsfile = TDMS.TDMSDataBuilder.OpenExisting(path);
  43. isopen = true;
  44. InitConfig();
  45. }
  46. public virtual void InitData(TDMS.ITDMSFile file)
  47. {
  48. tdmsfile?.Close();
  49. tdmsfile?.Dispose();
  50. tdmsfile = file;
  51. isopen = true;
  52. InitConfig();
  53. }
  54. private protected virtual void InitConfig()
  55. {
  56. if (tdmsfile == null) return;
  57. var group = tdmsfile.Contains(nameof(ShakerConfigModel)) ? tdmsfile[nameof(ShakerConfigModel)] : null;
  58. if (group == null) return;
  59. GetConfig(ShakerConfig, group!);
  60. group = tdmsfile.Contains(nameof(ShakerControlModel)) ? tdmsfile[nameof(ShakerControlModel)] : null;
  61. if (group == null) return;
  62. GetConfig(ShakerControl, group!);
  63. group = tdmsfile.Contains(nameof(DeviceInfoModel)) ? tdmsfile[nameof(DeviceInfoModel)] : null;
  64. if (group == null) return;
  65. GetConfig(DeviceInfo, group!);
  66. TimeDomainReview.InitData();
  67. THDReview.InitData();
  68. InitData();
  69. }
  70. private protected void GetConfig<T>(T config,TDMS.ITDMSChannelGroup group)
  71. {
  72. typeof(T).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
  73. .ToList()
  74. .ForEach(x =>
  75. {
  76. if (x.FieldType.IsAssignableTo(typeof(IList)) || x.FieldType.IsArray)
  77. {
  78. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val))
  79. {
  80. byte[] bytes = new byte[val.Length / 2];
  81. for (int i = 0; i < bytes.Length; i++)
  82. {
  83. bytes[i] = System.Convert.ToByte(val.Substring(i * 2, 2), 16);
  84. }
  85. x.SetValue(config,ShakerApp.Tools.Tools.Deserialize(x.FieldType, bytes));
  86. }
  87. else
  88. {
  89. x.SetValue(config,Activator.CreateInstance(x.FieldType));
  90. }
  91. }
  92. else if(x.FieldType == typeof(string))
  93. {
  94. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val))
  95. {
  96. x.SetValue(config,val);
  97. }
  98. else
  99. {
  100. x.SetValue(config,string.Empty);
  101. }
  102. }
  103. else if (x.FieldType.IsEnum)
  104. {
  105. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val))
  106. {
  107. x.SetValue(config,Enum.Parse(x.FieldType, val));
  108. }
  109. else
  110. {
  111. x.SetValue(config,Enum.GetValues(x.FieldType));
  112. }
  113. }
  114. else if (x.FieldType == typeof(byte))
  115. {
  116. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && byte.TryParse(val, out var b))
  117. {
  118. x.SetValue(config,b);
  119. }
  120. else
  121. {
  122. x.SetValue(config,(byte)0);
  123. }
  124. }
  125. else if (x.FieldType == typeof(sbyte))
  126. {
  127. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && sbyte.TryParse(val, out var b))
  128. {
  129. x.SetValue(config,b);
  130. }
  131. else
  132. {
  133. x.SetValue(config,(sbyte)0);
  134. }
  135. }
  136. else if (x.FieldType == typeof(short))
  137. {
  138. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && short.TryParse(val, out var b))
  139. {
  140. x.SetValue(config,b);
  141. }
  142. else
  143. {
  144. x.SetValue(config,(short)0);
  145. }
  146. }
  147. else if (x.FieldType == typeof(ushort))
  148. {
  149. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && ushort.TryParse(val, out var b))
  150. {
  151. x.SetValue(config,b);
  152. }
  153. else
  154. {
  155. x.SetValue(config,(ushort)0);
  156. }
  157. }
  158. else if (x.FieldType == typeof(int))
  159. {
  160. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && int.TryParse(val, out var b))
  161. {
  162. x.SetValue(config,b);
  163. }
  164. else
  165. {
  166. x.SetValue(config,(int)0);
  167. }
  168. }
  169. else if (x.FieldType == typeof(uint))
  170. {
  171. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && uint.TryParse(val, out var b))
  172. {
  173. x.SetValue(config,b);
  174. }
  175. else
  176. {
  177. x.SetValue(config,(uint)0);
  178. }
  179. }
  180. else if (x.FieldType == typeof(long))
  181. {
  182. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && long.TryParse(val, out var b))
  183. {
  184. x.SetValue(config,b);
  185. }
  186. else
  187. {
  188. x.SetValue(config,(long)0);
  189. }
  190. }
  191. else if (x.FieldType == typeof(ulong))
  192. {
  193. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && ulong.TryParse(val, out var b))
  194. {
  195. x.SetValue(config,b);
  196. }
  197. else
  198. {
  199. x.SetValue(config,(ulong)0);
  200. }
  201. }
  202. else if (x.FieldType == typeof(float))
  203. {
  204. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && float.TryParse(val, out var b))
  205. {
  206. x.SetValue(config,b);
  207. }
  208. else
  209. {
  210. x.SetValue(config,(float)0);
  211. }
  212. }
  213. else if (x.FieldType == typeof(double))
  214. {
  215. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && double.TryParse(val, out var b))
  216. {
  217. x.SetValue(config,b);
  218. }
  219. else
  220. {
  221. x.SetValue(config,(double)0);
  222. }
  223. }
  224. else if (x.FieldType == typeof(bool))
  225. {
  226. if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && bool.TryParse(val, out var b))
  227. {
  228. x.SetValue(config,b);
  229. }
  230. else
  231. {
  232. x.SetValue(config,false);
  233. }
  234. }
  235. });
  236. }
  237. public virtual void CloseFile()
  238. {
  239. tdmsfile?.Close();
  240. tdmsfile?.Dispose();
  241. tdmsfile = null;
  242. }
  243. public class TimeDomainReviewViewModel : DisplayViewModelBase<IModel>
  244. {
  245. private bool isinint = false;
  246. List<OxyPlot.Series.LineSeries> _LineSeries = new List<OxyPlot.Series.LineSeries>();
  247. public OxyPlot.PlotModel PlotModel { get; } = new OxyPlot.PlotModel();
  248. private BaseDataReviewItemViewModel _Parent;
  249. public uint SampleRate { get => sampleRate; set =>SetProperty(ref sampleRate , value); }
  250. public uint TotalPages
  251. {
  252. get => Math.Clamp(totalPages, 1, uint.MaxValue);
  253. set
  254. {
  255. SetProperty(ref totalPages, value);
  256. OnPropertyChanged(nameof(MaxPageIndex));
  257. OnPropertyChanged(nameof(MaxReadPages));
  258. OnPropertyChanged(nameof(PageIndex));
  259. OnPropertyChanged(nameof(ReadPages));
  260. }
  261. }
  262. public uint PageIndex
  263. {
  264. get =>Math.Clamp(pageIndex,MinPageIndex,MaxPageIndex);
  265. set
  266. {
  267. SetProperty(ref pageIndex, value);
  268. OnPropertyChanged(nameof(MaxReadPages));
  269. OnPropertyChanged(nameof(ReadPages));
  270. LoadData();
  271. }
  272. }
  273. public uint MinPageIndex => 1;
  274. public uint MaxPageIndex => TotalPages;
  275. public uint ReadPages
  276. {
  277. get =>Math.Clamp(readPages,MinReadPages,MaxReadPages);
  278. set
  279. {
  280. SetProperty(ref readPages, value);
  281. LoadData();
  282. }
  283. }
  284. public uint MinReadPages => 1;
  285. public uint MaxReadPages => Math.Clamp(TotalPages - PageIndex + 1, 1, 10000);
  286. public TimeDomainReviewViewModel(BaseDataReviewItemViewModel parent)
  287. {
  288. _Parent = parent;
  289. PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis()
  290. {
  291. MajorGridlineStyle = OxyPlot.LineStyle.Solid,
  292. Position = OxyPlot.Axes.AxisPosition.Bottom,
  293. Key = "X",
  294. Title = App.Current?.FindResource("Time") +"",
  295. Unit = "s",
  296. MinimumPadding = 0,
  297. MaximumPadding = 0,
  298. });
  299. PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis()
  300. {
  301. MajorGridlineStyle = OxyPlot.LineStyle.Solid,
  302. Position = OxyPlot.Axes.AxisPosition.Left,
  303. Key = "Y",
  304. Title = App.Current?.FindResource("")+"",
  305. MinimumPadding = 0,
  306. MaximumPadding = 0,
  307. });
  308. PlotModel.Legends.Add(new OxyPlot.Legends.Legend()
  309. {
  310. IsLegendVisible = true,
  311. });
  312. }
  313. private TDMS.ITDMSChannelGroup? _DataGroup;
  314. private List<TDMS.ITDMSChannel> _Channels = new List<TDMS.ITDMSChannel>();
  315. private uint readPages;
  316. private uint pageIndex;
  317. private uint totalPages;
  318. private uint sampleRate;
  319. public override void InitData()
  320. {
  321. isinint = false;
  322. base.InitData();
  323. _DataGroup = _Parent.tdmsfile.Contains(BaseMainPageViewModel<IModel>.TimeDomainData) ? _Parent.tdmsfile[BaseMainPageViewModel<IModel>.TimeDomainData] : null;
  324. if (_DataGroup == null)
  325. {
  326. DataReviewViewModel.Instance.ShowError(App.Current?.FindResource("TestFileReadError")+"");
  327. return;
  328. }
  329. _Channels.Clear();
  330. _LineSeries.Clear();
  331. PlotModel.Series.Clear();
  332. if(_DataGroup.ChildCount ==0)
  333. {
  334. DataReviewViewModel.Instance.ShowError(App.Current?.FindResource("TestFileReadError") + "");
  335. return;
  336. }
  337. PlotModel.InvalidatePlot(false);
  338. for(ulong i=0;i<_DataGroup.ChildCount;i++)
  339. {
  340. _Channels.Add(_DataGroup[(int)i]!);
  341. _LineSeries.Add(new OxyPlot.Series.LineSeries()
  342. {
  343. XAxisKey = "X",
  344. YAxisKey = "Y",
  345. DataFieldX = nameof(OxyPlot.DataPoint.X),
  346. DataFieldY = nameof(OxyPlot.DataPoint.Y),
  347. Title = App.Current?.FindResource(_Channels[^1].Name)+"",
  348. Tag = _Channels[^1].Unit,
  349. });
  350. PlotModel.Series.Add(_LineSeries[^1]);
  351. }
  352. PlotModel.InvalidatePlot(true);
  353. SampleRate = _Parent.ShakerConfig.SampleRate;
  354. TotalPages = (uint)Math.Ceiling(_Channels[0].ChildCount / (double)SampleRate);
  355. ReadPages = 1;
  356. PageIndex = 1;
  357. isinint = true;
  358. LoadData();
  359. }
  360. private void LoadData()
  361. {
  362. if (!isinint) return;
  363. uint start = (PageIndex - 1) * SampleRate;
  364. uint len = ReadPages * SampleRate;
  365. len = (uint)Math.Clamp(len, len, _Channels[^1].ChildCount - start);
  366. double pro = 1d / SampleRate;
  367. //var datas = Enumerable.Repeat(new OxyPlot.DataPoint(), 1000_000).ToList();
  368. PlotModel.InvalidatePlot(false);
  369. for(int i=0;i<_Channels.Count;i++)
  370. {
  371. uint index = 0;
  372. _LineSeries[i].ItemsSource = _Channels[i].GetDataValues<double>(start, len).Select(x =>
  373. {
  374. return new OxyPlot.DataPoint((index++) * pro, x);
  375. }).ToList();
  376. // _LineSeries[i].ItemsSource = datas;
  377. }
  378. PlotModel.InvalidatePlot(true);
  379. }
  380. }
  381. public class THDReviewViewModel:DisplayViewModelBase<IModel>
  382. {
  383. private int[] indexLenght = new int[0];
  384. private List<TDMS.ITDMSChannel> channels = new List<TDMS.ITDMSChannel>();
  385. [AllowNull]
  386. TDMS.ITDMSChannel freqchannel;
  387. ulong datalen = 0;
  388. public uint MaxFrame => 10000;
  389. public uint Current
  390. {
  391. get => current;
  392. set
  393. {
  394. SetProperty(ref current, value);
  395. LoadData();
  396. }
  397. }
  398. public AvaloniaList<uint> Frames { get; } = new AvaloniaList<uint>();
  399. public bool IsFixed { get => isFixed; set =>SetProperty(ref isFixed ,value); }
  400. BaseDataReviewItemViewModel _parent;
  401. TDMS.ITDMSChannelGroup? _Group;
  402. private uint current = 1;
  403. private bool isFixed = true;
  404. public override string Title => IsFixed ? "SweepCount" : "THD";
  405. public THDReviewViewModel(BaseDataReviewItemViewModel parent)
  406. {
  407. _parent = parent;
  408. PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis()
  409. {
  410. Position = OxyPlot.Axes.AxisPosition.Bottom,
  411. MajorGridlineStyle = OxyPlot.LineStyle.Solid,
  412. Key="X",
  413. Title = App.Current?.FindResource("FrameXTitle")+ "",
  414. });
  415. PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis()
  416. {
  417. Position = OxyPlot.Axes.AxisPosition.Left,
  418. MajorGridlineStyle = OxyPlot.LineStyle.Solid,
  419. Title="THD",
  420. Unit ="%",
  421. Key ="Y",
  422. });
  423. PlotModel.Legends.Add(new OxyPlot.Legends.Legend()
  424. {
  425. IsLegendVisible = true,
  426. });
  427. }
  428. public override void InitData()
  429. {
  430. base.InitData();
  431. if(_parent.PageType == MainPageType.SinePage && _parent is SineDataReviewViewModel sine)
  432. {
  433. if(sine.SweepConfig.SignalType == SignalType.Fixed)
  434. {
  435. PlotModel.Axes[0].Title = App.Current?.FindResource("FrameXTitle") + "";
  436. PlotModel.Axes[0].Unit = "";
  437. }
  438. else
  439. {
  440. PlotModel.Axes[0].Title = App.Current?.FindResource("Frequency") + "";
  441. PlotModel.Axes[0].Unit = "Hz";
  442. }
  443. IsFixed = sine.SweepConfig.SignalType == SignalType.Fixed;
  444. OnPropertyChanged(nameof(Title));
  445. }
  446. channels.Clear();
  447. PlotModel.Series.Clear();
  448. _Group = _parent.tdmsfile.Contains(BaseMainPageViewModel<IModel>.THDData) ? _parent.tdmsfile[BaseMainPageViewModel<IModel>.THDData] : null;
  449. if(IsEnabled && _Group!=null)
  450. {
  451. for(int i=0; i < (int)_Group.ChildCount;i++)
  452. {
  453. var ch = _Group[i];
  454. if (ch == null || !ShakerDataViewModel.Instance.AllowTHDChannels.Contains(ch.Name)) continue;
  455. channels.Add(ch);
  456. PlotModel.Series.Add(new OxyPlot.Series.LineSeries()
  457. {
  458. XAxisKey = "X",
  459. YAxisKey = "Y",
  460. DataFieldX = nameof(DataPoint.X),
  461. DataFieldY = nameof(DataPoint.Y),
  462. Title = App.Current?.FindResource(ch.Name)+"",
  463. });
  464. }
  465. freqchannel = _Group.Contains(nameof(SweepData.Frequency)) ? _Group[nameof(SweepData.Frequency)] : null;
  466. var sweepindexchannel = _Group.Contains(nameof(SineMainPageViewModel.SweepIndex)) ? _Group[nameof(SineMainPageViewModel.SweepIndex)] : null;
  467. if(sweepindexchannel!=null)
  468. {
  469. var max = sweepindexchannel.GetDataValues<int>((uint)sweepindexchannel.ChildCount-1, 1)[0];
  470. indexLenght = new int[max+1];
  471. int index = 0;
  472. for(int i=0;i<max+1;i++)
  473. {
  474. while (true)
  475. {
  476. uint readlen = Math.Min(MaxFrame, (uint)(sweepindexchannel.ChildCount - (uint)index));
  477. if (readlen == 0) break;
  478. var temp = sweepindexchannel.GetDataValues<int>((uint)index, readlen);
  479. int c = temp.Count(x => x == i);
  480. indexLenght[i] += c;
  481. if (c == readlen)
  482. {
  483. index += (int)readlen;
  484. continue;
  485. }
  486. else
  487. {
  488. if (temp[^1]!=i)
  489. {
  490. index += c;
  491. break;
  492. }
  493. }
  494. }
  495. }
  496. Frames.Clear();
  497. Frames.AddRange(Enumerable.Range(1, max+1).Select(x => (uint)x).ToList());
  498. }
  499. else
  500. {
  501. indexLenght = new int[0];
  502. var total = (int)Math.Ceiling(datalen / (float)MaxFrame);
  503. Frames.Clear();
  504. Frames.AddRange(Enumerable.Range(1, total).Select(x => (uint)x).ToList());
  505. }
  506. datalen = channels.Min(x => x.ChildCount);
  507. Current = 1;
  508. }
  509. else
  510. {
  511. PlotModel.InvalidatePlot(false);
  512. PlotModel.InvalidatePlot(true);
  513. }
  514. OnPropertyChanged(nameof(Frames));
  515. OnPropertyChanged(nameof(IsEnabled));
  516. }
  517. private void LoadData()
  518. {
  519. if (datalen == 0) return;
  520. if (_parent is not SineDataReviewViewModel sine) return;
  521. uint start = (Current - 1) * MaxFrame;
  522. uint len = (uint)Math.Min(datalen - (ulong)start, (ulong)MaxFrame);
  523. PlotModel.InvalidatePlot(false);
  524. if(freqchannel==null || sine.SweepConfig.SignalType == SignalType.Fixed)
  525. {
  526. for (int i = 0; i < channels.Count; i++)
  527. {
  528. int index = 0;
  529. (PlotModel.Series[i] as LineSeries)!.ItemsSource = channels[i].GetDataValues<float>(start, len).Select(x =>
  530. {
  531. return new DataPoint(index++, x * 100);
  532. }).ToList();
  533. }
  534. }
  535. else
  536. {
  537. start = 0;
  538. var indexindex = Frames.ToList().FindIndex(x => x == Current);
  539. if(indexindex>0)
  540. {
  541. start = (uint)indexLenght.Skip(indexindex).Sum();
  542. }
  543. len = (uint)indexLenght[indexindex];
  544. var freq = freqchannel.GetDataValues<double>(start, len);
  545. for (int i = 0; i < channels.Count; i++)
  546. {
  547. int index = 0;
  548. (PlotModel.Series[i] as LineSeries)!.ItemsSource = channels[i].GetDataValues<float>(start, len).Select(x =>
  549. {
  550. return new DataPoint(freq[index++], x * 100);
  551. }).ToList();
  552. }
  553. }
  554. PlotModel.InvalidatePlot(true);
  555. }
  556. public OxyPlot.PlotModel PlotModel { get; } = new OxyPlot.PlotModel();
  557. public bool IsEnabled => _Group != null && _Group.ChildCount > 0;
  558. }
  559. }
  560. }