BlowingScanAnaylze.cs 60.1 KB
Newer Older
1 2 3
using FLY.Thick.Blowing;
using FLY.Thick.Blowing.UI.Fix.Client;
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 189 190 191 192 193 194 195 196 197 198
                    markdata.StartTime = scanInfo.StartTime;
                    markdata.ThicksDT = scanInfo.ThicksDT;
                    markdata.Thicks = scanInfo.thicks;
                    markdata.R = scanInfo.R;

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



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

            if (mBufList.Count()==0)
239
                return;
240

潘栩锋's avatar
潘栩锋 committed
241 242 243 244
            BufList2ScanInfoList();


            //当MarkNo1.Number 不在范围内, 限制它们
245 246 247 248 249 250 251 252 253 254 255 256
            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
257 258
            }
        }
259 260 261 262 263 264 265 266
        int GetDefaultNumber()
        {
            int count = mBufList.Count();
            int endNo = BufListLastNo;

            int beginNo = endNo - count + 1;
            return beginNo + SolveCnt;
        }
267
        public int KeepInRange(int no)
潘栩锋's avatar
潘栩锋 committed
268
        {
269 270 271 272 273 274 275 276 277 278 279 280 281
            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
282 283 284 285 286 287 288 289

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

            //ToThicks_SolveEquation();
            IsStep2Ing = false;
        }
303 304 305 306

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

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



            IsStep2Ing = true;

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

            double minParam = RAngle - RAngleRange / 2;
            double maxParam = RAngle + RAngleRange / 2;
353 354 355 356
            if (minParam < RAngleMin)
                minParam = RAngleMin;
            if (maxParam > RAngleMax)
                maxParam = RAngleMax;
357 358 359 360

            double bestParam = RAngle;
            double bestR;

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

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

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

        }

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

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

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
            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());
447
            }
448
            
449 450
            IsStep2Ing = false;
        }
451
        bool autoSearchFilmLength(int idx1, int idx2, out double bestFl)
452 453 454 455 456
        {
            ParamRs.Clear();

            double minParam = FilmLength - FilmLengthRange / 2;
            double maxParam = FilmLength + FilmLengthRange / 2;
457 458 459 460
            if (minParam < FilmLengthMin)
                minParam = FilmLengthMin;
            if (maxParam > FilmLengthMax)
                maxParam = FilmLengthMax;
461 462 463 464

            double bestParam = FilmLength;
            double bestR;

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

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

512

513
        /// <summary>
514
        /// 自动查找膜距离2
515
        /// </summary>
516
        public void StepAutoSearchFilmLength2()
517
        {
518
            if (mBufList.Count() == 0)
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
                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))
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 636 637 638
                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)
639
                return;
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 709 710 711

            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;
712
            }
713 714 715 716 717
            
        }


        List<Range> GetSameDirScanInfoIdxs() {
718 719 720 721

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

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

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

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

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

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

797 798 799 800
            if (!autoSearchRAngle(idx1, idx2, out double bestRa))
            {
                SearchMsg = $"查找失败!!旋转角度查找失败";
                goto _end;
801
            }
802 803 804 805 806 807 808 809 810 811 812 813 814
            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();

815 816 817 818
            MarkNos.ForEach(m => m.Refresh());

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

820
            _end:
821 822
            IsStep2Ing = false;
        }
823 824 825 826 827

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

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

843 844
            //最后两个方向扫描数量误差不能大于2
            int width = sameDirScanInfoIdxs[sameDirScanInfoIdxs.Count() - 2].Width;
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 936 937 938
            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;
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 967 968 969
            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)
            {
970
                if (ParamRs.Find(_rar => _rar.Param == rar.Param) == null)
971 972 973 974 975
                {
                    ParamRs.Add(rar);
                }
            }
            ParamRs.Sort((rar1, rar2) => { return rar1.Param.CompareTo(rar2.Param); });
976 977
            NotifyPropertyChanged(nameof(ParamRs));

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

992

潘栩锋's avatar
潘栩锋 committed
993 994 995 996 997 998 999 1000 1001 1002 1003

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

                if (ep_idx > (f.Thicks.Length - 1))
                    ep_idx = f.Thicks.Length - 1;

