//------------------------------------------------------------------------------
//	Form1 で使っているイベントハンドラおよび描画以外のメソッド
//
//		作成者：三上直樹，2023/04/04 作成，©三上直樹 2023
//------------------------------------------------------------------------------

using System.Windows.Forms;

using System.Numerics;
using Mikami.WindowsApplication;

using static System.Math;
using static System.Numerics.Complex;

namespace FIR_Design_Windowing
{
	public partial class Form1 : Form
	{
		// フィルタの通過／阻止帯域により，入力可／不可な箇所を有効にする
		private void EnableCtrlBand()
		{
			if (passBand_.IsChecked("LPF", "HPF"))
				CommonProc.Disable(label8, label9, textBox6);
			else
				CommonProc.Enable(label8, label9, textBox6);
		}

		// 設計パラメータの入力
		private bool ParmInput()
		{
			const int MIN_ORDER = 2;
			// フィルタの次数
			if (!textBox1.ToInt(out nOrder_,
								v => (v >= MIN_ORDER) && (v <= MAX_ORDER_),
								"フィルタの次数を " + MIN_ORDER.ToString() + " 以上，"
								+ MAX_ORDER_.ToString() + " 以下にしてください．"
								)) return false;
			nTaps_ = nOrder_ + 1;
			if ((nOrder_ % 2 != 0) && passBand_.IsChecked("BRF"))
			{
				MessageBox.Show("BRF を選択した場合，次数は偶数次にしてください．");
				return false;
			}

			// 標本化周波数
			if (!textBox2.ToDouble(out fSkHz_)) return false;
			fSample_ = Abs(fSkHz_)*1.0E3;			// Hz 単位に変換

			// 遮断周波数
			if (!textBox5.ToDouble(out fcLow_,
								   v => (v > 0.0) && (v < fSkHz_/2),
								   "遮断周波数1を標本化周波数の 1/2 未満の正の値に設定してください．"
								   )) return false;	// 遮断周波数

			if (passBand_.IsChecked("BPF", "BRF"))	// BPF, BRF の場合
			{
				if (!textBox6.ToDouble(out fcHigh_,
									   v => (v > 0.0) && (v < fSkHz_/2) && (v > fcLow_),
									   "遮断周波数２を標本化周波数の 1/2 未満の正の値で，\r\n"+
									   "遮断周波数１より大きな値に設定してください．"
									   )) return false;
			}
			fcLow_ = fcLow_*1000.0; 			// Hz 単位に変換
			fcHigh_ = fcHigh_*1000;				// Hz 単位に変換

			// 減衰量，Kaiser 窓の場合
			if (windowType_.Checked == "Kaiser")
				if (!textBox4.ToDouble(out att_, v => v >= 20.0,
									   "減衰量 ≧ 20 にしてください．")) return false;

			return true;
		}

		// 設計の結果を RitchTextBox へ出力する
		private void OutputToRitchTextBox()
		{
			richTextBox1.Clear();

			richTextBox1.AppendText("// 使用窓関数   " + windowType_.Checked + " 窓\r\n");
			richTextBox1.AppendText($"// 標本化周波数 (kHz){fSkHz_, 12:F6}\r\n");
			richTextBox1.AppendText($"// 次数{nOrder_, 12:D}\r\n");
			richTextBox1.AppendText("// 種類         " + passBand_.Checked + "\r\n");

			if (!textBox6.Enabled)
				richTextBox1.AppendText($"// 遮断周波数 (kHz)  {fcLow_/1000, 12:F6}\r\n");
			else
			{
				richTextBox1.AppendText($"// 遮断周波数１ (kHz){fcLow_/1000, 12:F6}\r\n");
				richTextBox1.AppendText($"// 遮断周波数２ (kHz){fcHigh_/1000, 12:F6}\r\n");
			}

			if (windowType_.Checked == "Kaiser")
				richTextBox1.AppendText($"// 減衰量 (dB) {att_, 6:F2}\r\n");

			if (radioButton12.Checked) WriteInt((int)numericUpDown1.Value);
			else					   WriteFloatDouble((int)numericUpDown1.Value);
		}

		// float, double の場合の出力
		private void WriteFloatDouble(int num)
		{
			string s1 = radioButton10.Checked ? " 0.000000E+00f" :
												" 0.000000000000E+00";
			string fmt = s1 + ";-" + s1.Remove(0, 1);	// 負の数への対応

			string sOut = "        ";
			int count = 0;
			for (int n=0; n<nTaps_; n++)
			{
				sOut = sOut + " " + hk_[n].ToString(fmt) + ",";
				count++;
				if (count >= num)
				{
					if (n == (hk_.Length - 1))
						sOut = sOut.Remove(sOut.Length - 1);
					richTextBox1.AppendText(sOut + "\r\n");
					count = 0;
					sOut = "        ";
				}
			}
			if (sOut != "        ")
				richTextBox1.AppendText(sOut.Remove(sOut.Length - 1) + "\r\n");
		}

		// int の場合の出力
		private void WriteInt(int num)
		{
			string sOut = "        ";
			int count = 0;
			for (int n=0; n<nTaps_; n++)
			{
				sOut += $" {(int)Round(32768*hk_[n]), 6:D},";
				count++;
				if (count >= num)
				{
					if (n == (hk_.Length - 1))
						sOut = sOut.Remove(sOut.Length - 1);
					richTextBox1.AppendText(sOut + "\r\n");
					count = 0;
					sOut = "        ";
				}
			}
			if (sOut != "        ")
				richTextBox1.AppendText(sOut.Remove(sOut.Length - 1) + "\r\n");
		}

		// 振幅特性の計算
		private void CalcAmp(ref float[] logA_k)
		{
			float Amin_dB = (float)(20.0*Log10(A_MIN_));
			double dw = PI/F_DIV_;
			for (int n=0; n<logA_k.Length; n++)
			{
				double x = HwA(n*dw);
				logA_k[n] = (x < A_MIN_) ? Amin_dB : (float)(20.0*Log10(x));
			}
		}

		// 正規化角周波数を与えてそのときの振幅特性の値を得る
		private double HwA(double w)
		{
			Complex hz = Zero;
			Complex jw = -ImaginaryOne*w;
			for (int k=0; k<nTaps_; k++) hz += hk_[k]*Exp(k*jw);
			return Abs(hz);
		}
	}
}
