Software for the Modularized Spectrum Analyzer
This page is a Description of the Software Code that controls the Spectrum Analyzers.
    I have previously written several Liberty Basic software routines to control the different versions of the Spectrum Analyzer.  I have now combined them all, into one version that will operate any of my Spectrum Analyzer designs (SSAProto, SSABoard, and MSA).  On this page, I will try to describe the  the program.  But, since there are over 2000 lines of code, I will not describe the action of each code line.  If you want to know what a specific line of code does, e-mail me.  I will be happy to respond.  wsprowls@yahoo.com
Page Started Nov. 30, 2004 and is in progress.  Use your browser's "Refresh" for latest info.
Updated Mar 15, 2006, change software to revision 107, added a 16 bit A to D serial process
Updated June 24, 2006, change software to revision 108 and update this page.

If you came to this page from a Link, return by using your browser's Back button, or click the following:
Go Back to the Modularized Spectrum Analyzer Main Page

This is a fairly long page.  Use the following buttons to navigate to the sections of interest:
What computer is needed to operate the Spectrum Analyzers?
What software is needed?
How to download the Spectrum Analyzer Software
Describe what the software is doing.
How to Operate and Calibrate the Spectrum Analyzer, this will take you to a different page

Computer Required to operate the Spectrum Analyzer:
    PC or Laptop Computer with LPT 1 standard parallel port.  Windows or OS/2.
    Monitor can be any size, but must be set for a minimum of 800 by 600 pixel resolution.  More is fine.
    I am using a Toshiba Satellite Laptop, 700 MHz Celeron.  return to top

Software Required to
operate the Spectrum Analyzer:
    Liberty Basic 3.01 or more recent.  I wrote the program in this "Basic" code because I am not a software guru.  I was famaliar only with HP Basic and Commodore Basic and this is very similar.  It is also very inexpensive.  Go visit their web site at www.libertybasic.com.  They have a free version of Liberty Basic 4.0, and although it is a trial version, it will operate the Spectrum Analyzer with this software.
    If you can do the programming, you can rewrite my code in some other software.  If you look at the code, a description is annotated with the program lines.  That should tell you what you want the program to do.  The code is in text format.  Just copy and paste the code into your Liberty basic .bas file, and it will run just fine. 
return to top

How to download the Spectrum Analyzer Software?
    Here is the Liberty Basic Code spectrumanalyzer.bas for the Modularized Spectrum Analyzer.  This software code will also work fine for the SSA Prototype, SSA Board, and Modularized Spectrum Analyzer.  I am even changing previous links to use this software.  I will continually update this software for more types of PLL's.  The revision number will be on the first line of code.  If I find an error or enhance the operating characteristics, I will note the revision as 102, 103, 104, etc.  Any 10x version of software will work fine with the MSA, as designed.  If I change the software to a revision that will not work for the original MSA, SSAP, or SSAB, I will not link to it on this page.  I have no plans to do that at the moment, but one day, I am going to design a Control Board for USB interface that will require a major revision.
    If you are using Netscape, left clicking on the above link will open the code in a text format.  To download the program to your Liberty Basic folder, right click on the link and save as a link target.
    It you are using Explorer, clicking on the link will open a request window for saving or opening.  It will open as a text document.  It will save as a .bas file. Save it in your Liberty Basic folder.
    No matter how you save this code, keep the original in a safe spot and copy it with a different name.  Use the copied version when opening and changing the global variables, for the first time.  If you happen to mess up, you will have the original version to start over.
    This software is quite lengthly, due to the subroutines that handle the various PLL types and other informational remarks. 
Any lines that begin with apostrophe are remarks and are not compiled.  You can shorten the code by deleting the subroutines and remarks that are not needed, but I don't advise that, unless you become quite familiar with the Liberty Basic. The program will not run any faster with the subroutines and remarks deleted, however, it will compile a little faster.
    When the Spectrum Analyzer's Program is opened in Liberty Basic, the Liberty Basic Code Window will open.  The Global Variables must be established by changing some of the code lines at the beginning of the code.   The SA's Program is started when the RUN button in the Liberty Basic Code Window is clicked.  Upon running, two windows will open, covering up the Code Window.  They are the Spectrum Analyzer Graph Window and Spectrum Analyzer Working Window.  return to top

Software Descriptions
    This program is described here, with the following assumptions:
1. The 2nd LO frequency (PLL 2) is a fixed frequency, locked to the Master Oscillator
.  PLL 2 can be deleted and substituted with an SRD Multiplier or similar multiplier, locked to the Master Oscillator.  If used, the PLL 2 will be used as an Integer-N PLL, even if it has Fractional-N capability.
2. All Final Xtal Filters, used within the same program, must be within the bandwidth of the 1st IF Filter.  For example, if the Spectrum Analyzer's 1st IF Filter is a Cavity Filter with a bandwidth of 2 MHz, then the total spread of the Final Xtal Filters can be no greater than 2 MHz.  ie, final filters are 10.0 MHz, 10.6 MHz, 10.7 MHz, 11.15 MHz.  Total spread is 11.15 - 10.0 = 1.15 MHz
3. PLL's 1, 2, and 3 are built with LMX 2325, 2326, 2350, 2353's or the ADF 2112.  All PLL's can be the same, or a combination, thereof.
4. The
Master Clock must be an integer multiple of the Phase Frequency of PLL 2.  For the LMX series PLLs, the integer multiple must be 3 or greater.
5.  Optional PLL 3, Tracking Generator can use either a Fractional-N or Integer-N PLL.  Fractional-N would be preferred, since the TG could be programmed in smaller increments, to be more compatible with odd frequency Final Xtal Filters.