1021 1022
                double sum = 0;
                int cnt = 0;
潘栩锋's avatar
潘栩锋 committed
1023 1024 1025 1026 1027
                for (int j = bp_idx; j <= ep_idx; j++)
                {
                    int idx = j;
                    int pos = j * posOfGrid + posOfGrid / 2;//一个grid的中间脉冲,也就是大概而已
                    int thick = f.Thicks[idx];
1028 1029
                    sum += thick;
                    cnt++;
潘栩锋's avatar
潘栩锋 committed
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045

                    pos -= border.Begin;//膜上面的位置
                    ScanPosCell scanpos = new ScanPosCell() { pos = pos, thick = thick, dt = f.ThicksDt[idx] };

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

潘栩锋's avatar
潘栩锋 committed
1050 1051 1052 1053 1054 1055
                ScanInfoList.Add(scaninfocell);
            }



        }
1056

潘栩锋's avatar
潘栩锋 committed
1057
        /// <summary>
1058
        /// 第2步,修改 旋转角度,膜距离 执行, 耗时很短
潘栩锋's avatar
潘栩锋 committed
1059
        /// </summary>
1060
        void GetSolveEquation()
潘栩锋's avatar
潘栩锋 committed
1061
        {
1062
            //获取角度信息
潘栩锋's avatar
潘栩锋 committed
1063 1064
            for (int i = 0; i < mBufList.Count(); i++)
            {
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
                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
1084
                {
1085 1086
                    if (!getSolveIdxs.Contains(index))
                        getSolveIdxs.Add(index);
潘栩锋's avatar
潘栩锋 committed
1087
                }
1088 1089
                index = idx2 - i;
                if (index >= 0)
潘栩锋's avatar
潘栩锋 committed
1090
                {
1091 1092
                    if (!getSolveIdxs.Contains(index))
                        getSolveIdxs.Add(index);
潘栩锋's avatar
潘栩锋 committed
1093 1094
                }
            }
1095
            foreach (var index in getSolveIdxs)
潘栩锋's avatar
潘栩锋 committed
1096
            {
1097
                GetSolveEquation(rAngle, filmLength, index);
潘栩锋's avatar
潘栩锋 committed
1098 1099
            }
        }
1100

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

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

1129
            scaninfocell.equationList.Clear();
潘栩锋's avatar
潘栩锋 committed
1130

1131
            scaninfocell.State = ScanInfoCell.STATE.OK;
潘栩锋's avatar
潘栩锋 committed
1132

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

1137 1138
                mRDetectCore.RAngle = rAngle;
                mRDetectCore.FilmLength = filmLength;
1139

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

                //探头直径转为角度范围
                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
1165
                    {
1166 1167
                        scaninfocell.Direction = DIRECTION.FIX;
                        scaninfocell.State = ScanInfoCell.STATE.Err_Solve;
潘栩锋's avatar
潘栩锋 committed
1168 1169 1170
                        break;
                    }
                }
1171 1172
                scaninfocell.AddEquation(j, sensor_angle);
            }
潘栩锋's avatar
潘栩锋 committed
1173 1174
        }

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

1196
            }
潘栩锋's avatar
潘栩锋 committed
1197
        }
1198 1199


潘栩锋's avatar
潘栩锋 committed
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
        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;
            //    }
            //}
            //平均值图
            {
                int[] _sum = new int[scaninfo.nbolts];
                int[] _cnt = new int[scaninfo.nbolts];

                foreach (EquationCell e in scaninfo.equationList)
                {
                    int avg = e.GetAvg();
                    foreach (KeyValuePair<int, int> kv in e.boltPower)
                    {
                        _sum[kv.Key] += avg;
                        _cnt[kv.Key] += 1;
                        scaninfo.thicks_avg[kv.Key] = _sum[kv.Key] / _cnt[kv.Key];
                    }
                }
            }
            List<EquationCell> equationlist = new List<EquationCell>();
            scaninfo.solveMember.Clear();
