BlowingScanAnaylze.cs 58.6 KB
Newer Older
1
using FLY.Thick.Blowing;
2
using FLY.Thick.Blowing.UI;
3
using FLY.Thick.BlowingScan.Common;
潘栩锋's avatar
潘栩锋 committed
4 5 6 7
using MathNet.Numerics.LinearAlgebra.Double;
using Misc;
using System;
using System.Collections.Generic;
8
using System.Collections.ObjectModel;
潘栩锋's avatar
潘栩锋 committed
9 10 11 12 13 14 15 16 17
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;

namespace FLY.Thick.BlowingScan.UI.Client
{
    public class BlowingScanAnaylze : INotifyPropertyChanged
    {
18
        const double FilmLengthMin = 5;
19
        const double FilmLengthMax = 70;
20 21
        const double RAngleMin = 200;
        const double RAngleMax = 360;
潘栩锋's avatar
潘栩锋 committed
22 23
        #region 缓存区

24

潘栩锋's avatar
潘栩锋 committed
25 26
        /// <summary>
        /// 从BlowingScanService 接收过来的数据;
27
        /// 缓冲区最后一个记录序号
潘栩锋's avatar
潘栩锋 committed
28
        /// </summary>
29
        public int BufListLastNo { get; private set; } = -1;
潘栩锋's avatar
潘栩锋 committed
30 31 32

        /// <summary>
        /// 从BlowingScanService 接收过来的数据;
33
        /// 缓冲区数量
潘栩锋's avatar
潘栩锋 committed
34
        /// </summary>
35
        public int BufListCount { get; private set; } = 0;
36

潘栩锋's avatar
潘栩锋 committed
37 38 39 40
        /// <summary>
        /// 从BlowingScanService 接收过来的数据;
        /// 缓冲区
        /// </summary>
41
        public List<FlyData_BlowingScan> mBufList = new List<FlyData_BlowingScan>();
潘栩锋's avatar
潘栩锋 committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
        public ObservableCollection<ScanInfoCell> ScanInfoList { get; } = new ObservableCollection<ScanInfoCell>();
        #endregion

        #region 试调整参数
        private int solvecnt = 4;
        /// <summary>
        /// 多少次扫描解一次方程
        /// </summary>
        public int SolveCnt
        {
            get { return solvecnt; }
            set
            {
                if (value < 4)
                    value = 4;

                if (solvecnt != value)
                {
                    solvecnt = value;
                }
            }
        }

        private int smooth = 1;
        /// <summary>
        /// 平滑
        /// </summary>
        public int Smooth
        {
            get { return smooth; }
            set
            {
                if (value < 0)
                    value = 0;
                if (smooth != value)
                {
                    smooth = value;
                }
            }
        }



        /// <summary>
        /// 旋转架转动角度
        /// </summary>
        public double RAngle { get; set; } = 350;


        /// <summary>
        /// 人字架到测厚仪膜的长度 单位m
        /// </summary>
        public double FilmLength { get; set; } = 23;

        #endregion

        #region 常量参数

        public int N2 { get; set; } = 400;

        public int Sensor { get; set; } = 240;


        public int OrgBoltNo { get; set; } = 1;

        public int NBolts { get; set; } = 88;

        #endregion

        #region 状态

        public bool IsStep2Ing { get; set; }

        #endregion

117 118
        #region 自动
        /// <summary>
119
        /// 旋转架转动角度 查找范围 50°
120
        /// </summary>
121
        public int RAngleRange { get; set; } = 90;
122 123

        /// <summary>
124
        /// 旋转架转动角度 查找范围 20m
125
        /// </summary>
126
        public int FilmLengthRange { get; set; } = 20;
127

128 129 130 131
        /// <summary>
        /// 查找过程信息
        /// </summary>
        public string SearchMsg { get; private set; }
132
        #endregion
133 134
        
        BlowingDetectCore mRDetectCore;
潘栩锋's avatar
潘栩锋 committed
135 136 137

        public BlowingScanAnaylze()
        {
138 139 140 141 142 143 144 145 146 147 148
            MarkNos = new List<MarkData> { MarkNo1, MarkNo2 };
            for (int i = 0; i < MarkNos.Count(); i++) {
                var markData = MarkNos[i];
                markData.Name = $"记录{i+1}";
                markData.PropertyChanged += MarkNo_PropertyChanged;
            }
           
            MarkNos[0].IsFocus = true;
        }
        public void Init(BlowingDetectCore mRDetectCore) {
            this.mRDetectCore = mRDetectCore;
潘栩锋's avatar
潘栩锋 committed
149 150 151 152
        }
        public int GetMarkNoFromRList(int idx)
        {
            if (idx >= ScanInfoList.Count())
153
                return BufListLastNo;
潘栩锋's avatar
潘栩锋 committed
154
            else if (idx < 0)
155
                return (BufListLastNo - (ScanInfoList.Count() - 1));
潘栩锋's avatar
潘栩锋 committed
156 157


158
            int markno = idx + (BufListLastNo - (ScanInfoList.Count() - 1));
潘栩锋's avatar
潘栩锋 committed
159 160 161 162 163

            return markno;
        }
        int GetIdxFromRList(int markno)
        {
164
            int idx = markno - (BufListLastNo - (ScanInfoList.Count() - 1));
潘栩锋's avatar
潘栩锋 committed
165 166 167 168 169 170
            if (idx >= ScanInfoList.Count())
                return -1;
            else if (idx < 0)
                return -1;
            return idx;
        }
171

潘栩锋's avatar
潘栩锋 committed
172 173 174 175

        private void MarkNo_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            MarkData markdata = sender as MarkData;
176
            if (e.PropertyName == nameof(MarkData.Number))
潘栩锋's avatar
潘栩锋 committed
177 178 179 180 181
            {
                int idx = GetIdxFromRList(markdata.Number);
                if (idx >= 0)
                {
                    markdata.IsValid = true;
182 183 184
                    var scanInfo = ScanInfoList[idx];
                    var flydata = mBufList[idx];
                    if (!scanInfo.HasCast)//解方程
潘栩锋's avatar
潘栩锋 committed
185
                        ToThicks_SolveEquation(idx);
186

187 188
                    markdata.StartTime = scanInfo.StartTime;
                    markdata.ThicksDT = scanInfo.ThicksDT;
189
                    markdata.Thks = scanInfo.thks;
190 191 192 193 194 195
                    markdata.R = scanInfo.R;

                    markdata.Direction = scanInfo.Direction;
                    markdata.Border = flydata.FilmRange;
                    markdata.PosOfGrid = flydata.PosOfGrid;
                    markdata.Time = flydata.Time;
潘栩锋's avatar
潘栩锋 committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
                }
                else
                {
                    markdata.IsValid = false;
                }
                UpdateCurrR();
                UpdateIsFocus();
            }
        }
        /// <summary>
        /// 能进入第2步解方程
        /// </summary>
        /// <returns></returns>
        public bool CanStep2()
        {
211
            if (mBufList.Count() == 0)
潘栩锋's avatar
潘栩锋 committed
212 213 214 215 216
                return false;
            else if (IsStep2Ing)
                return false;
            return true;
        }
217 218 219



潘栩锋's avatar
潘栩锋 committed
220 221 222 223 224 225
        /// <summary>
        /// 更新 BufList
        /// </summary>
        /// <param name="firstbm"></param>
        /// <param name="lastbm"></param>
        /// <param name="datas"></param>
226
        public void Step1(int lastNo, List<FlyData_BlowingScan> datas, bool isAdd)
潘栩锋's avatar
潘栩锋 committed
227
        {
228 229 230 231 232 233 234 235
            if (!isAdd)
                mBufList.Clear();
            
            BufListLastNo = lastNo;
            mBufList.AddRange(datas);
            BufListCount = mBufList.Count();

            if (mBufList.Count()==0)
236
                return;
237

潘栩锋's avatar
潘栩锋 committed
238 239 240 241
            BufList2ScanInfoList();


            //当MarkNo1.Number 不在范围内, 限制它们
242 243 244 245 246 247 248 249 250 251 252 253
            for (int i = 0; i < MarkNos.Count(); i++) {
                var markData = MarkNos[i];
                if (markData.Number == -1)
                    markData.Number = GetDefaultNumber();
                markData.Number = KeepInRange(markData.Number);

                if (i > 0) {
                    if (markData.Number == MarkNos[i-1].Number)
                    {
                        markData.Number = MarkNos[i - 1].Number + SolveCnt;
                    }
                }
潘栩锋's avatar
潘栩锋 committed
254 255
            }
        }
256 257 258 259 260 261 262 263
        int GetDefaultNumber()
        {
            int count = mBufList.Count();
            int endNo = BufListLastNo;

            int beginNo = endNo - count + 1;
            return beginNo + SolveCnt;
        }
264
        public int KeepInRange(int no)
潘栩锋's avatar
潘栩锋 committed
265
        {
266 267 268 269 270 271 272 273 274 275 276 277 278
            int count = mBufList.Count();
            int endNo = BufListLastNo;

            int beginNo = endNo - count + 1;

            int index = no - beginNo;
            if (index < 0)
                index = 0;
            else if (index >= count)
                index = count;
            no = beginNo + index;

            return no;
潘栩锋's avatar
潘栩锋 committed
279 280 281 282 283 284 285 286

        }
        /// <summary>
        /// 解方程
        /// </summary>
        public void Step2()
        {
            IsStep2Ing = true;
287
            if (mBufList.Count()==0)
潘栩锋's avatar
潘栩锋 committed
288 289 290 291
            {
                IsStep2Ing = false;
                return;
            }
292
            GetSolveEquation();
潘栩锋's avatar
潘栩锋 committed
293
            ClearAllResult();
294 295
            foreach (var markData in MarkNos)
                markData.Refresh();
潘栩锋's avatar
潘栩锋 committed
296 297 298 299

            //ToThicks_SolveEquation();
            IsStep2Ing = false;
        }
300 301 302 303