6.  PLL 1 could be set up as a Fractional-N PLL, but, I don't recommend it, due to excessive spurs.
7.  The Log Detector can be either an LM3356, AD3806 or AD3807.
8.  The Analog to Digital conversion can use 8 bit or 12 bit parallel, or 16 bit serial process.

Here are descriptions of the Software.  Click on any one to jump to the Block's individual Description.  To keep this page from being overly long, I will not show every line of code in the program.  There are over 2000 lines of code.  I suggest you open a seperate window for, or print out, the code to view, while looking at the code descriptions.  Get the code here.
  You can open and read the code with any text reader program, such as Notepad.
    There are 3 Main Blocks to this software program.  The Global Variables, Main Routines, and Sub-Routines.  The Global Variables are used throughout the program.  The program flow follows the Main Routines.  The Sub-Routines are called upon by the Main Routines.

Global Variables, and their functions:
   
This is the beginning of the program, and it is where the user must define the Global Variables that are specific to his Spectrum Analyzer.  Some of the variables are defaults.  That is, they are starting values for the Spectrum Analyzer Program and will be changed by software action while the SA Program is running.  Other variables, once established, will never be changed.  Here is a description of how and where the global variables are used in the program.

    nomainwin  
This just tells the program not to open a main window.  This program will open two windows, later in the code.
    masterclock = 64 
This is the frequency of the Master Clock, in MHz.  Enter the EXACT frequency of your Master Clock, up to 6 decimal places.  If you don't know it's frequency, enter what you think it should be (like, what it is marked).  If it is adjustable, enter the frequency you know it will be after it is calibrated.  You will be able to calibrate it later, during the MSA calibration procedure.  The program uses this to calculate the actual (and correct) frequency of the Local Oscillator 1, Local Oscillator 2, and the optional Tracking Generator.
    cf = 0 
This is the center frequency default, all frequencies in MHz., used to determine the frequency at the center of the sweep.  It will be shown and can be changed in the "Center Freq" Box of the Working Window.
    sw = .02
This is the default sweep width, in MHz.  The SA will sweep from one half sw below CF to one half above the CF (center frequency).
  It will be shown and can be changed in the Working Window's, "Sweep Width" Box.
    wat = 0  
This is a whole number that is used later in the code, to slow down the sweep speed.  This is so that the hardware will have time to settle before data is taken.  This is a default, and
will be shown and can be changed in the Working Window, "Wait" Box.
    sps = 400  
Steps per sweep, default.  This is the number of steps in each sweep. Used to determine where in the sweep the program is.  Value can be changed in "Steps/Sweep" Box, of Working Window.  This number can be any whole number between
1 and 720.
    mkr1 = 100 
This is the default step number, where the marker 1 will place information in the Graph Window. It w
ill be shown, and can be changed in the "Place Markers at Steps" Boxs.  It can be a whole number from 0 to the value that is in "sps".  If a marker is not wanted, the value of the "mkr" can be changed to a number higher than "sps".  For example, entering "450" will not allow a marker to be displayed.
    mkr2 = 200
Marker 2 step placement, default.  Same as above
    mkr3 = 300  
Marker 3 step placement, default.  Same as above
    finalfreq1 = 10.7  
Normally, this is the center frequency (in MHz) of Final Xtal Filter # 1.  This will be the final I.F. frequency that enters the Log. Detector. This variable is used to determine the correct LO1 freq, and the Tracking Generator Frequency.  There are provisions, in the software, for 4 final filters.  Each one can be selected in the "Select Final Filter:" boxes of the Working Window.  In certain cases, the operator may want to change this global variable to "offset" the final I.F.  Just remember, whatever frequency is placed into this global variable, that is what the final I.F. frequency is going to be, no matter what the
Final Xtal Filter # 1 frequency is.
    The Final Xtal Filter and the final I.F. can be any frequency, within reason.  It should not be less than about 8 MHz.  This is due to the characteristics of the cavity filter used for I.F 1.  It will not reject the generated image frequencies if a Final I.F. is too low.  Higher final I.F. frequencies are limited only by the bandwidth of the final I.F. amplifiers and the Log Detector.  When using the AD83xx series of Log Detectors, a final I.F. of 21 MHz or 45 MHz is perfectly acceptable.  I chose 10.7 MHz because there are many inexpensive off-the-shelf Monolithic Crystal Filters in this frequency range.
    finalbw1 = 2.0 
This is the band width (in KHz) of Final Xtal Filter # 1.  This is not used in calculations, only placed into the "Final I.F. Freq" Box, along with the Final Freq value.
    sagain1 = 0 
This is the total gain (in dB) of MSA with Final Filter #1 installed.  Used to calibrate Graph Window.  On initial set-up, use a value of "
0".  During MSA calibration, this value will be changed to reflect the actual gain of the MSA circuitry.  For example, if the MSA has a gain of 37 dB from the input of the MSA to the input of the Log Detector, the value "37" will be entered here.
    finalfreq2 = 10.7   'freq of Final Xtal Filter # 2
    finalbw2 = 10.0     'BW (in KHz)of Final Xtal Filter # 2
    sagain2 = 0         'total gain of MSA with Final Filter #2 installed

    finalfreq3 = 10.7   'freq of Final Xtal Filter # 3
    finalbw3 = 30       'BW (in KHz)of Final Xtal Filter # 3
    sagain3 = 0         'total gain of MSA with Final Filter #3 installed

    finalfreq4 = 10.7   'freq of Final Xtal Filter # 4
    finalbw4 = 200      'BW (in KHz)of Final Xtal Filter # 4
    sagain4 = 0         'total gain of MSA with Final Filter #4 installed