1242 1243 1244

            
            for (int i = 0; i < SolveCnt; i++)
潘栩锋's avatar
潘栩锋 committed
1245
            {
1246 1247 1248 1249
                int index = scaninfo_idx - i;
                if (index < 0)
                    break;
                if (ScanInfoList[index].Direction == DIRECTION.FIX)
潘栩锋's avatar
潘栩锋 committed
1250 1251
                    continue;

1252
                equationlist.AddRange(ScanInfoList[index].equationList);
潘栩锋's avatar
潘栩锋 committed
1253
                //用到的扫描副
1254
                scaninfo.solveMember.Add(index);
潘栩锋's avatar
潘栩锋 committed
1255
            }
1256
            
潘栩锋's avatar
潘栩锋 committed
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
            //计算 每个分区的权
            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)
1267
                    scaninfo.power[kv.Key] += kv.Value;
潘栩锋's avatar
潘栩锋 committed
1268 1269 1270 1271
                    //else
                    //    scaninfo.power[kv.Key+scaninfo.nbolts] += kv.Value;
                }
            }
1272

1273
            if (scaninfo.solveMember.Count() < 3) //方程不够!!!!
潘栩锋's avatar
潘栩锋 committed
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
            {
                scaninfo.State = ScanInfoCell.STATE.Err_Solve;
                return false;
            }

            if (equationlist.Count < 100)//方程数太少
            {
                scaninfo.State = ScanInfoCell.STATE.Err_Solve;
                return false;
            }
1284 1285
            int[] thks = scaninfo.thicks;
            SolveEquation(equationlist, thks);
潘栩锋's avatar
潘栩锋 committed
1286 1287 1288 1289 1290 1291


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

            //不能有任何一个NULL_VALUE
1292
            if (thks.Any(thk => !Misc.MyBase.ISVALIDATA(thk)))
1293 1294
            {
                scaninfo.State = ScanInfoCell.STATE.Err_Solve;
1295
                return false;
1296
            }
1297

1298 1299 1300 1301 1302

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


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

1305 1306 1307 1308 1309 1310 1311
            return true;
        }
        /// <summary>
        /// 平滑thks
        /// </summary>
        /// <param name="thks"></param>
        /// <param name="smooth">平滑半径</param>
1312
        static void SmoothFrame(int[] thks, int smooth)
1313 1314
        {
            if (smooth > 0)
潘栩锋's avatar
潘栩锋 committed
1315
            {
1316 1317 1318
                int[] data = new int[thks.Count()];

                for (int i = 0; i < thks.Count(); i++)
潘栩锋's avatar
潘栩锋 committed
1319 1320 1321
                {
                    int sum = 0;

1322
                    for (int j = 0; j < (smooth * 2 + 1); j++)
潘栩锋's avatar
潘栩锋 committed
1323
                    {
1324
                        int index = i + j - smooth;
潘栩锋's avatar
潘栩锋 committed
1325
                        if (index < 0)
1326 1327 1328 1329
                            index += thks.Count();
                        else if (index >= thks.Count())
                            index -= thks.Count();
                        sum += thks[index];
潘栩锋's avatar
潘栩锋 committed
1330
                    }
1331
                    data[i] = (int)(sum / (smooth * 2 + 1));
潘栩锋's avatar
潘栩锋 committed
1332
                }
1333
                Array.Copy(data, thks, thks.Count());
潘栩锋's avatar
潘栩锋 committed
1334 1335
            }
        }
1336
        /// <summary>
1337
        /// 计算方程每个原始数据 与 结果的相关性
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
        /// </summary>
        /// <param name="equationList"></param>
        /// <param name="frame_out"></param>
        /// <returns></returns>
        static double SingleR(List<EquationCell> equationList, int[] frame_out)
        {
            List<int> calThks = new List<int>();
            List<int> actThks = new List<int>();
            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;
1354
                    cnt += kv.Value;
1355 1356 1357 1358 1359
                }
                if (cnt > 0)
                {
                    int totalThk = (int)(sum / cnt);
                    calThks.Add(totalThk);
1360
                    
1361 1362 1363 1364 1365
                    actThks.Add(ec.thick);
                }
            }
            return Misc.MyMath.Correl(calThks, actThks);
        }