        /// <summary>
        /// 自动查找旋转角度
        /// </summary>
304
        public void StepAutoSearchRAngle()
305
        {
306
            if (mBufList.Count() == 0)
307 308 309
                return;
            int idx1 = GetIdxFromRList(MarkNo1.Number);
            int idx2 = GetIdxFromRList(MarkNo2.Number);
310 311 312
            if (idx1 < 0 || idx2 < 0)
                return;
            if (idx1 == idx2)
313
            {
314 315 316
                SearchMsg = "查找失败!!记录1 与 记录2 必须不一样";
                return;
            }
潘栩锋's avatar
潘栩锋 committed
317

318 319 320 321 322 323 324 325
            List<Range> sameDirScanInfoIdxs = GetSameDirScanInfoIdxs();
            //两个都必须在相同的方向
            var r1 = sameDirScanInfoIdxs.Find(r => r.Contain(idx1));
            if (r1 == null)
                return;//异常,居然不属于任何一个方向
            if (!r1.Contain(idx2)) {
                SearchMsg = "查找失败!!记录1 与 记录2 必须在相同的方向";
                return;
326
            }
327 328 329 330 331 332 333 334 335 336 337 338 339 340



            IsStep2Ing = true;

            
            if (autoSearchRAngle(idx1, idx2, out double bestParam))
            {
                RAngle = bestParam;
                GetSolveEquation();
                ClearAllResult();
                MarkNos.ForEach(m => m.Refresh());
            }
            
341 342
            IsStep2Ing = false;
        }
343
        bool autoSearchRAngle(int idx1, int idx2, out double bestRa)
344 345
        {
            ParamRs.Clear();
346
            NotifyPropertyChanged(nameof(ParamRs));
347 348 349

            double minParam = RAngle - RAngleRange / 2;
            double maxParam = RAngle + RAngleRange / 2;
350 351 352 353
            if (minParam < RAngleMin)
                minParam = RAngleMin;
            if (maxParam > RAngleMax)
                maxParam = RAngleMax;
354 355 356 357

            double bestParam = RAngle;
            double bestR;

358 359
            //安全第一,刷新一下
            GetSolveEquationRange(RAngle, FilmLength, idx1, idx2);
360 361 362 363 364 365 366
            TrySolveEquationAndGetR(idx1, idx2, out bestR);

            while (true)
            {
                double step = (maxParam - minParam) / 8;
                if (step < 0.1)
                    step = 0.1;
367
                searchMsgHeader = $"最佳旋转角度={bestParam:F1}°相关性={bestR:F5} 步长={step:F1}";
368 369 370
                if (!SearchParam(minParam, maxParam, step, 0.05, out bestParam, out bestR,
                    (double par, out double r) =>
                    {
371 372 373
                        //GetSolveEquation(par, FilmLength, idx1);
                        //GetSolveEquation(par, FilmLength, idx2);
                        //获取角度信息
374 375 376 377 378 379
                        //for (int i = 0; i < mBufList.Count(); i++)
                        //{
                        //    GetSolveEquation(par, FilmLength, i);
                        //}
                        GetSolveEquationRange(par, FilmLength, idx1, idx2);

380 381 382 383 384 385
                        return TrySolveEquationAndGetR(idx1, idx2, out r);
                    })
                )
                {
                    //异常停止
                    bestRa = bestParam;
386
                    SearchMsg = $"最佳旋转角度={bestParam:F1}°相关性={bestR:F5}| 异常停止";
387 388 389 390 391 392
                    return false;
                }
                if (step <= 0.1)
                {
                    //查找完成
                    bestRa = bestParam;
393
                    SearchMsg = $"最佳旋转角度={bestParam:F1}°相关性={bestR:F5}| 查找完成";
394 395 396 397
                    return true;
                }
                minParam = bestParam - step * 2;
                maxParam = bestParam + step * 2;
398 399 400 401
                if (minParam < RAngleMin)
                    minParam = RAngleMin;
                if (maxParam > RAngleMax)
                    maxParam = RAngleMax;
402 403 404 405 406 407 408 409 410
            }

        }