These are the values of the other 3 filters.  If only one filter is used, then enter the same values as entered for Filter 1.  If using the I.F. 1 cavity filter I have designed, all 4 filters must be within 2 MHz of each other.  This is because the bandwidth of the cavity filter is 2 MHz.
    appxDDS = 10.7 
This is the
center frequency of the DDS xtal filter and the nominal DDS output frequency (Ref. for PLL1).  The program uses this value as an approximation when calculating LO 1 frequency.
    ddsfilbw = .015
This is the bandwidth of the DDS output filter. 
This value is only used as an error check, when commanding the DDS.
    The DDS filter is chosen for minimum bandwidth, to minimize DDS spurious.  But, it must be wide enough to allow for full "steering" of the PLL 1.  The minimum bandwidth that can be used is derived from the formula: 
PLL1phasefreq = (VCO 1 minimum frequency) x ddsfilbw/appxDDS.
rewritten : 
ddsfilbw  =  PLL1phasefreq x appxDDS / (VCO 1 minimum frequency)  or
ddsfilbw =  .972 MHz x 10.7 MHz / 1000 MHz = .0104 MHz.  A 15 KHz BW filter satisfies this requirement, for the Integer-N PLL 1.
  If Fractional-N PLL 1 is used, the following formual is used:
 
ddsfilbw  = ( PLL1phasefreq/16) x appxDDS / (VCO 1 minimum frequency).  Using the Fractional example:  ddsfilbw =  (3.57 MHz/16) x 10.7 MHz / 1000 MHz = .002387 MHz.  Therefore, a 2.5 KHz BW (or wider) filter would work nicely for the Fractional-N PLL.
    PLL1 = 2326   
Enter the suffix of the PLL chip you are using in this position: (LMX) 2325, 2326, 2350, 2353, (ADF) 4112.  The program will use "if" statements using these values to determine which PLL subroutine to use for commanding.
    PLL1phasefreq = .972 
This is the Phase Detector Frequency (PDF) you have designed for PLL 1, in MHz.  It is also the step size for PLL 1 and determines the value of it's Rcounter.  "PLL1phasefreq" must be less than the following formula: PLL1phasefreq = (VCO 1 minimum frequency) x ddsfilbw/appxDDS.  The determining factor is the DDS output frequency and it's narrow band filter.  Assume that the lowest frequency of the LO 1 will be 1000 MHz, the DDS output frequency is 10.7 MHz, and the DDS filter has a band width of 15 KHz.  Formula:  PLL1phasefreq = 1000 x .015 / 10.7 = 1.401869 (MHz)  The number, 1.4 would give the best phase noise characteristics for PLL 1, however, the LMX 2326 would be given illegal codes to it's "Bcounter".  The highest phase frequency allowed for the LMX2326, without illegal codes, is 1.05 MHz.  If 1.05 was selected as the phase frequency, the LMX 2326 must divide the reference frequency by 10.19.  Since the reference divider within the LMX2326 must be a whole number value, the divider will be 11, since 10 would give too high a phase frequency.  Therefore, 10.7/11 = .9727 (MHz).  This is the number to put into the global variable, PLL1phasefreq.
    PLL1mode = 0
This variable is the usage of PLL1:  "
1" = Fractional-N Mode,  "0" = Integer-N Mode.  The previous instruction, for setting up the global variable "PLL1phasefreq", assumed that PLL 1 is operating as an Integer-N phase locked loop.  All of the PLLs mentioned (2325, 2326, 2350, 2353,4112) will operate as an Integer-N.  Two of these chips, LMX 2350 and 2353, can also be used as Fractional-N.  The advantage of a Fractional-N PLL is, a higher PLL phase detector frequency (PDF) can be used, which results in an improvement in PLL phase noise.  The disadvantage is, Fractional-N counters create significant spurs.
  If the builder desires the use of the LMX 2350 or 2353 as Fractional-N, then enter a "1" into the variable "PLL1mode", and use the following instructions for the "PLL1phasefreq" global variable:
        PLL1phasefreq = 3.57       (when PLL 1 is used as Fractional-N)
This is the formula to determine the VCO frequency when using a Fractional-N PLL :
VCO freq = [(B x P) + A + F/16 ] x PDF   where:
VCO freq will range from 1000 MHz to 2000 MHz
P is the preselector and will be 16 for maximum PDF
B is the numerical Bcounter and can be from
A is the numerical Acounter
F is the fractional counter (0 to 15)
PDF is the phase detector frequency,  the number we will obtain to enter into the variable, "PLL1mode"
The chip has an Acounter, Bcounter relationship that must be followed:  The Bcounter must equal to, or greater than (Acounter + 2).
Since the preselector is 16, then the Acounter can be as high as 15.  This means the Bcounter can not be less than 17.
  By using the above formula, we can solve for PDF:
  PDF = VCO freq/ [(B x P) + A + F/16 ],
PDF = 1000 MHz/
[(17 x 16) + 0 + 0/16 ] = 3.676 MHz.  If the Reference frequency is 10.7 MHz, the Rcounter is Ref/PDF = 10.7/3.676 = 2.91
Of course, the Rcounter must be next whole number,  3.  The PDF will then be: Ref/Rcounter = 10.7/3 = 3.57 MHz. 
This is the number to put into the global variable, PLL1phasefreq.
    PLL1loop = 1  
