FitForOneShiftResult DecideShift(EqualIntervalData targetData, ScanParameter originalParameter) { var gains = new Dictionary <decimal, Vector <double> >(); Dictionary <decimal, decimal> residuals = new Dictionary <decimal, decimal>(); var best_fit_result = new FitForOneShiftResult(); List <decimal> shiftList = new List <decimal>(); // 1回目 for (int m = -6; m < 7; m++) { shiftList.Add(0.5M * m); // とりあえず。 } Trace.WriteLine($"SearchShift START!! {DateTime.Now:O} [{Thread.CurrentThread.ManagedThreadId}]"); best_fit_result = SearchBestShift(shiftList, best_fit_result); var best_shift = best_fit_result.Shift; Trace.WriteLine($"SearchShift Completed!! {DateTime.Now:O} [{Thread.CurrentThread.ManagedThreadId}]"); Trace.WriteLine($"シフト値は {best_shift} がよさそうだよ!"); // 2回目 shiftList.Clear(); for (int i = 1; i < 5; i++) { shiftList.Add(best_shift + 0.1M * i); shiftList.Add(best_shift - 0.1M * i); } return(SearchBestShift(shiftList, best_fit_result)); #region ローカル関数 #region **与えられたシフト量から最適なものを探す(SearchBestShift) FitForOneShiftResult SearchBestShift( IEnumerable <decimal> shiftCandidates, FitForOneShiftResult previousResult) { var best_result = previousResult; // ※たぶん,メンバ変数にする必要がある. var _cancellation_token = new CancellationToken(); object lockObject = new object(); var loopResult = Parallel.ForEach <decimal, FitForOneShiftResult>( shiftCandidates, new ParallelOptions { CancellationToken = _cancellation_token }, () => best_result, (shift, state, best) => { return(FitForOneShift(shift)); }, (result) => { lock (lockObject) { if (!best_result.Residual.HasValue || best_result.Residual.Value > result.Residual.Value) { best_result = result; } } } ); return(best_result); #region ローカル関数 #region ***1つのシフト量に対してフィッティングを行う(FitForOneShift) // とりあえず同期版を使う. // IO待ちのメソッドではないので,asyncにしない方がよい? FitForOneShiftResult FitForOneShift(decimal shift) { Trace.WriteLine($"shift : {shift} {DateTime.Now:O} [{Thread.CurrentThread.ManagedThreadId}]"); var shifted_parameter = originalParameter.GetShiftedParameter(shift); // ここを非同期にすると,制御が返らなくなる? // シフトされた参照スペクトルを読み込む。 var standards = LoadShiftedStandardsData(ReferenceSpectra, shifted_parameter); // フィッティングを行い、 //Trace.WriteLine($"Cycle {cycle}"); var gain = GetOptimizedGains(WithOffset, targetData, standards.ToArray()); //gains.Add(shift, ); for (int j = 0; j < ReferenceSpectra.Count; j++) { Trace.WriteLine($" {ReferenceSpectra[j].Name} : {gain[j]} [{Thread.CurrentThread.ManagedThreadId}]"); } Trace.WriteLine($" Const : {gain[ReferenceSpectra.Count]} [{Thread.CurrentThread.ManagedThreadId}]"); // 残差を取得する。 var residual = EqualIntervalData.GetTotalSquareResidual(targetData, gain.ToArray(), standards.ToArray()); // 残差2乗和 //residuals.Add(shift, residual); Trace.WriteLine($"residual = {residual} [{Thread.CurrentThread.ManagedThreadId}]"); return(new FitForOneShiftResult { Gain = gain, Shift = shift, Residual = residual }); } #endregion #endregion } #endregion #endregion }
/// <summary> /// /// </summary> /// <param name="cycle">対象サイクル.デバッグ出力にしか使用していません.</param> /// <param name="data"></param> /// <param name="originalParameter"></param> /// <returns></returns> //public async Task<FittingResult> FitOneCycle(int cycle, EqualIntervalData data, ScanParameter originalParameter) public FittingResult FitOneCycle(int cycle, EqualIntervalData data, ScanParameter originalParameter) { #region 固定参照スペクトルを取得する。(一時的にコメントアウト中) /* * List<decimal> fixed_data = new List<decimal>(); * if (FixedSpectra.Count > 0) * { * var v_data = await FixedSpectra.ForEachAsync( * async sp => await sp.GetShiftedDataAsync(d_data.Parameter, 3), 10); * * for (int j = 0; j < v_data.First().Count; j++) * { * fixed_data.Add(v_data.Sum(one => one[j])); * } * } */ #endregion /// フィッティング対象となるデータ。すなわち、もとのデータからFixされた分を差し引いたデータ。 //var target_data = fixed_data.Count > 0 ? data.Substract(fixed_data) : data; // なんだけど、とりあえずはFixedを考慮しない。 var target_data = data; if (!FixEnergyShift) { #region A.最適なエネルギーシフト量を見つける場合 Trace.WriteLine($"Cycle {cycle} START!! {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); var best_fitting_result = DecideShift(target_data, originalParameter); var best_shift = best_fitting_result.Shift; Trace.WriteLine($" {cycle} 本当に最適なシフト値は {best_shift} だよ!"); Trace.WriteLine($"Cycle {cycle} END!! {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); // シフトされた参照スペクトルを読み込む。 var best_shifted_parameter = originalParameter.GetShiftedParameter(best_shift); //var best_standards = LoadShiftedStandardsDataAsync(ReferenceSpectra, best_shifted_parameter); var best_standards = LoadShiftedStandardsData(ReferenceSpectra, best_shifted_parameter); var best_gain = best_fitting_result.Gain; return(new FittingResult { Shift = best_shift, Gains = best_gain.Select(d => Convert.ToDecimal(d)).ToArray(), Standards = best_standards }); #endregion } else { #region B.エネルギーシフト量を自分で与える場合 var shifted_parameter = originalParameter.GetShiftedParameter(FixedEnergyShift); // シフトされた参照スペクトルを読み込む。 var standards = LoadShiftedStandardsData(ReferenceSpectra, shifted_parameter); // フィッティングを行い、 Trace.WriteLine($"Cycle {cycle}"); var gains = GetOptimizedGains(WithOffset, target_data, standards.ToArray()); for (int j = 0; j < ReferenceSpectra.Count; j++) { Trace.WriteLine($" {ReferenceSpectra[j].Name} : {gains[j]}"); } Trace.WriteLine($" Const : {gains[ReferenceSpectra.Count]}"); return(new FittingResult { Shift = FixedEnergyShift, Standards = standards, Gains = gains.Select(d => Convert.ToDecimal(d)).ToArray() }); #endregion } // 出力は呼び出し元で行う! }