        /// <summary>
        /// 自动查找膜距离
        /// </summary>
        public void StepAutoSearchFilmLength()
        {
411
            if (mBufList.Count() == 0)
412
                return;
413

414 415
            int idx1 = GetIdxFromRList(MarkNo1.Number);
            int idx2 = GetIdxFromRList(MarkNo2.Number);
416 417 418
            if (idx1 < 0 || idx2 < 0)
                return;
            if (idx1 == idx2)
419
            {
420 421 422
                SearchMsg = "查找失败!!记录1 与 记录2 必须不一样";
                return;
            }
423

424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
            List<Range> sameDirScanInfoIdxs = GetSameDirScanInfoIdxs();
            //两个都必须在不相同的方向
            var r1 = sameDirScanInfoIdxs.Find(r => r.Contain(idx1));
            if (r1 == null)
                return;//异常,居然不属于任何一个方向
            if (r1.Contain(idx2))
            {
                SearchMsg = "查找失败!!记录1 与 记录2 必须在不相同的方向";
                return;
            }


            IsStep2Ing = true;

            if (autoSearchFilmLength(idx1, idx2, out double bestParam))
            {
                FilmLength = bestParam;
                GetSolveEquation();
                ClearAllResult();
                MarkNos.ForEach(m => m.Refresh());
444
            }
445
            
446 447
            IsStep2Ing = false;
        }
448
        bool autoSearchFilmLength(int idx1, int idx2, out double bestFl)
449 450 451 452 453
        {
            ParamRs.Clear();

            double minParam = FilmLength - FilmLengthRange / 2;
            double maxParam = FilmLength + FilmLengthRange / 2;
454 455 456 457
            if (minParam < FilmLengthMin)
                minParam = FilmLengthMin;
            if (maxParam > FilmLengthMax)
                maxParam = FilmLengthMax;
458 459 460 461

            double bestParam = FilmLength;
            double bestR;

462 463
            //安全第一,刷新一下
            GetSolveEquationRange(RAngle, FilmLength, idx1, idx2);
464
            TrySolveEquationAndGetR(idx1, idx2, out bestR);
465
            
466 467 468 469 470 471

            while (true)
            {
                double step = (maxParam - minParam) / 8;
                if (step < 0.1)
                    step = 0.1;
472
                searchMsgHeader = $"最佳膜距离={bestParam:F1}m 相关性={bestR:F5} 步长={step:F1}";
473 474 475
                if (!SearchParam(minParam, maxParam, step, 0.05, out bestParam, out bestR,
                    (double par, out double r) =>
                    {
476 477 478
                        //GetSolveEquation(RAngle,par, SearchIdx1);
                        //GetSolveEquation(RAngle,par, SearchIdx2);
                        //获取角度信息
479 480 481 482 483
                        //for (int i = 0; i < mBufList.Count(); i++)
                        //{
                        //    GetSolveEquation(RAngle, par, i);
                        //}
                        GetSolveEquationRange(RAngle, par, idx1, idx2);
484 485 486 487 488 489
                        return TrySolveEquationAndGetR(idx1, idx2, out r);
                    })
                )
                {
                    //异常停止
                    bestFl = bestParam;
490
                    SearchMsg = $"最佳膜距离={bestParam:F1}m 相关性={bestR:F5}| 异常停止";
491 492 493 494 495 496
                    return false;
                }
                if (step <= 0.1)
                {
                    //查找完成
                    bestFl = bestParam;
497
                    SearchMsg = $"最佳膜距离={bestParam:F1}m 相关性={bestR:F5}| 查找完成";
498 499 500 501
                    return true;
                }
                minParam = bestParam - step * 2;
                maxParam = bestParam + step * 2;
502 503 504 505
                if (minParam < FilmLengthMin)
                    minParam = FilmLengthMin;
                if (maxParam > FilmLengthMax)
                    maxParam = FilmLengthMax;
506 507 508
            }
        }

509

510
        /// <summary>
511
        /// 自动查找膜距离2
512
        /// </summary>
513
        public void StepAutoSearchFilmLength2()
514
        {
515
            if (mBufList.Count() == 0)
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
                return;

            var markData = MarkNos.Find(m => m.IsFocus);
            if (markData == null)
                return;
            int idx = GetIdxFromRList(markData.Number);
            if (idx < 0)
                return;

            List<Range> sameDirScanInfoIdxs = GetSameDirScanInfoIdxs();
            //整个范围,必须横跨一个转向

            var r1 = sameDirScanInfoIdxs.Find(r => r.Contain(idx));
            if (r1 == null)
                return;//异常,居然不属于任何一个方向
            
            int idx2 = idx - SolveCnt + 1;

            if (r1.Contain(idx2))
535
            {
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
                SearchMsg = "查找失败!!解方程范围,必须横跨一个转向点";
                return;
            }



            IsStep2Ing = true;
            

  
            
           if (idx >= 0)
            {
                if (autoSearchFilmLength2(idx, out double bestParam))
                {
                    FilmLength = bestParam;
                    GetSolveEquation();
                    ClearAllResult();
                    MarkNos.ForEach(m => m.Refresh());
                }
            }
            IsStep2Ing = false;
        }
        bool autoSearchFilmLength2(int idx, out double bestFl)
        {
            ParamRs.Clear();

            double minParam = FilmLength - FilmLengthRange / 2;
            double maxParam = FilmLength + FilmLengthRange / 2;
            if (minParam < FilmLengthMin)
                minParam = FilmLengthMin;
            if (maxParam > FilmLengthMax)
                maxParam = FilmLengthMax;

            double bestParam = FilmLength;
            double bestR;

            GetSolveEquationRange(RAngle, FilmLength, idx);
            ToThicks_SolveEquation(idx);
            bestR = ScanInfoList[idx].R;

            while (true)
            {
                double step = (maxParam - minParam) / 8;
                if (step < 0.1)
                    step = 0.1;
                searchMsgHeader = $"最佳膜距离={bestParam:F1}m 自相关性={bestR:F5} 步长={step:F1}";

                if (!SearchParam(minParam, maxParam, step, 0.05, out bestParam, out bestR,
                    (double par, out double r) =>
                    {
                        //更新连续N个扫描的方程
                        GetSolveEquationRange(RAngle, par, idx);

                        bool ret = ToThicks_SolveEquation(idx);
                        r = ScanInfoList[idx].R;
                        return ret;
                    })
                )
                {
                    //异常停止
                    bestFl = bestParam;
                    SearchMsg = $"最佳膜距离={bestParam:F1}m 自相关性={bestR:F5}| 异常停止";
                    return false;
                }

                if (step <= 0.1)
                {
                    //查找完成
                    bestFl = bestParam;
                    SearchMsg = $"最佳膜距离={bestParam:F1}m 自相关性={bestR:F5}| 查找完成";
                    return true;
                }
                minParam = bestParam - step * 2;
                maxParam = bestParam + step * 2;

                if (minParam < FilmLengthMin)
                    minParam = FilmLengthMin;
                if (maxParam > FilmLengthMax)
                    maxParam = FilmLengthMax;
            }
        }




        /// <summary>
        /// 自动查找旋转角度
        /// </summary>
        public void StepAutoSearchRAngle2()
        {
            if (mBufList.Count() == 0)
                return;
            
            var markData = MarkNos.Find(m => m.IsFocus);
            if (markData == null)
                return;

            int idx = GetIdxFromRList(markData.Number);
            if (idx < 0)
636
                return;
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708

            IsStep2Ing = true;
            

            if (autoSearchRAngle2(idx, out double bestParam))
            {
                RAngle = bestParam;
                GetSolveEquation();
                ClearAllResult();

                MarkNos.ForEach(m => m.Refresh());
            }
            
            IsStep2Ing = false;
        }
        bool autoSearchRAngle2(int idx, out double bestRa)
        {
            ParamRs.Clear();
            NotifyPropertyChanged(nameof(ParamRs));

            double minParam = RAngle - RAngleRange / 2;
            double maxParam = RAngle + RAngleRange / 2;
            if (minParam < RAngleMin)
                minParam = RAngleMin;
            if (maxParam > RAngleMax)
                maxParam = RAngleMax;

            double bestParam = RAngle;
            double bestR;

            GetSolveEquationRange(RAngle, FilmLength, idx);
            ToThicks_SolveEquation(idx);
            bestR = ScanInfoList[idx].R;

            while (true)
            {
                double step = (maxParam - minParam) / 8;
                if (step < 0.1)
                    step = 0.1;
                searchMsgHeader = $"最佳旋转角度={bestParam:F1}°自相关性={bestR:F5} 步长={step:F1}";

                if (!SearchParam(minParam, maxParam, step, 0.05, out bestParam, out bestR,
                    (double par, out double r) =>
                    {

                        GetSolveEquationRange(par, FilmLength, idx);

                        bool ret = ToThicks_SolveEquation(idx);
                        r = ScanInfoList[idx].R;
                        return ret;
                    })
                )
                {
                    //异常停止
                    bestRa = bestParam;
                    SearchMsg = $"最佳旋转角度={bestParam:F1}°自相关性={bestR:F5}| 异常停止";
                    return false;
                }
                if (step <= 0.1)
                {
                    //查找完成
                    bestRa = bestParam;
                    SearchMsg = $"最佳旋转角度={bestParam:F1}°自相关性={bestR:F5}| 查找完成";
                    return true;
                }
                minParam = bestParam - step * 2;
                maxParam = bestParam + step * 2;

                if (minParam < RAngleMin)
                    minParam = RAngleMin;
                if (maxParam > RAngleMax)
                    maxParam = RAngleMax;
709
            }
710 711 712 713 714
            
        }