For non-inverting loop filter, enter "
2"; for inverting op amp, enter "1".  This commands the phase detector output in the PLL chip to either, invert or not invert.  It is not used in the LMX 2325 IC.
    PLL2 = 2326  
Again, enter the PLL suffix: 2325, 2326, 2350, 2353, 4112, or,  0 when using a multiplier scheme for LO 2.  If "0" is used, the program will not send a command for PLL 2.
    appxLO2 = 1024 
This is the 2nd LO frequency, nominally, 1024 (in MHz).  This is a coarse frequency used to determine the PLL2 commands.  Even if PLL 2 is replaced by a multiplier scheme, enter the frequency of LO 2
(in MHz).
    PLL2phasefreq = 4  
This is the Phase Detector Frequency (PDF) you have designed for PLL 2, in MHz.  It is also the step size for PLL 2 and determines the value of it's Rcounter.  You can use 8 Mhz, for better phase noise, but make sure the Loop Filter is designed for it.  If VCO2/PLL2 is less than 1024 MHz, the 4 or 8 MHz will result in illeagle commands to PLL 2.
    PLL2loop = 2
This tells the software if PLL2 is configured with a loop filter that is inverting or non inverting.  The published schematics for PLL2 have non inverting loop filters, enter "2".  If an inverting op amp is used in the loop filter, enter "1".  It is acceptable to use a VCO2 that has a reverse tuning characteristic.  This is the code to change, if that is the case.
    PLL3 = 2326 
Again, enter the PLL suffix of the PLL chip you are using in the Tracking Generator: 2325, 2326, 2350, 2353,4112, or  enter 0 (zero) for no Tracking Generator.
    PLL3off = 970
Output frequency (in MHz) of PLL3/VCO3 when the Tracking Generator is turned "off". 
  Used to determine the command word when commanding the PLL3 "off".  This is because the PLL3 is not powered down and the VCO3 will continually run.  A frequency must be chosen so that PLL 3 will not cause interference to the MSA during normal spectral analysis.
    PLL3mode = 0
1 = Fractional Mode, 0 = Integer Mode
.  Used as part of the command word when commanding the PLL3.  If PLL3 chip can be used as a Fractional-N, it is advised to use it this way.  It will allow a higher phase detector frequency, providing better stability, with lower step sizes.
    PLL3phasefreq = .005
This is the Tracking Generator's PLL3 phase detector frequency (PDF), which will determine the step size of LO3 (PLL3/VCO3).  It is advisable to use the highest PDF possible.  The software will calculate the correct frequency to program PLL3 in this manner:  PLL3 freq = LO2 freq - Final I.F. Frequency.  For example, if LO2 = 1024 MHz and
Final I.F. Frequency = 10.700 MHz, then PLL3 will be commanded to 1013.3 MHz.  Therefore, a good PDF to use would be .1 MHz.  If, however, the Final Xtal Filter has a center frequency of 11.15 MHz, the PLL3 would be commanded to 1012.85 MHz.  A PDF of 100 KHz would not be acceptable, because the step size is 100 KHz and could only step to 1012.80 or 1012.90 MHz.  The PDF would have to be changed to 50 KHz (.05 MHz).  Another example:  The Final Xtal Filter has a center frequency of 9.955 MHz, the PLL3 would be commanded to 1014.045 MHz.  Here, the PDF would have to be .005 (MHz).
    If a Fractional-N PLL is used, the PDF (the variable, "PLL3phasefreq") will be 16 times the step frequency.  Therefore, if the step size required is .005 (MHz), the PDF will be .08 (MHz).
    If the designer is using a Final Xtal Filter that is not a multiple integer of 5 KHz, there is a way to make the PLL3 command to a frequency that creates a final I.F. that is extremely close (if not right on) to the  Final Xtal filter's center frequency.  For example, a Final Xtal Filter is 9.954 MHz (CF) with a bandwidth of 2 KHz.  We would like the PLL3 to create a frequency of 1014.046 MHz.  However, with a step size of 5 KHz, the closest stepped frequency would be 1014.045 MHz.  This would create a final I.F. of  9.955 MHz, which is 1 KHz away from the center frequency of the Xtal Filter.  The measurement will be 3 dB lower due to the signal being on the edge of the filter response.
    There is no rule that a PLL's PDF must be some value of "whole number frequency".  With some innovative calculations, we can create a PDF that will, in turn, create a frequency of 1014.046 MHz.  The frequency formula for an integer PLL is :  VCO output frequency  =  N x Reference Clock / R, where N is the PLL's N counter, and R is the PLL's reference clock divider.  With a Reference Clock of 64 MHz and VCO output frequency (wanted) of 1014.046 MHz, the N to R ratio is 1014.046/64 = 15.844469.  Both N and R must be whole numbers.  With some itterative calculations, it is found that N = 14446 and R = 913.  Substituting N and R into the frequency formula:
VCO output frequency  =  N x Reference Clock / R,   14446 x 64 MHz / 913 = 1014.046 MHz.  The PDF = Reference Clock/913 = .070098576 MHz.  I did not sit around all day with a calculator trying to find these numbers.  I wrote a short iterative program in Liberty Basic to find them for me.  You can grab it here, called, findpllpdf.bas. You only need to know the Master Clock frequency,  and the frequency of LO2.
    PLL3loop = 2
This tells the software if PLL3 is configured with a loop filter that is inverting or non inverting.  The published schematics for PLL3 have non inverting loop filters, enter "2".  If an inverting op amp is used in the loop filter, enter "1".  It is acceptable to use a VCO3 that has a reverse tuning characteristic.  This is the code to change, if that is the case.
    glitchtime = 5000
