//--------------------------------------------------------------
//	直接形 100次 FIR フィルタ入出力信号の波形の描画
//
//		作成者：三上直樹，2023/01/30 作成，ⓒ三上直樹 2023
//--------------------------------------------------------------

using System;
using System.Windows.Forms;

using Mikami;
using Mikami.WindowsApplication;
using Mikami.Filter;

using static System.Math;

namespace FIRフィルタ100次_正弦波入力_波形
{
	public partial class Form1 : Form
	{
		private const int N_START_ = 1200;
		private const int N_USE_ = 150;
		private const int N_DATA_ = N_START_ + N_USE_ + 40000/100;
		private const int OVS_ = 4;					// オーバーサンプリング比

		private const float X_MIN_ = 100.0f;		// 周波数の最小値
		private const float X_MAX_ = 4300.0f;		// 周波数の最大値
		private const float FS_ = 10000.0f;			// 標本化周波数 = 10 kHz

		// tFactor_: 周波数と TrackBar のツマミの位置の関係を表す係数
		private readonly double tFactor_ = Log10(X_MAX_/X_MIN_)/(X_MAX_ - X_MIN_);

		private readonly float dpiFactor_;			// 異なる DPI システム用スケール変換係数
		private readonly RadioGroup scaleV_;		// 縦倍率の情報を保持
		private readonly RadioGroup scaleH_;		// 横倍率の情報を保持
		private readonly WaveformDrawer drawer_;	// 波形描画用

		private float[] xn_ = new float[N_DATA_];	// 入力信号に対応する配列
		private float[] yn_ = new float[N_DATA_];	// 出力信号に対応する配列

		private float[] xm_, ym_;					// 補間した信号

		public Form1()
		{
			InitializeComponent();

			// 異なる DPI のシステムに対応するスケール変換の係数を取得
			dpiFactor_ = CreateGraphics().DpiX/96.0f;

			trackBar1.Minimum = (int)X_MIN_;	// TrackBar の最小値を設定
			trackBar1.Maximum = (int)X_MAX_;	// TrackBar の最大値を設定

			numericUpDown1.Maximum = (decimal)X_MAX_;
			numericUpDown1.Minimum = (decimal)X_MIN_;
			numericUpDown1.Value = numericUpDown1.Minimum;

			scaleV_ = new RadioGroup(groupBox1);
			scaleH_ = new RadioGroup(groupBox2);

			drawer_ = new WaveformDrawer(Font, pictureBox1.Height, OVS_, dpiFactor_);

			FormCloseConfirm.Set(this);			// 終了時に確認できるようにする
		}

		// 終了
		private void button1_Click(object sender, EventArgs e)
		{
			Close();
		}

		// 入力の正弦波の周波数を trackBar1 で設定し，正弦波を発生させる
		private void trackBar1_Scroll(object sender, EventArgs e)
		{
			int iFrq = (int)Round(X_MIN_*Pow(10, tFactor_*(trackBar1.Value - X_MIN_)));
			numericUpDown1.Value = iFrq;
		}

		// 周波数を numericUpDown1 で設定する
		private void numericUpDown1_ValueChanged(object sender, EventArgs e)
		{
			double frq = (double)numericUpDown1.Value;
			trackBar1.Value = (int)(X_MIN_ + Round(Log10(frq/X_MIN_)/tFactor_));
			label4.Text = (frq < 1000) ? frq.ToString() + " Hz"
									   : (frq/1000.0).ToString("#.000") + " kHz";

			SineGeneration(frq);
			Filtering();
		}

		// numericUpDown1 の入力文字列を全選択の状態にする
		private void numericUpDown1_Click(object sender, EventArgs e)
		{
			numericUpDown1.Select(0, numericUpDown1.Value.ToString().Length);
		}

		// numericUpDown1 で Enter キー入力時の Beep 音を消す
		private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter) e.SuppressKeyPress = true;
		}

		// 出力波形の倍率（振幅）の設定

		private void radioButton1_Click(object sender, EventArgs e)
		{
			pictureBox2.Invalidate();
		}

		// 時間軸の倍率の設定
		private void radioButton8_Click(object sender, EventArgs e)
		{
			pictureBox1.Invalidate();
			pictureBox2.Invalidate();
		}
		
		// 入力波形の描画指令
		private void pictureBox1_Paint(object sender, PaintEventArgs e)
		{
			drawer_.Draw(e.Graphics, xm_, N_START_, "1", scaleH_.Checked);
		}

		// 出力波形の描画指令
		private void pictureBox2_Paint(object sender, PaintEventArgs e)
		{
			drawer_.Draw(e.Graphics, ym_, N_START_, scaleV_.Checked, scaleH_.Checked);
		}

		// 入力正弦波の周波数の目盛描画
		private void pictureBox3_Paint(object sender, PaintEventArgs e)
		{
			DrawTickValue.Execute(e.Graphics, this, X_MAX_/X_MIN_);
		}

		// 正弦波発生
		private void SineGeneration(double frq)
		{
			double pi2fT = 2*PI*frq/FS_;
			for (int n=0; n<N_DATA_; n++)
				xn_[n] = (float)Sin(pi2fT*(n-N_START_));

			xm_ = Interpolator.Execute(xn_, N_DATA_);	// 帯域制限補間
			pictureBox1.Invalidate();
		}

		// フィルタ処理
		private void Filtering()
		{
			FIR_Direct fir = new FIR_Direct(hk_);
//			FIR_Transposed fir = new FIR_Transposed(hk_);
			for (int n=0; n<N_DATA_; n++) yn_[n] = fir.Execute(xn_[n]);

			ym_ = Interpolator.Execute(yn_, N_DATA_);	// 帯域制限補間
			pictureBox2.Invalidate();
		}
	}
}