潘栩锋's avatar
潘栩锋 committed
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
        /// <summary>
        /// 解方程
        /// </summary>
        /// <param name="equationList">N条方程</param>
        /// <param name="frame_out">输出的结果</param>
        void SolveEquation(List<EquationCell> equationList, int[] frame_out)
        {

            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);
                vectorB[rowindex] = ec.thick;
                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++)
            {
                frame_out[i] = (int)X[i];
            }
        }

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



        #region 两组数据

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

1426 1427
        public MarkData MarkNo1 { get; } = new MarkData();
        public MarkData MarkNo2 { get; } = new MarkData();
潘栩锋's avatar
潘栩锋 committed
1428

1429
        public List<MarkData> MarkNos { get; private set; }
潘栩锋's avatar
潘栩锋 committed
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
        void UpdateCurrR()
        {
            if (MarkNo1.IsValid && MarkNo2.IsValid)
            {
                CurrR = Misc.MyMath.Correl(MarkNo1.Thicks, MarkNo2.Thicks);
            }
            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;
                }
            }
        }
1470

潘栩锋's avatar
潘栩锋 committed
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500

        #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;
            }
        }
1501
        public bool Load(string path, out List<FlyData_BlowingScan> bufList)
潘栩锋's avatar
潘栩锋 committed
1502
        {
1503
            bufList = new List<FlyData_BlowingScan>();
潘栩锋's avatar
潘栩锋 committed
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514

            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))
                    {
1515
                        bufList.Add(f);
潘栩锋's avatar
潘栩锋 committed
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 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
                    }
                    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
    {
1563 1564
        public string Name { get; set; } = "记录";

潘栩锋's avatar
潘栩锋 committed
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
        public int Number { get; set; } = -1;

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

潘栩锋's avatar
潘栩锋 committed
1576 1577 1578 1579 1580
        /// <summary>
        /// 扫描时间
        /// </summary>
        public DateTime StartTime { get; set; } = DateTime.MinValue;

1581

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

1587

潘栩锋's avatar
潘栩锋 committed
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
        /// <summary>
        /// 下面解方程得到的一幅数据对应的数据,与 StartTime 不一样
        /// </summary>
        public DateTime ThicksDT { get; set; } = DateTime.MinValue;


        /// <summary>
        /// 一幅数据
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public int[] Thicks { get; set; }

1600

潘栩锋's avatar
潘栩锋 committed
1601 1602 1603 1604 1605 1606
        /// <summary>
        /// 膜边界,单位脉冲
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public Range Border { get; set; }

1607

潘栩锋's avatar
潘栩锋 committed
1608 1609 1610 1611
        /// <summary>
        /// pos / grid
        /// </summary>
        public int PosOfGrid { get; set; } = 10;
1612

潘栩锋's avatar
潘栩锋 committed
1613 1614 1615 1616
        /// <summary>
        /// orgthick时间
        /// </summary>
        public DateTime Time { get; set; } = DateTime.MinValue;
1617

潘栩锋's avatar
潘栩锋 committed
1618 1619 1620 1621 1622 1623
        /// <summary>
        /// 厚度数据,  大小 grid总数
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public int[] OrgThicks { get; set; }

1624

潘栩锋's avatar
潘栩锋 committed
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636
        /// <summary>
        /// 权重图
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public int[] Power { get; set; }

        /// <summary>
        /// 均值图
        /// </summary>
        [PropertyChanged.DoNotCheckEquality]
        public int[] AvgThicks { get; set; }

1637 1638 1639 1640
        /// <summary>
        /// 方程数据与解方程后的结果相关性
        /// </summary>
        public double R { get; set; } = -1;
潘栩锋's avatar
潘栩锋 committed
1641 1642 1643 1644 1645 1646 1647
        public MarkData()
        {

        }

        public void Refresh()
        {
1648
            NotifyPropertyChanged(nameof(Number));
潘栩锋's avatar
潘栩锋 committed
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
        }

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

1663

潘栩锋's avatar
潘栩锋 committed
1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759
    public class ScanPosCell
    {
        public DateTime dt = DateTime.MinValue;
        public int pos;//位于膜的位置,不是机架
        public int thick;//两层的厚度
                         //由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;
            scanpos.thick = thick;
            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

        public int thick = 0;
        public int mainBolt;//主分区号
        public void Add(int boltindex1, int boltindex2, int thick)
        {
            if (boltPower.ContainsKey(boltindex1))
            {
                boltPower[boltindex1]++;
            }
            else
            {
                boltPower.Add(boltindex1, 1);
            }

            if (boltPower.ContainsKey(boltindex2))
            {
                boltPower[boltindex2]++;
            }
            else
            {
                boltPower.Add(boltindex2, 1);
            }
            this.thick += thick;
        }

        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;
        }

        public int GetAvg()
        {
            int cnt = 0;
            for (int i = 0; i < boltPower.Count(); i++)
            {
                cnt += boltPower.Values.ElementAt(i);
            }
            if (cnt > 0)
                return thick / cnt;
            else
                return Misc.MyBase.NULL_VALUE;
        }
    }
    public class ScanInfoCell : INotifyPropertyChanged
    {

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

潘栩锋's avatar
潘栩锋 committed
1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782

        #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;
1783

潘栩锋's avatar
潘栩锋 committed
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
        /// <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;

1822 1823 1824 1825
        /// <summary>
        /// thicks 与 方程列表 的相关性
        /// </summary>
        public double R = -1;
潘栩锋's avatar
潘栩锋 committed
1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839
        /// <summary>
        /// 一幅数据
        /// </summary>
        public int[] thicks;

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

        /// <summary>
        /// 复位区号
        /// </summary>
        public int orgboltno;
1840 1841 1842 1843 1844

        /// <summary>
        /// 厚度均值
        /// </summary>
        public double Avg { get; set; }
潘栩锋's avatar
潘栩锋 committed
1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883
        #endregion

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

        public ScanInfoCell(int nbolts, int orgboltno)
        {
            this.nbolts = nbolts;
            this.orgboltno = orgboltno;
            thicks = new int[nbolts];
            power = new int[nbolts];
            thicks_avg = new int[nbolts];
            for (int i = 0; i < nbolts; i++)
            {
                thicks[i] = Misc.MyBase.NULL_VALUE;
                thicks_avg[i] = Misc.MyBase.NULL_VALUE;
            }
        }

        int GetBoltIndexFromAngle(double a)
        {
            int boltno1st = 1;
            int nbolts = thicks.Count();
            int boltindex = (int)(a / 360 * nbolts);

            boltindex += orgboltno - boltno1st;

1884
            while (boltindex >= nbolts)
潘栩锋's avatar
潘栩锋 committed
1885
                boltindex -= nbolts;
1886 1887

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

潘栩锋's avatar
潘栩锋 committed
1890 1891 1892 1893 1894 1895 1896 1897
            return boltindex;
        }

        /// <summary>
        /// 完成了一些方程,返回true
        /// </summary>
        /// <param name="scanpos_idx"></param>
        /// <returns></returns>
1898
        public bool AddEquation(int scanpos_idx, double sensor_angle)
潘栩锋's avatar
潘栩锋 committed
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940
        {

            ScanPosCell scanpos = frame[scanpos_idx];


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


            //TOD0
            equation.Add(
                GetBoltIndexFromAngle(scanpos.angle1),
                GetBoltIndexFromAngle(scanpos.angle2),
                scanpos.thick);

            for (int i = 1; i < sensor_angle / 2; i++)
            {
                equation.Add(
                    GetBoltIndexFromAngle(scanpos.angle1 + i),
                    GetBoltIndexFromAngle(scanpos.angle2 + i),
                    scanpos.thick);

                equation.Add(
                    GetBoltIndexFromAngle(scanpos.angle1 - i),
                    GetBoltIndexFromAngle(scanpos.angle2 - i),
                    scanpos.thick);
            }
            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
    }
}