This is time added when the DDS or PLL changes drastically.  
  Later in the program, an if/then statement uses this value and will slow down the program. This is so that the PLLs and final Xtal Filter will have time to settle before data is taken.  This value is somewhat arbitrary and depends of the speed of the home computer being used.  This seems to be a good number for my Celeron 700 MHz, but may have to be increased for a faster computer.  The actual time of the waiting period can be changed when the program is running by changing the value in the Working Window's box, called, "Wait".
    topref = 0
This is the default top reference line on scale, in dBm input to the MSA.  It is used to create the Log Scale in the Graph Window.  This value should not be greater than the maximum input to the MSA when the Log Detector begins compression.  For initial operation, and before calibration, enter "
0".  After calibration, this number will reflect the actual power input to the MSA.
    botref = -100
This is the default bottom reference line on scale, in dBm input to MSA.  This number cannot be greater than the value in the variable, "topref".
'[CalibrationFile]    'change following variables for your Log Det/AtoD combination.
adconv = 8
There are 3 different Analog to Digital Converter designs that can be used for the MSA.  Enter "
8" for the original 8 bit, enter "12" for optional 12 bit ladder, or enter "16" for the serial AtoD.
maxpower = 0
This is, normally, the input power level (in dBm) to the Log Detector when the Log Detector begins compression.  For the LM3356 design, it is approximately "0" dBm.  For the AD83xx series Log Det, it is about + "10" dBm.  But, it can be anything and will be treated as the maximum input to the Log Detector.  Be sure to enter the sign if negative, ie, "-3" dBm.  Before calibration, enter "
0".
The following are nominal values to enter, before calibration.
maxbits = 255       (or   4095   for 12 bit, or     65535 for 16 bit)
This is the bit value when maxpower is applied to Log Det.  During calibration, the A/D is adjusted to create a value of maximum bits when the maxpower level is applied to the Log Detector.  For the 12 bit A/D the nominal value is "4095" and for the 16 bit A/D it is "65535"
minus10bits = 239
      (or   3741   for 12 bit, or     59850 for 16 bit)
This is the bit value when 10 dB less than maxpower is applied to the Log Det.
minus20bits = 211
      (or   3384   for 12 bit, or     54140 for 16 bit)
This is the bit value when 20 dB less than maxpower is applied to the Log Det.
minus30bits = 183       (or   3024   for 12 bit, or     48380 for 16 bit)
This is the bit value when 30 dB less than maxpower is applied to the Log Det.
minus40bits = 155       (or   2673   for 12 bit, or     42770 for 16 bit)
This is the bit value when 40 dB less than maxpower is applied to the Log Det.
minus50bits = 123       (or   2323   for 12 bit, or     37170 for 16 bit)
This is the bit value when 50 dB less than maxpower is applied to the Log Det.
minus60bits = 95       (or   1981   for 12 bit, or     31700 for 16 bit)
This is the bit value when 60 dB less than maxpower is applied to the Log Det.
minus70bits = 63       (or   1631   for 12 bit, or     26100 for 16 bit)
This is the bit value when 70 dB less than maxpower is applied to the Log Det.
minus80bits = 37       (or   1299   for 12 bit, or     20780 for 16 bit)
This is the bit value when 80 dB less than maxpower is applied to the Log Det.
minus90bits = 24       (or   971   for 12 bit, or     15540 for 16 bit)
This is the bit value when 90 dB less than maxpower is applied to the Log Det.
minus100bits = 23       (or   697   for 12 bit, or     11150 for 16 bit)
This is the bit value when 100 dB less than maxpower is applied to the Log Det.
minus110bits = 23       (or   577   for 12 bit, or     9230 for 16 bit)
This is the bit value when 110 dB less than maxpower is applied to the Log Det.
minus120bits = 23       (or   556   for 12 bit, or     8900 for 16 bit)
This is the bit value when 120 dB less than maxpower is applied to the Log Det.
minus130bits = 23       (or   553   for 12 bit, or     8850 for 16 bit)
This is the bit value when 130 dB less than maxpower is applied to the Log Det.  Notice that the last 4 variables are the same or close to it.  This is due my using the MC3356 Log Det, which has only 90 dB of dynamic range.  The AD83xx series has over 100 dB of range, and these values will increase during calibration.
'The following are nominal values you can start with, before calibration.
'maxbits =      255     4095    65535   ver107
'minus10bits =  241     3741    59850   ver107
'minus20bits =  213     3384    54140   ver107
'minus30bits =  186     3024    48380   ver107
'minus40bits =  158     2673    42770   ver107
'minus50bits =  126     2323    37170   ver107
'minus60bits =  97      1981    31700   ver107
'minus70bits =  65      1631    26100   ver107
'minus80bits =  39      1299    20780   ver107
'minus90bits =  28      971     15540   ver107
'minus100bits = 23      697     11150   ver107
'minus110bits = 23      577     9230   ver107
'minus120bits = 23      556     8900   ver107
'minus130bits = 23      553     8850   ver107

port = hexdec("&H378")  
This is the LPT printer port data address for many home computers.  "Port" is used as a simplification when commanding 8 Bits to the LPT 1 printer port.  This address, and the following "status" and "control", should work for almost all home computers.  If it does not, the operator must determine the correct addresses to use for his computer.
status = hexdec("&H379")
This is the LPT printer port status address for specific computer.
  "Status" is used as a simplification when reading Bits on the LPT 1 printer port.