        List<Range> GetSameDirScanInfoIdxs() {
715 716 717 718

            List<Range> sameDirScanInfoIdxs = new List<Range>();

            //必须有个方向切换点
719
            for (int i = 0; i < ScanInfoList.Count(); i++)
720
            {
721
                int idx = i;
722 723
                var direction = ScanInfoList[idx].Direction;

724
                if (direction != DIRECTION.FIX)
725 726 727
                {
                    if (sameDirScanInfoIdxs.Count() == 0)
                        sameDirScanInfoIdxs.Add(new Range() { Begin = idx, End = idx });
728 729
                    else
                    {
730
                        Range range = sameDirScanInfoIdxs.Last();
731 732
                        int idxEnd = range.End;
                        if (ScanInfoList[idxEnd].Direction == direction)
733
                        {
734
                            range.End = idx;
735
                        }
736
                        else
737 738 739 740 741 742 743
                        {
                            //另一个方向
                            sameDirScanInfoIdxs.Add(new Range() { Begin = idx, End = idx });
                        }
                    }
                }
            }
744 745 746 747 748 749 750 751 752 753 754 755 756
            return sameDirScanInfoIdxs;
        }
        /// <summary>
        /// 自动查找全部参数
        /// </summary>
        public void StepAutoSearchParams()
        {
            IsStep2Ing = true;
            if (mBufList.Count() == 0)
            {
                IsStep2Ing = false;
                return;
            }
757

758
            List<Range> sameDirScanInfoIdxs = GetSameDirScanInfoIdxs();
759 760 761 762 763
            if (sameDirScanInfoIdxs.Count < 3)
            {
                SearchMsg = "查找失败!!旋转次数<3";
                goto _end;
            }
764

765 766
            int IdxOfSameDirRangeForSearchRAngle = -1;
            int IdxOfSameDirRangeForSearchFilmLength = -1;
767 768
            int minInfoCnt = SolveCnt * 2 + 2;
            for (int i = 1; i < sameDirScanInfoIdxs.Count - 1; i++)
769
            {
770
                int idx = sameDirScanInfoIdxs.Count - 1 - i;
771

772
                if (sameDirScanInfoIdxs[idx].Width > minInfoCnt)
773 774 775 776 777 778
                {
                    //合符要求
                    if (IdxOfSameDirRangeForSearchRAngle == -1)
                    {
                        IdxOfSameDirRangeForSearchRAngle = i;
                    }
779
                    else
780 781 782 783 784 785 786 787 788 789 790
                    {
                        IdxOfSameDirRangeForSearchFilmLength = i;
                        break;
                    }
                }
            }
            if (IdxOfSameDirRangeForSearchFilmLength == -1)
            {
                SearchMsg = $"查找失败!!不能找到连续2次 在相同旋转内 扫描次数大于 {minInfoCnt}";
                goto _end;
            }
791 792
            int idx1 = sameDirScanInfoIdxs[IdxOfSameDirRangeForSearchRAngle].Mid;
            int idx2 = sameDirScanInfoIdxs[IdxOfSameDirRangeForSearchRAngle].Mid + SolveCnt - 1;
793

794 795 796 797
            if (!autoSearchRAngle(idx1, idx2, out double bestRa))
            {
                SearchMsg = $"查找失败!!旋转角度查找失败";
                goto _end;
798
            }
799 800 801 802 803 804 805 806 807 808 809 810 811
            RAngle = bestRa;

            idx1 = sameDirScanInfoIdxs[IdxOfSameDirRangeForSearchRAngle].Mid + SolveCnt / 2;
            idx2 = sameDirScanInfoIdxs[IdxOfSameDirRangeForSearchFilmLength].Mid + SolveCnt / 2;
            if (!autoSearchFilmLength(idx1, idx2, out double bestFl))
            {
                SearchMsg = $"查找失败!!膜距离查找失败";
                goto _end;
            }
            FilmLength = bestFl;
            GetSolveEquation();
            ClearAllResult();

812 813 814 815
            MarkNos.ForEach(m => m.Refresh());

            MarkNo1.Number = GetMarkNoFromRList(idx1);
            MarkNo2.Number = GetMarkNoFromRList(idx2);
816

817
            _end:
818 819
            IsStep2Ing = false;
        }
820 821 822 823 824

        /// <summary>
        /// 通过自相关性 自动查找全部参数
        /// </summary>
        public void StepAutoSearchParams2()
825
        {
826 827
            IsStep2Ing = true;
            if (mBufList.Count() == 0)
828
            {
829 830
                IsStep2Ing = false;
                return;
831
            }
832 833 834
            List<Range> sameDirScanInfoIdxs = GetSameDirScanInfoIdxs();

            if (sameDirScanInfoIdxs.Count < 3)
835
            {
836 837
                SearchMsg = "查找失败!!旋转次数<3";
                goto _end;
838 839
            }

840 841
            //最后两个方向扫描数量误差不能大于2
            int width = sameDirScanInfoIdxs[sameDirScanInfoIdxs.Count() - 2].Width;
842

843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
            int solveCnt = width;
            if (solveCnt < 5)
                solveCnt = 5;

            int IdxOfSameDirRangeForSearch=-1;

            for (int i = 0; i < sameDirScanInfoIdxs.Count; i++)
            {
                int index = sameDirScanInfoIdxs.Count - 1 - i;
                int index0 = index - 1;
                //需要让 解方程 数为 minInfoCnt 对称 卡在 转向点 
                if (index0 >= 0)
                {
                    if ((sameDirScanInfoIdxs[index0].Width > solveCnt / 2) && (sameDirScanInfoIdxs[index].Width > solveCnt / 2))
                    {
                        IdxOfSameDirRangeForSearch = sameDirScanInfoIdxs[index].Begin + solveCnt / 2 - 1;
                        break;
                    }
                }
            }
            if (IdxOfSameDirRangeForSearch == -1)
            {
                SearchMsg = $"查找失败!!不能找到解方程 数为 {solveCnt} 对称 卡在 转向点";
                goto _end;
            }
            SolveCnt = solveCnt;

            if (!autoSearchFilmLength2(IdxOfSameDirRangeForSearch, out double bestFl))
            {
                SearchMsg = $"查找失败!!膜距离查找失败";
                goto _end;
            }
            FilmLength = bestFl;


            if (!autoSearchRAngle2(IdxOfSameDirRangeForSearch, out double bestRa))
            {
                SearchMsg = $"查找失败!!旋转角度查找失败";
                goto _end;
            }
            RAngle = bestRa;


            GetSolveEquation();
            ClearAllResult();

            MarkNos.ForEach(m => m.Refresh());

            MarkNo1.Number = GetMarkNoFromRList(IdxOfSameDirRangeForSearch);
            MarkNo2.Number = MarkNo1.Number - SolveCnt;

            _end:
            IsStep2Ing = false;
        }
        public class ParamR:INotifyPropertyChanged
        {
            public double Param { get; set; }
            public double R { get; set; }
            public ParamR(double par, double r)
            {
                Param = par;
                R = r;
            }

            public event PropertyChangedEventHandler PropertyChanged;

            public override string ToString()
            {
                return $"{Param:F2}:R={R:F5}";
            }
        }
        /// <summary>
        /// 旋转角度查找过程!!!
        /// </summary>
        public List<ParamR> ParamRs { get; set; } = new List<ParamR>();

        delegate bool GetRHandler(double param, out double r);

        string searchMsgHeader;
        /// <summary>
        /// 给定范围,步距,查找最大相关性时的旋转角度
        /// 中间过程记录在RaRs
        /// </summary>
        /// <param name="minPar">参数最小值</param>
        /// <param name="maxPar">参数最大值</param>
        /// <param name="step">步距</param>
        /// <param name="minStep">最小步距</param>
        /// <param name="bestPar">最佳参数</param>
        /// <param name="getR">更新参数解方程且获取相关性</param>
        /// <returns>不能解方程返回 false</returns>
        bool SearchParam(double minPar, double maxPar, double step, double minStep, out double bestPar, out double bestR, GetRHandler getR)
        {
            bestPar = 0;
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
            bestR = -1;
            List<ParamR> parList = new List<ParamR>();

            for (double par = minPar; par <= maxPar; par += step)
            {
                var rar = ParamRs.Find(_rar => Math.Abs(_rar.Param - par) < minStep);
                if (rar != null)
                {
                    //已经测试过!!!!
                    parList.Add(rar);
                    continue;
                }
                double r;
                bool ret = getR(par, out r);
                if (ret)
                {
                    parList.Add(new ParamR(par, r));
                }
                SearchMsg = searchMsgHeader + $"| 参数:{par:F1} 相关性={r:F5}";
            }
            if (parList.Count() == 0)
                return false;
            //找到最大值
            {
                double r = parList.Max(rar => rar.R);
                bestR = r;
                bestPar = parList.Find(_r => _r.R == r).Param;
            }
            //把列表插入到 RaRs
            foreach (var rar in parList)
            {
967
                if (ParamRs.Find(_rar => _rar.Param == rar.Param) == null)
968 969 970 971 972
                {
                    ParamRs.Add(rar);
                }
            }
            ParamRs.Sort((rar1, rar2) => { return rar1.Param.CompareTo(rar2.Param); });
973 974
            NotifyPropertyChanged(nameof(ParamRs));

975 976
            return true;
        }
潘栩锋's avatar
潘栩锋 committed
977 978 979
        /// <summary>
        /// 清除全部计算结果
        /// </summary>
980
        void ClearAllResult()
潘栩锋's avatar
潘栩锋 committed
981 982 983 984 985 986 987 988
        {
            for (int i = 0; i < mBufList.Count(); i++)
            {
                ScanInfoCell scaninfo = ScanInfoList[i];
                scaninfo.HasCast = false;
            }
        }

989

潘栩锋's avatar
潘栩锋 committed
990 991 992 993 994 995 996 997 998 999 1000

