Overview

While listening to shortwave, I noticed that huge chunks of the spectrum were being swamped at certain times of day. Since my spectrum analyzers are all analog, I decided to write a quick script to allow use of the HP 3586 selective level meter as a rudimentary spectrum analyzer.

Instructions

To use the script, edit it with a text editor and change the starting frequency ($freq_start), ending frequency($freq_end), step size($freq_increment), and number of sweeps to perform ($scan_rep). All frequencies are in kilohertz. Then, run the script and redirect output to a file. For example,

ataylor:~$ perl hp3586_specan.pl > output.data.txt

After the sweep is finished you can generate 2D or 3D plots with the following gnuplot scripts. Either change the xrange and yrange to match your data or comment out the lines so gnuplot autoscales each axis.

# 2D Plot
#
# General
#
set term postscript
set output "filename.ps"
set xrange [9250:10250]
set yrange [-115:-60]
set xlabel 'Frequency (kHz)'
set ylabel 'Amplitude (dBm)'
set pointsize 0.4
#
# Plot everything
#
plot "filename.dat" using 1:3 notitle with lines

# 3D Plot
#
# General
#
set term postscript enhanced eps
set output "filename.pdf"
set xrange [9200:10300]
set zrange [-110:-75]
set xlabel 'Frequency (kHz)'
set ylabel 'Time (Unix)'
#
# Plot everything
#
set view map
set palette defined (-110 "blue", -105 "white", -95 "red")
splot "filename.dat" using 1:2:3 notitle with points palette pt 5 ps 0.6

Source Code

The source code below contains two sleep() statements. You can reduce them in order to perform a faster sweep, but reducing them too far will cause odd behavior when the 3586 is not yet ready to supply a reading at the new frequency. As an example, it took just over two hours for a sweep from 9.25-10.25 MHz in 1 kHz steps with a 3.1 kHz RBW and sample averaging, as shown in the sample data file on this page.

# Quick script to use HP 3586C SLM
# as a rudimentary spectrum analyzer.

use Device::SerialPort;

# Set up the serial port
# 19200, 81N on the USB ftdi driver
my $port = Device::SerialPort->new("/dev/ttyUSB0");
$port->databits(8);
$port->baudrate(19200);
$port->parity("none");
$port->stopbits(1);

# Initialize Prologix USB-GPIB Controller
$port->write("++mode 1\n");
$port->write("++auto 1\n");
$port->write("++addr 16\n");

# Initialize HP 3586C
$port->write("Remote\n");
$port->write("B3\n"); # Set BW Filter
$port->write("T1\n"); # Terminate in 50 ohms
$port->write("A1\n"); # Average: On

# Frequency Sweep Definition
$freq_start = 9250;
$freq_end = 10250;
$freq_increment = 1;
$freq_index = $freq_start;
while ($freq_index <= $freq_end) {
  push (@frequency, $freq_index);
  $freq_index = $freq_index + $freq_increment;
}

$scan_rep = 70;
$scan_index = 1;
print "#(kHz)         (UNIXtime)              (dBm)\n";
print "Freq           Time                    Amplitude\n";
while ($scan_index <= $scan_rep) {
  print "# Starting Repetition: $scan_index\n";
  # Gather and print the measurements
  # If you want to sweep faster, adjust the two sleep() statements.
  #   Check manual for minimum settling times for your configuration of
  #   BW filter, averaging, etc.
  foreach $freq (@frequency) {
    $port->write("FR,$freq,KZ\n");
    sleep(6);
    $port->write("TR\n");
    sleep(2);
    my $char = $port->lookfor();
    $char =~ s/N//g;
    $char =~ s/\r//g; # To match the newlines from the HP 3586C
    chomp $char;
    $time = time; 
    print "$freq        $time       $char \n";
  }

  $scan_index = $scan_index + 1;
}

Files