/// <summary> /// 指定したディレクトリから,測定データをロードします. /// </summary> /// <param name="directory"></param> /// <returns></returns> public async Task LoadFromAsync(string directory) { // まずパラメータだけでROISpectraを生成する。 var roi_spectra = await ReadParaPeakAsync(directory); // サイクルごと→元素範囲ごとで格納されているが、 // 元素範囲ごと→サイクルごとの方が使いやすいと思うので、そのように変換する。 for (int j = 0; j < roi_spectra.Length; j++) { roi_spectra[j].Data = new EqualIntervalData[Cycles]; } // データを読み込む。 using (var reader = new BinaryReader(new FileStream(Path.Combine(directory, "data.peak"), FileMode.Open, FileAccess.Read))) { // サイクルごと for (int i = 0; i < Cycles; i++) { // 元素範囲ごと for (int j = 0; j < roi_spectra.Length; j++) { roi_spectra[j].Data[i] = await EqualIntervalData.GenerateAsync(reader, roi_spectra[j].Parameter.PointsCount); } } } Spectra = roi_spectra.ToDictionary(spec => spec.Name); }
/// <summary> /// 各要素の差をとった新たなインスタンスを返します.(otherの方が要素が少ない場合,例外を発生するような気がします.) /// </summary> /// <param name="other"></param> /// <returns></returns> public EqualIntervalData Substract(IList <decimal> other) { var data = new EqualIntervalData(); for (int i = 0; i < this.Count; i++) { data.Add(this[i] - other[i]); } data.IsRawData = false; return(data); }
// とりあえず. public void LoadFrom(string directory) { // パラメータを読み込む。 _scanParameter = ScanParameter.Generate(directory); // データを読み込む。 using (var reader = new BinaryReader(new FileStream(Path.Combine(directory, "data"), FileMode.Open, FileAccess.Read))) { _data = EqualIntervalData.Generate(reader); } }
/// <summary> /// 残差2乗和を求めてそれを返します。 /// </summary> /// <param name="data">測定データ.</param> /// <param name="reference">(一般には複数の)参照データ.</param> /// <returns></returns> static decimal CulculateResidual(bool with_offset, IList <decimal> data, params IList <decimal>[] references) // C# 6.0 で,params引数に配列型以外も使えるようになった. { // 2.最適値なゲイン係数(+オフセット値)を求める var gains = GetOptimizedGains(with_offset, data, references); // 3.残差を求める var residual = EqualIntervalData.GetTotalSquareResidual(data, gains.ToArray(), references); // 残差2乗和 Trace.WriteLine($"residual = {residual}"); return(residual); }
public async Task LoadFromAsync(string directory) { // パラメータを読み込む。 _scanParameter = await ScanParameter.GenerateAsync(directory); // データを読み込む。 using (var reader = new BinaryReader(new FileStream(Path.Combine(directory, "data"), FileMode.Open, FileAccess.Read))) { _data = await EqualIntervalData.GenerateAsync(reader); } //Loaded(this, EventArgs.Empty); }
public async Task FitSingleProfile(FittingProfile profile) { var d_data = WideScan.GetRestrictedData(profile.RangeBegin, profile.RangeEnd).Differentiate(_differentialWindow); var fitting_results = new FittingProfile.FittingResult(); // キーはサイクル数. EqualIntervalData target_data = new EqualIntervalData(); // 1.まず,フィッティングの計算を行う. { #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を考慮しない。 target_data = d_data.Data; //fitting_tasks.Add(i, profile.FitOneCycle(i, target_data[i], d_data.Parameter)); fitting_results = profile.FitOneCycle(-1, target_data, d_data.Parameter); } // 2.その後に,チャート出力を行う? Gnuplot charts = await Output(d_data.Parameter, profile, target_data, fitting_results); // pltファイルも出力してみる。 using (var writer = new StreamWriter(GetCsvFileName(profile.Name, -1) + ".plt")) { await charts.OutputPltFileAsync(writer); } // チャートを描画する。 await charts.Draw(); }
public static EqualIntervalData Generate(BinaryReader reader) { var data = new EqualIntervalData(); while (reader.PeekChar() > -1) { // エンディアンが逆なので、単純にreader.ReadInt32()とはいかない! int count = reader.ReadInt32Inverse(); data.Add(count); } data.IsRawData = true; return(data); }
// (0.2.0) #region *生成(GenerateAsync) /// <summary> /// JEOL形式のスペクトルデータを読み込みます. /// </summary> /// <param name="reader"></param> /// <returns></returns> public static async Task <EqualIntervalData> GenerateAsync(BinaryReader reader) { var data = new EqualIntervalData(); while (reader.PeekChar() > -1) { // エンディアンが逆なので、単純にreader.ReadInt32()とはいかない! int count = await reader.ReadInt32Async(); data.Add(count); } data.IsRawData = true; return(data); }
// (0.2.0) public static async Task <EqualIntervalData> GenerateAsync(BinaryReader reader, int length) { var data = new EqualIntervalData(); for (int i = 0; i < length; i++) { // エンディアンが逆なので、単純にreader.ReadInt32()とはいかない! int count = await reader.ReadInt32Async(); data.Add(count); } data.IsRawData = true; return(data); }
/// <summary> /// 2次?のSavizky-Golay法によって微分した結果を返します。要素数が2mだけ少なくなります. /// </summary> /// <param name="m"></param> /// <returns></returns> public EqualIntervalData Differentiate(int m, decimal step) { var data = new EqualIntervalData(); for (int i = m; i < this.Count - m; i++) { decimal count = 0; for (int j = 1; j <= m; j++) { count += this[i + j] * j; count -= this[i - j] * j; } data.Add(3 * count / (m * (m + 1) * (2 * m + 1) * step)); } return(data); }
/// <summary> /// 自身の一部範囲を含んだインスタンスを生成して返します. /// </summary> /// <param name="startIndex"></param> /// <param name="endIndex"></param> /// <returns></returns> public EqualIntervalData GetSubData(int startIndex, int endIndex) { if (startIndex >= 0 && endIndex < this.Count && startIndex <= endIndex) { var data = new EqualIntervalData(); for (int i = startIndex; i <= endIndex; i++) { data.Add(this[i]); } data.IsRawData = true; return(data); } else { throw new ArgumentException("もとのデータの範囲内で指定して下さい。"); } }
// (0.2.1) #region *[static][async]テキストファイルから生成(GeenrateFromText) public static async Task <EqualIntervalData> GenerateFromText(StreamReader reader, bool isRaw) { var data = new EqualIntervalData(); while (!reader.EndOfStream) { var count = await reader.ReadLineAsync(); if (isRaw) { data.Add(int.Parse(count)); } else { data.Add(decimal.Parse(count)); } } data.IsRawData = isRaw; return(data); }
// (0.1.0)メソッド名をFitからOutputに変更.というか,これどこにおけばいいのかな? private async Task <Gnuplot> Output( ScanParameter originalParameter, FittingProfile profile, EqualIntervalData target_data, FittingProfile.FittingResult result) { // フィッティングした結果をチャートにする? // ★とりあえずFixedなデータは表示しない。 bool output_convolution = result.Standards.Count > 1; // それには、csvを出力する必要がある。 //string fitted_csv_path = Path.Combine(FittingCondition.OutputDestination, $"{FittingCondition.Name}_{layer}.csv"); using (var csv_writer = new StreamWriter(GetCsvFileName(profile.Name))) { await OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution).ConfigureAwait(false); } // チャート出力の準備? return(ConfigureChart(result, profile, output_convolution)); }
// (0.1.0)メソッド名をFitからOutputに変更.というか,これどこにおけばいいのかな? #region *CSVを出力して,グラフ描画の準備を行う(Output) /// <summary> /// フィッティングした結果から,チャートの出力を設定します. /// </summary> /// <param name="cycle"></param> /// <param name="originalParameter"></param> /// <param name="profile"></param> /// <param name="target_data"></param> /// <param name="result"></param> /// <returns></returns> private async Task <Gnuplot> Output( int cycle, ScanParameter originalParameter, FittingProfile profile, EqualIntervalData target_data, FittingProfile.FittingResult result) { // フィッティングした結果をチャートにする? // ★とりあえずFixedなデータは表示しない。 Trace.WriteLine($"Let's start outputting! cycle{cycle} {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); bool output_convolution = result.Standards.Count > 1; // それには、csvを出力する必要がある。 using (var csv_writer = new StreamWriter(GetCsvFileName(cycle, profile.Name))) { await OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution); } Trace.WriteLine($"CSV output Completed! cycle{cycle} {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); // チャート出力の準備? return(ConfigureChart(result, profile, output_convolution, cycle)); #region こうすると,1024バイトほど書き込んだところで落ちる. // どう違うのかはよくわかっていない. /* * Gnuplot chartConfiguration; * // chartConfigurationを構成して返す処理とcsv出力処理が入り交じっているので注意.(こういう書き方しか思いつかなかった.) * using (var csv_writer = new StreamWriter(GetCsvFileName(cycle, profile.Name))) * { * //var outputCsvTask = OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution); * //chartConfiguration = ConfigureChart(cycle, result, profile, output_convolution); * //await outputCsvTask; * await OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution); * } * return chartConfiguration; */ #endregion }
private async Task OutputFittedCsv(StreamWriter writer, ScanParameter originalParameter, EqualIntervalData targetData, FittingProfile.FittingResult result, bool outputConvolution) { for (int k = 0; k < originalParameter.PointsCount; k++) { List <string> cols = new List <string>(); // 0列: エネルギー値 cols.Add((originalParameter.Start + k * originalParameter.Step + result.Shift).ToString("f2")); // 1列: 測定データ cols.Add(targetData[k].ToString("f3")); // 2~N列: 各成分(標準データ×ゲイン) decimal conv = 0; for (int j = 0; j < result.Standards.Count; j++) { var intensity = result.GetGainedStandard(j, k); conv += intensity; cols.Add(intensity.ToString("f3")); } // 最終列: 成分の総和 if (outputConvolution) { cols.Add(conv.ToString("f3")); } await writer.WriteLineAsync(string.Join(",", cols)); } }
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 } // 出力は呼び出し元で行う! }