control = hexdec("&H37A")
This is the LPTprinter port command address for specific computer.  "Control" is used as a simplification when commanding 4 Bits to the LPT 1 printer port.
x = 720
This is the width of the horizontal Frequency Graph. It is 720 pixels in width(x).  For larger monitors with a higher resolution than 800 by 600, this value can be changed to the user's preference.
y = 300
This is the height of the vertical Amplitude Graph and is 300 pixels high(y). Again, f
or larger monitors with a higher resolution than 800 by 600, this value can be changed to the user's preference.
windowwide = 800 
This is the total width of the Working and Graph Windows.  They are 800 pixels wide. 
Again, for larger monitors with a higher resolution than 800 by 600, this value can be changed to the user's preference.
maxscale = 255
This is the height of Log Amplitude Scale, in pixels, and must be less than the value "y"
Again, for larger monitors with a higher resolution than 800 by 600, this value can be changed to the user's preference.
windowhigh = 180
This is the total height of the Working Window and is 180 pixels in height
Again, for larger monitors with a higher resolution than 800 by 600, this value can be changed to the user's preference.
graphhigh = 415
This is the total height of the Graph Window and is 415 pixels in height
Again, for larger monitors with a higher resolution than 800 by 600, this value can be changed to the user's preference.
This ends the portion of Global Variables, that are normally changed by the user.  The Variables from this point, on, are not to be changed without justification.
    The following variables are specific to the Control Board that I designed for the MSA and can be changed if necessary.
finalfreq = finalfreq1  'default, sweeping will begin with data entered into the finalfreq1 Global
finalbw = finalbw1      'default
, sweeping will begin with data entered into the finalbw1 Global
sagain = sagain1        'default, sweeping will begin with data entered into the sagain1 Global
contclear = 11           'global control bits to take all command lines low
cont1and2 = 3           'global control bits to activate PLL1/PLL2(EnaP)J1 and J2, (Select Input)
cont3and4 = 15         'global control bits to activate PLL3/spare(EnaT)J3 and J4, (Init Printer)
contwclk = 9             'global control bits to take DDS wclk line high, (Auto Feed)
contfqud = 10            'global control bits to take DDS fqud line high, (Strobe)
contreset = 8      'global control bits to take DDS wclk and fqud lines high, to reset the DDS, if
                                the DDS has had the modification.
lepllj1 = 4        'global port data to send LE on J1 (PLL 1), if cont1and2 is set
lepllj2 = 8        'global port data to send LE on J2 (PLL 2), if cont1and2 is set
lepllj3 = 16       'global port data to send LE on J3 (PLL 3), if cont3and4 is set
lepllj4 = 32       'global port data to send LE on J4 (spare), if cont3and4 is set (not used)

out port, 0                 'begin the program by sending the computer's 8 bit data lines low
out control, contreset:  'this will reset the DDS, if modified
out control, contclear      'begin
the program by sending the computer's 4 command lines low

Main Routines
, and their functions:
[Command PLL 3]
    This commands the Tracking Generator "OFF", actually to a specific frequency determined by the Global Variable, "PLL3off".  gosub [SetUpPLL3]  If there is no optional Tracking Generator (global variable PLL3 = 0) there will be no PLL 3 command action.

[Command PLL 2]
    This section of code will command PLL2 to create the LO 2 frequency that is set in the global variable,
"appxLO2".  This area is hardcoded for Integer-N commanding, even if using Fractional-N type PLL's.  It will jump to the appropriate PLL subroutine [CommandxxxxR] and ititialize and command the Rcounter portion of PLL 2.  It will return and then jump to the appropriate PLL subroutine [CommandxxxxN] and command the Ncounter portion of PLL 2.  If the R or N counter is out of range, an error message will be created and displayed when the program is halted.
    The subroutine knows which PLL to command, by using the variables Jcontrol = cont1and 2, and LEPLL = lepllj2.  These were globals established at the beginning of the program.

    In all of my designs, I am using 1024 MHz as the 2 nd Local Oscillator (PLL 2).  1024 is a 16 th harmonic of the Master Oscillator of 64 MHz, and makes for a good Step Recovery Diode Multiplier scheme.  If an SRD or other multiplier scheme replaces the PLL 2 module, this section will skip over commanding PLL 2.  It will, however, calculate the exact frequency of LO 2 for later use in the program.

[DeterminePLL1ReferenceDivider]
This section calculates the initial reference divider portion of PLL 1.  It will then gosub [CommandPLL1ReferenceDivider] where, it determines if PLL 1 is Fractional or Integer, the preselector value, and reference counter value.  It will then jump to the appropriate gosub [CommandxxxxR] and ititialize and command PLL 1.  The subroutine knows which PLL to command, by using the variables Jcontrol = cont1and 2, and LEPLL = lepllj1.  These were globals established at the beginning of the program.
    If the Rcounter is out of range, an error message will be created and displayed when the program is halted.

[SetUpWorkingWindow]
    This section immediatly jumps to the subroutine [createWorkingWindow].  Here, the Working Window is created with text, boxes, and buttons.  The global variables are inserted into the appropriate boxes.  The global variables "windowwide" and "windowhigh" create the size of the Working Window.  These were set for a monitor that has a resolution of 800 by 600 pixels.  If your monitor has higher resolution, the window will not totally fill the width of the screen, as they will on an 800x600 monitor.
    It will place the Working Window on the monitor screen, with the top left corner of the window at the monitor's pixel location of x,1 and y,415.  Monitor pixel locations begin at the top left of the screen (x,1 and y,1).  For an 800x600 monitor, the top right pixel location is x,800 and y,1.  Lower left is x,1 and y,600.  Lower right is x,800 and y,600.