        /// <summary>
        /// 转为 位置与厚度信息
        /// </summary>
        void BufList2ScanInfoList()
        {
            ScanInfoList.Clear();
            for (int i = 0; i < mBufList.Count(); i++)
            {
                FlyData_BlowingScan f = mBufList[i];
                int posOfGrid = f.PosOfGrid;
1001
                //有效数据范围
潘栩锋's avatar
潘栩锋 committed
1002
                Range boltrange = new Range() { Begin = f.FilmRange.Begin + Sensor / 2 + N2, End = f.FilmRange.End - (Sensor / 2 + N2) };
1003
                //膜边界
潘栩锋's avatar
潘栩锋 committed
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
                Range border = f.FilmRange;

                ScanInfoCell scaninfocell = new ScanInfoCell(NBolts, OrgBoltNo);

                //对应的grid号
                int bp_idx = boltrange.Begin / posOfGrid;
                int ep_idx = boltrange.End / posOfGrid;

                if (bp_idx < 0)
                    bp_idx = 0;

1015 1016
                if (ep_idx > (f.Thks.Length - 1))
                    ep_idx = f.Thks.Length - 1;
潘栩锋's avatar
潘栩锋 committed
1017

1018 1019
                double sum = 0;
                int cnt = 0;
潘栩锋's avatar
潘栩锋 committed
1020 1021 1022 1023
                for (int j = bp_idx; j <= ep_idx; j++)
                {
                    int idx = j;
                    int pos = j * posOfGrid + posOfGrid / 2;//一个grid的中间脉冲,也就是大概而已
1024 1025
                    double thk = f.Thks[idx];
                    sum += thk;
1026
                    cnt++;
潘栩锋's avatar
潘栩锋 committed
1027 1028

                    pos -= border.Begin;//膜上面的位置
1029
                    ScanPosCell scanpos = new ScanPosCell() { pos = pos, thk = thk, dt = f.ThicksDt[idx] };
潘栩锋's avatar
潘栩锋 committed
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

                    //scaninfocell.StartTime 为整幅数据最早的时间
                    if (j == bp_idx)
                    {
                        scaninfocell.StartTime = scanpos.dt;
                    }
                    else
                    {
                        if (scaninfocell.StartTime > scanpos.dt)
                            scaninfocell.StartTime = scanpos.dt;
                    }
                    scaninfocell.frame.Add(scanpos);
                }
1043
                if (cnt > 0)
1044
                    sum = sum / cnt;
1045 1046
                scaninfocell.Avg = sum;

潘栩锋's avatar
潘栩锋 committed
1047 1048 1049 1050 1051 1052
                ScanInfoList.Add(scaninfocell);
            }



        }
1053

潘栩锋's avatar
潘栩锋 committed
1054
        /// <summary>
1055
        /// 第2步,修改 旋转角度,膜距离 执行, 耗时很短
潘栩锋's avatar
潘栩锋 committed
1056
        /// </summary>
1057
        void GetSolveEquation()
潘栩锋's avatar
潘栩锋 committed
1058
        {
1059
            //获取角度信息
潘栩锋's avatar
潘栩锋 committed
1060 1061
            for (int i = 0; i < mBufList.Count(); i++)
            {
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
                GetSolveEquation(RAngle, FilmLength, i);
            }
        }

