//---------------------------------------------------------------------------
//	GenerateInput()		入力信号生成と入力信号の表示指令
//	SignalGererate()	入力信号の生成
//	Ale()				線スペクトル強調器（ALE）実行指令
//	Axis()				時間軸の描画
//	Waveform()			波形の描画
//
//		作成者：三上直樹，2022/10/04 作成，ⓒ三上直樹 2022
//---------------------------------------------------------------------------

using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Drawing.Drawing2D;	// SmoothingMode で使用

using Mikami;
using Mikami.Filter;

using static System.Math;

namespace ALE_LMS_波形
{
	public partial class Form1 : Form
	{
		// 入力信号生成と入力信号の表示指令
		private void GenerateInput(double[] frq, double[] amp, double snr)
		{
			button2.Enabled = false;	// 処理結果を再生するボタンを使えない状態にする

			// 入力信号生成
			SignalGererate(frq, amp, xn_, snr);
			wfaIn_.SetData(xn_.Select(x => A0_*x).ToArray(), (int)FS_);

			pictureBox1.Invalidate();	// 入力信号の表示指令
			aleOk_ = false;
			pictureBox2.Invalidate();	// 出力信号表示用の PictureBox に横線のみ表示の指令
		}
		
		// 入力信号の生成
		private void SignalGererate(double[] frq, double[] amp, float[] xn, double snr)
		{
			var phi = frq.Select(x => 2*PI*x/FS_);

			for (int n=0; n<xn.Length; n++)
				xn[n] = phi.Select((x, k) => (float)(amp[k]*Sin(x*n))).Sum();

			// 雑音を付加
			double sum2 = xn_.Select(x => x*x).Sum();	// 雑音のない信号の２乗和の計算

			double sigma = Sqrt((sum2/xn.Length)/Pow(10.0, snr/10.0));
			GaussRand rnd = new GaussRand();
			xn_ = xn_.Select(x => x+(float)rnd.Execute(sigma, 0.0)).ToArray();
		}

		// 線スペクトル強調器（ALE）実行指令
		private bool Ale()
		{
			toolStripStatusLabel1.Text = "計算を開始します．";
			statusStrip1.Update();	// toolStripStatusLabel1 に直ちに表示する

			// 発散する場合，波形を描画しないようにするため
			yn_ = Enumerable.Repeat(3.0f, yn_.Length).ToArray();

			aleOk_ = true;			// 処理結果の波形を表示するため
			AleLMS filter = new AleLMS(delay_, ORDER_, mu_);
			int n;
			for (n=0; n<N_ALL_; n++)
			{
				yn_[n] = filter.Execute(xn_[n]);
				if (Abs(yn_[n]) > 100.0) break;  // 100 以上で発散とみなす
			}

			if (n != N_ALL_)
			{
				toolStripStatusLabel1.Text = "発散しました．";
				button2.Enabled = false;
				return false;
			}

			toolStripStatusLabel1.Text = "計算を終了しました．";
			button2.Enabled = true;
			return true;
		}

		// 時間軸の描画
		private void Axis(Graphics gr)
		{
			gr.ResetTransform();
			gr.TranslateTransform(6, 5);
			gr.DrawLine(Pens.Black, 0, 0, xw_, 0);

			int n0 = n_bgn_ % D_PIXEL_;
			for (int n=0; n<xw_+D_PIXEL_; n+=D_PIXEL_)
			{
				if (n-n0 >= 0 && n-n0 <= xw_)
				{
					double t = 1000.0*(n+D_PIXEL_*(n_bgn_/D_PIXEL_))/FS_;
					gr.DrawLine(Pens.Black, n-n0, 0, n-n0, -5);
					string tStr = t.ToString();
					gr.DrawString(tStr, Font, Brushes.Black,
								  n-n0-(2+3*tStr.Length)*dpiFactor_, 4);
				}
			}
		}

		// 波形の描画
		private void Waveform(Graphics gr, float[] x, int n_disp, bool signal = true)
		{
			if (n_disp <= 0) return;

			gr.ResetTransform();
			gr.TranslateTransform(6, pictureBox1.Height/2);
			gr.DrawLine(Pens.Black, 0, 0, xw_, 0);

			if (signal)
			{
				float amp = -0.5f*(pictureBox1.Height/2);
				PointF[] pt = new PointF[n_disp];
				for (int n=0; n<n_disp; n++)
				{
					if ((n+n_bgn_) > x.Length) break;
					pt[n] = new PointF(n, amp*x[n+n_bgn_]);
				}

				gr.SmoothingMode = SmoothingMode.AntiAlias;
				gr.DrawCurve(Pens.Blue, pt);
				gr.SmoothingMode = SmoothingMode.Default;
				pictureBox3.Invalidate();
			}
		}
	}
}