[GrabWorkingWindowData]
    This section will go to the subroutine [calcWindowInfo] and look at the values that are in the Working Window boxes to create variables that will be used in the rest of the program.  This section is a pointer location.  That is, any time the "RESTART" button is clicked in the Working Window, the program will return to this location to check to see if any of the variables have been changed by the operator.

[SetUpGraphWindow]
    This section will jump to the subroutine [CreateGraph].  The Graph Window is created using the global variables, windowwide and graphhigh.  Like the Working Window, these variables are for an 800x600 pixel monitor screen.
    The x-axis and titles are created using the previously established global variables.

[Sweep from Start Frequency]
   This section is the "reset" when the Spectrum Analyzer begins sweeping.  It resets the graph to the left side of the x-axis and the step number to "0".  Later in the program, when the spectrum analyzer is stepped to its last step, it is pointed back to this section to "start over".  The number of steps can be anything from 2 to 720.

[CalculateNextStep]
   This section will calculate and determine several values that are used to step the Spectrum Analyzer to its next step.
    Firts, it will calculate the exact input frequency that the SA will tune to: thisfreq = startfreq + (stepfreq * thisstep)
    It then calculates the frequency that LO 1 (PLL3) must be: LO1 = thisfreq + LO2 - finalfreq
    It then calculates the approximate Phase Detector Frequency (PDF) for PLL 1: appxphasef = appxDDS/rcounter1
   
It then calculates the approximate N counter value for PLL 1: appxncounter = LO1/appxphasef

[CreatePLL1asFractional]
   When PLL 1 is used as a Fractional-N PLL, this section will calculate the variables for PLL 1.
    The Ncounter and Fcounter is calculated.  Then, the DDS output frequency is calculated.
    Since Fractional-N PLL's create some known spurs, a calculation is made to determine if a potential spur is likely to be created at this frequency:  harnonicb = int(firstif/fractionalfreq)
If there is a likely spur, the F counter is changed by one count.  This changes the PDF of PLL 1 a small amount and the DDS output frequency is recalculated.
    If the operator has pushed the Spur Test button, [Spurtest], the F counter will be changed one count and the DDS will be recalculated again: ddsoutput = actphasef * rcounter1
The data is ready to command the PLL 1 N counter section and the DDS.

[CreatePLL1asInteger]
    If PLL 1 is Integer, the Ncounter is calculated.  Then, the DDS output frequency is calculated.  The data is ready to command the PLL 1 N counter section and DDS.

[CommandPLL1Ndivider]
    First, it will reset the extra wait statement: glitch = 0.  If the data for PLL 1 has not changed from the previous step, then it won't waste time recommanding PLL 1.
    If commanding PLL 1 is required, add some wait time to the settling time routine:  glitch=1
    If PLL 1 is Fractional, change the preselector of PLL 1 to 16.
    It will select the correct PLL and then command the appropriate N-counter portion: if PLL1 = xxxx then gosub [CommandxxxxN].  It will return with an error message if the N counter is out of range.  Variables are established for the next step to determine if the PLL 1 will need recommanding: ncount = ncounter

[CommandDDS]
   This section begins be verifying that the DDS output frequency is within the bandwidth of the DDS Xtal filter:  if ddsoutput-appxDDS>xfilbw/2 then beep:error$="DDSoutput too high for filter".
A determination is made if the DDS frequency is lower than the previous step.  If so, add some
wait time to the settling time routine:  glitch=1
Then it will jump to the subroutine [DDScommand] and command the DDS.

[SettleDownTime]
   This section is a wait statement to slow down the computer while the Spectrum Analyzer circuits are settling down.  When PLL 1 becomes unlocked, due to commanding the Ncounter, or, if the DDS changes a large amount, the PLL 1 loop filter will require several hundred microseconds for reacquisition.  This is where the glitch addition comes into play.  Also, time is required for the Log Detector to settle, due to the bandwidth of the Final Xtal Filter" : for waittime = 0 to (wats * 100) + (glitch*glitchtime), next waittime.  Every home computer has a different speed, and the global variables "wats" and "glitchtime" can be changed accordingly.  We would like the Spectrum Analyzer to sweep as fast as possible, but slow enough to guarantee correct Log Detector information.

[ReadLogData]
   This section determines which A/D scheme is used and will jump to the appropriate subroutine [logData8Bit] ,  [logData12Bit] , or [logData12Bit].  This is where the A to D process takes place.  It will return with an amplitude value called, "bitsy", which will be used in the next routine.

[ConvertLogData]
The value "bitsy" is used in subroutine [ConvertBitsToPower] , to calculate a power level.  This power level is then converted to pixels, in subroutine [ConvertPowerToPixels] , to be used in the next section for plotting.  An array is created to store the data taken at this sweep step so that it can be retrieved later.

[PlotLogData]
   This section will jump to the subroutine [PlotData].  This is where the data is plotted into the Graph Window.

[DetermineNextOperation]
   If the "Show Variables" window is open, it will be updated with the latest information.  The program will then determine if the operator has halted the sweep.  If so, gosub [Halted].
    If not halted, the sweep will continue at [IncrementOneStep]

[IncrementOneStep]
    A number is added to this step number:  thisstep = thisstep + 1
    If this new step number is higher than the maximum steps in this sweep,  then go back to [SweepFromStartFreq] and sweep from the first step.  If not, then go back to [CalculateNextStep]  and continue sweeping at the next step.


Sub-Routines, and their functions:

[CommandPLL1ReferenceDivider]
This specifies the rcounter for PLL1 and commands it in the appropriate subroutine [CommandxxxxR]