        /// <summary>
        /// 更新idx1, idx2前面连续SolveCnt个扫描的方程
        /// </summary>
        /// <param name="rAngle"></param>
        /// <param name="filmLength"></param>
        /// <param name="idx1"></param>
        /// <param name="idx2"></param>
        void GetSolveEquationRange(double rAngle, double filmLength, int idx1, int idx2) 
        {
            List<int> getSolveIdxs = new List<int>();

            for (int i = 0; i < SolveCnt; i++)
            {
                int index = idx1 - i;
                if (index >= 0)
潘栩锋's avatar
潘栩锋 committed
1081
                {
1082 1083
                    if (!getSolveIdxs.Contains(index))
                        getSolveIdxs.Add(index);
潘栩锋's avatar
潘栩锋 committed
1084
                }
1085 1086
                index = idx2 - i;
                if (index >= 0)
潘栩锋's avatar
潘栩锋 committed
1087
                {
1088 1089
                    if (!getSolveIdxs.Contains(index))
                        getSolveIdxs.Add(index);
潘栩锋's avatar
潘栩锋 committed
1090 1091
                }
            }
1092
            foreach (var index in getSolveIdxs)
潘栩锋's avatar
潘栩锋 committed
1093
            {
1094
                GetSolveEquation(rAngle, filmLength, index);
潘栩锋's avatar
潘栩锋 committed
1095 1096
            }
        }
1097

潘栩锋's avatar
潘栩锋 committed
1098
        /// <summary>
1099
        /// 更新idx前面连续SolveCnt个扫描的方程
潘栩锋's avatar
潘栩锋 committed
1100
        /// </summary>
1101 1102 1103 1104
        /// <param name="rAngle"></param>
        /// <param name="filmLength"></param>
        /// <param name="idx"></param>
        void GetSolveEquationRange(double rAngle, double filmLength, int idx) 
潘栩锋's avatar
潘栩锋 committed
1105
        {
1106
            for (int i = 0; i < SolveCnt; i++)
潘栩锋's avatar
潘栩锋 committed
1107
            {
1108 1109 1110 1111
                int index = idx - i;
                if (index < 0)
                    break;
                GetSolveEquation(rAngle, filmLength, index);
1112
            }
1113
        }
潘栩锋's avatar
潘栩锋 committed
1114

1115 1116 1117 1118 1119 1120
        /// <summary>
        /// 只获取某次扫描的方程
        /// </summary>
        /// <param name="rAngle"></param>
        /// <param name="filmLength"></param>
        /// <param name="idx"></param>
1121
        void GetSolveEquation(double rAngle, double filmLength, int idx)
1122 1123 1124
        {
            FlyData_BlowingScan f = mBufList[idx];
            ScanInfoCell scaninfocell = ScanInfoList[idx];
潘栩锋's avatar
潘栩锋 committed
1125

1126
            scaninfocell.equationList.Clear();
潘栩锋's avatar
潘栩锋 committed
1127

1128
            scaninfocell.State = ScanInfoCell.STATE.OK;
潘栩锋's avatar
潘栩锋 committed
1129

1130 1131 1132
            for (int j = 0; j < scaninfocell.frame.Count(); j++)
            {
                ScanPosCell scanpos = scaninfocell.frame[j];
潘栩锋's avatar
潘栩锋 committed
1133

1134 1135
                mRDetectCore.RAngle = rAngle;
                mRDetectCore.FilmLength = filmLength;
1136

1137 1138 1139
                int ret = mRDetectCore.GetFilmInfo(
                    out FilmInfo filminfo,
                    scanpos.dt, f.FilmRange.Width, scanpos.pos);
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

                //探头直径转为角度范围
                double sensor_angle = 180.0 * Sensor / f.FilmRange.Width;

                if (ret == 0)
                {
                    scanpos.angle1 = filminfo.angle1;
                    scanpos.angle2 = filminfo.angle2;
                    scanpos.direction = filminfo.direction;
                    //TODO
                    scanpos.rotateAngle = 180 * scanpos.pos / f.FilmRange.Width;
                }
                else
                {
                    scaninfocell.State = ScanInfoCell.STATE.Err_GetAngle;
                    break;
                }
                if (j == 0)
                    scaninfocell.Direction = scanpos.direction;
                else
                {
                    if (scaninfocell.Direction != scanpos.direction)
潘栩锋's avatar
潘栩锋 committed
1162
                    {
1163 1164
                        scaninfocell.Direction = DIRECTION.FIX;
                        scaninfocell.State = ScanInfoCell.STATE.Err_Solve;
潘栩锋's avatar
潘栩锋 committed
1165 1166 1167
                        break;
                    }
                }
1168 1169
                scaninfocell.AddEquation(j, sensor_angle);
            }
潘栩锋's avatar
潘栩锋 committed
1170 1171
        }

1172 1173 1174 1175 1176 1177 1178
        /// <summary>
        /// 解2次扫描的方程,且计算它们的相关性
        /// </summary>
        /// <param name="scaninfo_idx0"></param>
        /// <param name="scaninfo_idx1"></param>
        /// <param name="r"></param>
        /// <returns></returns>
1179
        bool TrySolveEquationAndGetR(int scaninfo_idx0, int scaninfo_idx1, out double r)
1180 1181
        {
            if (ToThicks_SolveEquation(scaninfo_idx0) && ToThicks_SolveEquation(scaninfo_idx1))
潘栩锋's avatar
潘栩锋 committed
1182
            {
1183 1184
                ScanInfoCell scaninfo0 = ScanInfoList[scaninfo_idx0];
                ScanInfoCell scaninfo1 = ScanInfoList[scaninfo_idx1];
1185
                r = Misc.MyMath.Correl(scaninfo0.thks, scaninfo1.thks);
1186
                return true;
潘栩锋's avatar
潘栩锋 committed
1187
            }
1188
            else
1189 1190 1191
            {
                r = -1;
                return false;
潘栩锋's avatar
潘栩锋 committed
1192

1193
            }
潘栩锋's avatar
潘栩锋 committed
1194
        }
1195 1196


潘栩锋's avatar
潘栩锋 committed
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
        bool ToThicks_SolveEquation(int scaninfo_idx)
        {
            ScanInfoCell scaninfo = ScanInfoList[scaninfo_idx];

            scaninfo.HasCast = true;

            if (scaninfo.State != ScanInfoCell.STATE.OK)
                return false;

            if (scaninfo.Direction == DIRECTION.FIX)//当前是Fix 不解方程
            {
                scaninfo.State = ScanInfoCell.STATE.Err_Solve;
                return false;
            }

            //全部方向都必须一致,当然也不能是Fix
            //for (int i = 0; i < (SolveCnt - 1); i++)
            //{
            //    if (scaninfo.Direction != ScanInfoList[scaninfo_idx - 1 - i].Direction)
            //    {
            //        scaninfo.State = ScanInfoCell.STATE.ERR_Solve_Maybe;
            //        break;
            //    }
            //}

            List<EquationCell> equationlist = new List<EquationCell>();
            scaninfo.solveMember.Clear();
1224 1225 1226

            
            for (int i = 0; i < SolveCnt; i++)
潘栩锋's avatar
潘栩锋 committed
1227
            {
1228 1229 1230 1231
                int index = scaninfo_idx - i;
                if (index < 0)
                    break;
                if (ScanInfoList[index].Direction == DIRECTION.FIX)
潘栩锋's avatar
潘栩锋 committed
1232 1233
                    continue;

1234
                equationlist.AddRange(ScanInfoList[index].equationList);
潘栩锋's avatar
潘栩锋 committed
1235
                //用到的扫描副
1236
                scaninfo.solveMember.Add(index);
潘栩锋's avatar
潘栩锋 committed
1237
            }
1238
            
潘栩锋's avatar
潘栩锋 committed
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
            //计算 每个分区的权
            for (int i = 0; i < scaninfo.power.Count(); i++)
            {
                scaninfo.power[i] = 0;
            }
            foreach (EquationCell e in equationlist)
            {
                foreach (KeyValuePair<int, int> kv in e.boltPower)
                {
                    //if(e.mainBolt == kv.Key)
1249
                    scaninfo.power[kv.Key] += kv.Value;
潘栩锋's avatar
潘栩锋 committed
1250 1251 1252 1253
                    //else
                    //    scaninfo.power[kv.Key+scaninfo.nbolts] += kv.Value;
                }
            }
1254

1255
            if (scaninfo.solveMember.Count() < 3) //方程不够!!!!
潘栩锋's avatar
潘栩锋 committed
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
            {
                scaninfo.State = ScanInfoCell.STATE.Err_Solve;
                return false;
            }

            if (equationlist.Count < 100)//方程数太少
            {
                scaninfo.State = ScanInfoCell.STATE.Err_Solve;
                return false;
            }
1266
            double[] thks = scaninfo.thks;
1267
            SolveEquation(equationlist, thks);
潘栩锋's avatar
潘栩锋 committed
1268 1269 1270 1271 1272


            //2105 条方程,耗时 0.3s
            //SolveEquation(equationlist, ScanInfoList[scaninfo_idx].thicks);

1273 1274
            //不能有任何一个double.NaN
            if (thks.Any(thk => double.IsNaN(thk)))
1275 1276
            {
                scaninfo.State = ScanInfoCell.STATE.Err_Solve;
1277
                return false;
1278
            }
1279

1280 1281 1282 1283 1284

            SmoothFrame(thks, Smooth);
            scaninfo.R = SingleR(equationlist, thks);


1285
            scaninfo.ThicksDT = ScanInfoList[scaninfo.solveMember.Last()].StartTime;
潘栩锋's avatar
潘栩锋 committed
1286

1287 1288 1289 1290 1291 1292 1293
            return true;
        }
        /// <summary>
        /// 平滑thks
        /// </summary>
        /// <param name="thks"></param>
        /// <param name="smooth">平滑半径</param>
1294
        static void SmoothFrame(double[] thks, int smooth)
1295 1296
        {
            if (smooth > 0)
潘栩锋's avatar
潘栩锋 committed
1297
            {
1298
                double[] data = new double[thks.Count()];
1299 1300

                for (int i = 0; i < thks.Count(); i++)
潘栩锋's avatar
潘栩锋 committed
1301
                {
1302
                    double sum = 0;
潘栩锋's avatar
潘栩锋 committed
1303

1304
                    for (int j = 0; j < (smooth * 2 + 1); j++)
潘栩锋's avatar
潘栩锋 committed
1305
                    {
1306
                        int index = i + j - smooth;
潘栩锋's avatar
潘栩锋 committed
1307
                        if (index < 0)
1308 1309 1310 1311
                            index += thks.Count();
                        else if (index >= thks.Count())
                            index -= thks.Count();
                        sum += thks[index];
潘栩锋's avatar
潘栩锋 committed
1312
                    }
1313
                    data[i] = sum / (smooth * 2 + 1);
潘栩锋's avatar
潘栩锋 committed
1314
                }
1315
                Array.Copy(data, thks, thks.Count());
潘栩锋's avatar
潘栩锋 committed
1316 1317
            }
        }
1318
        /// <summary>
1319
        /// 计算方程每个原始数据 与 结果的相关性
1320 1321 1322 1323
        /// </summary>
        /// <param name="equationList"></param>
        /// <param name="frame_out"></param>
        /// <returns></returns>
1324
        static double SingleR(List<EquationCell> equationList, double[] frame_out)
1325
        {
1326 1327
            List<double> calThks = new List<double>();
            List<double> actThks = new List<double>();
1328 1329 1330 1331 1332 1333 1334 1335
            foreach (EquationCell ec in equationList)
            {
                double[] datas = ec.GetPower(frame_out.Count());
                double sum = 0;
                double cnt = 0;
                foreach (var kv in ec.boltPower)
                {
                    sum += frame_out[kv.Key] * kv.Value;
1336
                    cnt += kv.Value;
1337 1338 1339
                }
                if (cnt > 0)
                {
1340
                    double totalThk = sum / cnt;
1341
                    calThks.Add(totalThk);
1342
                    
1343
                    actThks.Add(ec.thk);
1344 1345 1346 1347
                }
            }
            return Misc.MyMath.Correl(calThks, actThks);
        }
潘栩锋's avatar
潘栩锋 committed
1348 1349 1350 1351 1352
        /// <summary>
        /// 解方程
        /// </summary>
        /// <param name="equationList">N条方程</param>
        /// <param name="frame_out">输出的结果</param>
1353
        void SolveEquation(List<EquationCell> equationList, double[] frame_out)
潘栩锋's avatar
潘栩锋 committed
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
        {

            int nrow = equationList.Count();
            //A~AX = A~B
            //转换为 DenseMatrix 与 DenseVector
            DenseMatrix matrixA = new DenseMatrix(nrow, NBolts);
            DenseMatrix matrixAT = new DenseMatrix(NBolts, nrow);
            DenseVector vectorB = new DenseVector(nrow);
            DenseVector vectorATB = new DenseVector(NBolts);


            int rowindex = 0;

            foreach (EquationCell ec in equationList)
            {

                double[] datas = ec.GetPower(NBolts);

                matrixA.SetRow(rowindex, datas);

                matrixAT.SetColumn(rowindex, datas);
1375
                vectorB[rowindex] = ec.thk;
潘栩锋's avatar
潘栩锋 committed
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
                rowindex++;
            }

            DenseMatrix ATA = (DenseMatrix)matrixA.TransposeThisAndMultiply(matrixA);
            DenseVector ATB = (DenseVector)matrixA.TransposeThisAndMultiply(vectorB);

            DenseVector X = (DenseVector)ATA.Solve(ATB);

            int j;
            for (int i = 0; i < NBolts; i++)
            {
1387
                frame_out[i] = X[i];
潘栩锋's avatar
潘栩锋 committed
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
            }
        }

