フィルターがうまく動作しないので、フィルターをテストするプログラムを作ることにした。 もともとAF段をPCで処理するダイレクトコンバージョン受信機を作っていたんだけど、だんだん離れていくような気もするけど、これはこれで楽しいのでこのまま進めることにする。
まずは、発振器を作る。 前に作っていたものをちょっと見直した。
縦軸も横軸も適当で、波形が見えるように無理やり調整した。
後で直す予定。 ソースコードも前に掲載したかもしれないけど、改めてアップしておく。
もともと複素信号のシミュレーションをするために作ったものだけど、今回は実信号だけ利用する。
発振器本体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Numerics; namespace FilterTest { class oscillator { private double _frequency; //Hz private int _sample_rate; private double _amp; //振幅 Max -1.0~1.0 private bool _real; //real=true 実信号 real=false 複素信号 private bool _swap; //実部と虚部の入れ替え private double sin_value; private double cos_value; private Complex osc_vect; //コンストラクタ public oscillator(double freq, int sample_rate, double amp, bool real, bool swap) { _frequency = freq; _sample_rate = sample_rate; _amp = amp; _real = real; _swap = swap; update(); osc_vect = new Complex(0, 1); } public double frequency { get { return _frequency; } set { _frequency = value; update(); } } public int sample_rate { get { return _sample_rate; } set { _sample_rate = value; update(); } } public double amp { get { return _amp; } set { _amp = value; update(); } } public bool real { get { return _real; } set { _real = value; } } public bool swap { get { return _swap; } set { _swap = value; } } //パラメータの更新 private void update() { var anglepertikc = 2.0 * Math.PI * _frequency / _sample_rate; sin_value = Math.Sin(anglepertikc); cos_value = Math.Cos(anglepertikc); } public Complex tick() { Complex vect; vect = (osc_vect.Real * cos_value - osc_vect.Imaginary * sin_value) + Complex.ImaginaryOne * (osc_vect.Imaginary * cos_value + osc_vect.Real * sin_value); osc_vect = vect; if (real) vect = vect.Real + vect.Real*Complex.ImaginaryOne; else if (swap) vect = vect.Imaginary + Complex.ImaginaryOne * vect.Real; return _amp * vect; } public void reset_angle() { osc_vect = Complex.ImaginaryOne; } } } |
グラフ表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.Windows.Forms; using System.Drawing.Drawing2D; using System.Numerics; namespace FilterTest { class DrawGraph { private PictureBox picturebox_; private float x0_; //x軸原点 private float y0_; //y軸原点 private float y1_; //y軸1に対するピクセル値 private float width_; private Font myfont_ = new Font("MS UI Gothic", 10); private SolidBrush mysolidbrush_ = new SolidBrush(Color.Black); private const float x_offset = 10.0F; private const float y_offset = 10.0F; //コンストラクタ public DrawGraph(PictureBox myPictureBox) { picturebox_ = myPictureBox; x0_ = picturebox_.Left; y0_ = picturebox_.ClientSize.Height - 1; y1_ = y0_ /(float)(1.2* 32000); width_ = picturebox_.ClientSize.Width - 1; } public void DrawAxis(Graphics gr) { DrawVerticalLines(gr, Pens.Black); DrawHolizontalLines(gr, Pens.Black); } private void DrawHolizontalLines(Graphics gr, Pen mypen) { float yn = y0_ / 10; for (int i = 0; i <= y0_; i += 1) gr.DrawLine(mypen, 0, y0_ - yn * i, width_, y0_ - yn * i); } private void DrawVerticalLines(Graphics gr, Pen mypen) { float xn = width_ / 10; for (int i = 0; i <= (int)width_; i += 1) gr.DrawLine(mypen, xn * i, 0, xn * i, y0_); } public void DrawData(Graphics gr, Complex[] gdata) { Pen mypen = new Pen(Color.Red); for(int i=0; i<gdata.Length; i++) gdata[i] = 10000.0 * gdata[i]; PointF ioldPoint = new PointF(0, (float)(y0_ + y1_ * gdata[0].Real - y0_/2)); PointF qoldPoint = new PointF(0, (float)(y0_ + y1_ * gdata[0].Imaginary - y0_ / 2)); float tick = width_ / gdata.Length*10; for (int i = 1; i < gdata.Length - 1; i++) { mypen.Color = Color.Green; PointF inewPoint = new PointF(i * tick, (float)(y0_ + y1_ * gdata[i].Real-y0_/2)); gr.DrawLine(mypen, ioldPoint, inewPoint); ioldPoint = inewPoint; mypen.Color = Color.Red; PointF qnewPoint = new PointF(i * tick, (float)(y0_ + y1_ * gdata[i].Imaginary - y0_ / 2)); gr.DrawLine(mypen, qoldPoint, qnewPoint); qoldPoint = qnewPoint; } } } } |
本体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Numerics; namespace FilterTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private DrawGraph dg; private oscillator osc; private Queue<Complex[]> sig; private int datapoint = 1024; private double freq = 800.0; private int sample = 44100; private double amp = 1.0; private void Form1_Load(object sender, EventArgs e) { dg = new DrawGraph(pictureBox1); osc = new oscillator(freq, sample, amp, true, false); //実信号に設定 sig = new Queue<Complex[]>(); } private void btn_START_Click(object sender, EventArgs e) { timer1.Start(); } private void btn_STOP_Click(object sender, EventArgs e) { timer1.Stop(); } private void pictureBox1_Paint(object sender, PaintEventArgs e) { dg.DrawAxis(e.Graphics); if (sig.Count > 0) //データがあれば描画 dg.DrawData(e.Graphics, sig.Dequeue()); } private void timer1_Tick(object sender, EventArgs e) { Complex[] data = new Complex[datapoint]; for(int i = 0; i < datapoint; i++) { data[i] = osc.tick(); } sig.Enqueue(data); pictureBox1.Invalidate(); } } } |
Threadを使わないで色んなグラフを表示するために、FIFOを使っているけど一つの信号だけなら不要かも。