2

タイトルが言ったように:

2つのトラックバーを備えたフォームがあります。1 つは周波数用で、もう 1 つは振幅用です。オンザフライで変更するためのタイマーを設定しました。

private void timer1_Tick(object sender, EventArgs e)
    {
        float amplitude, frequency;

        amplitude = Convert.ToSingle(trackBar1.Value) / 100;
        label1.Text = amplitude.ToString() + " V";

        frequency = trackBar2.Value;
        label2.Text = frequency.ToString() + " Hz";
    }

また、どのタイプの信号を表示するかを決定するための 4 つのラジオ ボタンもあります (正弦、正方形、三角形、のこぎり)。

これを ImageList (信号のイメージを変更) で実装しました。

信号の種類を描画してトラックバーで調整するにはどうすればよいですか? したがって、オシロスコープのようになります。

あなたの答えとコードをありがとう。

4

3 に答える 3

1

さまざまな信号タイプを作成することから始めましょう。これは、振幅 1 の 1 つの波長を作成する関数です。

private PointF[] CreateBaseSignal(SignalType signalType)
{
  switch (signalType)
  {
    case SignalType.Sine:
      const int oversampling = 32;
      PointF[] signal = new PointF[oversampling];
      for (int i = 0; i < signal.Length; i++)
      {
        signal[i].X = (float) i / oversampling;
        signal[i].Y = Convert.ToSingle(Math.Sin((double) i / oversampling * 2 * Math.PI));
      }
      return signal;

    case SignalType.Square:
      return new PointF[]
      {
        new PointF(0.0f, -1.0f),
        new PointF(0.5f, -1.0f),
        new PointF(0.5f, 1.0f),
        new PointF(1.0f, 1.0f),
      };

    case SignalType.Triangle:
      return new PointF[]
      {
        new PointF(0.0f, -1.0f),
        new PointF(0.5f, 1.0f),
      };

    case SignalType.Sawtooth:
      return new PointF[]
      {
        new PointF(0.0f, -1.0f),
        new PointF(1.0f, 1.0f),
      };

    default:
      throw new ArgumentException("Invalid signal type", "signalType");
  }
}

次に、選択した振幅と周波数で実際の信号を作成します。

private PointF[] CreateSignal(PointF[] baseSignal, float frequency, float amplitude)
{
  PointF[] signal = new PointF[Convert.ToInt32(Math.Ceiling(baseSignal.Length * frequency))];
  for(int i = 0; i < signal.Length; i++)
  {
    signal[i].X = baseSignal[i % baseSignal.Length].X / frequency + (i / baseSignal.Length) / frequency;
    signal[i].Y = baseSignal[i % baseSignal.Length].Y * amplitude;
  }
  return signal;
}

この信号を PictureBox にプロットする前に、幅と高さに合わせて信号をスケーリングします。

private PointF[] ScaleSignal(PointF[] signal, int width, int height)
{
  const float maximumAmplitude = 10.0f;
  PointF[] scaledSignal = new PointF[signal.Length];
  for(int i = 0; i < signal.Length; i++)
  {
    scaledSignal[i].X = signal[i].X * width;
    scaledSignal[i].Y = signal[i].Y * height / 2 / maximumAmplitude;
  }
  return scaledSignal;
}

Graphics.DrawLine を使用して信号をプロットすると、Bitmap.SetPixel よりもはるかに優れています。これは、データ ポイントが高周波数でも接続されるためです。Bitmap.SetPixel も非常に遅いため、適切なパフォーマンスを実現するには、Bitmap.LockBits と安全でないコードを使用して単一のピクセルを操作する必要があります。Graphics.DrawLine を使用すると、線幅やアンチエイリアスなども制御できます。

信号を PointF 配列に保存したので、単純な Graphics.DrawLines メソッドを使用して、データ ポイントを反復処理する代わりに信号をプロットできます。

private void PlotSignal(PointF[] signal, PictureBox pictureBox)
{
  Bitmap bmp = new Bitmap(pictureBox.ClientSize.Width, pictureBox.ClientSize.Height);
  signal = ScaleSignal(signal, bmp.Width, bmp.Height); // Scale signal to fit image

  using(Graphics gfx = Graphics.FromImage(bmp))
  {
    gfx.SmoothingMode = SmoothingMode.HighQuality;
    gfx.TranslateTransform(0, bmp.Height / 2); // Move Y=0 to center of image
    gfx.ScaleTransform(1, -1); // Make positive Y axis point upward
    gfx.DrawLine(Pens.Black, 0, 0, bmp.Width, 0); // Draw zero axis
    gfx.DrawLines(Pens.Blue, signal); // Draw signal
  }

  // Make sure the bitmap is disposed the next time around
  Image old = pictureBox.Image;
  pictureBox.Image = bmp;
  if(old != null)
    old.Dispose();
}

信号を頻繁に再描画する場合は、毎回新しいオブジェクトを作成するのではなく、Bitmap オブジェクトと Graphics オブジェクトを再利用することをお勧めします。各再描画の間に Graphics.Clear を呼び出すことを忘れないでください。

すべてを 1 つの大きなステートメントにまとめると、次のようになります。

PlotSignal(
  CreateSignal(
    CreateBaseSignal(signalType),
    frequency,
    amplitude),
  thePictureBox);
于 2012-04-14T12:12:15.423 に答える
0

あなたが高速プロットライブラリを探しているなら、私はダイナミックデータディスプレイが本当に好きです

動的データ表示

これはWPFコンポーネントですが、高速でスムーズな描画アプリケーションの場合、後でよりも早くWPFに移植する価値があると思います。とにかく、現時点ではプロジェクトにそれほど深く関わっていないように感じます。

WPFの開発は、このコンポーネントでは停止しているようです(ただし、Silverlightでは引き続き作業中です)。ドキュメントはひどいですが、ソースコードは上記のリンクから入手できるので、必要に応じて拡張でき(非常によく書かれていて、非常に拡張可能です)、ドキュメントがほぼ完全に不足している代わりに、ソースは非常に貴重です。

于 2012-04-13T13:02:19.080 に答える
0

ピクチャ ボックス コントロールに正弦波をプロットする場合、フォームにピクチャ ボックス コントロールを作成し、次の手順を実行します。

    int width = pictureBox1.Width;
    int height = pictureBox1.Height;
    Bitmap b = new Bitmap(width, height);

    for (int i = 0; i < width; i++)
    {
        int y = (int)((Math.Sin((double)i * 2.0 * Math.PI / width) + 1.0) * (height - 1) / 2.0);
        b.SetPixel(i, y, System.Drawing.Color.Red);
    }
    pictureBox1.Image = b;
于 2012-04-13T13:22:12.580 に答える