Tools.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Runtime.CompilerServices;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Xml.Schema;
  9. namespace Shaker.Models.Tools
  10. {
  11. public static class Tools
  12. {
  13. /// <summary>
  14. /// 单边谱扩展到双边谱
  15. /// </summary>
  16. /// <param name="unilateralSpectrum"></param>
  17. /// <returns></returns>
  18. public static double[] UnilateralSpectrumToBilateralSpectrum(double[] unilateralSpectrum)
  19. {
  20. double[] result = new double[unilateralSpectrum.Length << 1];
  21. result[0] = unilateralSpectrum[0];
  22. Unsafe.CopyBlock(ref Unsafe.As<double, byte>(ref result[1]), ref Unsafe.As<double, byte>(ref unilateralSpectrum[0]), (uint)(unilateralSpectrum.Length * Unsafe.SizeOf<double>()));
  23. double[] temp = unilateralSpectrum.Reverse().ToArray();
  24. Unsafe.CopyBlock(ref Unsafe.As<double, byte>(ref result[unilateralSpectrum.Length+1]), ref Unsafe.As<double, byte>(ref temp[0]), (uint)((unilateralSpectrum.Length-1) * Unsafe.SizeOf<double>()));
  25. return result;
  26. }
  27. public static void CalcSlope(double[] x, double[] y,ref double k,ref double b)
  28. {
  29. if(x ==null || y==null || x.Length!=2||y.Length!=2)
  30. {
  31. k = 0;
  32. b = 0;
  33. return;
  34. }
  35. k = (y[1] - y[0]) / (x[1] - x[0]);
  36. b = y[0] - x[0] * k;
  37. }
  38. public static int FindFrequencyIndex(this SweepConfigModel model, double freq)
  39. {
  40. if (model.SweepItems.Count < 2) return -1;
  41. uint uintfreq = (uint)(freq * 100);
  42. for (int i = 0; i < model.SweepItems.Count - 1; i++)
  43. {
  44. if ((uint)(model.SweepItems[i].Frequency * 100) <= uintfreq && uintfreq <= (uint)(model.SweepItems[i + 1].Frequency * 100)) return i;
  45. }
  46. return model.SweepItems.Count - 1;
  47. }
  48. public static void CalcAmpt(this SweepConfigModel model, double freq,ref double value,ref double upstop,ref double upwarn,ref double downstop,ref double downwarn)
  49. {
  50. int index = model.FindFrequencyIndex(freq);
  51. if (index == -1) return;
  52. value = 0;
  53. SweepItemModel nowmodel = model.SweepItems[index];
  54. switch (nowmodel.SweepValueType)
  55. {
  56. case SweepValueType.FixedDisplacement:
  57. value = freq * nowmodel.Value * freq * 4 * Math.PI * Math.PI / 9800f;
  58. break;
  59. case SweepValueType.FixedVelocity:
  60. value = freq * 2 * Math.PI * nowmodel.Value / 9.8f;
  61. break;
  62. case SweepValueType.FixedAcceleration:
  63. value = nowmodel.Value;
  64. break;
  65. case SweepValueType.DynamicAcceleration:
  66. {
  67. if (index == model.SweepItems.Count - 1)
  68. {
  69. value = nowmodel.Value;
  70. }
  71. else
  72. {
  73. SweepItemModel nextmodel = model.SweepItems[index + 1];
  74. double k = 0;
  75. double b = 0;
  76. Tools.CalcSlope([Math.Log10(nowmodel.Frequency), Math.Log10(nextmodel.Frequency)], [Math.Log10(nowmodel.Value), Math.Log10(nextmodel.Value)], ref k, ref b);
  77. value = Math.Pow(10, k * Math.Log10(freq) + b);
  78. }
  79. }
  80. break;
  81. }
  82. upstop = Math.Pow(10, nowmodel.UpStop / 20) * value;
  83. upwarn = Math.Pow(10, nowmodel.UpWarn / 20) * value;
  84. downstop = Math.Pow(10, nowmodel.DownStop / 20) * value;
  85. downwarn = Math.Pow(10, nowmodel.DownWarn / 20) * value;
  86. }
  87. public static double CalcAmpt(this SweepConfigModel model, double freq)
  88. {
  89. int index = model.FindFrequencyIndex(freq);
  90. if (index == -1) return 0;
  91. double value = 0;
  92. SweepItemModel nowmodel = model.SweepItems[index];
  93. switch (nowmodel.SweepValueType)
  94. {
  95. case SweepValueType.FixedDisplacement:
  96. value = freq * nowmodel.Value * freq * 4 * MathF.PI*MathF.PI / 9800f;
  97. break;
  98. case SweepValueType.FixedVelocity:
  99. value = freq * 2 * MathF.PI * nowmodel.Value / 9.8f;
  100. break;
  101. case SweepValueType.FixedAcceleration:
  102. value = nowmodel.Value;
  103. break;
  104. case SweepValueType.DynamicAcceleration:
  105. {
  106. if (index == model.SweepItems.Count - 1)
  107. {
  108. value = nowmodel.Value;
  109. }
  110. else
  111. {
  112. SweepItemModel nextmodel = model.SweepItems[index + 1];
  113. double k = 0;
  114. double b = 0;
  115. Tools.CalcSlope(new double[] { Math.Log10(nowmodel.Frequency), Math.Log10(nextmodel.Frequency) }, new double[] { Math.Log10(nowmodel.Value), Math.Log10(nextmodel.Value) }, ref k, ref b);
  116. value = Math.Pow(10, k * Math.Log10(freq) + b);
  117. }
  118. }
  119. break;
  120. }
  121. return value;
  122. }
  123. public static double TimeToOCT(this SweepConfigModel model, double time)
  124. {
  125. double oct = 0;
  126. switch(model.SweepType)
  127. {
  128. case SweepType.Linear:
  129. oct = (model.EndFrequency - model.StartFrequency) / time * 60;
  130. break;
  131. case SweepType.Log:
  132. default:
  133. oct = Math.Log2(model.EndFrequency / model.StartFrequency) / time * 60;
  134. break;
  135. }
  136. return oct;
  137. }
  138. public static double OCTToTime(this SweepConfigModel model, double oct)
  139. {
  140. double time = 0;
  141. switch(model.SweepType)
  142. {
  143. case SweepType.Linear:
  144. time = (model.EndFrequency - model.StartFrequency) / oct * 60;
  145. break;
  146. case SweepType.Log:
  147. default:
  148. time = Math.Log2(model.EndFrequency / model.StartFrequency) / oct * 60;
  149. break;
  150. }
  151. return time;
  152. }
  153. public static double DisplacementToVelocity(double displacement, double freq)
  154. {
  155. return displacement * 2 * Math.PI * freq / 1000;
  156. }
  157. public static double DisplacementToAcceleration(double displacement, double freq)
  158. {
  159. return displacement * 2 * Math.PI * freq * 2*Math.PI*freq / 9800;
  160. }
  161. public static double VelocityToAcceleration(double velocity, double freq)
  162. {
  163. return velocity * 2 * Math.PI * freq / 9.8;
  164. }
  165. public static double VelocityToDisplacement(double velocity, double freq)
  166. {
  167. return velocity * 1000 / (2 * Math.PI * freq);
  168. }
  169. public static double AccelerationToDisplacement(double acceleration, double freq)
  170. {
  171. return acceleration * 9800 / (2 * Math.PI * freq * 2 * Math.PI * freq);
  172. }
  173. public static double AccelerationToVelocity(double acceleration, double freq)
  174. {
  175. return acceleration * 9.8f / (2 * Math.PI * freq );
  176. }
  177. /// <summary>
  178. /// 工程量转电压
  179. /// </summary>
  180. /// <param name="value">工程量</param>
  181. /// <param name="sensitivity">灵敏度</param>
  182. /// <returns>电压</returns>
  183. public static double QuantitiesToVoltage(double value, double sensitivity)
  184. {
  185. return value * sensitivity / 1000;
  186. }
  187. /// <summary>
  188. /// 工程量转电压
  189. /// </summary>
  190. /// <param name="value">工程量</param>
  191. /// <param name="sensitivity">灵敏度</param>
  192. /// <returns>电压</returns>
  193. public static float QuantitiesToVoltage(float value, float sensitivity)
  194. {
  195. return value * sensitivity / 1000;
  196. }
  197. /// <summary>
  198. /// 电压转工程量
  199. /// </summary>
  200. /// <param name="value">电压</param>
  201. /// <param name="sensitivity">灵敏度</param>
  202. /// <returns>工程量</returns>
  203. public static double VoltageToQuantities(double value, double sensitivity)
  204. {
  205. return value * 1000 / sensitivity;
  206. }
  207. /// <summary>
  208. /// 电压转工程量
  209. /// </summary>
  210. /// <param name="value">电压</param>
  211. /// <param name="sensitivity">灵敏度</param>
  212. /// <returns>工程量</returns>
  213. public static float VoltageToQuantities(float value, float sensitivity)
  214. {
  215. return value * 1000 / sensitivity;
  216. }
  217. /// <summary>
  218. /// 计算计数的间隔时间
  219. /// </summary>
  220. /// <param name="maxCount">最大计数</param>
  221. /// <returns></returns>
  222. public static double CalcInterval(uint maxCount)
  223. {
  224. return 1d / (maxCount << 1);
  225. }
  226. /// <summary>
  227. /// 二维数组转置
  228. /// </summary>
  229. /// <typeparam name="T"></typeparam>
  230. /// <param name="source"></param>
  231. /// <param name="destination"></param>
  232. /// <param name="rowcount"></param>
  233. /// <param name="colnumcount"></param>
  234. public static void ArrayTranspose<T>(ref T source, ref T destination, int rowcount, int colnumcount,int maxcolnumcount)
  235. {
  236. if (rowcount == 0 || colnumcount == 0) return;
  237. for (int i = 0; i < rowcount; i++)
  238. {
  239. for (int j = 0; j < colnumcount; j++)
  240. {
  241. Unsafe.Add(ref destination, i * maxcolnumcount + j) = Unsafe.Add(ref source, j * rowcount + i);
  242. }
  243. }
  244. }
  245. public static double CalcLevel(double currentlevel,double level)
  246. {
  247. return Math.Pow(10, level / 20) * currentlevel;
  248. }
  249. public static float CalcLevel(float currentlevel, float level)
  250. {
  251. return MathF.Pow(10, level / 20) * currentlevel;
  252. }
  253. /// <summary>
  254. /// 解交织
  255. /// </summary>
  256. /// <typeparam name="T"></typeparam>
  257. /// <param name="source"></param>
  258. /// <param name="destination"></param>
  259. /// <param name="rowcount"></param>
  260. /// <param name="colnumcount"></param>
  261. public static void Deinterweaving<T>(ref T source, ref T destination, int rowcount, int colnumcount,int maxcolnumcount) => ArrayTranspose(ref source, ref destination, rowcount, colnumcount,maxcolnumcount);
  262. public static byte[] CompressionBytes(byte[] arrays)
  263. {
  264. if (arrays == null || arrays.Length == 0) return new byte[0];
  265. using (MemoryStream ms =new MemoryStream())
  266. {
  267. using (System.IO.Compression.DeflateStream ds = new System.IO.Compression.DeflateStream(ms, System.IO.Compression.CompressionLevel.SmallestSize, true))
  268. {
  269. ds.Write(arrays, 0, arrays.Length);
  270. }
  271. return ms.ToArray();
  272. }
  273. }
  274. public static byte[] DecompressionBytes(byte[] arrays)
  275. {
  276. if (arrays == null || arrays.Length == 0) return new byte[0];
  277. using (MemoryStream ms = new MemoryStream(arrays))
  278. {
  279. using (System.IO.Compression.DeflateStream ds = new System.IO.Compression.DeflateStream(ms, System.IO.Compression.CompressionMode.Decompress,true))
  280. {
  281. using (MemoryStream memoryStream = new MemoryStream())
  282. {
  283. ds.CopyTo(memoryStream);
  284. return memoryStream.ToArray();
  285. }
  286. }
  287. }
  288. }
  289. public static byte[] CompressionWaves<T>(ref T f,uint count) where T : unmanaged
  290. {
  291. if(count==0)return new byte[0];
  292. byte[] temp = new byte[Unsafe.SizeOf<T>() * count];
  293. Unsafe.CopyBlock(ref temp[0], ref Unsafe.As<T, byte>(ref f), (uint)temp.Length);
  294. return CompressionBytes(temp);
  295. }
  296. public static T[] DecompressionWaves<T>(byte[] f) where T : unmanaged
  297. {
  298. if (f ==null || f.Length == 0) return new T[0];
  299. byte[] temp = DecompressionBytes(f);
  300. T[] result = new T[temp.Length / Unsafe.SizeOf<T>()];
  301. Unsafe.CopyBlock( ref Unsafe.As<T, byte>(ref result[0]),ref temp[0], (uint)temp.Length);
  302. return result;
  303. }
  304. public static HistogramData[] Histogram(ref float value,uint count,ref float max,ref float min,int histogramCount = 256)
  305. {
  306. if (count == 0 || histogramCount ==0) return new HistogramData[0];
  307. max = float.MaxValue;
  308. min = float.MinValue;
  309. for(int i=0;i<count;i++)
  310. {
  311. max = MathF.Max(Unsafe.Add(ref value, i), max);
  312. min = MathF.Min(Unsafe.Add(ref value, i), min);
  313. }
  314. float invert = (max - min) / histogramCount;
  315. float temomin = min;
  316. var result = Enumerable.Range(0, (int)histogramCount).Select(x =>new HistogramData(x * invert + temomin, (x + 1) * invert + temomin, (uint)0)).ToArray();
  317. for(int i=0;i<count;i++)
  318. {
  319. int index = (int)Math.Floor((Unsafe.Add(ref value, i) - min) / invert);
  320. if (index == histogramCount) index--;
  321. result[index].H++;
  322. }
  323. return result;
  324. }
  325. public static HistogramData[] Histogram(ref float value, uint count, float max, float min, int histogramCount = 256)
  326. {
  327. if (count == 0 || histogramCount == 0) return new HistogramData[0];
  328. float invert = (max - min) / histogramCount;
  329. var result = Enumerable.Range(0, (int)histogramCount).Select(x => new HistogramData(x * invert + min, (x + 1) * invert + min, (uint)0)).ToArray();
  330. for (int i = 0; i < count; i++)
  331. {
  332. int index = (int)Math.Floor((Unsafe.Add(ref value, i) - min) / invert);
  333. if (index == histogramCount) index--;
  334. result[index].H++;
  335. }
  336. return result;
  337. }
  338. /// <summary>
  339. /// 按SI单位制为数字添加后缀
  340. /// </summary>
  341. /// <param name="value">需要转换的数字</param>
  342. /// <param name="decimals">小数位数</param>
  343. /// <param name="unit">附加单位</param>
  344. /// <returns></returns>
  345. public static string ValueChangeToSI(double value,double exp = 1000, int decimals = 1, string unit = "", bool invalid = false)
  346. {
  347. string formatstring = "#0";
  348. if (!invalid)
  349. {
  350. if (decimals > 0)
  351. {
  352. formatstring += ".";
  353. for (int i = 0; i < decimals; i++) formatstring += "#";
  354. }
  355. }
  356. else
  357. {
  358. formatstring = "N" + decimals;
  359. }
  360. if (double.IsNaN(value)) return "NaN";
  361. if (value == 0)
  362. {
  363. return value.ToString(formatstring) + unit;
  364. }
  365. if (Math.Abs(value) < 0.0000000000001) return Math.Round(0f, decimals) + unit;
  366. string SI = "yzafpnμmDkMGTPEZY";
  367. double d = Math.Log(Math.Abs(value), exp);
  368. double number = Math.Round(value / Math.Pow(exp, Math.Floor(d)), decimals);
  369. d += 8;
  370. string s = SI.Substring((int)d, 1);
  371. if (s == "D") s = "";
  372. return number.ToString(formatstring) + s + unit;
  373. }
  374. public static void CalcAmpt(ref float value, uint count,float max,float min, ref float highlevel,ref float lowlevel,ref float ampt)
  375. {
  376. if (count == 0) return;
  377. if(count ==1)
  378. {
  379. highlevel = value;
  380. lowlevel = value;
  381. ampt = 0;
  382. return;
  383. }
  384. var hisdata = Histogram(ref value, count,max,min);
  385. var orderdata = hisdata.OrderBy(x => x.H).ToArray();
  386. if((orderdata[^1].H + orderdata[^2].H)/(float)count>=0.05f)
  387. {
  388. int index1 = Array.FindIndex(hisdata, x => x.H == orderdata[^1].H);
  389. int index2 = Array.FindIndex(hisdata, x => x.H == orderdata[^2].H);
  390. if(index1<index2)
  391. {
  392. lowlevel = hisdata[index1].Center;
  393. highlevel = hisdata[index2].Center;
  394. }
  395. else
  396. {
  397. lowlevel = hisdata[index1].Center;
  398. highlevel = hisdata[index1].Center;
  399. }
  400. ampt = highlevel - lowlevel;
  401. }
  402. else
  403. {
  404. highlevel = max;
  405. lowlevel = min;
  406. ampt = max - min;
  407. }
  408. }
  409. public struct HistogramData
  410. {
  411. public HistogramData()
  412. {
  413. }
  414. public HistogramData(float start, float end, uint h)
  415. {
  416. Start = start;
  417. End = end;
  418. H = h;
  419. }
  420. public float Start;
  421. public float End;
  422. public uint H;
  423. public float Center => (Start + End) / 2;
  424. }
  425. }
  426. }