        #region INotifyPropertyChanged 接口
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        #endregion



        #region 两组数据

1406
        public double CurrR { get; set; } = -1;
潘栩锋's avatar
潘栩锋 committed
1407

1408 1409
        public MarkData MarkNo1 { get; } = new MarkData();
        public MarkData MarkNo2 { get; } = new MarkData();
潘栩锋's avatar
潘栩锋 committed
1410

1411
        public List<MarkData> MarkNos { get; private set; }
潘栩锋's avatar
潘栩锋 committed
1412 1413 1414 1415
        void UpdateCurrR()
        {
            if (MarkNo1.IsValid && MarkNo2.IsValid)
            {
1416
                CurrR = Misc.MyMath.Correl(MarkNo1.Thks, MarkNo2.Thks);
潘栩锋's avatar
潘栩锋 committed
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
            }
            else
            {
                CurrR = -1;
            }
        }
        void UpdateIsFocus()
        {
            int idx1 = GetIdxFromRList(MarkNo1.Number);
            int idx2 = GetIdxFromRList(MarkNo2.Number);

            for (int i = 0; i < ScanInfoList.Count(); i++)
            {
                ScanInfoList[i].IsFocus = false;
                ScanInfoList[i].IsFocus2 = false;
            }

            if (idx1 > 0)
            {
                ScanInfoList[idx1].IsFocus = true;
                foreach (int i in ScanInfoList[idx1].solveMember)
                {
                    ScanInfoList[i].IsFocus = true;
                }
            }

            if (idx2 > 0)
            {
                ScanInfoList[idx2].IsFocus2 = true;
                foreach (int i in ScanInfoList[idx2].solveMember)
                {
                    ScanInfoList[i].IsFocus2 = true;
                }
            }
        }
1452

潘栩锋's avatar
潘栩锋 committed
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482

        #endregion

        #region 调试
        public bool Save(string path)
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(path, false, Encoding.GetEncoding("GB2312")))
                {
                    bool hasHeader = false;
                    foreach (FlyData_BlowingScan f in mBufList)
                    {
                        if (!hasHeader)
                        {
                            hasHeader = true;
                            sw.WriteLine(f.GetHeader());
                        }
                        sw.WriteLine(f.ToString());
                    }
                    sw.Flush();
                    sw.Close();
                }
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }
1483
        public bool Load(string path, out List<FlyData_BlowingScan> bufList)
