OBW Code
OBW Code
To control your Agilent E4446A Spectrum Analyzer programmatically via C#, you’ll
typically communicate using SCPI commands over a VISA interface (GPIB, LAN, or
USB). You can use NI VISA, Keysight IO Libraries, or Tek VISA to handle the
communication.
You'll need:
using System;
using System.Linq;
class OccupiedBandwidthCalc
try
io.WriteString("*CLS");
io.WriteString(":INIT; *WAI");
io.WriteString(":TRAC? TRACE1");
io.WriteString(":FREQ:STAR?");
io.WriteString(":FREQ:STOP?");
double currentSum = 0;
currentSum = 0;
lowerIdx = i;
upperIdx = j;
goto Done;
}
Done:
// Place markers
io.WriteString($":CALC:MARK1:X {lowerFreq}");
io.WriteString($":CALC:MARK2:X {upperFreq}");
// Output result
Great question! To visualize the trace and highlight the Occupied Bandwidth (OBW)
region between the lower and upper frequency limits, you can use Windows Forms with a
charting library (like System.Windows.Forms.DataVisualization.Charting).
Let’s walk through how to plot the spectrum trace and highlight the OBW region on a
graph with markers at the boundaries
Step-by-Step Plan
File > New > Project > "Windows Forms App (.NET Framework)"
Add a Chart control to your form from the toolbox.
using System.Windows.Forms.DataVisualization.Charting;
Let’s assume you already have the following arrays from your analyzer:
chart1.Series.Clear();
chart1.ChartAreas.Clear();
chart1.ChartAreas.Add("MainArea");
spectrumSeries.ChartType = SeriesChartType.Line;
spectrumSeries.Points.AddXY(freqMHz, powerValues[i]);
chart1.Series.Add(spectrumSeries);
TextAlignment = StringAlignment.Near,
BorderColor = Color.Red,
BorderWidth = 1
};
chart1.ChartAreas[0].AxisX.StripLines.Add(obwStrip);
// Add markers
lowerMarker.ChartType = SeriesChartType.Point;
lowerMarker.MarkerStyle = MarkerStyle.Cross;
lowerMarker.MarkerSize = 10;
lowerMarker.Color = Color.Red;
upperMarker.ChartType = SeriesChartType.Point;
upperMarker.MarkerStyle = MarkerStyle.Cross;
upperMarker.MarkerSize = 10;
upperMarker.Color = Color.Red;
chart1.Series.Add(lowerMarker);
chart1.Series.Add(upperMarker);
// Label axes
Output Preview
Perfect — exporting the chart as a PNG image and saving it on your PC is super simple in a Windows
Forms app using the built-in Chart.SaveImage() method.
Here’s a small function you can call after plotting the spectrum
try
chart1.SaveImage(filePath, ChartImageFormat.Png);
📁 Example Usage
SaveChartAsImage(fullPath);
SaveChartAsImage(fullPath);
}
if (sfd.ShowDialog() == DialogResult.OK)
{
SaveChartAsImage(sfd.FileName);
}
Great — you're close now! Let me walk you through exactly how to get these four things
from your Agilent E4446A spectrum analyzer using SCPI over C#.
io.WriteString("*CLS");
io.WriteString(":INIT:CONT OFF"); // Single sweep mode
// Configuration
io.WriteString(":FREQ:CENT 1GHz");
io.WriteString(":FREQ:SPAN 10MHz");
io.WriteString(":BAND 100kHz"); // RBW
io.WriteString(":BAND:VID 100kHz"); // VBW
// Trigger sweep
io.WriteString(":INIT; *WAI");
io.WriteString(":FREQ:STOP?");
double stopFreq = double.Parse(io.ReadString());
// Build freqArray
int pointCount = powerArray.Length;
double step = (stopFreq - startFreq) / (pointCount - 1);
Done:
double lowerFreq = freqArray[lowerIndex];
double upperFreq = freqArray[upperIndex];
Once you’ve got them, pass them to your chart plotting code
Awesome! Here’s your complete working C# code, all combined into a single Windows
Forms App that:
✅ Prerequisites
✅ Full C# Code
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using Ivi.Visa.Interop;
namespace OBW_Analyzer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
io.WriteString("*CLS");
io.WriteString(":INIT:CONT OFF");
// Setup configuration
io.WriteString(":FREQ:CENT 1GHz");
io.WriteString(":FREQ:SPAN 10MHz");
io.WriteString(":BAND 100kHz");
io.WriteString(":BAND:VID 100kHz");
io.WriteString(":INIT; *WAI");
io.WriteString(":FREQ:STOP?");
double stopFreq = double.Parse(io.ReadString());
io.IO.Close();
}
chart1.ChartAreas.Add("Main");
chart1.ChartAreas[0].AxisX.Title = "Frequency (MHz)";
chart1.ChartAreas[0].AxisY.Title = "Power (dBm)";
chart1.Series.Add(trace);
chart1.ChartAreas[0].AxisX.StripLines.Add(obwStrip);
if (sfd.ShowDialog() == DialogResult.OK)
{
chart1.SaveImage(sfd.FileName, ChartImageFormat.Png);
MessageBox.Show("Chart saved to:\n" + sfd.FileName,
"Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}
🖼 UI Summary
Element Name Purpose
After calculating lowerFreq and upperFreq, we’ll calculate OBW in MHz and display it on the
chart as a text annotation.
We'll find the frequency of the maximum power point in the trace and set the analyzer’s center
frequency to that value.
// OBW annotation
double obwMHz = (upperFreq - lowerFreq) / 1e6;
string obwText = $"99% OBW = {obwMHz:F3} MHz";
Before you send sweep commands, find the peak index and set it as center frequency:
io.WriteString(":FREQ:CENT 1GHz");
With this:
io.WriteString(":FREQ:CENT 1GHz");
io.WriteString(":FREQ:SPAN 100MHz");
io.WriteString(":INIT; *WAI");
io.WriteString(":TRAC? TRACE1");
io.WriteString(":FREQ:STAR?");
io.WriteString(":FREQ:STOP?");
io.WriteString($":FREQ:CENT {peakFreq}Hz");
💡 This will make your analyzer auto-center to the strongest signal before capturing the real OBW
measurement
X = peakFreqMHz,
Y = peakPower,
AnchorX = peakFreqMHz,
AnchorY = peakPower,
ForeColor = Color.DarkGreen,
Alignment = ContentAlignment.BottomCenter
};
chart1.Annotations.Add(peakNote);
Features Included:
namespace OBW_Analyzer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
io.IO =
(IMessage)rm.Open("TCPIP0::192.168.0.10::inst0::INSTR"); // Replace with
your VISA address
io.WriteString("*CLS");
io.WriteString(":INIT:CONT OFF");
// Step 1: Set wide span to find peak
io.WriteString(":FREQ:CENT 1GHz");
io.WriteString(":FREQ:SPAN 100MHz");
io.WriteString(":BAND 100kHz");
io.WriteString(":BAND:VID 100kHz");
io.WriteString(":INIT; *WAI");
io.WriteString(":FREQ:STAR?");
double tmpStart = double.Parse(io.ReadString());
io.WriteString(":FREQ:STOP?");
double tmpStop = double.Parse(io.ReadString());
io.WriteString(":FREQ:STAR?");
double startFreq = double.Parse(io.ReadString());
io.WriteString(":FREQ:STOP?");
double stopFreq = double.Parse(io.ReadString());
Done:
lowerFreq = freqArray[lowIdx];
upperFreq = freqArray[highIdx];
io.IO.Close();
}
chart1.ChartAreas.Add("Main");
chart1.ChartAreas[0].AxisX.Title = "Frequency (MHz)";
chart1.ChartAreas[0].AxisY.Title = "Power (dBm)";
// Spectrum trace
var trace = new Series("Spectrum") { ChartType =
SeriesChartType.Line };
for (int i = 0; i < freqArray.Length; i++)
trace.Points.AddXY(freqArray[i] / 1e6, powerArray[i]);
chart1.Series.Add(trace);
// OBW strip
var obwStrip = new StripLine
{
IntervalOffset = lowerFreq / 1e6,
StripWidth = (upperFreq - lowerFreq) / 1e6,
BackColor = Color.FromArgb(50, Color.Yellow),
BorderColor = Color.Red,
BorderWidth = 1
};
chart1.ChartAreas[0].AxisX.StripLines.Add(obwStrip);
// OBW markers
int idx1 = Array.FindIndex(freqArray, f => f >= lowerFreq);
int idx2 = Array.FindIndex(freqArray, f => f >= upperFreq);
AddMarker("OBW Start", lowerFreq / 1e6, powerArray[idx1]);
AddMarker("OBW End", upperFreq / 1e6, powerArray[idx2]);
// OBW annotation
double obwMHz = (upperFreq - lowerFreq) / 1e6;
var obwNote = new TextAnnotation
{
Text = $"99% OBW = {obwMHz:F3} MHz",
X = (lowerFreq + upperFreq) / 2e6,
Y = powerArray.Max(),
AnchorX = (lowerFreq + upperFreq) / 2e6,
AnchorY = powerArray.Max(),
Font = new Font("Arial", 10, FontStyle.Bold),
ForeColor = Color.Blue,
Alignment = ContentAlignment.TopCenter
};
chart1.Annotations.Add(obwNote);
// Peak annotation
double peakPower = powerArray.Max();
int peakIndex = Array.IndexOf(powerArray, peakPower);
double peakFreqMHz = freqArray[peakIndex] / 1e6;
if (sfd.ShowDialog() == DialogResult.OK)
{
chart1.SaveImage(sfd.FileName, ChartImageFormat.Png);
MessageBox.Show("Chart saved to:\n" + sfd.FileName,
"Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}
🎯 Recap
You're doing a great job calculating and visualizing the 99% occupied bandwidth. To add a
"mask" over the spectrum that matches the 99% bandwidth (or shows where the signal
should remain within), you can define a shape or limit over the frequency range of the 99%
OBW and draw it on the chart.
A mask in spectrum analysis usually refers to a region (either a simple power threshold line
or a more complex envelope) that a signal must stay within. For a 99% OBW mask, you'd
typically want a shaded area over the frequency range between lowerFreq and upperFreq,
and optionally also define upper and lower power limits.
Add this inside your PlotSpectrum function, after calculating lowerFreq, upperFreq, and
plotting the trace:
ChartType = SeriesChartType.Area,
BorderWidth = 0
};
chart1.Series.Add(maskSeries);
IntervalOffset = maskTop,
BorderColor = Color.Red,
BorderWidth = 1,
TextAlignment = StringAlignment.Far,
ForeColor = Color.Red
};
chart1.ChartAreas[0].AxisY.StripLines.Add(upperMaskLine);
IntervalOffset = maskBottom,
BorderColor = Color.Red,
BorderWidth = 1,
TextAlignment = StringAlignment.Near,
Font = new Font("Arial", 8),
ForeColor = Color.Red
};
chart1.ChartAreas[0].AxisY.StripLines.Add(lowerMaskLine);