[logData8Bit]
This is where the computer will command the D/A ladder network and pole the comparator until the correct Log Detector value is determined.  It treats the A to D process as a Successive Approximation Determination.  The final Log Det output variable, is called "bitsy" and has a value of 8 bits (0 to 255).
[logData12Bit]
This operates the same way as the 8 bit detection, but uses 12 bits instead of 8.  The final Log Det output variable, is called "bitsy" and has a value of 12 bits (0 to 4095).

[logData16Bit]
This is where the computer will access the serial AtoD converter and retrieve the data.  The software will two AtoD's at once.  However, only magnitude data is used in this software at this time.  The phase data is  written for later expansion.  The final Log Det output variable, is called "magdata" and has a value of 16 bits (0 to 65535).

[ConvertBitsToPower]
This converts the A/D bit value to power using the cal table

[ConvertPowerToPixels]
This converts the power to pixels for display

[PlotData]
This subroutine will plot one amplitude data point into the Graph Window at coordinates x and y. Where x is the horizontal point which represents the frequency step at which the data was taken and the y point is the amplitude of Log Detector (in pixels)
[insertMarker]
This adds information to the Graph at the Markers

[createWorkingWindow]
This creates the Working Window and inserts the default global variables

[calcWindowInfo]
This reads data in the Working Window boxes and creates new variables

[LeftButDown]
This reads the horizontal pixels in the Graph when the Mouse is "left clicked".  The data in the array is read and printed into the Working Window

[RightButDown]
This reads the horizontal pixels in the Graph when the Mouse is "right clicked".  The data in the array is read and printed into the Working Window

Cent : [centerbutton]
This will take the contents of the "This Freq" box and put it in the "Center Frequency" box and then wait for a "RESTART"

[CreateGraph]
This creates the Graph Window and draws the X and Y graph scale

[Reprintlines]
This reprints the reference graph lines for clarity

[DDScommand]
This commands the DDS in a parallel mode

[Command2325R] and [Command2325N]-this commands the specific LMX 2325 R and N counters
[Command2326R]
and [Command2326N]-this commands the specific LMX 2326 R and N counters
[Command2350R] and [Command2350N]-this commands the specific LMX 2350 R and N counters
[Command2353R] and [Command2353N]-this commands the specific LMX 2353 R and N counters
[Command4112R] and [Command4112N]-this commands the specific ADF 4112 R and N counters

[Halted]
When the sweep has been halted, the graph lines will be reprinted in the Graph Window.  If an error has taken place, the error will be printed into the Working Window's Message Box.  The statistics of the last sweep step will be printed into their appropriate boxes of the Working Window.  The operation will now "wait" for the operator to change one or more of the data parameters in the Working Window's red boxes and then click one of the BUTTONS in the Working Window.
 
    The following are the BUTTONS and the [Subroutines] that will be jumped to, when that buttton is clicked:

F1[button1]
This changes the Final Xtal Filter parameters to the Global Variables for Filter 1, then toggles D4 and Init lines on the LPT printer port.  It then waits for next button push.

F2[button2]
This changes the Final Xtal Filter parameters to the Global Variables for Filter 2, then toggles D5 and Init lines on the LPT printer port.  It then waits for next button push.

F3[button3]
This changes the Final Xtal Filter parameters to the Global Variables for Filter 3, then toggles D6 and Init lines on the LPT printer port.  It then waits for next button push.

F4[button4]
This changes the Final Xtal Filter parameters to the Global Variables for Filter 4, then toggles D7 and Init lines on the LPT printer port.  It then waits for next button push.

RESTART[Restart]
This will close the Graph Window and restart the sweep at [GrabWorkingWindowData]

REWRITE : [Rewrite]
Will
step the frequency by one step each time the button is clicked, and will plot a line trace in the Graph that won't be erased until the RESTART button is clicked.

REW.CONT : [Rewcont]
Will 
continue the sweep from the stopped position, and will plot a line trace in the Graph that won't be erased until the RESTART button is clicked.

ONESTEP : [OneStep]
Will step the frequency by one step each time the button is clicked

CONTINUE : [Continue]
Will continue the sweep from the stopped position

[ClearKeyBox]
This will clear any information in the "Hit Any Key" box, so that sweeping will be continuous.

[FocusKeyBox]
This will make the "Hit Any Key" box, accept a keyboard press, without having to click on it.

Track Gen is OFF (or ON) :  [Trkbutton]
This changes the data printed in the button, then turns the Tracking Generator on (or off), then waits.

[SetUpPLL3]
This commands the Tracking Generator frequency


Spur Test is OFF (or ON) : [Spurtest] This will cause the PDF of PLL 1 to change, making any self generated spur to move on the Graphed Plot.

Harmonic Window: [CreateHarmonicWindow]
This will open a small window inside the Graph Widow to display probable spur generator frequencies.
  It will then Wait for an action within that window.

[Image0][Image1][Image2][Image3][Image4][Image4][Image4]
Will inject data from Harmonic Window into the center frequency box and automatically Restart the sweep

[CloseHarmonicWindow]
Will close the Harmonic Window

Show Variables : [Showvar]
Will create a small window containing the status of variables used within this program.  A nice troubleshooting tool.

[updatevar]
Will update the status within the "Variables" window.

[Closevarwin]
Will close the variables window.

[finished]
Will close all windows and end the running program.


June 24, 2006  (I will continue the subroutine explanations as time permits)
You can email me, Scotty Sprowls, with questions or comments at   wsprowls@yahoo.com.   I'm a retired Design Engineer with plenty of time to answer you.  Best Wishes, all!