潘栩锋's avatar
潘栩锋 committed
1484
        {
1485
            bufList = new List<FlyData_BlowingScan>();
潘栩锋's avatar
潘栩锋 committed
1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496

            using (StreamReader sr = new StreamReader(path, Encoding.GetEncoding("GB2312")))
            {
                string header = sr.ReadLine();

                while (!sr.EndOfStream)
                {
                    string s = sr.ReadLine();
                    FlyData_BlowingScan f = new FlyData_BlowingScan();
                    if (f.TryParse(header, s))
                    {
1497
                        bufList.Add(f);
潘栩锋's avatar
潘栩锋 committed
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        #endregion

    }

    public class GageData : INotifyPropertyChanged
    {
        private Range border = new Range();
        /// <summary>
        /// 膜边界,单位脉冲
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public Range Border { get; set; }


        /// <summary>
        /// pos / grid
        /// </summary>
        public int PosOfGrid { get; set; } = 10;



        /// <summary>
        /// 厚度数据,  大小 grid总数
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public int[] OrgThicks { get; set; }




        #region INotifyPropertyChanged 接口

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
    public class MarkData : INotifyPropertyChanged
    {
1545 1546
        public string Name { get; set; } = "记录";

潘栩锋's avatar
潘栩锋 committed
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556
        public int Number { get; set; } = -1;

        /// <summary>
        /// 获取了焦点
        /// </summary>
        public bool IsFocus { get; set; }
        /// <summary>
        /// 有效
        /// </summary>
        public bool IsValid { get; set; }
1557

潘栩锋's avatar
潘栩锋 committed
1558 1559 1560 1561 1562
        /// <summary>
        /// 扫描时间
        /// </summary>
        public DateTime StartTime { get; set; } = DateTime.MinValue;

1563

潘栩锋's avatar
潘栩锋 committed
1564 1565 1566 1567 1568
        /// <summary>
        /// 旋转架旋转的方向,当同一次扫描中,有两个方向,Direction= Fix;
        /// </summary>
        public Misc.DIRECTION Direction { get; set; } = DIRECTION.FORWARD;

1569

潘栩锋's avatar
潘栩锋 committed
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
        /// <summary>
        /// 下面解方程得到的一幅数据对应的数据,与 StartTime 不一样
        /// </summary>
        public DateTime ThicksDT { get; set; } = DateTime.MinValue;


        /// <summary>
        /// 一幅数据
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
1580
        public double[] Thks { get; set; }
潘栩锋's avatar
潘栩锋 committed
1581

1582

潘栩锋's avatar
潘栩锋 committed
1583 1584 1585 1586 1587 1588
        /// <summary>
        /// 膜边界,单位脉冲
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public Range Border { get; set; }

1589

潘栩锋's avatar
潘栩锋 committed
1590 1591 1592 1593
        /// <summary>
        /// pos / grid
        /// </summary>
        public int PosOfGrid { get; set; } = 10;
1594

潘栩锋's avatar
潘栩锋 committed
1595 1596 1597 1598
        /// <summary>
        /// orgthick时间
        /// </summary>
        public DateTime Time { get; set; } = DateTime.MinValue;
1599

1600 1601 1602 1603
        /// <summary>
        /// 方程数据与解方程后的结果相关性
        /// </summary>
        public double R { get; set; } = -1;
潘栩锋's avatar
潘栩锋 committed
1604 1605 1606 1607 1608 1609 1610
        public MarkData()
        {

        }

        public void Refresh()
        {
1611
            NotifyPropertyChanged(nameof(Number));
潘栩锋's avatar
潘栩锋 committed
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625
        }

        #region INotifyPropertyChanged 接口
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        #endregion
    }

1626

潘栩锋's avatar
潘栩锋 committed
1627 1628 1629 1630
    public class ScanPosCell
    {
        public DateTime dt = DateTime.MinValue;
        public int pos;//位于膜的位置,不是机架
1631
        public double thk;//两层的厚度
潘栩锋's avatar
潘栩锋 committed
1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
                         //由pos转换!!
        public double angle1;//上层 位于膜泡的角度 0~360°
        public double angle2;//下层 位于膜泡的角度 0~360°
        public Misc.DIRECTION direction;//只有一整副数据都是同一个方向,才能解方程

        public double rotateAngle;//0~180° 可以认为是夹扁后膜的变形
        public ScanPosCell Clone()
        {
            ScanPosCell scanpos = new ScanPosCell();
            scanpos.dt = dt;
            scanpos.pos = pos;
1643
            scanpos.thk = thk;
潘栩锋's avatar
潘栩锋 committed
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656
            scanpos.angle1 = angle1;
            scanpos.angle2 = angle2;
            scanpos.direction = direction;
            scanpos.rotateAngle = rotateAngle;
            return scanpos;
        }
    }

    public class EquationCell
    {
        public Dictionary<int, int> boltPower = new Dictionary<int, int>();//key=boltindex, value=power
        public Dictionary<int, int> heatRotatePower = new Dictionary<int, int>();//key=boltindex, value=power

1657
        public double thk = 0;
潘栩锋's avatar
潘栩锋 committed
1658
        public int mainBolt;//主分区号
1659
        public void Add(int boltindex1, int boltindex2, double thk)
潘栩锋's avatar
潘栩锋 committed
1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677
        {
            if (boltPower.ContainsKey(boltindex1))
            {
                boltPower[boltindex1]++;
            }
            else
            {
                boltPower.Add(boltindex1, 1);
            }

            if (boltPower.ContainsKey(boltindex2))
            {
                boltPower[boltindex2]++;
            }
            else
            {
                boltPower.Add(boltindex2, 1);
            }
1678
            this.thk += thk;
潘栩锋's avatar
潘栩锋 committed
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702
        }

        public override string ToString()
        {
            string str = "";
            foreach (var b in boltPower)
            {
                str += "[" + b.Key.ToString() + "," + b.Value.ToString() + "] ";
            }
            return str;
        }
        public double[] GetPower(int nbolts)
        {
            double[] power = new double[nbolts];
            for (int i = 0; i < power.Count(); i++)
                power[i] = 0;

            foreach (var kv in boltPower)
            {
                power[kv.Key] = kv.Value;
            }
            return power;
        }

1703
        public double GetAvg()
潘栩锋's avatar
潘栩锋 committed
1704 1705 1706 1707 1708 1709 1710
        {
            int cnt = 0;
            for (int i = 0; i < boltPower.Count(); i++)
            {
                cnt += boltPower.Values.ElementAt(i);
            }
            if (cnt > 0)
1711
                return thk / cnt;
潘栩锋's avatar
潘栩锋 committed
1712
            else
1713
                return double.NaN;
潘栩锋's avatar
潘栩锋 committed
1714 1715 1716 1717 1718 1719 1720 1721 1722
        }
    }
    public class ScanInfoCell : INotifyPropertyChanged
    {

        /// <summary>
        /// 已经解完方程
        /// </summary>
        public bool HasCast { get; set; }
1723

潘栩锋's avatar
潘栩锋 committed
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745

        #region 数据
        public enum STATE
        {
            /// <summary>
            /// 获取角度出错
            /// </summary>
            Err_GetAngle,
            /// <summary>
            /// 解方程出错
            /// </summary>
            Err_Solve,
            /// <summary>
            /// 解方程可能出错
            /// </summary>
            ERR_Solve_Maybe,
            /// <summary>
            /// 没问题
            /// </summary>
            OK
        }
        public STATE State { get; set; } = STATE.OK;
1746

潘栩锋's avatar
潘栩锋 committed
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784
        /// <summary>
        /// 扫描时间
        /// </summary>
        public DateTime StartTime { get; set; } = DateTime.MinValue;

        /// <summary>
        /// 旋转架旋转的方向,当同一次扫描中,有两个方向,Direction= Fix;
        /// </summary>
        public Misc.DIRECTION Direction { get; set; } = DIRECTION.FIX;


        /// <summary>
        /// 当前在观察
        /// </summary>
        public bool IsFocus { get; set; }



        /// <summary>
        /// 当前在观察
        /// </summary>
        public bool IsFocus2 { get; set; }

        /// <summary>
        /// 原始数据(时间,位置,总厚度)
        /// </summary>
        public List<ScanPosCell> frame = new List<ScanPosCell>();
        /// <summary>
        /// 方程列表
        /// </summary>
        public List<EquationCell> equationList = new List<EquationCell>();


        /// <summary>
        /// 下面解方程得到的一幅数据对应的数据,与 StartTime 不一样
        /// </summary>
        public DateTime ThicksDT { get; set; } = DateTime.MinValue;

1785 1786 1787 1788
        /// <summary>
        /// thicks 与 方程列表 的相关性
        /// </summary>
        public double R = -1;
潘栩锋's avatar
潘栩锋 committed
1789 1790 1791
        /// <summary>
        /// 一幅数据
        /// </summary>
1792
        public double[] thks;
潘栩锋's avatar
潘栩锋 committed
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802

        /// <summary>
        /// 分区数
        /// </summary>
        public int nbolts;

        /// <summary>
        /// 复位区号
        /// </summary>
        public int orgboltno;
1803 1804 1805 1806 1807

        /// <summary>
        /// 厚度均值
        /// </summary>
        public double Avg { get; set; }
潘栩锋's avatar
潘栩锋 committed
1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818
        #endregion

        #region 分析观察
        /// <summary>
        /// 解方程 用的scaninfo
        /// </summary>
        public List<int> solveMember = new List<int>();
        /// <summary>
        /// 每个分区出现次数, 上下分区各不相同
        /// </summary>
        public int[] power;
1819

潘栩锋's avatar
潘栩锋 committed
1820 1821 1822 1823 1824 1825
        #endregion

        public ScanInfoCell(int nbolts, int orgboltno)
        {
            this.nbolts = nbolts;
            this.orgboltno = orgboltno;
1826
            thks = new double[nbolts];
潘栩锋's avatar
潘栩锋 committed
1827 1828 1829
            power = new int[nbolts];
            for (int i = 0; i < nbolts; i++)
            {
1830
                thks[i] = double.NaN;
潘栩锋's avatar
潘栩锋 committed
1831 1832 1833 1834 1835 1836
            }
        }

        int GetBoltIndexFromAngle(double a)
        {
            int boltno1st = 1;
1837
            int nbolts = thks.Count();
潘栩锋's avatar
潘栩锋 committed
1838 1839 1840 1841
            int boltindex = (int)(a / 360 * nbolts);

            boltindex += orgboltno - boltno1st;

1842
            while (boltindex >= nbolts)
潘栩锋's avatar
潘栩锋 committed
1843
                boltindex -= nbolts;
1844 1845

            while (boltindex < 0)
潘栩锋's avatar
潘栩锋 committed
1846
                boltindex += nbolts;
1847

潘栩锋's avatar
潘栩锋 committed
1848 1849 1850 1851 1852 1853 1854 1855
            return boltindex;
        }

        /// <summary>
        /// 完成了一些方程,返回true
        /// </summary>
        /// <param name="scanpos_idx"></param>
        /// <returns></returns>
1856
        public bool AddEquation(int scanpos_idx, double sensor_angle)
潘栩锋's avatar
潘栩锋 committed
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869
        {

            ScanPosCell scanpos = frame[scanpos_idx];


            EquationCell equation = new EquationCell();
            equationList.Add(equation);


            //TOD0
            equation.Add(
                GetBoltIndexFromAngle(scanpos.angle1),
                GetBoltIndexFromAngle(scanpos.angle2),
1870
                scanpos.thk);
潘栩锋's avatar
潘栩锋 committed
1871 1872 1873 1874 1875 1876

            for (int i = 1; i < sensor_angle / 2; i++)
            {
                equation.Add(
                    GetBoltIndexFromAngle(scanpos.angle1 + i),
                    GetBoltIndexFromAngle(scanpos.angle2 + i),
1877
                    scanpos.thk);
潘栩锋's avatar
潘栩锋 committed
1878 1879 1880 1881

                equation.Add(
                    GetBoltIndexFromAngle(scanpos.angle1 - i),
                    GetBoltIndexFromAngle(scanpos.angle2 - i),
1882
                    scanpos.thk);
潘栩锋's avatar
潘栩锋 committed
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898
            }
            return true;
        }

        #region INotifyPropertyChanged 接口
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
}