'4-4-2009 spectrumanalyzer.bas, version113-Rel. Released Version. For Verif MSA. Liberty ver 4.03 'Created from version113-7g 'this version is released as spectrumanalyzer.bas, dated 4-4-2009 'this version is tokenized as spectrumanalyzer.tkn, dated 4-4-2009 '------------Changes from Version 112 to version 113------------ '1a, Work on "Preset" configurations" '1a, 0 to 99 memories for VNA only.Insert #, click to save or to retrieve '1a, add buttons, boxes, subroutines, [SaveConfig],[GoConfig] '1a, add to [calcWindowInfo],"if steps > 720 then steps = 720:print #main.stepspersweepbox, steps 'ver113-1a '1a, add "dim configarray(200,750) '1a. add returnflag to [ChangeMagDisplayVNA][ChangePhaDisplayVNA] '1b. Work on Reference Plane extension '1b. add sub [RefPlaneExt] '1b. add to VNA Work Window, "plane extension" and box '2a. Changed command procedure in [CommandAllSlims],to prevent false triggering due to crappy LPT 'present data to buffer,latch buffer,disable buffer,present data+clk to buffer,latch buffer,disable buffer 'It now takes 6 port commands for each of the 40 serial bits. Was 3. Increased sweep time by 14.3 percent. '2b. Add to "Initialize circuits in MSA":if cb = 2 then out control, 4 'latch "0" into all SLIM Control Board Buffers '2b. Change initialization sequence of DDS1 and DDS 3 to keep current down. Reset,Involk Serial,Command to 0 Hz '2c. Complete change to subroutines: [ResetDDS1ser],[ResetDDS3serSLIM],[ResetDDS1serSLIM] '3a. Delete the manual Glitchtime Test in the Special Tests Window and the subroutine '3a. In [SpecialTests], delete: button #special.testglitch, "Test Glitchtime var", [TestGlitchtime], UL, 5, 80, 100, 20 'ver111-36c '3a. In [SpecialTests], delete: textbox #special.glitchbox, 105, 80, 75, 20 'create glitchbox 'ver111-36c '3a. In [SpecialTests], delete: print #special.glitchbox, "";glitchtime 'insert last glitchtime into glitchbox 'ver112-2d '3a. Delete subroutine: [TestGlitchtime] '3b. Delete subroutines: [CommandPLL1SlimCB][CommandPLL3SlimCB]. Were not used. '3c. Simplify code in [CommandAllSlims]. Retained same procedure. '3c. Changed command procedure in [CommandPLLslim],to prevent false triggering due to crappy LPT '3c. Changed many remarks in:[CommandDDS1][CommandDDS3][DDS3Track][DDS1Sweep] '4a. In [CommandDDS1], delete:if cb = 2 then gosub [CommandDDS1SlimCB]. Add:if cb = 2 then gosub [CommandAllSlims] '4a. In [CommandDDS3], delete:if cb = 2 then gosub [CommandDDS3SlimCB]. Add:if cb = 2 then gosub [CommandAllSlims] '4a. In [DDS3Track], delete:if cb = 2 then gosub [CommandDDS3SlimCB]. Add:if cb = 2 then gosub [CommandAllSlims] '4a. In [DDS1Sweep], delete:if cb = 2 then gosub [CommandDDS1SlimCB]. Add:if cb = 2 then gosub [CommandAllSlims] '4a. Delete subroutines [CommandDDS1SlimCB]and[CommandDDS3SlimCB]. not needed '4b. Delete[CreateGraphMSA],[CreateGraphVNA]and combine into[CreateGraphWindow] '4b. Changed line colors to darkgray and magnitude text to blue '4b. Delete[Reprintlines]as subroutine and combine into [CreateGraphWindow] '4b. in[Halted],change[Reprintlines] to [PrintGraph], and add:print #handle, "flush" '4b. In [insertMarker], add spaces to prevent leftover text '5a. Move Data printing function from Special Tests, to Menu items. '5a. Delete all attributes dealing with Special Tests Data Window.Delete[ChangeArrayData],[DisplayData] '5a. Add [OpenDataWindow][CloseDataWindow][MagnitudeMSAinput][MagBitsAtoD][MagCalTable][PhaProcessed][PhaBitsAtoD][PhaCalTable][MagPhaS21] '5a. Add to [CreateGraphWindow], menu #handle, "Data",etc '5b. change code within [MagPhaS21] to create Touchstone format '6a. Removed all User Global Variables and put them in an external text file.(\msaconfig.txt) '6a. In [EstablishUserVariables],Delete User Globals and replace with "input #configfile, line$..." '6a. In [button1][button2][button3][button4], add: path$ = "Path x" '6a. In [PrintGraph],add: Res BW = ";finalbw;" KHz, ";path$ '6a. In Initialize circuits in MSA, change line to A1=0 : A0=0 : path$ = "Path 1" '6a. Delete Final IF and BW Boxes. Put info in Graph Window '6a. Deleted Final IF Box and Resolution Box. Delete all references to finalifbox and resolutionbox. '6a. Fixed Touchstone format in [MagPhaS21] '6b. Combine Creation of SA and VNA Working Windows '6b. Delete [createWorkingWindowforMSA],[createWorkingWindowforVNA] '6b. Create[createCommonWorkingWindow],[WorkingWindowforMSA],[WorkingWindowforVNA] '6b. Changes to [GoMSAmode][GoVNAmode] '6c. Moved Go-MSA or Go-VNA Button to a Graph Window Menu Item '6c. In [CreateGraphWindow] add menu:if TGtop > 0 then menu #handle, "Mode", "Spec Anal Mode", [GoMSAmode], "VNA Mode", [GoVNAmode] 'ver113-6c '6c. In [WorkingWindowforMSA], delete "if TGtop > 0 then button #main.govna, "Go-VNA Mode", [GoVNAmode]" '6c. In [WorkingWindowforVNA], delete "button #main.gomsa, "Go-MSA Mode", [GoMSAmode], UL, 150, 63, 80, 20" '6c. In [WorkingWindowforVNA], delete "button #main.gomsa, "Go-MSA Mode", [GoMSAmode], UL, 150, 63, 80, 20" '6c. In 2.Initialize circuits in MSA,delete gosub [CommandFilter],gosub [CalTablePath1] '6c. also delete A1=0 : A0=0 : path$ = "Path 1" '6c. Add "returnflag = 1 : gosub [button1] : returnflag = 0" '6c. In [button1], add "if returnflag = 1 then return" '6d. make [ReadStep] a subroutine, add a Return. Move [ReadStep] into subroutine area. '6d. Add subroutine [UpdateBoxes] '6d. Change [Halted] '6d. Add [Scan] as a Label. '6d. in[Scan]change:"if haltsweep = 0 then haltsweep = 1:glitchhlt = 10:gosub [ReadStep]:goto [Scan]" '6d. Redo how One Step is handled '6d. Add line, if onestep = 1 then glitchhlt = 10:gosub [ReadStep]:gosub [ProcessAndPrint]:gosub [UpdateBoxes]:wait '6d. In [Scan],delete, if onestep = 1 then goto [Halted] 'we are in one step mode. '6e. Work Flushing problem '6e. I found the LB 4.03 auto save bug here, so previous versions might be corrupted. Look out. '6e. in [StartSweep], delete, print #handle, "discard" '6e. add subroutine [FlushAndDelete] '6e. in[IncrementOneStep],add, if thisstep > steps then gosub [FlushAndDelete]:goto [StartSweep] 'end of sweep, start over '6e. in[Halted],add,print #handle, "flush graph" 'create and name this segment, graph. All drawn items since last "Flush" '6e. stop and send to Sam '6f. changed remarks and Sequence of Main Routine and number the steps '6f. Was sent to Sam for marriage to ver113-6f-WithSEW-toScotty2 '7. Recieved from Sam as ver113-6f-WithSEW-toScotty2, now renamed to ver113-7 '7. Subroutines and references to [Button1]thru[Button4]were deleted by Sam. '7a. in [OpenDataWindow], add "if haltsweep = 1 then goto [Halted]" 'ver113-7a '7a. In[Create2350N], changed line to, "N1=1 '2350 RF_N register, must be 1", was N=1... '7a. and to, "rfnb17 = int(rfnb16/2):N17 = rfnb16 - 2*rfnb17" 'was 2*rgb17 '7a. Fix error, #main.waitbox got installed twice. I created error during -6b. '7a. in[WorkingWindowforVNA],delete: TextboxColor$ = "brown". delete: textbox #main.waitbox, 640, 55, 35, 20 '7a. In[WorkingWindowforVNA], add: "print #main.phasebotbox,-180" 're-added, got lost in -6f to -6f-toScotty2. 'ver113-7a '7a. move Sam's combobox stuff from[WorkingWindowforMSA][WorkingWindowforVNA],to[createCommonWorkingWindow] '7b. in[CalPDMinvdeg]add comments: 'to find the amount of phase shift when the PDM state is inverted, and, 'invdeg is a calibration value used in [ConvertPhadata], (phase of inverted PDM) - (invdeg) = real phase of PDM. ver113-7b '7b. delete both 'Sam wate=10 '7c. add latest updates from Sam. '7c. changed line to prevent truncation: staticText #config.filtInstruct "List your final filters: frequency bandwidth",configFiltLeft-7,configFiltTop-35,130,35 'ver113-7c '7c. in Conf Mgr Wind, delete "Save File" button: '7c. delete "button #config.save "Save File", [configBtnSave],UL,configButtonLeft+70,configButtonTop+30,110,25 '7c. delete routine [configBtnSave] '7c. in[SelectFilter],change line"path$="Path "+str$(filtIndex+1)"to"path$="Path "+str$(filtIndex)" '7c. in [WorkingWindowforMSA],change"button #main.magdisp, "Norm Erase", [ChangeMagDisplayMSA], UL, 640, 80, 65, 20 'ver113-7c '7c. in [WorkingWindowforMSA],change"magdisp = 1" '7c. in[menuRunConfig],[menuRunCal]add:if haltsweep=1 then goto [Halted]'sew6 ver113-7c '7c. in[calManRunManager]add:calEditorPathNum=0 'SEW6 '7c. in calManEnter, move call calManEnterInstructions "" '7c. change routine[menuRunCal] '7c. in[SelectFilter], only add:#main.msgbox, "!setfocus" 'SEW6 '7d. change doSpecialGraph=2 to doSpecialGraph=0 '7d. in [calManMeasure],change, "for measStep=0 to steps", to, "for measStep=0 to 9" '7d. change "calDoPhase" to "calGetDoPhase()", up to, but not past --Start Global Variables for Mag/Freq Calibration Module-- '7d. add comments and rearrange from textbox #calman.data1 to statictext #calman.Lref2 '7d. moved subroutine [calManMenuMeasure] to just above [calManMeasure] for my convenience '7d. SEW9 changes to subroutine,[menuRunConfig] '7d. in sub calManEnter, change "p$=using("####.##",pow-calManRefPower)"to"p$=using("####.##",calManRefPower-pow)" '7d. Modified [calManMeasure], change error routines '7e. [calManEnterAll] should begin with for i=0 to steps; not for i=1 to steps. '7e. SEW replaced "sub calManGetFreqInput" with a new updated routine '7e. In Cal Manager Window, changed texteditor labels to either, ' Frequency Calibration Table, or Path Calibration Table '7e. In sub calConvertMagPhase, change "interpY" to "phaseCorrect" '7e. In[VNAlinTest],add"if delfreq=0 then notice "Sweep must be preset to show 360-720 degrees." :wait" '7e. In sub calManEnterInstructions, altered the instructions for each "#calman.enterInstruct" '7e. Reset PDM to Normal, on Restart.Reinstall a previously deleted line in[CalculateAllStepsForLO3Synth],"phaarray(thisstep,0) = 0" '7e. In [SpecialTests],add:TextboxColor$ = "red" '7f. In "function configDataError$()",deleted several "errors" that are permissable under certain restrictions. '7f. in [Halted],add"print #handle, "delsegment graph"",to free up memory '7g. Multiple changes to conform to ver113-7eSEWcal2 and cal3 '----------Notes to Myself. The following are things I want to do:-------------- 'If Calibration Manager Window is open and we close MSA, we 'need to go close Calibration Manager Window without saving anything. 'I thought we had already done this, check previous versions 'Add buttons to VNA WW. "Use MSA Reference Calibration", ' "Use Line Reference Calibration", "Use No Calibration" 'Guarantee full command on "Restart" ' Perhaps, on "Restart" do a semi-re-initialization 'Change PDM wait time calculation 'During VNA sweep, if the phase bits jump more than xx%, add waittime and mearure again. 'Move Special Tests Button to Graph Window Menu Item 'Work on One-Step, make Restart button show Running. Then halt will flush one steps. 'Is it possible to to just reprint secreen in bitmap? At [Halt], delsegement everything, then save screen, then re-write screen 'Re-visit the power rush on DDS 'add a menu item "save Working and Graph Windows" as a text file, containing ALL data for future re-creation 'Add more calibration points.see \SamMods\CalAdjust.bas 'Possibly, split [CommandAllSlims] into [PreCommandAllSlims]and[CommandAllSlims].SLIM only. 'For Original Control Board, delete option for parallel DDS1. Use Serial, only. 'add Sam's Configuration table to delete global changes 'Re-command PLO2 on every [Restart] 'Change phase data to reflect the scale used in the Graph Window 'Allow line width change and color change from menu 'Control Sweep using Mouse. 'Interesting:The Text File created by the Menu has the options of "save, save as, open, etc" '-------------Sequence of Main Routine for Original or Slim MSA/TG/VNA--------------- 'Notes: The SLIM MSA (SLIM Control Board) can command all 6 modules at one time (PLO1,DDS1,PLO3,DDS3,PDM,FilterBank). ' However, the FilterBank is commanded independently. So is PLO2. ' The Original MSA (original Control Board) must command the modules independently. '1.Establish User Global variables from external msaconfig.txt '2.Establish hard Global variables '3.Create Working Window, for Spectrum Analyzer Mode, and insert the Default Global Variables '4.measure computer speed and update global, glitchtime '5.Command Filter Bank to Path one ' access the Path 1 Magnitude Calibration Table ' access the MagError vs Freq Calibration Table '6.if configured, initialize DDS3 by reseting to serial mode. Frequency is commanded to zero '7.if configured, initialize PLO3. No frequency command yet. '8.initialize and command PLO2 to proper frequency '9.Initialize PLO 1. No frequency command yet. '10.initialize DDS1 by reseting to serial mode. Frequency is commanded to zero '11.[GrabWorkingWindowData] get info from Working Window and update variables '12.[CreateGraphWindow], using Working Window data '13.Calculate the command information for first step through last step of the sweep and put in arrays '14.[StartSweep]'Begin sweeping from step 0 '15.[CommandThisStep](1.9ms). command relevant Control Board and modules '16.Determine sequence of operations after commanding the modules ' a. if in OneStep mode, then ' add extra settling time ' read data of thisstep. gosub [ReadStep] ' process data of thisstep. gosub [ProcessAndPrint] ' wait here, until the next button push ' b. if ThisStep is the first step after a halt, then ' add extra settling time ' read data of thisstep. gosub [ReadStep] ' goto [Scan] ' c. if ThisStep is not the first step after halt (middle of sweep), then ' process and print the Previous Step. gosub [ProcessAndPrintLastStep](3.8ms) ' [ProcessAndPrint](3.8ms) /1.9 ' [ConvertMagPhaseData](2.5ms) /.53 ' call calConvertMagPhase(1.2ms) ' freqerror=calConvertFreqError(thisfreq)(0.9ms) /.085 ' [CalcMagpowerPixel](0.4ms) ' [PlotDataToScreen](1.3ms) /1.3 ' read data of thisstep. gosub [ReadStep](1.9ms) ' goto [Scan] '17.[Scan] Check to see if a button has been pushed ' If a button was pushed (other than OneStep) goto [Halted] ' If not, continue to [IncrementOneStep] '18.[IncrementOneStep] ' add 1 to the value of thisstep ' if the new value of thisstep exceeds the number of steps in this sweep ' "Glue" the full sweep plot into memory ' go back to [StartSweep] ' if not, go back to [CommandThisStep] and continue sweeping '19.[Halted] ' process and print ThisStep. gosub [ProcessAndPrint] ' reprint Graph lines and text. gosub [PrintGraph] ' "Glue" Graph into memory ' wait for operator action. '--------Start of Code, Main Routine--------- '1.Establish User Global variables from external msaconfig.txt. all of the following are in msaconfig.txt '[EstablishUserVariables] '----Start of global variables set from a configuration file; some depend on construction of the 'spectrum analyzer; others are just convenient defaults that can be changed at runtime.--------- '[EstablishUserVariables] 'all of the following are "default" values and are dependent on the construction of your Spectrum Analyzer global masterclock 'Exact frequency of the Master Clock (in MHz). Example: 64.000056 or 63.999937 'You can start with default configuration and change after calibration. global centfreq 'Sweep center frequency, in MHz. For initial set-up use "0" global sweepwidth 'Sweep width in MHz. For initial set-up use 10 times the BW of Final Xtal Filter 'delver113-7c global wate 'value to "slow" the sweep speed for more accurate data. Use "0" as default. 'delver113-7c global glitchtime 'default=0, causing a self determination at startup. global adconv 'AtoD topology."8" for original 8 bit,"12" for optional 12 bit ladder,"16" for serial 16 bit AtoD, or "22" for serial 12 bit AtoD ver111-36e global topref 'Top magnitude reference line on graph scale, in dBm input to MSA. For initial set-up, use "0" global botref 'Bottom magnitude reference line on scale, in dBm input to MSA. For initial set-up, use "-100" global cb '0= old Control Board, 1= old Control Board with new harness, 2 = SLIM Control Board ver111-22 global dds1parser '0 if DDS 1 is in parallel mode, 1 if serial 'ver111-21."0" not allowed on SLIM Control Board ver111-29 global appxdds1 'nominal DDS1 output frequency (in MHz) that steers PLL 1; . Near 10.7. 'appxdds1 must be the center freq. of DDS1 xtal filter; exact value determined in calibration. global dds1filbw 'DDS1 xtal filter bandwidth (in MHz), at the 3 dB points). global PLL1 'PLL 1 model. Allowed values are 2325, 2326, 2350, 2353, or 4112 global PLL1phasefreq 'approx. Phase Detector Frequency (MHz) for PLL 1. Use .974 when DDS1 filter is 15 KHz wide 'PLL1phasefreq must be less than the following formula: 'PLL1phasefreq < (VCO 1 minimum frequency) x dds1filbw/appxdds1 global PLL1mode '0 = Integer Mode, 1 = Fractional Mode for PLL 1. 'I don't recommend Fractional Mode for PLL 1, although it will work (noiser) global PLL1phasepolarity '1 for non-inverting loop filter1; 0 inverting op amp; enter 0 for SLIM MSA global PLL2 'PLL 2 model. Allowed values are 2325, 2326, 2350, 2353, or 4112, or 0 for SRD multiplier global appxLO2 '2nd LO frequency (MHz). 1024 is nominal, Must be integer multiple of PLL2phasefreq global PLL2phasefreq 'PLL2 phase frequency (MHz). See appxLO2". 4 is nominal global PLL2phasepolarity 'for non-inverting loop filter, enter 1(SLIM MSA); for inverting op amp, enter 0 global TGtop 'Tracking Generator Topology:"0" for not installed, "1" for original Trk Gen, '"2" for New TG (DDS3/PLL3 combination) ver111-18 global PLL3 'PLL 3 model. Allowed values are 2325, 2326, 2350, 2353, or 4112, or 0 for no Trk Gen ' 2350 and 2353 can be used as fractional-N global appxdds3 'nominal DDS3 output frequency (in MHz) that steers PLL 1; Near 10.7. 'appxdds3 must be the center freq. of DDS3 xtal filter; exact value determined in calibration. 'Enter "0" if TGtop = 0(no TG) or 1. The original Trk Gen does not use a DDS3. ver111-17 global dds3filbw 'DDS3 xtal filter bandwidth (in MHz), at the 3 dB points). global PLL3phasepolarity '1 for non-inverting loop filter; 0 for inverting op amp; enter 0 for SLIM MSA global PLL3mode '0 = Integer Mode, 1 = Fractional Mode for PLL 1. 'Enter "1" only if PLL3 = 2350 or 2353. Enter "0" for new DDS3/PLL3 combination (SLIM MSA). global PLL3phasefreq 'TrkGen PLL3 phase frequency (MHz). If TG is DDS3/PLL3 combo, use same technique as PLL1phasefreq 'if Original TG (TGtop=1) then this must be a sub-multiple of both Master Clock and Final Xtal Filter Frequency global sgpreset '(in MHz)Default Output freq of Tracking Generator when in Signal Generator Mode global offset 'Enter "0" (Mhz). Default Tracking Generator frequency output, relative to MSA input. ver111-18 global maxpdmout 'bit count for Phase AtoD converter when Phase Det Module output is maximum. ver112-1a 'For SLIM-ADC-16 = 65535, SLIM-ADC-12 = 4095. For the Original Control Board and: '12 Bit Parallel AtoD = 4095, 16 Bit Serial AtoD = 65535, or 8 Bit Parallel AtoD = 255. These are adjustable during calibration global invdeg 'actual phase change when PDM is inverted. Nominally, 180. Enter actual value after calibration. '--SEW End of variables initialized from configuration file '--SEW2 added the following global declarations to make these available to true subroutines 'del13-7c global steps 'whole number of steps per sweep. 1 thru 720 is acceptable. 400 is a good number. 'del13-7c global thisstep 'keeps track of current step number during a sweep global globalPort, globalGlitchtime 'Used to pass new port value back from config routine w/o making port and glitchtime global. ver113.7c global doSpecialGraph '=0 for normal graph; =1 to graph mag cal; =2 to graph freq cal. 'del13-7c global port, status, control 'Parallel port addresses global finalfreq, finalbw 'freq and bandwidth of current final filter global hasVNA '=1 if the build includes VNA; otherwise 0 global calManWindHndl$ 'holds handle of open window for calibration manager, or blank if not running global configWindHndl$ 'Handle to our main window SEWcal3 moved to here from cal module 'configFilters is a list of final filters; second dimension 0=freq (MHz), 1=BW (KHz); 'zero entry of first dimension not used dim MSAFilters(40,1) global MSANumFilters 'Number of filters in list dim MSAFiltStrings$(40) 'Same info as MSAFilters(), but freq and bw are combined in a string; zero entry is used '******SEWgraph globals for graph params global firstScan 'Set to 1 for first scan after background grid for graph is drawn global graphAppearance$ 'Name of selected appearance preset, per gUsePresetColors global graphMarLeft, graphMarRight, graphMarTop, graphMarBot global haltAtEnd 'Flag set to 1 to cause a halt at end of current sweep 'SEWgraph 'Additional variables that need to be available to subroutines global vna, centfreq, sweepwidth,startfreq, stepfreq, wate, planeadj global topref, botref, sgout, offset, topphase, botphase, centphase '--SEW end of global declarations 'The following four variables were not moved to the configurtion file steps = 400 marker1 = 100 'marker 1 step placement, default. A marker will be placed on the graph, at this step number marker2 = 200 'marker 2 step placement, default. If no markers are wanted, enter the value, 750, in each marker default marker3 = 300 'marker 3 step placement, default. If the value is greater than "steps", no marker will display '--SEW3 added these initialization procedures 'killver113-7d doSpecialGraph=2 'Change to do special graph for testing call uInitFirstUse 'Initialize Utilities Module call configInitFirstUse 'Initialize Configuration Module call calInitFirstUse 100, 800 'Initialize Mag/Freq Calibration Module--100 max mag cal points; 800 max freq cal points if configFileExists()=0 then dum=configRunManager(1) 'Lets user enter configuration data, and saves to file '1 signals we are running on startup so no cancellation is allowed else errStr$=configLoadData$() 'Initializes the configuration globals from the configuration file if errStr$<>"" then 'errStr$ is blank if no error occurred; otherwise it describes the error notice "Configuration File Error; "+errStr$;"; Default values used" call configInitializeDefaults 'Load default values because of file error end if end if '----Convert Globals into Locals port=globalPort 'SEW5 add ver113-7c glitchtime=globalGlitchtime 'SEW5 add ver113-7c status=port+1 'SEW5 add ver113-7c control=port+2 'SEW5 add ver113-7c '------End, declaration of globals------------ call calInstallFile 0 'Loads frequency calibration file; creates one if necessary for i=MSANumFilters to 1 step -1 'For each filter, create the file if necessary and load it 'Each one loaded replaces the data from the previous one. We are just 'trying to be sure they exist and are OK. 'We do this in reverse order to path 1 will be the last one and stays in place 'This also sets finalfreq and finalbw call calInstallFile i next i path$="Path 1" 'Note physical selection of filter 1 is done in step 5 below for i=1 to MSANumFilters 'For each filter, combine freq and bw into nicely aligned string. Used to load #main.FiltList 'cngver113-7c MSAFiltStrings$(i-1)=configFormatFilter$(MSAFilters(i,0), MSAFilters(i,1)) MSAFiltStrings$(i-1)="P"+str$(i)+" "+configFormatFilter$(MSAFilters(i,0), MSAFilters(i,1)) 'ver113-7c next i 'SEW SCOTTY-Note that path$ is used when opening a Working Window to determine 'which filter to select in FiltList, and that filter file is installed and the 'filter is physically selected. That way, when you switch between SA and VNA the 'filter stays the same. No biggie now, without bank selection. So long as path$ 'is set before opening a Working Window, the filter will be set up properly and 'there is no need for prior initialization of anything other than path$. '--SEW3 end of initialization procedures '--Normally, nothing below this line will ever need changing----- '2.Establish hard Global variables x = 720 'graph horizontal is 720 pixels in width(x), for 800x600 pixel monitor y = 300 'graph vertical is 300 pixels in amplitude(y) windowwide = 800 'Working and Graph Windows are 800 pixels wide maxscale = 255 'height of Log Scale, in pixels, must be less than y windowhigh = 185 'Working Window is 180 pixels in height graphhigh = 415 'Graph Window is 415 pixels in height '-SEW deleted intialization of finalfreq and finalbw; done elsewhere 'the following lines of code are operations and will not be changed by the user unless 'a different type of Control Board is used. 'delver113-6a port = hexdec("&H378") 'LPT printer port, data address for most computers 'delver113-6a status = hexdec("&H379") 'LPT printer port, status address for most computers 'delver113-6a control = hexdec("&H37A") 'LPT printer port, control address for most computers contclear = 11 'global to take all LPT control lines low STRB = 10 'global to take LPT-pin 1 high. (Strobe line,STRB)(was fqud) ver111-22 AUTO = 9 'global to take LPT-pin 14 high. (Auto Feed line,AUTO)(was wclk) ver111-22 INIT = 15 'global to take LPT-pin 16 high. (Init Printer line,INIT)(was enat) ver111-22 SELT = 3 'global to take LPT-pin 17 high. (Select In line,SELT)(was enap) ver111-22 INITSELT = 7 'global to take both LPT-pins 16 & 17 high. (INIT,SELT)(was enapt) ver111-22 STRBAUTO = 8 'global to take both LPT-pins 1 & 14 high. (FQUD,WCLK)(was wclkfqud) ver111-22 dim datatable(800,3) 'data from most current sweep, (0)thisstep,(1)thisfreq,(2)processed magpower,(3)processed phase dim magarray(800,3) 'magni pixels for each step#: (0)thispointx, (1)oldmagpixel,(2)thispointmag(3)magdata dim phaarray(800,4) '(0)pdmcmd; phase pixels for each step#:(1)oldphapixel,(2)thispointphase,(3)phadata,(4)pdmread ver111-39d dim calarray(800,2) 'calibration data for each step#: (0)notused,(1)magpower during cal,(2)phaseofpdm during cal dim PLL1array(800,48) '(0-23)N23thruN0,(24-39)notused,(40)pdf1,(43)LO1freq,(45)ncounter,(46)Fcounter,(47)Acounter,(48)Bcounter. ver111-30a dim PLL3array(800,48) '(0-23)N23thruN0,(24-39)notused,(40)pdf3,(43)LO3freq,(45)ncounter,(46)Fcounter,(47)Acounter,(48)Bcounter. ver111-30a dim DDS1array(800,46) '(0-39)sw0-sw39,(40-44)w0-w4,(45)base,(46)actualdds1output dim DDS3array(800,46) '(0-39)sw0-sw39,(40-44)w0-w4,(45)base,(46)actualdds3output dim cmdallarray(800,39) '(0-15)DDS1+DDS3, (16-39)PLL1+DDS1+PLL3+DDS3 dim configarray(200,750) 'configurations ver113-1a if cb=0 then le1=4:le2=8:le3=16:fqud1=STRB:fqud3=2 'ver111-31b if cb=1 then le1=1:le2=1:le3=4:fqud1=2:fqud3=8 'ver111-31b if cb=2 then le1=1:le2=16:le3=4:fqud1=2:fqud3=8 'ver111-31b if adconv = 8 then pdmlowlim = 51 : pdmhighlim = 205 'establish boundries for 8 bit parallel A to D ver111-36f if adconv = 12 then pdmlowlim = 819 : pdmhighlim = 3277 'establish boundries for 12 bit parallel A to D ver111-36f if adconv = 16 then pdmlowlim = 13107 : pdmhighlim = 52429 'establish boundries for 16 bit serial A to D ver111-36f if adconv = 22 then pdmlowlim = 819 : pdmhighlim = 3277 'establish boundries for 12 bit serial A to D ver111-37a nomainwin '3.Create Working Window, for Spectrum Analyzer Mode, and insert the Default Global Variables gosub [createCommonWorkingWindow] 'create Working Window for SA using global default values '4.measure computer speed and update global, glitchtime 'Determine speed of computer 'ver111-37c if glitchtime = 0 then gosub [AutoGlitchtime] 'ver111-37c 'return with glitchtime, number approximates 1 millisecond of computer processing speed with Liberty Basic 'this is a "coarse" calculation. print #main.msgbox,"glitchtime = ";glitchtime 'ver111-37c '5.Command Filter Bank to Path one out port, 0 'begin with all data lines low if cb = 2 then out control, 4 'latch "0" into all SLIM Control Board Buffers'ver113-2b out control, contclear 'begin with all control lines low 'the following are meaningless values to guarantee first time commanding. Used in subroutine, [DetermineModule] lastdds1output = appxdds1:lastdds3output = appxdds3:lastpdmstate = 2 'ver111-28 'Initialize Final Filter path to Path 1 (1 of 4). This is an optional hardware addition to the MSA 'ver111-29: no final filter bank module has been released. 'However, assume these are the command schemes for the filters: '4 bank, using A0 and A1, and a latch line A2. To be used with original Control Board or SLIM Control Board '4 bank, using A0 and A1, with no latch line. To be used with SLIM Control Board, only. 'The SLIM Control Board can support an 8 bank, using A0,A1,A2 as control, with no latching capability 'delver113-6c A1=0 : A0=0 : path$ = "Path 1" 'default Filter Bank to path 1. ver113-6a 'delver113-6c gosub [CommandFilter]'ver111-29 'delver113-6c gosub [CalTablePath1] 'ver111-39a 'SEW added next two lines, which implement the above comments and also replace 'the call to button1, which is gone. A1=0 : A0=0 : path$ = "Path 1" 'default Filter Bank to path 1. ver113-7 gosub [CommandFilter]'ver113-7 'SEW deleted comment about Path 1 cal variables being in calpwrX... Those are gone 'InitializeTrkGen, if installed '6.if configured, initialize DDS3 by reseting to serial mode. Frequency is commanded to zero if TGtop = 0 then goto [endInitializeTrkGen]' there is no Tracking Generator ver111-22 'Initialize DDS 3 if cb = 0 and TGtop = 2 then Jcontrol = INIT:swclk = 32:sfqud = 2:gosub [ResetDDS3ser] 'ver111-7 '[ResetDDS3ser]needs:port,control,Jcontrol,swclk,sfqud,contclear ; resets DDS3 into Serial mode if cb = 2 then gosub [ResetDDS3serSLIM] 'ver111-29 '7.if configured, initialize PLO3. No frequency command yet. 'Initialize PLL 3. 'CreatePLL3R,CommandPLL3R appxpdf=PLL3phasefreq 'ver111-4 if TGtop = 1 then reference=masterclock 'ver111-4 if TGtop = 2 then reference=appxdds3 'ver111-4 gosub [CreateRcounter]'needs:reference,appxpdf ; creates:rcounter 'ver111-14 rcounter3=rcounter : pdf3=pdf 'ver111-7 'CommandPLL3R and Init Buffers datavalue = 8:levalue = 4 'PLL3 data and le bit values ver111-28 gosub [CommandPLL3R]'needs:PLL3mode,PLL3phasepolarity,INIT,PLL3 ; Initializes and commands PLL3 R Buffer(s) 'ver111-7 [endInitializeTrkGen] '8.initialize and command PLO2 to proper frequency 'CreatePLL2R appxpdf=PLL2phasefreq 'ver111-4 reference=masterclock 'ver111-4 gosub [CreateRcounter]'needed:reference,appxpdf ; creates:rcounter,pdf 'ver111-14 rcounter2 = rcounter 'ver111-7 pdf2 = pdf 'actual phase detector frequency of PLL 2 'ver111-7 'CommandPLL2R and Init Buffers datavalue = 16: levalue = 16 'PLL2 data and le bit values ver111-28 gosub [CommandPLL2R]'needs:PLL2phasepolarity,SELT,PLL2 ; Initializes and commands PLL2 R Buffer(s) 'CreatePLL2N appxVCO = appxLO2 : reference = masterclock gosub [CreateIntegerNcounter]'needs:appxVCO,reference,rcounter ; creates:ncounter,fcounter(0) ncounter2 = ncounter:fcounter2 = fcounter gosub [CreatePLL2N]'needs:ncounter,fcounter,PLL2 ; returns with Bcounter,Acounter, and N Bits N0-N23 Bcounter2=Bcounter: Acounter2=Acounter LO2=((Bcounter*preselector)+Acounter+(fcounter/16))*pdf2 'actual LO2 frequency 'CommandPLL2N Jcontrol = SELT : LEPLL = 8 datavalue = 16: levalue = 16 'PLL2 data and le bit values ver111-28 gosub [CommandPLL]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111-5 '9.Initialize PLO 1. No frequency command yet. '[InitializePLL1]'set PLL1 to proper Rcount and initialize appxpdf=PLL1phasefreq 'ver111-4 reference=appxdds1 'ver111-4 gosub [CreateRcounter]'needed:reference,appxpdf ; creates:rcounter,pdf 'ver111-4 rcounter1 = rcounter 'ver111-4 'CommandPLL1R and Init Buffers datavalue = 2: levalue = 1 'PLL1 data and le bit values ver111-28 gosub [CommandPLL1R]'needs:rcounter1,PLL1mode,PLL1phasepolarity,SELT,PLL1 ; Initializes and commands PLL1 R Buffer(s) '10.initialize DDS1 by reseting. Frequency is commanded to zero 'It should power up in parallel mode, but could power up in a bogus condition. if cb = 0 and dds1parser = 0 then gosub [ResetDDS1par]'(Orig Control)'needs:control,STRBAUTO,contclear ; resets DDS1 on J5, parallel ver111-21 if cb = 0 and dds1parser = 1 then gosub [ResetDDS1ser]'(Orig Control)'needed:control,AUTO,STRB,contclear ; resets DDS1 on J5, into serial mode ver111-21 if cb = 2 then gosub [ResetDDS1serSLIM]'reset serial DDS1 without disturbing Filter Bank or PDM 'ver111-29 '11.[GrabWorkingWindowData] get info from Working Window and update variables [GrabWorkingWindowData] gosub [calcWindowInfo] '12.[CreateGraphWindow], using Working Window data gosub [CreateGraphWindow] 'create Graph Window, Spectrum Analyzer Mode. ver113-4b '13.Calculate the command information for first step through last step of the sweep and put in arrays gosub [CalculateAllStepsForLO1Synth] 'ver111-18 if TGtop > 0 then gosub [CalculateAllStepsForLO3Synth] 'ver111-18 gosub [CreateCmdAllArray] 'ver111-31b '14.[StartSweep]'Begin sweeping from step 0 'SEW StartSweep begins the outer loop that repeats the entire scan process until halted. 'SEW The scan loop continues until a user action which aborts the scan, or in the case of 'SEW OneStep it continues only for a single point. scanResumed=0 'used to indicate whether we start with a new scan(0) or resume where we left off(1)SEW [StartSweep]'enters from above, or [IncrementOneStep]or[FocusKeyBox]([OneStep][Continue]) 'delver113-6e print #handle, "discard" 'clear out pc memory of drawn segments, to prevent computer from running out of RAM 'SEW rewrote entire step 14 to use "if" blocks relating to scanResumed, 'which is set in [FocusKeyBox] before calling here. if scanResumed=1 then 'Perform same increment as [IncrementOneStep] if we are resuming if thisstep = steps and syncsweep = 1 then gosub [SyncSweep] 'ver112-2b thisstep = thisstep + 1 'add 1 to step number and continue sweeping if thisstep > steps then scanResumed=0 : gosub [FlushAndDelete] end if if scanResumed=0 then 'Retest because scanResumed may have been changed immediately above thisstep = 0 'reset step number for beginning of sweep if invdeg = 1 then gosub [CalPDMinvdeg] 'special routine for calibrating Phase Detector Module else scanResumed=0 'Reset flag end if 'SEW added the next two lines; uncomment during testing to get timing in message box 'timer #main.msgbox, str$(Time$("ms")-startTime) 'SEW for testing 'timer startTime=Time$("ms") 'SEW for testing '15.[CommandThisStep]. command relevant Control Board and modules 'SEW CommandThisStep begins the inner loop that moves from step to step to complete a single 'SEW scan.This branch label is accessed only from the end of the loop. [CommandThisStep]'needs:thisstep ; commands PLL1,DDS1,PLL3,DDS3,PDM 'ver111-7 'a. first, check to see if any or all the 5 module commands are necessary [DetermineModule] 'b. calculate how much delay is needed for each module[DetermineModule], but use only the largest one[WaitStatement]. 'c. send individual data, clocks, and latch commands that are necessary for[CommandOrigCB] 'or for SLIM, use [CommandAllSlims] for commanding concurrently 'ver111-31c gosub [DetermineModule] 'determine which, if any, module needs commanding. ver111-27 cmdneeded = glitchp1 + glitchd1 + glitchp3 + glitchd3 + glitchpdm 'ver111-38a if cmdneeded > 0 and cb = 0 then gosub [CommandOrigCB]'old Control (150 usec, 0 SW) 'ver111-28ver111-38a 'if cb = 1 then gosub [CommandRevB]'old Control looking like SLIM 'not created yet if cmdneeded > 0 and cb = 2 then gosub [CommandAllSlims]'ver111-38a '16.Determine sequence of operations after commanding the modules if onestep = 1 then 'in the One Step mode glitchhlt = 10 'add extra settling time gosub [ReadStep] 'read this step gosub [ProcessAndPrint] 'process and print this step gosub [UpdateBoxes] wait 'wait here for next button push ver113-6d end if if haltsweep = 0 then 'in first step after a Halt haltsweep = 1 'change flag to say we are not in first step after a Halt, for future steps glitchhlt = 10 'add extra settling time gosub [ReadStep] 'read this step 'ver113-6d else 'if neither, then in middle of sweep. process and print the previous step, then read this step gosub [ProcessAndPrintLastStep] gosub [ReadStep]'read this step 'ver113-6d 'if line calibrating the VNA, halt on the last step if calfwd = 1 and thisstep = steps then beep:print #main.calibfwd, "Calibrated":goto [EndSweep] 'ver111-30b end if '17.[Scan] Check to see if a button has been pushed [Scan] 'ver113-6d 'delver113-6d if onestep = 1 then goto [Halted] 'we are in one step mode. ver111-26 scan 'check for any button push and go there. ver111-26 'otherwise, continue sweeping by entering [IncrementOneStep] '18.[IncrementOneStep] 'SEW IncrementOneStep is the end of both the inner loop over points and the outer loop 'SEW over scans. goto [CommandThisStep] continues the inner loop with the next point. 'SEW goto[StartSweep] continues the outer loop with the next scan. 'SEW [IncrementOneStep] is commented out to be clear it is not used for any goto. '[IncrementOneStep] if thisstep = steps and syncsweep = 1 then gosub [SyncSweep] 'ver112-2b thisstep = thisstep + 1 'add 1 to step number and continue sweeping if thisstep > steps then gosub [FlushAndDelete]:goto [StartSweep] 'end of sweep, start over'ver113-6e goto [CommandThisStep] 'ver111-3 [EndSweep] 'SEW This label marks the end of the scan loops and is used to abort the scan '19.[Halted] [Halted]'changed ver113-6d gosub [ProcessAndPrint]'get raw data, process, print to the computer monitor ver111-22 if calfwd = 1 and thisstep < steps then print #main.calibfwd, "Calibrate ?" 'ver111-30b calfwd = 0 'exit vna calibration mode. ver111-30b haltsweep = 0 'this says the sweep has been halted, so don't print the first command of the next sweep step 'ver111-20 gosub [PrintGraph] 'redraw graph (lines and text) when sweep is stopped. ver113-4b print #handle, "delsegment graph" 'delete the segment named, "graph". This frees up computer RAM. ver113-7f print #handle, "flush graph" 'create and name this segment, graph. All drawn items since last "Flush". ver113-6e 'this "graph" segment would include graph lines and text, and 'all plotting from step 0 to this step it was halted, or 'all plotting from the last step it was halted to this step it was halted, or if test<>0 then print #main.msgbox,test 'this is used for troubleshooting. Coder can insert 'test = (any variable) anywhere in the code, and it will get displayed in the Messages Box during Halt. gosub [UpdateBoxes] wait 'wait for operator to: 'Change red parameters in Working Window and then "Restart" 'Change green parameters in Working Window and then "Restart","Continue", or "One Step" 'Click any Button for appropriate action '----SubRoutines------ [FlushAndDelete]'ver113-6e 'enter here at the end of each full sweep, to control screen plots and computer memory. #handle, "delsegment plot" 'delete the segment named, "plot". This frees up computer RAM. #handle, "flush plot" 'create and name this segment, "plot". A segment is all drawn items since last "Flush" '"flush plot" will create new memory named,"plot", and will not overwrite previous memories, named "plot" 'must "delsegment plot" to free old memory before creating a new one 'if sweep is halted during the first sweep after a [Restart] the "plot" segment will be empty 'if sweep is halted after at least one full sweep, the "plot" segment will contain all "elements" of previous sweep 'there will always be 3 segments on screen before a cover-up. "plot", "graph", and "unnamed" (the present elements) 'after cover-up, only 2 segments, "plot" and "graph", are re-written on screen return [UpdateBoxes]'ver113-6d print #main.stepnobox,thisstep print #main.thisfreqbox,datatable(thisstep,1) 'this is "thisfreq" print #main.thispowerbox,datatable(thisstep,2) 'this is "magpower" if vna = 1 then print #main.thisphasebox,datatable(thisstep,3);" deg" call DisplayButtonsForHalted 'SEW8 replaced print #main.restart, "Restart" leftdownpixelx = x+1 'ver111-36a return [ReadStep]'and put raw data bits into arrays. made subroutine and moved 'ver113-6d gosub [WaitStatement]'needs:wate,glitch variables,glitchtime ;slows program before reading data 'ver111-20b magdata = 0 'reset this variable before reading data if vna = 1 or varwindow = 1 then gosub [ReadPhase] 'ver112-1b 'and return with phadata(in bits). Also installed into pharray(thisstep,3). ' If serial AtoD, magdata is returned, but not installed in any array 'the phadata could be in dead zone, but in SA mode, we don't care. 'if in VNA Mode and PDM is in automatic, check for phasedata (bits) for limits if vna = 1 and setpdm = 0 and (phadata < pdmlowlim or phadata > pdmhighlim) then gosub [InvertPDmodule] 'ver112-2b 'if magdata is collected during [ReadPhase], skip Read Magnitude ver111-22 if magdata = 0 then gosub [ReadMagnitude]'and return with raw magdata bits 'ver111-22 magarray(thisstep,3) = magdata 'put raw data into array ver111-19 return [ProcessAndPrintLastStep] rememberstep = thisstep 'remember where we were when entering this routine 'ver111-19 'since we are processing and printing the previous step, use raw data in array(thisstep - 1,data) thisstep = thisstep - 1 'ver111-26 if thisstep < 0 then thisstep = steps 'ver111-26 gosub [ProcessAndPrint]'get raw data, process, print to the computer monitor ver111-22 thisstep = rememberstep 'ver111-19 return [WaitStatement]'needed:wate,glitch()(p1,d1,p3,d3,pdm,hlt),glitchtime ; this slows the program 'ver111-27 glitch = max(max(max(glitchp1, glitchd1),max(glitchp3, glitchd3)), max(glitchpdm, glitchhlt)) 'ver111-27 'glitchp1=PLL1:glitchd1=DDS1:glitchp3=PLL3:glitchd3=DDS3:glitchpdm=PDM(10):glitchhlt=halted(10) waittime = (wate + glitch)*glitchtime 'ver111-27 'in my Toshiba, a waittime count of 80 gives a delay of approx, 1 millisecond 'therefore, each increment of any "glitchXX" or "wate" (Wait Box) should add 1 ms of delay before a "read" timecounter = 0 'ver111-27 [TimeLoop] 'ver111-27 if timecounter < waittime then timecounter = timecounter + 1:goto [TimeLoop] 'ver111-27 glitchp1=0:glitchd1=0:glitchp3=0:glitchd3=0:glitchpdm=0:glitchhlt=0 'reset glitch variables back to 0 'ver111-27 return 'to [ReadStep]or[InvertPDmodule]or[CalPDMinvdeg] [AutoGlitchtime] 'ver111-37c glitchtime = 100000 whatiswate = wate wate = 1 a = time$("ms") 'time of day, in milliseconds. This uses the computer's internal clock gosub [WaitStatement] b = time$("ms") glitchtime = glitchtime/(b-a) 'glitchtime is the value required for a 1 ms wait time wate = whatiswate 'change wate back to it's original global value return [ReadMagnitude]'needed: port,status ; creates: magdata (and phadata for serial A/D's) if adconv = 8 then gosub [Read8Bitmag] 'and return here with magdata if adconv = 12 then gosub [Read12Bitmag] 'and return here with magdata if adconv = 16 then gosub [ReadAD16Status]:gosub [Process16Mag] 'combined ver111-34a 'and return here with just magdata 'ver111-33b if adconv = 22 then gosub [ReadAD22Status]:gosub [Process22Mag] 'ver111-37a 'and return here with just magdata 'ver111-37a return 'to [ReadStep] [ReadPhase]'needed: port,status ; creates: phadata (and magdata for serial A/D's) if adconv = 8 then gosub [Read8Bitpha] 'and return here with phadata if adconv = 12 then gosub [Read12Bitpha] 'and return here with phadata if adconv = 16 then gosub [ReadAD16Status]:gosub [Process16MagPha] 'combined ver111-34a if adconv = 22 then gosub [ReadAD22Status]:gosub [Process22MagPha] 'ver111-37a 'and return here with phadata (and magdata, if serial AtoD) 'ver111-33b 'if calibrating the PDM inversion, don't put raw data into arrays, used only in [CalPDMinvdeg] if invdeg = 1 then return 'to [CalPDMinvdeg] 'ver111-29 phaarray(thisstep,3) = phadata 'put raw data into array 'ver112-2a phaarray(thisstep,4) = phaarray(thisstep,0) 'PDM state at which this data is taken. ver112-2a 'it is only used in Variables Windows to show state of PDM when data was collected. return 'to [ReadStep] [InvertPDmodule]'this will change the state of the PDM 'ver111-28 'entered from [ReadStep]. It was determined that phadata is out of limit boundries 'this new version will re-command PDM, and read phase, but not test for dead zone again, just assumes data to be viable if phaarray(thisstep,0) = 0 then newpdmstate = 1 'ver112-2a if phaarray(thisstep,0) = 1 then newpdmstate = 0 'ver112-2a for i = thisstep to steps 'ver111-20a phaarray(i,0) = newpdmstate 'inverts pdmcmd for thisstep and subsequent steps to end of sweep. ver111-28 next i 'ver111-20a 'now, go and command the PDM to the new state (Command PDM only!) gosub [CommandPDMonly] 'command just the PDM ver111-28 'now, wait for PDM to settle before going back and reading data again, due to huge glitch created during PDM flip glitchpdm = 10 : gosub [WaitStatement] 'wait 10 milliseconds 'ver111-28 'SEW SCOTTY--You would avoid wasting a lot of time if the above said 'glitchpdm=max(10, 5*wate). It's guaranteed that far more wait time is needed here than anywhere 'else. For calManMeasure, I have to do a long wait at every point, even though there 'is a high probability it is not needed at any of them. A user doing a scan is in the same boat. goto [ReadPhase] 'and re-read the phase but don't test for dead zone ver111-28 [CalPDMinvdeg] 'to find the amount of phase shift when the PDM state is inverted 'invdeg is a calibration value used in [ConvertPhadata], (phase of inverted PDM) - (invdeg) = real phase of PDM. ver113-7b 'the VNA must be in "0" sweepwidth, freq close to the transition point. rememberpdmstate = phaarray(thisstep,0) 'ver112-2e print #main.restart, "Cal PDM" 'ver111-36d beep phaarray(thisstep,0) = 0 'command PDM to Normal 'ver111-29 gosub [CommandPDMonly] 'ver111-29 glitchpdm = 5000 'should equate to 5 seconds of delay 'ver111-29 gosub [WaitStatement] 'ver111-29 gosub [ReadPhase]'return here with phadata 'ver111-29 'the 16 bit serial has just been "hit" with a conv (D7)in Commanding the Orig PDM. OK to hit it again? Yes. 'expect phadata to be either 80% or 20% of maxpdmout phase0 = 360*phadata/maxpdmout 'convert to degrees phaarray(thisstep,0) = 1 'command PDM to Inverted 'ver111-29 gosub [CommandPDMonly] 'ver111-29 glitchpdm = 5000 'should equate to 5 seconds of delay 'ver111-29 gosub [WaitStatement] 'ver111-29 gosub [ReadPhase]'return here with phadata 'ver111-29 'expect phadata to be either 20% or 80% of maxpdmout phase1 = 360*phadata/maxpdmout 'convert to degrees invdeg = phase1 - phase0 if invdeg < 0 then invdeg = invdeg + 360 invdeg = val(using("####.##",invdeg)) 'PDM's phase shift when inverted, in .01 degree resolution call DisplayButtonsForHalted 'SEW8 replaced print #main.restart, "Restart" print #main.invdegbox,invdeg print #main.msgbox,phase0;" ";phase1 'ver112-1b beep 'ver111-36d 'put PDM into the state at which it entered this subroutine phaarray(thisstep,0) = rememberpdmstate 'ver112-2e gosub [CommandPDMonly] 'ver112-2e wait [Read8Bitmag]'needed: port,status ; creates: magdata 'This will 8 bit parallel on Original or Slim Control Board. ver111-29 ' if inp(status) < 128 then wait (status bit 7) line is high (D/A 127 then wait line is low (magnitude voltage 63 then ack line is high (phase voltage>ladder) 'the data will always be 1 bit less than crossover region phadata = 0 if cb = 2 then out control, AUTO 'enable P3 on SLIM Control Board. ver111-29 out port, phadata + 128 'set D/A MSB to "1", creates 2.5v out of D/A ladder magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 128 out port, phadata + 64 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 64 out port, phadata + 32 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 32 out port, phadata + 16 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 16 out port, phadata + 8 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 8 out port, phadata + 4 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 4 out port, phadata + 2 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 2 out port, phadata + 1 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 1 out port, 0 'return data to zero if cb = 2 then out control, contclear 'disable P3 on SLIM Control Board. ver111-29 return 'return, with phadata [Read12Bitmag]'needed: port,status ; creates: magdata 'This will read 12 bit parallel, WAIT line, on Original or Slim Control Board. ver111-29 ' if inp(status) < 128 then wait line (status bit 7)is high (D/A 127 then wait line is low (magnitude voltage 63 then ack line is high (phase voltage>ladder) ' if inp(status) < 64 then ack line is low (phase voltage 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 2048: word = word + 8 out port,word +4 +16 +32 ' put 4 into MSB latch, D/A = 1024 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 1024: word = word + 4 out port,word +2 +16 +32 ' put 2 into MSB latch, D/A = 512 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 512: word = word + 2 out port,word +1 +16 +32 ' put 1 into MSB latch, D/A = 256 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 256: word = word + 1 out port,word +16 +32 ' put appxm. into MSB latch, D/A = appx out port,word +16 +32 +64 ' latch MSB with appx word = 0 out port,8 +16 +64 ' put 8 into middle latch, D/A = 128 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 128: word = word + 8 out port,word +4 +16 +64 ' put 4 into middle latch, D/A = 64 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 64: word = word + 4 out port,word +2 +16 +64 ' put 2 into middle latch, D/A = 32 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 32: word = word + 2 out port,word +1 +16 +64 ' put 1 into middle latch, D/A = 16 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 16: word = word + 1 out port,word +16 +64 ' put appxm. into middle latch, D/A = appx out port,word +16 +32 +64 ' latch middle with appx word = 0 out port,8 +32 +64 ' put 8 into LSB latch, D/A = 8 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 8: word = word + 8 out port,word +4 +32 +64 ' put 4 into LSB latch, D/A = 4 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 4: word = word + 4 out port,word +2 +32 +64 ' put 2 into LSB latch, D/A = 2 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 2: word = word + 2 out port,word +1 +32 +64 ' put 1 into LSB latch, D/A = 1 magpha = inp(status) if magpha > 127 then magpha = magpha - 128 if magpha > 63 then phadata = phadata + 1 out port, 0 'return data to zero if cb = 2 then out control, contclear 'disable P3 on SLIM Control Board. ver111-29 return ' return with phadata [ReadAD16Status]'needed: port,status ; creates: 16 status port words (stat15-stat0)mag,(and, pha if two A/D's installed) 'ver111-33a 'written for Analog Devices, AD7685, but other 16 bit serial AtoD's will probably work with this code 'reads 16 bit serial using Original or Slim Control Board. ver111-33c 'good for 16 Bit Original AtoD Module or SLIM-ADC-16 'MAG is WAIT, PHASE is ACK, SCLK is BD6, CVNis BD7. if cb = 2 then out control, AUTO 'enable P3 on SLIM Control Board. ver111-29 out port, 128 'take CVN high out port, 64 'CVN low, SCLK=1 'bit 15 is valid stat15 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'bit 14 is valid out port, 64 'CVN low, SCLK=1 stat14 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat13 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat12 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat11 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat10 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat9 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat8 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat7 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat6 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat5 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat4 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat3 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat2 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat1 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'bit 0 is valid 'a/d outputs would go high z on 16th SCLK trailing edge.Only 15 have been sent. stat0 = inp(status) 'read data, statX is 8 bit word if cb = 2 then out control, contclear 'disable P3 on SLIM Control Board. ver111-29 'we now have raw a/d status words in stat15-stat0 return 'to [ReadMagnitude]or[ReadPhase]with status words [Process16MagPha]'ver111-33a 'process the stat15-0 for both magnitude and phase.Determines magdata bit (D7) and phadata bit (D6) in each word magdata = 0 phadata = 0 if stat15>127 then stat15=stat15-128:magdata = magdata + 32768 'WAIT is low, MAG is high if stat15<64 then phadata = phadata + 32768 'ACK is low, PHASE is high if stat14>127 then stat14=stat14-128:magdata = magdata + 16384 if stat14<64 then phadata = phadata + 16384 if stat13>127 then stat13=stat13-128:magdata = magdata + 8192 if stat13<64 then phadata = phadata + 8192 if stat12>127 then stat12=stat12-128:magdata = magdata + 4096 if stat12<64 then phadata = phadata + 4096 if stat11>127 then stat11=stat11-128:magdata = magdata + 2048 if stat11<64 then phadata = phadata + 2048 if stat10>127 then stat10=stat10-128:magdata = magdata + 1024 if stat10<64 then phadata = phadata + 1024 if stat9>127 then stat9=stat9-128:magdata = magdata + 512 if stat9<64 then phadata = phadata + 512 if stat8>127 then stat8=stat8-128:magdata = magdata + 256 if stat8<64 then phadata = phadata + 256 if stat7>127 then stat7=stat7-128:magdata = magdata + 128 if stat7<64 then phadata = phadata + 128 if stat6>127 then stat6=stat6-128:magdata = magdata + 64 if stat6<64 then phadata = phadata + 64 if stat5>127 then stat5=stat5-128:magdata = magdata + 32 if stat5<64 then phadata = phadata + 32 if stat4>127 then stat4=stat4-128:magdata = magdata + 16 if stat4<64 then phadata = phadata + 16 if stat3>127 then stat3=stat3-128:magdata = magdata + 8 if stat3<64 then phadata = phadata + 8 if stat2>127 then stat2=stat2-128:magdata = magdata + 4 if stat2<64 then phadata = phadata + 4 if stat1>127 then stat1=stat1-128:magdata = magdata + 2 if stat1<64 then phadata = phadata + 2 if stat0>127 then stat0=stat0-128:magdata = magdata + 1 if stat0<64 then phadata = phadata + 1 return 'to [ReadPhase] with magdata and phadata [Process16Mag]'ver111-33a 'process the stat15-0 for magnitude only. Determines magdata bit (D7) in each word magdata = 0 if stat15>127 then magdata = magdata + 32768 'WAIT is low, MAG is high if stat14>127 then magdata = magdata + 16384 'WAIT is low, MAG is high if stat13>127 then magdata = magdata + 8192 'WAIT is low, MAG is high if stat12>127 then magdata = magdata + 4096 'WAIT is low, MAG is high if stat11>127 then magdata = magdata + 2048 'WAIT is low, MAG is high if stat10>127 then magdata = magdata + 1024 'WAIT is low, MAG is high if stat9>127 then magdata = magdata + 512 'WAIT is low, MAG is high if stat8>127 then magdata = magdata + 256 'WAIT is low, MAG is high if stat7>127 then magdata = magdata + 128 'WAIT is low, MAG is high if stat6>127 then magdata = magdata + 64 'WAIT is low, MAG is high if stat5>127 then magdata = magdata + 32 'WAIT is low, MAG is high if stat4>127 then magdata = magdata + 16 'WAIT is low, MAG is high if stat3>127 then magdata = magdata + 8 'WAIT is low, MAG is high if stat2>127 then magdata = magdata + 4 'WAIT is low, MAG is high if stat1>127 then magdata = magdata + 2 'WAIT is low, MAG is high if stat0>127 then magdata = magdata + 1 'WAIT is low, MAG is high return 'to [ReadMagnitude]with magdata [ReadAD22Status]'needed: port,status ; creates: 12 status port words (stat11-stat0)mag,(and, pha if two A/D's installed) 'ver111-37a 'written for Linear Technology, LTC1860, but other 12 bit serial AtoD's will probably work with this code 'reads 12 bit serial using Original or Slim Control Board. ver111-33c 'good for serial, 12 Bit Original AtoD Module or SLIM-ADC-12 'MAG is WAIT, PHASE is ACK, SCLK is BD6, CVN is BD7. if cb = 2 then out control, AUTO 'enable P3 if SLIM Control Board. ver112-2d 'delver112-2d out control, AUTO 'enable P3 on SLIM Control Board out port, 128 'take CVN high out port, 64 'CVN low, SCLK=1 'serial data out is not valid yet, still Hi-Z out port, 0 'CVN low, SCLK=0 Bit 11 is valid. fix error ver111-39c out port, 64 'CVN low, SCLK=1 fix error ver111-39c stat11 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat10 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat9 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat8 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat7 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat6 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat5 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat4 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat3 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat2 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'next bit is valid out port, 64 'CVN low, SCLK=1 stat1 = inp(status) 'read data, statX is 8 bit word out port, 0 'CVN low, SCLK=0 'bit 0 is valid out port, 64 'CVN low, SCLK=1 'not necessary for LTC1860 stat0 = inp(status) 'read data, statX is 8 bit word out port, 0 'SCLK=0 'LTC1860 would go to zero on the 13th SCLK trailing edge. Only 12 have been sent. if cb = 2 then out control, contclear 'disable P3 if SLIM Control Board. ver112-2d 'we have raw a/d status words in stat11-stat0 return 'to [ReadMagnitude]or[ReadPhase]with status words [Process22MagPha]'ver111-37a 'process the stat11-0 for both magnitude and phase.Determines magdata bit (D7) and phadata bit (D6) in each word magdata = 0 phadata = 0 if stat11>127 then stat11=stat11-128:magdata = magdata + 2048 'WAIT is low, MAG is high if stat11<64 then phadata = phadata + 2048 'ACK is low, PHASE is high if stat10>127 then stat10=stat10-128:magdata = magdata + 1024 if stat10<64 then phadata = phadata + 1024 if stat9>127 then stat9=stat9-128:magdata = magdata + 512 if stat9<64 then phadata = phadata + 512 if stat8>127 then stat8=stat8-128:magdata = magdata + 256 if stat8<64 then phadata = phadata + 256 if stat7>127 then stat7=stat7-128:magdata = magdata + 128 if stat7<64 then phadata = phadata + 128 if stat6>127 then stat6=stat6-128:magdata = magdata + 64 if stat6<64 then phadata = phadata + 64 if stat5>127 then stat5=stat5-128:magdata = magdata + 32 if stat5<64 then phadata = phadata + 32 if stat4>127 then stat4=stat4-128:magdata = magdata + 16 if stat4<64 then phadata = phadata + 16 if stat3>127 then stat3=stat3-128:magdata = magdata + 8 if stat3<64 then phadata = phadata + 8 if stat2>127 then stat2=stat2-128:magdata = magdata + 4 if stat2<64 then phadata = phadata + 4 if stat1>127 then stat1=stat1-128:magdata = magdata + 2 if stat1<64 then phadata = phadata + 2 if stat0>127 then stat0=stat0-128:magdata = magdata + 1 if stat0<64 then phadata = phadata + 1 return 'to [ReadPhase] with magdata and phadata [Process22Mag]'ver111-37a 'process the stat11-0 for magnitude only. Determines magdata bit (D7) in each word magdata = 0 if stat11>127 then magdata = magdata + 2048 'WAIT is low, MAG is high if stat10>127 then magdata = magdata + 1024 'WAIT is low, MAG is high if stat9>127 then magdata = magdata + 512 'WAIT is low, MAG is high if stat8>127 then magdata = magdata + 256 'WAIT is low, MAG is high if stat7>127 then magdata = magdata + 128 'WAIT is low, MAG is high if stat6>127 then magdata = magdata + 64 'WAIT is low, MAG is high if stat5>127 then magdata = magdata + 32 'WAIT is low, MAG is high if stat4>127 then magdata = magdata + 16 'WAIT is low, MAG is high if stat3>127 then magdata = magdata + 8 'WAIT is low, MAG is high if stat2>127 then magdata = magdata + 4 'WAIT is low, MAG is high if stat1>127 then magdata = magdata + 2 'WAIT is low, MAG is high if stat0>127 then magdata = magdata + 1 'WAIT is low, MAG is high return 'to [ReadMagnitude]with magdata [ProcessAndPrint]'process and print "thisstep" 'ver111-22 'SEW3 changed the next few lines to have phase degrees adjusted for phase-change-over-signal-level 'The calculation of the phase adjustment, difPhase, is made in ConvertMagPhaseData (formerly ConvertMagData). 'That correction is then added to phase in ConvertPhadata.Note that ConvertPhadata must now be 'called after ConvertMagPhaseData so difPhase is valid when ConvertPhadata is executed. gosub [ConvertMagPhaseData] 'convert magdata (bits read) to magpower (dBm) and thispointmag (pixels) if vna = 1 then gosub [ConvertPhadata]'convert phadata (bits read) to phase (degrees) and thispointphase (pixels) 'ver111-19 gosub [PlotDataToScreen] return 'from [ProcessAndPrint] 'SEW2 added difPhase to the following comment [ConvertPhadata]'needed: phadata,PDM polarity,difPhase ; creates "phaseofpdm" and "thispointphase", the pixel value 'retrieve phadata from array 'convert phadata to phase, round off to .01 deg 'compensate phase using "invdeg" (if PDM was inverted during the phase reading) 'compensate phase using "difPhase", Phase Error Correction Factor' 'as determined in Path Calibration, (variation of phase readings over signal level) 'if in line cal, write phase to calarray 'if normal sweep, process phase by removing line calibration phase 'add or subtract Reference Plane Extension 'convert phase to +360 to 0 degree format and round off to .01 degree 'convert phase to +180 to -180 format 'convert phase to pixels, depending on scale 'grab raw phase data bits from array phadata = phaarray(thisstep,3) 'ver111-19 'convert phadata to absolute phase lead, referenced to 0 degrees. maxpdmout/4 = 90 degrees lead,maxpdmout/2 = 180 degrees lead phase = val(using("####.##",(360*phadata/maxpdmout))) 'converts phadata bits to absolute phase and round off to .01 degrees 'the absolute phase will normally be between limits of +288 and +72 degrees, 'however, it can be between 360 and 0 degrees if the PDM is "forced" into a set state (setpdm=1) 'if PDM was inverted, subtract the inverted phase change (norm to inv adds "invdeg" deg) phase = phase - (invdeg * phaarray(thisstep,0)) 'ver111-36g 'now, the absolute phase can be between +360 and appx -180 deg phase=phase-difPhase 'SEW3: subtract correction for change of phase over signal level. 'Scotty: does this mess up keeping the angle in range? 'Also, invdeg might be positive or negative, so phase could now be 'well over 360. To avoid something unanticipated, I changed 'the phase adjustment into while...wend loops while phase >360 : phase = phase - 360 : wend 'SEW3 just to be safe 'now, the absolute phase can be between +360 and appx -180 deg 'if negative make it real by adding 360 deg while phase <0 : phase = phase + 360 : wend 'SEW3 just to be safe 'now, the absolute phase will be between +360 and 0 deg 'if we are calibrating the line, put absolute phase into calibration array if calfwd = 1 then calarray(thisstep,2)= phase 'calculate phase with calibration table factored in phase = phase - calarray(thisstep,2) 'this gives the differential phase from calibration 'if we are calibrating the line, phase will be 0 'if we are normally sweeping, phase can be anything from +360 to -360 deg 'ver111-36g '[RefPlaneExt] add or subtract reference plane adjustment 'ver113-1b 'SEW deleted retrieval of planeadj, which is now in calcWindowInfo so that there 'are no references to the Working Window boxes during a sweep (enables background sweep) planeadj = val(planeadj$) 'planeadj is in nanoseconds 'convert the planeadj(nsec) to rotational delay(freq vs time) 'rotations = [planeadjustment/(1/f)] 'f is in MHz rotate = .001 * planeadj * datatable(thisstep,1) 'decimal number of rotations, 1.234 'drop whole number of rotations and change to degrees (0 to 360), round off to .01 degrees adddegrees = val(using("####.##",(360*(rotate - int(rotate))))) '+360 to 0 degrees phase = phase + adddegrees if phase > 360 then phase = phase - 360 if phase < -360 then phase = phase + 360 'now the phase can be between +360 and -360 'convert to standard +180 -180 format if phase < -180 then phase = phase + 360 'ver111-36g if phase > 180 then phase = phase - 360 'ver111-36g 'now, the differential phase can only be between +180 and -180 deg 'write the processed phase into the memory array, +180 to -180 deg datatable(thisstep,3) = phase 'put current phase measurement into the array, line value= thisstep if topphase > 180 then phase = phase + 360:if phase > 360 then phase = phase - 360 'ver111-36g if botphase < -180 then phase = phase - 360:if phase < -360 then phase = phase + 360 'ver111-36g if phase > topphase then phase = phase - 360:if phase < botphase then phase = phase + 360 'ver111-36g if phase < botphase then phase = phase + 360:if phase > topphase then phase = phase - 360 'ver111-36g thispointphase = maxscale * (phase - botphase)/(topphase - botphase) 'convert phasedisplay to pixels 'ver111-36g if phase > topphase then thispointphase = maxscale 'ver111-36g if phase < botphase then thispointphase = 0 'ver111-36g return 'to [ProcessAndPrint] '--SEW Replaced [ConvertMagData] and [ConvertFreq] with following combined routine, 'to utilize the calibration module to interpolate the necessary correction factors 'to convert the raw ADC reading into dbm, and then to correct that number for variations 'over frequency. Phase correction is also calculated so the routine name was changed. 'That phase correction is difPhase and is subtracted from phase in ConvertPhadata 'SCOTTY: The phase correction for signal level has to be calculated here, because it 'is a function of magnitude ADC reading and so can be interpolated at the same time 'as that ADC reading is converted to mag power. This messes up the terminology a bit 'because we now have ConvertPhadata and ConvertMagPhaseData. But it works. [ConvertMagPhaseData]'convert magnitude data bits to MSA input power(in dBm) and to pixels. ver111-39a 'needed: magarray,calibration table 'this converts magdata to MSA input power, using 'a Magnitude Error Correction Factor, (determined in Frequency Calibration) 'If in VNA mode, it also finds the phase correction for the power level indicated 'by magdata, and put it into difPhase, to be subtracted from phase later. if doSpecialGraph=0 then 'Normal scan. Apply the calibration magdata = magarray(thisstep,3) 'Apply mag calibration to get power and phase correction 'vna is 1 if we are in VNA mode, and signals whether to calculate phase correction call calConvertMagPhase magdata, vna, power, difPhase thisfreq = datatable(thisstep,1) freqerror=calConvertFreqError(thisfreq) 'find frequency cal adjustment else if doSpecialGraph=1 then 'Graph mag calibration table. Find the min and max ADC values 'and make magdata run linearly from the minimum to the maximum. 'Any non-linearities in the graph then reflect the calibration 'We do nothing with phase call calGetMagPoint 1,minADC, calMag, calPhase 'ignore calMag and calPhase call calGetMagPoint calNumMagPoints(),maxADC, calMag, calPhase slope=(maxADC-minADC)/steps magdata=minADC+slope*thisstep 'Apply mag calibration to get power, but forget phase correction call calConvertMagPhase magdata, 0, power, dum 'skip freq cal else 'Force power to 0 dbm and then find the frequency compensation. 'The resulting graph will show the shape of the frequency compensation 'curve. power=0 thisfreq = datatable(thisstep,1) freqerror=calConvertFreqError(thisfreq) 'find freq cal adjustment end if end if goto [CalcMagpowerPixel] '--SEW End of new routine to make calibration adjustments [CalcMagpowerPixel] power = power + freqerror if convdatapwr = 1 then gosub [ConvertDataToPower] 'ver112-2b 'round off MSA input power to .01 dBm, magpower, no matter which AtoD is used magpower = val(using("####.##",power)) if calfwd = 1 then calarray(thisstep,1)= magpower 'this inserts the power into the calarray for magnitude reference if vna = 1 then magpower = magpower - calarray(thisstep,1) 'this gives the differential power from calibration datatable(thisstep,2) = magpower 'put current power measurement into the array, line value= thisstep '[ConvertPowerToPixels]'needed:magpower,topref,botref ; creates thispointmag (pixels) if magpower > topref then thispointmag = maxscale 'normally, maxscale=255 if magpower <= topref and magpower >= botref then thispointmag = maxscale*(magpower-botref)/(topref-botref) if magpower < botref then thispointmag = 0 'thispointmag is in pixels, from 0 to maxscale return 'to [ProcessAndPrint] return [PlotDataToScreen] 'magdisp: 0=magoff, 1=normerase, 2=normstick, 3=histerase, 4=histstick 'phadisp: 0=phaoff, 1=erase, 2=stick thispointx = magarray(thisstep,0) 'calculation is in [CalculateAllStepsForLO1Synth] ver111-25 '(erase) 'if magdisp=3 then erase old histo line by covering old histo line with a vertical white line if magdisp = 3 then print #handle, "color white ; line ";thispointx;" ";y-magarray(thisstep,2);" ";thispointx;" ";y 'ver111-25 'if magdisp=1 then erase old mag segment by covering old mag segment with a white line if magdisp = 1 and thisstep > 0 then print #handle, "color white ; line ";thispointx;" ";y-magarray(thisstep,2);" ";magarray(thisstep-1,0);" ";y-magarray(thisstep-1,1) 'ver111-25 if magdisp = 1 and thisstep = 0 then print #handle, "color white ; line ";thispointx;" ";y-magarray(thisstep,1);" ";thispointx;" ";y-magarray(thisstep,1) 'ver111-25 'if phadisp=1 then erase old pha segment by covering old pha segment with a white line if phadisp = 1 and thisstep > 0 then print #handle, "color white ; line ";thispointx;" ";y-phaarray(thisstep,2);" ";magarray(thisstep-1,0);" ";y-phaarray(thisstep-1,1) 'ver111-25 if phadisp = 1 and thisstep = 0 then print #handle, "color white ; line ";thispointx;" ";y-phaarray(thisstep,2);" ";thispointx;" ";y-phaarray(thisstep,2) 'ver111-25 '(print) 'if magdisp=3or4 then print new histo line in black if magdisp = 3 or magdisp = 4 then print #handle, "color black ;line ";thispointx;" ";y-thispointmag;" ";thispointx;" ";y 'ver111-25 'if magdisp=1or2 then print new mag segment in blue if (magdisp = 1 or magdisp = 2) and thisstep > 0 then print #handle, "color blue ;line ";thispointx;" ";y-thispointmag;" ";magarray(thisstep-1,0);" ";y-magarray(thisstep-1,2) 'ver111-25 if (magdisp = 1 or magdisp = 2) and thisstep = 0 then print #handle, "color blue ;line ";thispointx;" ";y-thispointmag;" ";thispointx;" ";y-thispointmag 'ver111-25 magarray(thisstep,1) = magarray(thisstep,2) 'used for removing in next step magarray(thisstep,2) = thispointmag 'used for writing in next step 'ver111-19 'if phadisp=1or2 then print new pha segment in red if (phadisp = 1 or phadisp = 2) and thisstep > 0 then print #handle, "color red ;line ";thispointx;" ";y-thispointphase;" ";magarray(thisstep-1,0);" ";y-phaarray(thisstep-1,2) 'ver111-25 if (phadisp = 1 or phadisp = 2) and thisstep = 0 then print #handle, "color red ;line ";thispointx;" ";y-thispointphase;" ";thispointx;" ";y-thispointphase 'ver111-25 phaarray(thisstep,1) = phaarray(thisstep,2) 'this is the previous sweep's y-axis pixel value at this step #, used in next step for clearing old trace phaarray(thisstep,2) = thispointphase 'this is the newest y-axis pixel value for this step, used in next step to extend new trace if thisstep = marker1 then gosub [insertMarker]'and return here after inserting marker if thisstep = marker2 then gosub [insertMarker]'and return here after inserting marker if thisstep = marker3 then gosub [insertMarker]'and return here after inserting marker if varwindow = 1 then gosub [updatevar] 'moved here from [ProcessAndPrint] ver111-34a return 'to [ProcessAndPrint] [insertMarker]'needed:thispointx,thispointmag,magdata,magpower,phaseofpdm : display marker info print #handle, "color black ; line ";thispointx;" ";(y-15)-thispointmag;" ";thispointx;" ";(y-2)-thispointmag 'ver111-25 print #handle, "line ";thispointx;" ";y+6;" ";thispointx;" ";y+10 if vna = 0 then print #handle, "\\"; datatable(thisstep,1);" MHz\";magarray(thisstep,3); " = bits \";datatable(thisstep,2);" dBm " 'ver113-4b if vna = 1 then print #handle, "\\"; datatable(thisstep,1);" MHz\";datatable(thisstep,2);" dB \";datatable(thisstep,3); " deg " 'ver113-4b return 'return to [PlotDataXX] [CreateRcounter]'needed:reference,appxpdf ; creates:rcounter,pdf 'ver111-4 rcounter = int(reference/appxpdf) 'ver111-4 if (reference/appxpdf) - rcounter >= .5 then rcounter = rcounter + 1 'rounds off rcounter 'ver111-4 pdf = reference/rcounter 'ver111-4 return 'to (Initialize PLL 3),[InitializePLL2],or[InitializePLL1]with rcounter,pdf 'ver111-4 [CommandPLL1R]'needed:rcounter1,PLL1mode,PLL1phasepolarity,SELT,PLL1 rcounter = rcounter1 preselector = 32 : if PLL1mode = 1 then preselector = 16 phasepolarity = PLL1phasepolarity 'inverting op amp is 0, non-inverting loop is 1 fractional = PLL1mode '0 for Integer-N; 1 for Fractional-N Jcontrol = SELT 'for PLL 1, on Control Board J1, the value is "3" LEPLL = 4 'for PLL 1, on Control Board J1, the value is "4" PLL = PLL1 gosub [CommandRBuffer]'needs:rcounter,preselector,phasepolarity,fractional,Jcontrol,LEPLL,PLL if len(errora$)>0 then error$ = "PLL 1, " + errora$:print #main.msgbox,error$:wait 'ver111-37e return [CommandPLL2R]'needed:reference,appxpdf,PLL2phasepolarity,SELT,PLL2 preselector = 32 phasepolarity = PLL2phasepolarity 'inverting op amp is 0, non-inverting loop is 1 fractional = 0 '0 for Integer-N; PLL 2 should not be fractional due to increased noise Jcontrol = SELT 'for PLL 2, on Control Board J2, the value is "3" LEPLL = 8 'for PLL 2, on Control Board J2, the value is "8" PLL = PLL2 gosub [CommandRBuffer]'needs:rcounter,preselector,phasepolarity,fractional,Jcontrol,LEPLL,PLL if len(errora$)>0 then error$ = "PLL 2, " + errora$:print #main.msgbox,error$:wait 'ver111-37e return 'to 'CommandPLL2R and Init Buffers [CommandPLL3R]'needed:PLL3mode,PLL3phasepolarity,INIT,PLL3 preselector = 32 : if PLL3mode = 1 then preselector = 16 phasepolarity = PLL3phasepolarity 'inverting op amp is 0, non-inverting loop is 1 fractional = PLL3mode '0 for Integer-N; 1 for Fractional-N Jcontrol = INIT 'for Tracking Gen PLL, on Control Board J3, the value is "15" LEPLL = 16 'for Tracking Gen PLL, on Control Board J3, the value is "16" PLL = PLL3 gosub [CommandRBuffer]'needs:rcounter,preselector,phasepolarity,fractional,Jcontrol,LEPLL,PLL if len(errora$)>0 then error$ = "PLL 3, " + errora$:print #main.msgbox,error$:wait 'ver111-37e return 'to 'CommandPLL3R and Init Buffers [CommandRBuffer]'needed:rcounter,preselector,phasepolarity,fractional,Jcontrol,LEPLL,PLL if PLL = 2325 then gosub [Command2325R]'needs:rcounter,preselector,Jcontrol,port,LEPLL,contclear ; commands LMX2325 rcounter and registers if PLL = 2326 then gosub [Command2326R]'needs:rcounter,phasepolarity,Jcontrol,port,LEPLL,contclear ; commands LMX2326 rcounter and registers if PLL = 2350 then gosub [Command2350R]'needs:rcounter,phasepolarity,Jcontrol,port,LEPLL,contclear,fractional ; commands LMX2350 rcounter if PLL = 2353 then gosub [Command2353R]'needs:rcounter,phasepolarity,Jcontrol,port,LEPLL,contclear,fractional ; commands LMX2353 rcounter if PLL = 4112 then gosub [Command4112R]'needs:rcounter,preselector,phasepolarity,Jcontrol,port,LEPLL,contclear ; commands AD4112 rcounter return [CreateIntegerNcounter]'needed:appxVCO,reference,rcounter ; creates:ncount,ncounter,fcounter(0),pdf ncount = appxVCO/(reference/rcounter) 'approximates the Ncounter for PLL ncounter = int(ncount) 'approximates the ncounter for PLL if ncount - ncounter >= .5 then ncounter = ncounter + 1 'rounds off ncounter fcounter = 0 pdf = appxVCO/ncounter 'actual phase freq of PLL return 'to 'CreatePLL2N,'[CalculateThisStepPLL1],or '[CalculateThisStepPLL3] with ncount, ncounter and fcounter(=0) [CreateFractionalNcounter]'needed:appxVCO,reference,rcounter ; creates:ncount,ncounter,fcounter,pdf ncount = appxVCO/(reference/rcounter) 'approximates the Ncounter for PLL ncounter = int(ncount) 'actual value for PLL Ncounter fcount = ncount - ncounter fcounter = int(fcount*16) 'ver111 if (fcount*16) - fcounter >= .5 then fcounter = fcounter + 1 'rounds off fcounter ver111 if fcounter = 16 then ncounter = ncounter + 1:fcounter = 0 pdf = appxVCO/(ncounter + (fcounter/16)) 'actual phase freq for PLL 'ver111-10 return 'with ncount,ncounter,fcounter,pdf [AutoSpur]'needed:LO1,LO2,finalfreq,appxdds1,dds1output,rcounter1,finalbw,fcounter,ncounter,spurcheck;changes pdf,dds1output '[AutoSpur] is a continuation of [CreateFractionalNcounter], used only in MSA when PLL 1 is Fractional spur = 0 'reset spur, and determine if there is potential for a spur firstif = LO2 - finalfreq fractionalfreq = dds1output/(rcounter1*16) harnonicb = int(firstif/fractionalfreq) if (firstif/fractionalfreq)-harnonicb >=.5 then harnonicb = harnonicb + 1 'rev108 harnonica = harnonicb - 1 harnonicc = harnonicb + 1 firstiflow = LO2 - (finalfreq + finalbw/1000) firstifhigh = LO2 - (finalfreq - finalbw/1000) if harnonica*fractionalfreq > firstiflow and harnonica*fractionalfreq < firstifhigh then spur = 1 if harnonicb*fractionalfreq > firstiflow and harnonicb*fractionalfreq < firstifhigh then spur = 1 if harnonicc*fractionalfreq > firstiflow and harnonicc*fractionalfreq < firstifhigh then spur = 1 if spur = 1 and (dds1outputappxdds1) then fcounter = fcounter + 1 if fcounter = 16 then ncounter = ncounter + 1:fcounter = 0 'rev108 if fcounter <0 then ncounter = ncounter - 1:fcounter = 15 'rev108 pdf = LO1/(ncounter + (fcounter/16)) dds1output = pdf * rcounter1 'actual output of DDS1(input Ref to PLL1) return 'with possibly new ncounter,fcounter,pdf,dds1output [ManSpur]'needed:spurcheck,dds1output,appxdds1,fcounter,ncounter '[ManSpur] is a continuation of [CreateFractionalNcounter], used only in MSA when PLL 1 is Fractional if spurcheck = 1 and (dds1outputappxdds1) then fcounter = fcounter + 1 'causes -shift in pdf1 if fcounter = 16 then ncounter = ncounter + 1:fcounter = 0 'rev108 if fcounter < 0 then ncounter = ncounter - 1:fcounter = 15 'rev108 pdf = LO1/(ncounter + (fcounter/16)) dds1output = pdf * rcounter1 'actual output of DDS1(input Ref to PLL1) return 'with possibly new:ncounter,fcounter,pdf,dds1output [CreatePLL1N]'needed:ncounter,fcounter,PLL1mode,PLL1 preselector = 32 : if PLL1mode = 1 then preselector = 16 PLL = PLL1 gosub [CreateNBuffer]'needs:ncounter,fcounter,PLL,preselector;creates:Bcounter,Acounter, and N Bits N0-Nx if len(errora$)>0 then error$ = "PLL 1, " + errora$:print #main.msgbox,error$:wait 'ver111-37e Bcounter1=Bcounter: Acounter1=Acounter return 'returns with Bcounter1,Acounter1,N0thruNx [CreatePLL2N]'needed:ncounter,fcounter,PLL2 preselector = 32 PLL = PLL2 gosub [CreateNBuffer]'needs:ncounter,fcounter,PLL,preselector;creates:Bcounter,Acounter, and N Bits N0-Nx if len(errora$)>0 then error$ = "PLL 2, " + errora$:print #main.msgbox,error$:wait 'ver111-37e return 'to 'CreatePLL2N [CreatePLL3N]'needed:ncounter,fcounter,PLL3mode,PLL3 ver111-14 preselector = 32 : if PLL3mode = 1 then preselector = 16 PLL = PLL3 gosub [CreateNBuffer]'needs:ncounter,fcounter,PLL,preselector;creates:Bcounter,Acounter, and N Bits N0-Nx if len(errora$)>0 then error$ = "PLL 3, " + errora$:print #main.msgbox,error$:wait 'ver111-37e Bcounter3=Bcounter: Acounter3=Acounter return 'returns with Bcounter3,Acounter3,N0thruNx [CreateNBuffer]'needed:PLL,ncounter,fcounter,preselector if PLL = 2325 then gosub [Create2325N]'needs:ncounter,preselector; creates LMX2325 N Buffer ver111 if PLL = 2326 then gosub [Create2326N]'needs:ncounter ; creates LMX2326 N Buffer ver111 if PLL = 2350 then gosub [Create2350N]'needs:ncounter,preselector,fcounter; creates LMX2350 RFN Buffer ver111 if PLL = 2353 then gosub [Create2353N]'needs: ncounter,preselector,fcounter; creates LMX2353 N Buffer ver111 if PLL = 4112 then gosub [Create4112N]'needs:ncounter,preselector; creates AD4112 N Buffer ver111 return 'with Bcounter,Acounter, and N Bits N0-N23 [Command2325R]'needed:rcounter,preselector,control,Jcontrol,port,LEPLL,contclear ; commands LMX2325 rcounter and registers if rcounter <3 then beep:errora$ = "2325 Rcounter is < 3":return 'with errora$ ver111-37c if rcounter >16383 then beep:errora$ = "2325 Rcounter is > 16383":return 'with errora$ ver111-37c N0 = 1 'address bit, 0 sets the N Buffer, 1 is for R Buffer rc1 = int(rcounter/2):N1 = rcounter - 2*rc1 'binary conversion from decimal rc2 = int(rc1/2):N2 = rc1 - 2*rc2 rc3 = int(rc2/2):N3 = rc2 - 2*rc3 rc4 = int(rc3/2):N4 = rc3 - 2*rc4 rc5 = int(rc4/2):N5 = rc4 - 2*rc5 rc6 = int(rc5/2):N6 = rc5 - 2*rc6 rc7 = int(rc6/2):N7 = rc6 - 2*rc7 rc8 = int(rc7/2):N8 = rc7 - 2*rc8 rc9 = int(rc8/2):N9 = rc8 - 2*rc9 rc10 = int(rc9/2):N10 = rc9 - 2*rc10 rc11 = int(rc10/2):N11 = rc10 - 2*rc11 rc12 = int(rc11/2):N12 = rc11 - 2*rc12 rc13 = int(rc12/2):N13 = rc12 - 2*rc13 rc14 = int(rc13/2):N14 = rc13 - 2*rc14 N15 = 1: if preselector = 64 then N15 = 0 'sets preselector divide ratio, 1=32, 0=64 gosub [CommandPLL]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111 return [Create2325N]'needed:ncounter,preselector; creates LMX2325 n buffer Bcounter = int(ncounter/preselector) Acounter = ncounter- (Bcounter * preselector) if Bcounter<3 then beep:errora$ = "2325 Bcounter < 3":return 'with errora$ ver111-37c if Bcounter>2047 then beep:errora$ = "2325 Bcounter > 2047":return 'with errora$ ver111-37c if Bcounter16383 then beep:errora$="2326 R counter >16383":return 'with errora$ ver111-37c N0 = 0 'R address bit 0, must be 0 N1 = 0 'R address vit 1, must be 0 ra0 = int(rcounter/2):N2 = rcounter- 2*ra0 'LSB ra1 = int(ra0/2):N3 = ra0- 2*ra1 ra2 = int(ra1/2):N4 = ra1- 2*ra2 ra3 = int(ra2/2):N5 = ra2- 2*ra3 ra4 = int(ra3/2):N6 = ra3- 2*ra4 ra5 = int(ra4/2):N7 = ra4- 2*ra5 ra6 = int(ra5/2):N8 = ra5- 2*ra6 ra7 = int(ra6/2):N9 = ra6- 2*ra7 ra8 = int(ra7/2):N10 = ra7- 2*ra8 ra9 = int(ra8/2):N11 = ra8- 2*ra9 ra10 = int(ra9/2):N12 = ra9- 2*ra10 ra11 = int(ra10/2):N13 = ra10- 2*ra11 ra12 = int(ra11/2):N14 = ra11- 2*ra12 ra13 = int(ra12/2):N15 = ra12- 2*ra13 'MSB N16 = 0 'Test Bit N17 = 0 'Test Bit N18 = 0 'Test Bit N19 = 0 'Test Bit N20 = 0 'Lock Detector Mode, 0=3 refcycles, 1=5 cycles '[Command2326Rbuffer]'need Jcontrol,LEPLL,contclear gosub [CommandPLL]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111 return [Create2326N]'needed:ncounter ; creates LMX2326 n buffer ver111 Bcounter = int(ncounter/32) Acounter = int(ncounter-(Bcounter*32)) if Bcounter < 3 then beep:errora$="2326 Bcounter <3":return 'with errora$ ver111-37c if Bcounter > 8191 then beep:errora$="2326 Bcounter >8191":return 'with errora$ ver111-37c if Bcounter < Acounter then beep:errora$="2326 Bcounter 32767 then beep:errora$="2350 Rcounter >32767":return 'with errora$ ver111-37c N0=0 '2350 RF_R register, 2 bits, must be 0 N1=1 '2350 RF_R register, 2 bits, must be 1 rfra2 = int(rcounter/2):N2 = rcounter- 2*rfra2 rfra3 = int(rfra2/2):N3 = rfra2- 2*rfra3 rfra4 = int(rfra3/2):N4 = rfra3- 2*rfra4 rfra5 = int(rfra4/2):N5 = rfra4- 2*rfra5 rfra6 = int(rfra5/2):N6 = rfra5- 2*rfra6 rfra7 = int(rfra6/2):N7 = rfra6- 2*rfra7 rfra8 = int(rfra7/2):N8 = rfra7- 2*rfra8 rfra9 = int(rfra8/2):N9 = rfra8- 2*rfra9 rfra10 = int(rfra9/2):N10 = rfra9- 2*rfra10 rfra11 = int(rfra10/2):N11 = rfra10- 2*rfra11 rfra12 = int(rfra11/2):N12 = rfra11- 2*rfra12 rfra13 = int(rfra12/2):N13 = rfra12- 2*rfra13 rfra14 = int(rfra13/2):N14 = rfra13- 2*rfra14 rfra15 = int(rfra14/2):N15 = rfra14- 2*rfra15 rfra16 = int(rfra15/2):N16 = rfra15- 2*rfra16 N17 = phasepolarity 'RF phase polarity, 1=positive action, 0=inverted action N18=1 'LSB of RF charge pump sel, 4 Bits, 16 levels, 100ua/level N19=1 'total current = (100ua * bit value)+100ua N20=1 '100ua to 1600ua: ie, 800ua = 0111, 1600ua = 1111 N21=1 'MSB of RF charge pump sel, 4 Bits 100ua/bit N22=0 'V2 enable voltage doubler =1 0=norm Vcc N23 = fractional 'DLL mode, delay line cal, 0=slow 1=fast,fractional mode '[CommandRFRbuffer2350] gosub [CommandPLL]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111 return [Create2350N]'needed: ncounter,preselector,fcounter; creates LMX2350 RFN Buffer Bcounter = int(ncounter/preselector) Acounter = int(ncounter-(Bcounter*preselector)) if Bcounter < 3 then beep:errora$="2350 Bcounter <3":return 'with errora$ ver111-37c if Bcounter > 1023 then beep:errora$="2350 Bcounter >1023":return 'with errora$ ver111-37c if Bcounter < Acounter + 2 then beep:errora$="2350 Bcounter32767 then beep:errora$ = "2353 Rcounter is > 32767":return 'with errora$ ver111-37c N0 = 0 'R address bit 0 N1 = 1 'R address bit 1 ra0 = int(rcounter/2):N2 = rcounter- 2*ra0 'LSB R buffer ra1 = int(ra0/2):N3 = ra0- 2*ra1:ra2 = int(ra1/2):N4 = ra1- 2*ra2 ra3 = int(ra2/2):N5 = ra2- 2*ra3:ra4 = int(ra3/2):N6 = ra3- 2*ra4 ra5 = int(ra4/2):N7 = ra4- 2*ra5:ra6 = int(ra5/2):N8 = ra5- 2*ra6 ra7 = int(ra6/2):N9 = ra6- 2*ra7:ra8 = int(ra7/2):N10 = ra7- 2*ra8 ra9 = int(ra8/2):N11 = ra8- 2*ra9:ra10 = int(ra9/2):N12 = ra9- 2*ra10 ra11 = int(ra10/2):N13 = ra10- 2*ra11:ra12 = int(ra11/2):N14 = ra11- 2*ra12 ra13 = int(ra12/2):N15 = ra12- 2*ra13:ra14 = int(ra13/2):N16 = ra13- 2*ra14 'MSB R buffer N17 = phasepolarity 'phase detector polarity 1=normal,0=reverse for opamp N18 = 1 'LSB of Charge pump control, 100ua x1 +100ua N19 = 1 'Charge pump control, 100ua x2 +100ua N20 = 1 'Charge pump control, 100ua x4 +100ua N21 = 1 'MSB of Charge pump control, 100ua x8 +100ua N22 = 0 'Charge Pump Voltage Doubler Enabled when 1 N23 = fractional 'Delay Line Loop Cal mode, set to 1 for fractional N '[Cmd2353Rbuffer] gosub [CommandPLL]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111 return [Create2353N]'needed: ncounter,preselector,fcounter; creates LMX2353 N Buffer Bcounter = int(ncounter/preselector) Acounter = int(ncounter-(Bcounter*preselector)) if Bcounter < 3 then beep:errora$ = "2353 Bcounter is < 3":return 'with errora$ ver111-37c if Bcounter > 1023 then beep:errora$ = "2353 Bcounter is > 1023":return 'with errora$ ver111-37c if Bcounter < Acounter + 2 then beep:errora$ = "2353 Bcounter < Acounter+2":return 'with errora$ ver111-37c N0 = 1 'n address bit 0 N1 = 1 'n address bit 1 f0 = int(fcounter/2):N2 = fcounter - 2*f0 'fcounter bit 0 f1 = int(f0/2):N3 = f0 - 2*f1 'fcounter bit 1 f2 = int(f1/2):N4 = f1 - 2*f2 'fcounter bit 2 f3 = int(f2/2):N5 = f2 - 2*f3 'fcounter bit 3 (0 to 15) na0 = int(Acounter/2):N6 = Acounter- 2*na0 'Acounter bit 0 LSB na1 = int(na0/2):N7 = na0 - 2*na1 na2 = int(na1/2):N8 = na1 - 2*na2 na3 = int(na2/2):N9 = na2 - 2*na3 na4 = int(na3/2):N10 = na3 - 2*na4 'Acounter bit 4 MSB nb0 = int(Bcounter/2):N11 = Bcounter- 2*nb0 'Bcounter bit 0 LSB nb1 = int(nb0/2):N12 = nb0 - 2*nb1 nb2 = int(nb1/2):N13 = nb1 - 2*nb2 nb3 = int(nb2/2):N14 = nb2 - 2*nb3 nb4 = int(nb3/2):N15 = nb3 - 2*nb4 nb5 = int(nb4/2):N16 = nb4 - 2*nb5 nb6 = int(nb5/2):N17 = nb5 - 2*nb6 nb7 = int(nb6/2):N18 = nb6 - 2*nb7 nb8 = int(nb7/2):N19 = nb7 - 2*nb8 nb9 = int(nb8/2):N20 = nb8 - 2*nb9 'Bcounter bit 9 MSB N21 = 0 :if preselector = 32 then N21 = 1 '0=16/17 1=32/33 N22 = 0 'power down if 1 N23 = 0 'counter reset if 1 return [Command4112R]'needed: rcounter,preselector,phasepolarity,control,Jcontrol,port,LEPLL,contclear ; commands AD4112 rcounter '[Create4112InitBuffer]'needed:preselector,phasepolarity N23=1 'N24,23 prescaler: 0=8, 1=16, 2=32, 3=64 N22=0 'preselector defaulted to 32 if preselector =8 then N23=0:N22=0 if preselector =16 then N23=0:N22=1 if preselector =64 then N23=1:N22=1 N21=0 'Power Down Mode, 0=async, 1=sync use 0 N20=1 'N22,21,20 Phase Current for Set 2 N19=1 'current= min current + min current*bit value N18=1 'use bit value of 7 and 4.7 Kohm for 5.0 ma N17=1 'N18,17,16 Phase Current for Set 1 N16=1 'current= min current + min current*bit value N15=1 'use bit value of 7 and 4.7 Kohm for 5.0 ma N14=0 'N15,14,13,12 Fastlock Timer cycles N13=0 '4 Bits, Cycles= 3 cycles + 4*bit value N12=0 'Fastlock Time out value, use 0 N11=0 'use 4 bit value = 0 N10=0 '0=Fastlock Mode 1 (command), 1=Mode 2 (automatic) N9=0 '1=Fastlock enabled, 0 =Fastlock Disabled N8=0 '1=Tristate the phase det output, use 0 N7 = phasepolarity 'Phase det polarity, 1=pos 0=neg N6=0 'FoLD control(pin14 output), 0= tristate, 1= Digital Lock Detect N5=0 '2= N Divider out, 3= High output, 4= R Divider output N4=0 '5= Open drain lock detect, 6= Serial Data output, 7= Low output N3=0 'PD1, Power Down, 0=normal operation, 1=select power down mode N2=0 '1= Counter Reset Enable, allows reset of R,N counters,use 0 N1=1 'F1 address bit 1, must be 1 N0=1 'F1 address bit 0, must be 1 '[Command4112InitBuffer] gosub [CommandPLL]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111 '[Create4112Rbuffer]'needs:rcounter if rcounter >16383 then beep:errora$="4112 R counter >16383":return 'with errora$ ver111-37c N0 = 0 'R address bit 0, must be 0 N1 = 0 'R address vit 1, must be 0 ra0 = int(rcounter/2):N2 = rcounter- 2*ra0 'LSB R0 ra1 = int(ra0/2):N3 = ra0- 2*ra1 ra2 = int(ra1/2):N4 = ra1- 2*ra2 ra3 = int(ra2/2):N5 = ra2- 2*ra3 ra4 = int(ra3/2):N6 = ra3- 2*ra4 ra5 = int(ra4/2):N7 = ra4- 2*ra5 ra6 = int(ra5/2):N8 = ra5- 2*ra6 ra7 = int(ra6/2):N9 = ra6- 2*ra7 ra8 = int(ra7/2):N10 = ra7- 2*ra8 ra9 = int(ra8/2):N11 = ra8- 2*ra9 ra10 = int(ra9/2):N12 = ra9- 2*ra10 ra11 = int(ra10/2):N13 = ra10- 2*ra11 ra12 = int(ra11/2):N14 = ra11- 2*ra12 ra13 = int(ra12/2):N15 = ra12- 2*ra13 'MSB N16 = 0 'N17,16 Antibacklash width N17 = 0 '0=3ns, 1=1.5ns, 2=6ns, 3=3ns N18 = 0 'Test Bit, use 0 N19 = 0 'Test Bit, use 0 N20 = 0 'Lock Detector Mode, 0=3 refcycles, 1=5 cycles N21 = 0 'resyncronization enable 0=normal, 1=resync prescaler N22 = 1 '0=resync with nondelayed rf input, 1=resync with delayed rf N23 = 0 'reserved, use 0 '[Command4112Rbuffer] gosub [CommandPLL]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111 return '[endCommand4112R] [Create4112N]'needed: ncounter,preselector; creates AD4112 N Buffer Bcounter = int(ncounter/preselector) Acounter = int(ncounter-(Bcounter*preselector)) if Bcounter < 3 then beep:errora$="4112 N counter <3":return 'with errora$ ver111-37c if Bcounter > 8191 then beep:errora$="4112 N counter >8191":return 'with errora$ ver111-37c if Bcounter < Acounter then beep:errora$="4112 B counter= ddsclock/2 then beep:print #main.msgbox,"Error, ddsoutput > .5 ddsclock":goto [Halted] 'ver112-2c base = int(fullbase) 'rounded down to whole number if fullbase - base >= .5 then base = base + 1 'rounded to nearest whole number 'now, the actual ddsoutput can be determined by: ddsoutput = base*ddsclock/2^32 'Create Parallel Words 'needed:base w0= 0 'a "1" here will activate the x4 internal multiplier, but not recommended w1= int(base/2^24) 'w1 thru w4 converts decimal base code to 4 words, each are 8 bit binary w2= int((base-(w1*2^24))/2^16) w3= int((base-(w1*2^24)-(w2*2^16))/2^8) w4= int(base-(w1*2^24)-(w2*2^16)-(w3*2^8)) 'Create Serial Bits'needed:base ; creates serial word bits; sw0 thru sw39 b0 = int(base/2):sw0 = base - 2*b0 'LSB, Freq-b0. sw is serial word bit b1 = int(b0/2):sw1 = b0 - 2*b1:b2 = int(b1/2):sw2 = b1 - 2*b2 b3 = int(b2/2):sw3 = b2 - 2*b3:b4 = int(b3/2):sw4 = b3 - 2*b4 b5 = int(b4/2):sw5 = b4 - 2*b5:b6 = int(b5/2):sw6 = b5 - 2*b6 b7 = int(b6/2):sw7 = b6 - 2*b7:b8 = int(b7/2):sw8 = b7 - 2*b8 b9 = int(b8/2):sw9 = b8 - 2*b9:b10 = int(b9/2):sw10 = b9 - 2*b10 b11 = int(b10/2):sw11 = b10 - 2*b11:b12 = int(b11/2):sw12 = b11 - 2*b12 b13 = int(b12/2):sw13 = b12 - 2*b13:b14 = int(b13/2):sw14 = b13 - 2*b14 b15 = int(b14/2):sw15 = b14 - 2*b15:b16 = int(b15/2):sw16 = b15 - 2*b16 b17 = int(b16/2):sw17 = b16 - 2*b17:b18 = int(b17/2):sw18 = b17 - 2*b18 b19 = int(b18/2):sw19 = b18 - 2*b19:b20 = int(b19/2):sw20 = b19 - 2*b20 b21 = int(b20/2):sw21 = b20 - 2*b21:b22 = int(b21/2):sw22 = b21 - 2*b22 b23 = int(b22/2):sw23 = b22 - 2*b23:b24 = int(b23/2):sw24 = b23 - 2*b24 b25 = int(b24/2):sw25 = b24 - 2*b25:b26 = int(b25/2):sw26 = b25 - 2*b26 b27 = int(b26/2):sw27 = b26 - 2*b27:b28 = int(b27/2):sw28 = b27 - 2*b28 b29 = int(b28/2):sw29 = b28 - 2*b29:b30 = int(b29/2):sw30 = b29 - 2*b30 b31 = int(b30/2):sw31 = b30 - 2*b31 'MSB, Freq-b31 sw32 = 0 'x4 multiplier, 1=enable, but not recommended sw33 = 0 'control bit sw34 = 0 'power down bit sw35 = 0 'phase data sw36 = 0 'phase data sw37 = 0 'phase data sw38 = 0 'phase data sw39 = 0 'phase data return '[endCreateBaseForDDSarray] [ResetDDS1par]'needed:control,STRBAUTO,contclear ; resets DDS1 on J5(OrigControlBd), into parallel mode out control, STRBAUTO 'wclk and fqud lines high, causing DDS "Reset" line to go high out control, contclear 'wclk and fqud lines low (all control lines low) return [ResetDDS1ser]'OrigControlBoard.needed:AUTO,STRB,STRBAUTO ; set DDS1(J5)to serial mode. ver113-2c 'DDS (AD9850/9851) can be hard wired. pin2=D2=0, pin3=D1=1,pin4=D0=1, D3-D7 are don't care. 'this will reset DDS into parallel, involk serial mode, then command zero output out port, 3 'data=0000 0011, if the DDS is not already hard wired '(reset DDS1 to parallel)Data,WCLK up,WCLK up and FQUD up,WCLK up and FQUD down,WCLK down out control, AUTO 'WCLK up, FQUD=0 out control, STRBAUTO 'WCLK=1 and FQUD up out control, AUTO 'WCLK=1, FQUD down out control, contclear 'WCLK down, FQUD=0 '(end reset DDS1 to parallel) '(involk serial mode DDS1)WCLK up, WCLK down, FQUD up, FQUD down out control, AUTO:out control, contclear 'WCLK up, WCLK down out control, STRB:out control, contclear 'FQUD up, FQUD down 'even if the DDS1, D0-D2 is not hard wired, it will be in Serial Mode '(end involk serial mode DDS1) '(command DDS1 to flush registers)D7=0,WCLK up,WCLK down,(repeat39more),FQUD up,FQUD down out port, 0 'D7=0 for thisloop = 0 to 39 out control, AUTO:out control, contclear 'D7=0,WCLK up,WCLK down next thisloop out control, STRB:out control, contclear 'FQUD up, FQUD down '(end command DDS1 flush)DDS will output a DC signal return [ResetDDS3ser]'OrigControlBoard.needed:AUTO,STRB,STRBAUTO ; set DDS3(J4)to serial mode. ver113-2c 'DDS3 (AD9850/9851) must be hard wired. pin2=D2=0, pin3=D1=1,pin4=D0=1, D3-D7 are don't care. out control, Jcontrol 'enable Control Board J connector '(reset DDS3 to parallel)WCLK up and FQUD up,WCLK down and FQUD down out port, 34 'WCLK up and FQUD up. DDS register pointer will reset '(end reset DDS1 to parallel) out port, sfqud:out port, 0 ' DDSpin8, FQUD up, FQUD down. DDS register pointer will reset out port, swclk:out port, 0 ' DDSpin9, WCLK up, DDS WCLK down out port, sfqud:out port, 0 ' DDSpin8, FQUD up, FQUD down. DDS will go to 0 Hz. out control, contclear 'disable Control Board J connector return [ResetDDS1serSLIM]'reset serial DDS1 without disturbing Filter Bank or PDM. ver113-2c 'must have DDS (AD9850/9851) hard wired. pin2=D2=0, pin3=D1=1,pin4=D0=1, D3-D7 are don't care. 'this will reset DDS into parallel, involk serial mode, then command to 0 Hz. pdmcmd = phaarray(thisstep,0) 'ver111-39d '(reset DDS1 to parallel)WCLK up,WCLK up and FQUD up,WCLK up and FQUD down,WCLK down out port, filtbank + 1 'apply last known filter path and WCLK=D0=1 to buffer out control, SELT 'DDSpin9, WCLK up to DDS out control, contclear 'disable buffer,leaving filtbank, and WCLK=high to DDS out port, pdmcmd*64 + 2 'apply last known pdmcmd and FQUD=D3=1 to buffer out control, INIT 'DDSpin8, FQUD up,DDS resets to parallel,register pointer will reset out port, pdmcmd*64 'DDSpin8, FQUD down out control, contclear 'disable buffer, leaving last known PDM state latched out port, filtbank 'apply last known filter path and WCLK=D0=0 to buffer out control, SELT 'DDSpin9, WCLK down out control, contclear 'disable buffer,leaving filtbank '(end reset DDS1 to parallel) '(involk serial mode DDS1)WCLK up, WCLK down, FQUD up, FQUD down out port, filtbank + 1 'apply last known filter path and WCLK=D0=1 to buffer out control, SELT 'DDSpin9, WCLK up to DDS out port, filtbank 'apply last known filter path and WCLK=D0=0 to DDS out control, contclear 'disable buffer,leaving filtbank out port, pdmcmd*64 + 2 'apply last known pdmcmd and FQUD=D3=1 to buffer out control, INIT 'DDSpin8, FQUD up,DDS resets to parallel,register pointer will reset out port, pdmcmd*64 'DDSpin8, FQUD down out control, contclear 'disable buffer, leaving last known PDM state latched '(end involk serial mode DDS1) '(flush and command DDS1)D7,WCLK up,WCLK down,(repeat39more),FQUD up,FQUD down 'present data to buffer,latch buffer,disable buffer,present data+clk to buffer,latch buffer,disable buffer a=filtbank for thisloop = 0 to 39 out port, a:out control, SELT:out control, contclear: out port, a+1:out control, SELT:out control, contclear next thisloop out port, a:out control, SELT:out control, contclear 'leaving filtbank latched out port, pdmcmd*64 + 2 'apply last known pdmcmd and FQUD=D3=1 to buffer out control, INIT 'DDSpin8, FQUD up,DDS resets to parallel,register pointer will reset out port, pdmcmd*64 'DDSpin8, FQUD down out control, contclear 'disable buffer, leaving last known PDM state latched '(end flush command DDS1) return 'to '[InitializeDDS1] [ResetDDS3serSLIM]'reset serial DDS3 without disturbing Filter Bank or PDM. ver113-2c 'must have DDS (AD9850/9851) hard wired. pin2=D2=0, pin3=D1=1,pin4=D0=1, D3-D7 are don't care. 'this will reset DDS into parallel, involk serial mode, then command to 0 Hz. pdmcmd = phaarray(thisstep,0) 'ver111-39d '(reset DDS3 to parallel)WCLK up,WCLK up and FQUD up,WCLK up and FQUD down,WCLK down out port, filtbank + 1 'apply last known filter path and WCLK=D0=1 to buffer out control, SELT 'DDSpin9, WCLK up to DDS out control, contclear 'disable buffer,leaving filtbank, and WCLK=high to DDS out port, pdmcmd*64 + 8 'apply last known pdmcmd and FQUD=D3=1 to buffer out control, INIT 'DDSpin8, FQUD up,DDS resets to parallel,register pointer will reset out port, pdmcmd*64 'DDSpin8, FQUD down out control, contclear 'disable buffer, leaving last known PDM state latched out port, filtbank 'apply last known filter path and WCLK=D0=0 to buffer out control, SELT 'DDSpin9, WCLK down out control, contclear 'disable buffer,leaving filtbank '(end reset DDS3 to parallel) '(involk serial mode DDS3)WCLK up, WCLK down, FQUD up, FQUD down out port, filtbank + 1 'apply last known filter path and WCLK=D0=1 to buffer out control, SELT 'DDSpin9, WCLK up to DDS out port, filtbank 'apply last known filter path and WCLK=D0=0 to DDS out control, contclear 'disable buffer,leaving filtbank out port, pdmcmd*64 + 8 'apply last known pdmcmd and FQUD=D3=1 to buffer out control, INIT 'DDSpin8, FQUD up,DDS resets to parallel,register pointer will reset out port, pdmcmd*64 'DDSpin8, FQUD down out control, contclear 'disable buffer, leaving last known PDM state latched '(end involk serial mode DDS3) '(flush and command DDS3)D7,WCLK up,WCLK down,(repeat39more),FQUD up,FQUD down 'present data to buffer,latch buffer,disable buffer,present data+clk to buffer,latch buffer,disable buffer a=filtbank for thisloop = 0 to 39 out port, a:out control, SELT:out control, contclear: out port, a+1:out control, SELT:out control, contclear next thisloop out port, a:out control, SELT:out control, contclear 'leaving filtbank latched out port, pdmcmd*64 + 8 'apply last known pdmcmd and FQUD=D3=1 to buffer out control, INIT 'DDSpin8, FQUD up,DDS resets to parallel,register pointer will reset out port, pdmcmd*64 'DDSpin8, FQUD down out control, contclear 'disable buffer, leaving last known PDM state latched '(end flush command DDS3) return 'to '(InitializeDDS 3) 'SEW8 added RequireRestart sub RequireRestart 'Disable OneStep and Continue so user can only proceed by Restart haltsweep=0 call DisplayButtonsForHalted #main.onestep, "!disable" #main.continue, "!disable" end sub 'SEW8 added DisplayButtonsForRunning sub DisplayButtonsForRunning 'Display buttons for sweep in progress #main.onestep, "!enable" #main.continue, "!enable" #main.restart, "Running" end sub 'SEW8 added DisplayButtonsForHalted sub DisplayButtonsForHalted 'Display buttons for sweep halted, to enable resuming or restarting #main.onestep, "!enable" #main.continue, "!enable" #main.restart, "Restart" end sub 'SEW3 added menuRunConfig and menuRunCal 'SEW9 rewrote the following menuRunConfig. ver113-7d [menuRunConfig]'Graph Window Menu,Setup,Configuration Manager was selected 'the following 4 lines of code were the SEW3 new code: ' if haltsweep=1 then goto [Halted]'sew6 ver113-7c ' cancelled=configRunManager(0) '0 signals we are not running on startup so cancellation is allowed ' if cancelled then goto [Halted] 'Cancelled; halt scan and wait ' goto [finished] 'Must restart if config was changed 'the following 10 lines of code are for the new SEW9, ver113-7d: #main.FiltList, "selection? saveFilt$" cancelled=configRunManager(0) '0 signals we are not running on startup so cancellation is allowed if cancelled then 'Cancelled; restore filter setting; Halt or wait #main.FiltList, "select ";saveFilt$ 'Selects prior path #main.FiltList, "setfocus" 'Makes sure selection is visually activated gosub [SelectFilter] if haltsweep=1 then goto [Halted] 'Finish last point of sweep that was in progress. wait end if goto [finished] 'Must restart if config was changed 'end of now for SEW9, ver113-7d 'changedver113-7cSEW6[menuRunCal] [menuRunCal]'Menu item for config manager was selected 'SEW6 rewrote routine.ver113-7c #main.FiltList, "selection? saveFilt$" 'calRunManager will return with filter path 1 installed. call RequireRestart 'SEW8 Let the user proceed only by Restarting gosub [calManRunManager] #main.FiltList, "select ";saveFilt$ 'Selects path 1 #main.FiltList, "setfocus" 'Makes sure selection is visually activated gosub [SelectFilter] wait [CreateGraphWindow]'changed ver113-4b WindowWidth = windowwide WindowHeight = graphhigh UpperLeftX = 1 'the Graph window upper left corner is 1 pixel right.. UpperLeftY = 1 '...and 1 pixel down from the upper left of the screen '--SEW and SEW3Added the File and Edit menu items to save or copy the graph image 'and open ConfigMan, CalMan menu #handle, "File", "Save Image", [SaveImage] 'SEW menu #handle, "Edit", "Copy Image",[CopyImage] 'SEW menu #handle, "Setup", "Configuration Manager", [menuRunConfig], _ "Calibration Manager", [menuRunCal] 'SEW3 menu #handle, "Data", "Magnitude input to MSA",[MagnitudeMSAinput],"Magnitude AtoD Bits",[MagBitsAtoD],_ "Magnitude Calibration Table",[MagCalTable],"Phase Data, Processed",[PhaProcessed],_ "Phase AtoD Bits",[PhaBitsAtoD],"Phase Calibration Table",[PhaCalTable],"S21 Parameters",[MagPhaS21] 'ver113-5a if TGtop > 0 then menu #handle, "Mode", "Spec Anal Mode", [GoMSAmode], "VNA Mode", [GoVNAmode] 'ver113-6c if vna = 0 then open "Graph Window for MSA/VNA, Spectrum Analyzer Mode - version 113" for graphics_nsb as #handle if vna = 1 then open "Graph Window for MSA/VNA, Vector Network Analyzer Mode - version 113" for graphics_nsb as #handle print #handle, "when leftButtonDown [LeftButDown]" print #handle, "when rightButtonDown [RightButDown]" print #handle, "trapclose [finished]" 'goto [finished] if xit is clicked print #handle, "down" 'ready to draw [PrintGraph]'changed subroutine and name ver113-4b '(PrintGraphLines) This is an entry point, when comming from [Halted], to reprint the Graph print #handle, "color darkgray" 'all 11 graph lines, and all tick marks will be gray. print #handle, "line ";" ";x/2;" ";y;" ";x/2;" ";y+10 'draw center tickmark ticks = abs(steps/10) for tick = 0 to ticks print #handle, "line ";" ";x*tick/ticks;" ";y;" ";x*tick/ticks;" ";y+5 next tick 'this will draw a tickmark every 10 steps print #handle, "line ";0;" ";y-maxscale;" ";x;" ";y-maxscale 'draw a reference line for top power print #handle, "line ";0;" ";y-.9*maxscale;" ";x;" ";y-.9*maxscale print #handle, "line ";0;" ";y-.8*maxscale;" ";x;" ";y-.8*maxscale print #handle, "line ";0;" ";y-.7*maxscale;" ";x;" ";y-.7*maxscale print #handle, "line ";0;" ";y-.6*maxscale;" ";x;" ";y-.6*maxscale print #handle, "line ";0;" ";y-.5*maxscale;" ";x;" ";y-.5*maxscale print #handle, "line ";0;" ";y-.4*maxscale;" ";x;" ";y-.4*maxscale print #handle, "line ";0;" ";y-.3*maxscale;" ";x;" ";y-.3*maxscale print #handle, "line ";0;" ";y-.2*maxscale;" ";x;" ";y-.2*maxscale print #handle, "line ";0;" ";y-.1*maxscale;" ";x;" ";y-.1*maxscale print #handle, "line ";0;" ";y;" ";x;" ";y '(PrintMagReferences) mref$ = " dBm" print #handle, "color blue" 'the magnitude scale text, on right, will be blue. print #handle, "place ";2+x;" ";y-maxscale 'place pen to the right of the reference line print #handle, "\";topref;mref$ 'print reference pwr level and dBm print #handle, "place ";2+x;" ";y-.9*maxscale print #handle, "\";topref - .1*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.8*maxscale print #handle, "\";topref - .2*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.7*maxscale print #handle, "\";topref - .3*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.6*maxscale print #handle, "\";topref - .4*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.5*maxscale print #handle, "\";topref - .5*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.4*maxscale print #handle, "\";topref - .6*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.3*maxscale print #handle, "\";topref - .7*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.2*maxscale print #handle, "\";topref - .8*(topref - botref);mref$ print #handle, "place ";2+x;" ";y-.1*maxscale print #handle, "\";topref - .9*(topref - botref);mref$ print #handle, "place ";2+x;" ";y print #handle, "\";botref;mref$ if vna = 1 then gosub [PrintPhaReferences] print #handle, "color black" 'text at top of graph will be black print #handle, "place 150 15" 'ver113-5a print #handle, "\Center Frequency = "; centfreq; " MHz Sweep Width = ";sweepwidth;" MHz Res BW = ";finalbw;" KHz, ";path$ 'ver113-6a return [PrintPhaReferences]'new subroutine ver113-4b print #handle, "color red" 'the Phase text, on left, will be red print #handle, "place 2 40" print #handle, "\";topphase;" Deg." print #handle, "place 2 320" print #handle, "\";botphase;" Deg." return [createCommonWorkingWindow]'entered from (Create Working Window) or [GoMSAmode],[GoVNAmode] WindowWidth = windowwide 'the Working window is 800 pixels wide WindowHeight = windowhigh 'the Working window is 180 pixels in height UpperLeftX = 1 'the Working window upper left corner is 1 pixels right.. UpperLeftY = 415 '...and 415 pixels down from the upper left corner of the monitor screen ForegroundColor$ = "white" ComboboxColor$="blue" 'SEW2 moved ver113-7a combobox #main.FiltList, MSAFiltStrings$(), [menuSelectFilter],5,38,135,100 'Filter list'SEW2 ver113-7c statictext #main.message, "Message:", 5, 5, 50, 15 'delver113-6a statictext #main.finalif, "Final I.F.", 5, 65, 40, 12 statictext #main.centerfreq, "Center Frequency", 323, 1, 120, 12 statictext #main.centerfreq2, "MHz", 408, 18, 30, 12 statictext #main.placemarkers, "Place Markers at Steps:", 598, 1, 120, 12 statictext #main.topref, "Top Ref Line", 725, 1, 70, 12 statictext #main.topref2, "dBm", 765, 18, 30, 12 statictext #main.filter, "Select Final Filter Path:", 5, 25, 130, 12 statictext #main.sweepwidth, "Sweep Width:", 320, 40, 80, 12 statictext #main.sweepwidth2, "MHz", 383, 59, 30, 12 statictext #main.stepspersweep, "Steps/Sweep", 415, 40, 80, 12 statictext #main.stepspersweep2, "1-720", 460, 59, 40, 12 statictext #main.mhzperstep, "MHz/Step:", 530, 40, 80, 12 statictext #main.waittime, "Wait (ms)", 635, 40, 60, 12 'ver111-27 statictext #main.botref, "Bot Ref Line", 725, 40, 70, 12 statictext #main.botref2, "dBm", 765, 59, 30, 12 'delver113-6a statictext #main.resolutionbw, "Res. B.W.", 5, 88, 50, 12 statictext #main.thisstep, "Step", 235, 90, 50, 15 statictext #main.thisfreq, "This Freq", 283, 90, 50, 15 statictext #main.thispower, "Power (dBm)", 385, 90, 60, 15 statictext #main.leftclick, "LeftClick", 170, 110, 50, 12 statictext #main.rightclick, "RightClick", 170, 133, 50, 15 TextboxColor$ = "red" 'the following textboxes will be red textbox #main.centerfreqbox, 325, 15, 80, 20 ' create Center Freq box textbox #main.marker1box, 600, 15, 30, 20 'create Marker box 1 textbox #main.marker2box, 640, 15, 30, 20 'create Marker box 2 textbox #main.marker3box, 680, 15, 30, 20 'create Marker box 3 textbox #main.toprefbox, 725, 15, 35, 20 'create top reference line box textbox #main.sweepwidthbox, 325, 55, 55, 20 'create Sweep Width box textbox #main.stepspersweepbox, 420, 55, 35, 20 'create Steps per Sweep box textbox #main.botrefbox, 725, 55, 35, 20 'create bottom reference linebox TextboxColor$ = "brown" 'the following textboxes will be brown ver111-22 textbox #main.waitbox, 640, 55, 35, 20 ' create Wait box TextboxColor$ = "blue" 'the following textboxes will be blue textbox #main.msgbox, 65, 3, 165, 20 ' create Message box 'delver113-6a textbox #main.finalifbox, 65, 62, 65, 20 ' create Final IF box 'delver113-6a textbox #main.resolutionbox, 65, 86, 65, 20 ' create Resolution BW box textbox #main.mhzperstepbox, 522, 55, 80, 20 'create MHz per step box textbox #main.stepnobox, 230, 106, 35, 20 'create step box textbox #main.thisfreqbox, 270, 106, 75, 20 'create This Freq box textbox #main.thispowerbox, 385, 106, 65, 20 'create Power box textbox #main.stepnobox2, 230, 130, 35, 20 'create step box textbox #main.thisfreqbox2, 270, 130, 75, 20 'create This Freq box textbox #main.thispowerbox2, 385, 130, 65, 20 'create Power box 'SEW Filter buttons deleted button #main.centerbutton, "Cent", [centerbutton], UL, 350, 106, 30, 20 button #main.onestep, "One Step", [OneStep], UL, 720, 80, 65, 20 'moved ver111-24 button #main.continue, "Continue", [Continue], UL, 720, 105, 65, 20 button #main.restart, "Running", [Restart], UL, 720, 130, 65, 20 'changed to "Running" ver111-30c button #main.showvar, "Show Variables", [Showvar], UL, 150, 38, 80, 20 if vna = 0 then gosub [WorkingWindowforMSA] if vna = 1 then gosub [WorkingWindowforVNA] 'and return here to install common variable values print #main.centerfreqbox, "";centfreq 'default center freq print #main.sweepwidthbox, "";sweepwidth 'default sweep width print #main.stepspersweepbox, "";steps 'default steps per sweep print #main.marker1box, "";marker1 'insert marker1 default in Marker1 box print #main.marker2box, "";marker2 'insert marker2 default in Marker2 box print #main.marker3box, "";marker3 'insert marker3 default in Marker3 box print #main.waitbox, "";wate 'insert wate default, or last "wate" into wait box print #main.toprefbox, "";topref 'insert default top reference line print #main.botrefbox, "";botref 'insert default bottom reference line filtIndex=val(Word$(path$, 2))-1 'Index is one less than filter number, moved ver113-7a if filtIndex<0 or filtIndex>MSANumFilters then notice "Bad filter path number" 'helpful for debugging, moved ver113-7a #main.FiltList, "select ";MSAFiltStrings$(filtIndex) 'SEW2 Select filter for path$, moved ver113-7a gosub [SelectFilter] return [WorkingWindowforMSA] 'entered from [createCommonWorkingWindow] 'ver113-6b BackgroundColor$ = "darkblue" button #main.spurbutton, "Spur Test is OFF", [Spurtest], UL, 522, 80, 95, 20 'ver111-17 'delver113-6c if TGtop > 0 then button #main.govna, "Go-VNA Mode", [GoVNAmode], UL, 150, 63, 80, 20 if TGtop = 2 then gosub [CreateButtonsNewTG] 'ver111-17 if TGtop = 1 then gosub [CreateButtonsOldTG] 'ver111-17 button #main.magdisp, "Norm Erase", [ChangeMagDisplayMSA], UL, 640, 80, 65, 20 'ver113-7c button #main.special, "Special Tests", [SpecialTests], UL, 5, 113, 75, 20 'ver111-36b magdisp = 1 'ver113-7c phadisp = 0 'ver111-24 open "Working Window for MSA/VNA, Spectrum Analyzer Mode - version 113" for dialog as #main print #main, "trapclose [finished]" 'goto [finished] if xit is clicked 'delver113-6a print #main.finalifbox, "";finalfreq;" MHz" 'default final I.F. freq 'delver113-6a print #main.resolutionbox, "";finalbw;" KHz" 'default resolution BW if TGtop = 2 then print #main.freqoffbox, "";sgpreset 'ver111-18 if TGtop = 1 then print #main.freqoffbox, "";offset 'ver111-18 return [WorkingWindowforVNA] 'entered from [createCommonWorkingWindow] 'ver113-6b BackgroundColor$ = "darkred" statictext #main.phasetop, "Phase Top", 245, 1, 60, 12 statictext #main.phasetop2, "Deg.", 290, 18, 30, 15 statictext #main.phasebot, "Phase Bot", 245, 40, 60, 12 statictext #main.phasebot2, "Deg.", 290, 59, 30, 15 statictext #main.pdminvert, "PDM Inversion", 450,18,80,15 statictext #main.thisphase, "Phase", 460, 90, 50, 12 statictext #main.leftclick, "LeftClick", 170, 110, 50, 12 statictext #main.rightclick, "RightClick", 170, 133, 50, 15 TextboxColor$ = "red" 'the following textboxes will be red textbox #main.phasetopbox, 255, 15, 35, 20 ' create Phase top line reference box textbox #main.phasebotbox, 255, 55, 35, 20 ' create Phase bottom line reference box textbox #main.invdegbox, 530, 15, 50, 20 statictext #main.planeadj, "Plane Extension", 530, 133, 80, 15 'ver113-1b textbox #main.planeadjbox, 615, 130, 55, 20 'create "plane extension" box 'ver113-1b statictext #main.nsec, "nsec", 673, 133, 30, 15 'ver113-1b 'delver113-7a TextboxColor$ = "brown" 'the following textboxes will be brown ver111-22 'delver113-7a textbox #main.waitbox, 640, 55, 35, 20 ' create Wait box TextboxColor$ = "blue" 'the following textboxes will be blue textbox #main.thisphasebox, 455, 106, 60, 20 'create Phase box textbox #main.thisphasebox2, 455, 130, 60, 20 'create Phase box gentrk = 1:normrev = 0:offset = 0 'turn on tracking generator, normal, zero offset 'ver111-17 button #main.magdisp, "Mag Erase", [ChangeMagDisplayVNA], UL, 640, 80, 65, 20 'ver111-24 magdisp = 1 'begin with mag erasing before printing ver111-24 button #main.phadisp, "Pha Erase", [ChangePhaDisplayVNA], UL, 640, 105, 65, 20 'ver111-24 phadisp = 1 'begin with phase erasing before printing ver111-24 'delver113-6c button #main.gomsa, "Go-MSA Mode", [GoMSAmode], UL, 150, 63, 80, 20 button #main.calibfwd, "Calibrate ?", [Calfwd], UL, 150, 86, 65, 20 button #main.special, "Special Tests", [SpecialTests], UL, 5, 113, 75, 20 'ver112-2a button #main.saveconf, "Save Config", [SaveConfig], UL, 5, 135, 62, 20 'ver113-1a textbox #main.saveconfbox, 68, 135, 20, 20 'create configuration box 'ver113-1a button #main.goconf, "Go Config", [GoConfig], UL, 90, 135, 55, 20 'ver113-1a textbox #main.goconfbox, 146, 135, 20, 20 'create "go to configuration" box 'ver113-1a open "Working Window for MSA/VNA, Vector Network Analyzer Mode - version 113" for dialog as #main print #main, "trapclose [finished]" 'goto [finished] if xit is clicked 'delver113-6a print #main.finalifbox, "";finalfreq;" MHz" 'default final I.F. freq 'delver113-6a print #main.resolutionbox, "";finalbw;" KHz" 'default resolution BW print #main.invdegbox,invdeg print #main.phasetopbox,180 print #main.phasebotbox,-180 're-added, got lost in -6f to -6f-toScotty2. 'ver113-7a return 'to [createCommonWorkingWindow] and install common default values [SaveConfig] 'ver113-1a 'install the present set-up configurations into an array, 0-99 configurations if haltsweep = 1 then goto [Halted] 'create configarray(200,750),see dim configarray print #main.saveconfbox, "!contents? config$"; 'Entered Configuration number, 0-99 config = val(config$) 'if a negative number or no number or alpha is entered, make it "0" if config <1 then config = 0:print #main.saveconfbox,0 'if number is more than 99, make it 99 if config >99 then config = 99:print #main.saveconfbox,99 rememberthisstep = thisstep 'the following loop will load this config array with the present cal table numbers for thisstep = 0 to steps configarray(config,thisstep) = calarray(thisstep,1) 'magpower during cal configarray(config + 100,thisstep) = calarray(thisstep,2) 'phaseofpdm during cal next thisstep thisstep = rememberthisstep configarray(config,721) = A0:configarray(config,722) = A1 'filter path configarray(config,723) = centfreq 'center freq configarray(config,724) = sweepwidth 'sweep width configarray(config,725) = steps 'step/sweep configarray(config,726) = marker1 configarray(config,727) = marker2 configarray(config,728) = marker3 configarray(config,729) = topref 'top ref line configarray(config,730) = botref 'bot ref line configarray(config,731) = wate 'wait box configarray(config,732) = magdisp 'Magnitude display box configarray(config,733) = phadisp 'Phase display box configarray(config,734) = topphase 'Phase reference, top line box configarray(config,735) = botphase 'Phase reference, bottom line box configarray(config,736) = 1 '0=array is empty, 1=array has data print #main.msgbox,"Configuration is stored" wait [GoConfig] 'ver113-1a 'we are in VNA Mode, use number in box and retrieve variables. Install in Working Window if haltsweep = 1 then goto [Halted] print #main.goconfbox, "!contents? config$"; 'Entered Configuration number, 0-99 config = val(config$) 'if a negative number or no number or alpha is entered, make it "0" if config <1 then config = 0:print #main.goconfbox,0 'if number is more than 99, make it 99 if config >99 then config = 99:print #main.goconfbox,99 beep if configarray(config,736) = 0 then print #main.msgbox,"Config is empty, choose another":wait print #main.msgbox,"Config selected, use [Restart]" print #main.centerfreqbox,configarray(config,723) 'centerfreq,center frequency print #main.sweepwidthbox,configarray(config,724) 'sweepwidth,sweep width print #main.stepspersweepbox,configarray(config,725) 'steps,step/sweep print #main.marker1box,configarray(config,726) 'marker1 print #main.marker2box,configarray(config,727) 'marker2 print #main.marker3box,configarray(config,728) 'marker3 print #main.toprefbox,configarray(config,729) 'topref 'top ref line print #main.botrefbox,configarray(config,730) 'botref 'bot ref line print #main.waitbox,configarray(config,731)'wate 'wait box magdisp = configarray(config,732)-1 'condition of the magnitude display (erase,etc) phadisp = configarray(config,733)-1 'condition of the phase display (stick,etc) print #main.phasetopbox,configarray(config,734) 'topphase 'Phase reference, top line box print #main.phasebotbox,configarray(config,735) 'botphase 'Phase reference, bottom line box returnflag=1 gosub [ChangeMagDisplayVNA]' using magdisp-1 gosub [ChangePhaDisplayVNA]'using phadisp-1 returnflag=0 'now, put the memory data into present arrays rememberthisstep = thisstep for thisstep = 0 to steps calarray(thisstep,1) = configarray(config,thisstep) 'magpower during cal calarray(thisstep,2) = configarray(config + 100,thisstep) 'phaseofpdm during cal next thisstep thisstep = rememberthisstep 'assume filter path, PDM inversion box, does not need changing 'do these things: 'close variables window if open 'close special tests if open, including data window 'install config data into Working Window but, do not auto "Restart" wait [CreateButtonsNewTG] 'ver111-17 gentrk = 0 'when 0, in Signal Generator Mode, ie. LO3 remains fixed frequency at a default frequency normrev = 0 'make sure LO3 doesn't reverse during start-up button #main.sigenbutton, "Signal Generator", [SignalGeneratorbutton], UL, 460, 106, 100, 20 'ver111-17 button #main.presetbutton, "Preset", [Presetbutton], UL, 570, 106, 48, 20 'ver111-18 statictext #main.enterfreqtxt, "Enter Freq", 460, 133, 68, 15 'ver111-26 TextboxColor$ = "red" 'the following textboxes will be red textbox #main.freqoffbox, 538, 130, 72, 20 'create box for Sig Gen freq or Trk Gen offset freq'ver111-17 statictext #main.freqenter, "MHz", 615, 133, 24, 15 'ver111-17 return [CreateButtonsOldTG] 'ver111-17 gentrk = 1 'may not be needed normrev = 0 'may not be needed statictext #main.sigenbutton, "Tracking Generator", 460, 106, 100, 20 'ver111-17 statictext #main.presetbutton, "Offset", 570, 106, 48, 20 'ver111-17 statictext #main.enterfreqtxt, "Enter Offset", 460, 133, 68, 15 'ver111-26 TextboxColor$ = "red" 'the following textboxes will be red textbox #main.freqoffbox, 538, 130, 72, 20 'create Offset Freq box 'ver111-17 statictext #main.freqenter, "MHz", 615, 133, 24, 15 'ver111-17 return [SignalGeneratorbutton]'selects either "Signal Generator" or "Tracking Generator" 'ver111-17 if haltsweep = 1 then goto [Halted] 'ver111-26 'this button does not exist in old TG topology. Only in new TG topology. if gentrk = 0 then print #main.sigenbutton, "Tracking Generator" if gentrk = 0 then print #main.presetbutton, "Normal":normrev = 0 if gentrk = 0 then print #main.enterfreqtxt, "Enter Offset" 'ver111-26 if gentrk = 0 then print #main.freqoffbox, "";offset if gentrk = 0 then gentrk = 1:wait if gentrk = 1 then print #main.sigenbutton, "Signal Generator" if gentrk = 1 then print #main.presetbutton, "Preset" if gentrk = 1 then print #main.enterfreqtxt, "Enter Freq" 'ver111-26 if gentrk = 1 then print #main.freqoffbox, "";sgpreset if gentrk = 1 then gentrk = 0:wait [Presetbutton]'when in Sig Gen mode, enters the SGpreset into freqoffbox 'ver111-17 if haltsweep = 1 then goto [Halted] 'ver111-26 'this button does not exist in old TG topology. Only in new TG topology. if gentrk = 1 then goto [NormRevbutton] 'if in Tracking Generator Mode, go there 'if gentrk = 1, we are in Tracking Mode. The button is labeled "Normal" or "Reverse" 'if gentrk = 0, we are in Sig Gen Mode. The button is labeled "Preset" print #main.presetbutton, "Preset":print #main.freqoffbox, "";sgpreset:wait 'this puts "sgpreset" value into freqoffbox [NormRevbutton]'when in Tracking Mode, selects either Normal or Reverse tracking 'ver111-17 'this button does not exist in old TG topology. Only in new TG topology. if normrev = 0 then print #main.presetbutton, "Reverse":normrev = 1:wait if normrev = 1 then print #main.presetbutton, "Normal":normrev = 0:wait [ChangeMagDisplayMSA] 'ver111-24 if haltsweep = 1 then goto [Halted] 'ver111-26 magdisp = magdisp + 1 if magdisp > 4 then magdisp = 0 if magdisp = 0 then print #main.magdisp, "Trace Off" if magdisp = 1 then print #main.magdisp, "Norm Erase" if magdisp = 2 then print #main.magdisp, "Norm Stick" if magdisp = 3 then print #main.magdisp, "Histo Erase" if magdisp = 4 then print #main.magdisp, "Histo Stick" wait [ChangeMagDisplayVNA] 'ver111-24 if haltsweep = 1 then goto [Halted] 'ver111-26 magdisp = magdisp + 1 if magdisp > 2 then magdisp = 0 if magdisp = 0 then print #main.magdisp, "Mag Off" if magdisp = 1 then print #main.magdisp, "Mag Erase" if magdisp = 2 then print #main.magdisp, "Mag Stick" if returnflag=1 then return 'ver113-1a wait [ChangePhaDisplayVNA] 'ver111-24 if haltsweep = 1 then goto [Halted] 'ver111-26 phadisp = phadisp + 1 if phadisp > 2 then phadisp = 0 if phadisp = 0 then print #main.phadisp, "Pha Off" if phadisp = 1 then print #main.phadisp, "Pha Erase" if phadisp = 2 then print #main.phadisp, "Pha Stick" if returnflag=1 then return 'ver113-1a wait [GoMSAmode] if haltsweep = 1 then goto [Halted] 'ver111-26 'if the Special Tests Window is open, close it. if special=1 then returnflag=1:gosub [CloseSpecial]:returnflag=0 'ver112-2f vna = 0 redim calarray(800,2) 'clear out the calibration array when changing to MSA mode close #main 'close out working window for VNA close #handle 'close out Graph window for VNA gosub [CreateGraphWindow] 'ver113-4b gosub [createCommonWorkingWindow] 'ver113-6b goto [Restart] [GoVNAmode] if haltsweep = 1 then goto [Halted] 'ver111-26 'if the Special Tests Window is open, close it. if special=1 then returnflag=1:gosub [CloseSpecial]:returnflag=0 'ver112-2f if spurcheck = 1 and PLL1mode = 0 then rcounter1=rcounter1-1:gosub [CommandPLL1R]:spurcheck = 0 'ver111-24 vna = 1 redim calarray(800,2) 'clear out the calibration array when changing to VNA mode close #main 'close out working window for SA close #handle 'close out Graph window for SA gosub [CreateGraphWindow] 'ver113-4b gosub [createCommonWorkingWindow] 'ver113-6b goto [Restart] [calcWindowInfo] 'from [GrabWorkingWindowData] print #main.centerfreqbox, "!contents? centfreq$"; 'Center Freq box centfreq = val(centfreq$) 'change global to what user entered print #main.sweepwidthbox, "!contents? sweepwidth$"; 'Sweep Width box sweepwidth = val(sweepwidth$) 'change global to what user entered print #main.stepspersweepbox, "!contents? steps$"; 'Steps per Sweep box steps = val(steps$) 'change global to what user entered if steps > 720 then steps = 720:print #main.stepspersweepbox, steps 'ver113-1a startfreq = centfreq - sweepwidth/2 'start frequency of sweep stepfreq = sweepwidth/steps 'delta step frequency print #main.mhzperstepbox, stepfreq 'MHz per step box print #main.marker1box, "!contents? mark1$"; 'Marker1 box marker1 = val(mark1$) 'change global to what user entered print #main.marker2box, "!contents? mark2$"; 'Marker2 box marker2 = val(mark2$) 'change global to what user entered print #main.marker3box, "!contents? mark3$"; 'Marker3 box marker3 = val(mark3$) 'change global to what user entered print #main.waitbox, "!contents? wate$"; 'Wait box wate = val(wate$) 'change global to what user entered print #main.toprefbox, "!contents? topref$"; 'Top reference box topref = val(topref$) 'Log Det power, in dBm print #main.botrefbox, "!contents? botref$"; 'Bottom reference box botref = val(botref$) 'Log Det power, in dBm if botref>=topref then botref = topref-10:print #main.botrefbox, "";topref-10 if vna = 0 and TGtop > 0 then print #main.freqoffbox, "!contents? freqoff$"; 'Sig Gen Freq or TG offset box data ver111-18 if vna = 0 and TGtop = 2 and gentrk = 0 then sgout = val(freqoff$) 'ver111-18 if vna = 0 and TGtop > 0 and gentrk = 1 then offset = val(freqoff$) 'ver111-18 if vna = 1 then print #main.invdegbox, "!contents? invdeg$"; if vna = 1 then invdeg = val(invdeg$) if vna = 1 then print #main.phasetopbox, "!contents? topphasescale$"; 'Top reference line from Phase Top box if vna = 1 then print #main.phasebotbox, "!contents? botphasescale$"; 'Bot reference line from Phase Bot box if vna = 1 then topphase = val(topphasescale$) 'this is the phase of the top scale ref line if vna = 1 then botphase = val(botphasescale$) 'this is the phase of the bottom scale ref line if vna = 1 and botphase>=topphase then botphase = topphase-10:print #main.phasebotbox, "";botphase if vna = 1 then centphase = (topphase+botphase)/2 'this is the phase of the center scale ref line if vna=1 then print #main.planeadjbox, "!contents? planeadj$" 'SEW plane extension-->planeadj return 'goto [endGrabWorkingWindowData] [LeftButDown] 'when left mouse button is pressed, do the following if haltsweep = 1 then goto [Halted] 'ver111-26 leftdownpixelx = MouseX if leftdownpixelx > x then leftdownpixelx=x leftstep = int(steps*leftdownpixelx/x) if (steps*leftdownpixelx/x) - leftstep >= .5 then leftstep = leftstep + 1 'rounds off 'ver111-37d print #main.stepnobox,datatable(leftstep,0) 'display "thisstep" number from most current data print #main.thisfreqbox,datatable(leftstep,1) 'display "thisfreq" from most current data print #main.thispowerbox,datatable(leftstep,2) 'display "magpower" from most current data if vna = 1 then print #main.thisphasebox,datatable(leftstep,3);" deg" 'display phase measurement from most current data if varwindow = 1 then gosub [preupdatevar] 'ver111-36h will update variables window as Mouse is clicked wait [preupdatevar] 'ver111-36h remember = thisstep thisstep = datatable(leftstep,0) gosub [updatevar] thisstep = remember return [RightButDown] 'when right mouse button is pressed, do the following if haltsweep = 1 then goto [Halted] 'ver111-26 rightdownpixelx = MouseX if rightdownpixelx > x then rightdownpixelx=x rightstep = int(steps*rightdownpixelx/x) if (steps*rightdownpixelx/x) - rightstep >= .5 then rightstep = rightstep + 1 'rounds off 'ver111-37d print #main.stepnobox2,datatable(rightstep,0) 'display "thisstep" number from most current data print #main.thisfreqbox2,datatable(rightstep,1) 'display "thisfreq" from most current data print #main.thispowerbox2,datatable(rightstep,2) 'display "magpower" from most current data if vna = 1 then print #main.thisphasebox2,datatable(rightstep,3);" deg" 'display phase measurement from most current data 'in [Halted], leftdownpixelx is set to x+1 if leftdownpixelx = x+1 then wait 'ver111-36a 'this prevents sweep expansion if the left mouse button has not been clicked yet lowerfreq = datatable(leftstep,1) upperfreq = datatable(rightstep,1) if lowerfreq>upperfreq then lowerfreq=datatable(rightstep,1):upperfreq=datatable(leftstep,1) newsweepwidth = upperfreq-lowerfreq newcenterfreq = lowerfreq + newsweepwidth/2 print #main.centerfreqbox, "";newcenterfreq print #main.sweepwidthbox, "";newsweepwidth wait [centerbutton]'this will take the contents of the "This Freq" box and put it in the "Center Frequency" box if haltsweep = 1 then goto [Halted] 'ver111-26 print #main.thisfreqbox, "!contents? newcentfreq$" print #main.centerfreqbox, "";newcentfreq$ wait '--SEW2--Added the following to replace button1-button4, [menuSelectFilter] gosub [SelectFilter] 'This failsafe is done at the end, because the visual selection is made even if we leave at the top if haltsweep = 1 then goto [Halted] 'haltsweep is a signal to buttons etc. to halt the sweep wait [SelectFilter] 'Filter has been selected in the list of filters 'This can be called by a user click on the list or by a program gosub #main.FiltList, "selectionindex? filtIndex" 'Filter N is at index N in list if filtIndex=0 then 'filtIndex can be 0 if user typed something in the combo box filtIndex=1 #main.FiltList, "select ";MSAFiltStrings$(0) 'Select default #main.FiltList, "setfocus" 'SEW2 Needed to activate the highlight end if call calInstallFile filtIndex 'Loads file and sets finalfreq and finalbw path$="Path "+str$(filtIndex) 'Name of filter path; Path 1, ver113-7c if filtIndex<=2 then A1=0 else A1=1 'Set filter address if filtIndex=1 or filtIndex=3 then A0=0 else A0=1 gosub [CommandFilter] 'ver111-29 'Physically select filter 'SEW6 Remove the focus from list so scroll wheel doesn't accidentally affect it #main.msgbox, "!setfocus" 'SEW6 ver113-7c return 'to caller or to wait state if called from user clicking box '--SEW2--End of filter selection change [CommandFilter] 'ver111-29 if cb = 0 then filtbank = A1*8 + A0*4 : gosub [CommandFilterOrigCB] if cb = 2 then filtbank = A1*64 + A0*32 : gosub [CommandFilterSlimCB] return 'to [SelectFilter]'ver113-7a [CommandFilterOrigCB]'command 1 of 4 and latch it ver111-29 out port, filtbank 'presents A0 and A1 to control buffer out control, INIT 'presents A0 and A1 to Filter Bank out port, filtbank + 1 'latches A0 and A1 into Filter Bank using latch signal out port, filtbank 'leaves A0 and A1 on Filter Bank, removing latch signal out control, contclear 'removes A0 and A1 from Filter Bank out port, 0 'removes A0 and A1 from control buffer return 'to [CommandFilter] [CommandFilterSlimCB] 'ver111-29 out port, filtbank 'presents A0 and A1 to control buffer out control, SELT 'presents A0 and A1 to Filter Bank out port, filtbank + 128 'latches A0 and A1 into Filter Bank using latch signal out port, filtbank 'leaves A0 and A1 on Filter Bank, removing latch signal out control, contclear 'removes A0 and A1 from Filter Bank out port, 0 'removes A0 and A1 from control buffer return 'to [CommandFilter] [OneStep] if haltsweep = 1 then goto [Halted] 'ver111-26 onestep = 1 'ver111-26 goto [FocusKeyBox] [Continue] if haltsweep = 1 then goto [Halted] 'ver111-26 onestep = 0 'ver111-26 [FocusKeyBox] print #main.waitbox, "!contents? wate$"; 'Wait box ver111-22 wate = val(wate$) 'change global to what user entered ver111-22 call DisplayButtonsForRunning 'SEW8 replaced print #main.restart, "Running" gosub [ClearBoxes]'ver112-2c 'SEW changed the next two lines to set the scanResumed flag and then 'SEW goto the top of the scan loop. scanResumed=1 goto [StartSweep] [Restart] if haltsweep = 1 then goto [Halted] 'ver111-26 close #handle 'close out graph window when restarting 'When a window is closed, all graphics drawing operations are deleted from memory onestep = 0 'ver111-26 call DisplayButtonsForRunning 'SEW8 replaced print #main.restart, "Running" gosub [ClearBoxes]'ver112-2c goto [GrabWorkingWindowData] [ClearBoxes]'ver112-2c print #main.stepnobox,"" 'clear box print #main.thisfreqbox,"" 'clear box print #main.thispowerbox,"" 'clear box if vna = 1 then print #main.thisphasebox,"" 'clear box print #main.stepnobox2,"" 'clear box print #main.thisfreqbox2,"" 'clear box print #main.thispowerbox2,"" 'clear box if vna = 1 then print #main.thisphasebox2,"" 'clear box print #main.msgbox,"" return [Spurtest]'move the PDF of PLL1 to see if a signal is a self generated spur if haltsweep = 1 then goto [Halted] 'ver111-26 if spurcheck = 0 and PLL1mode = 0 then rcounter1=rcounter1+1:gosub [CommandPLL1R] if spurcheck = 0 then print #main.spurbutton, "Spur Test is ON":spurcheck=1:gosub [CalculateAllStepsForLO1Synth]:gosub [CreateCmdAllArray]:wait if spurcheck = 1 and PLL1mode = 0 then rcounter1=rcounter1-1:gosub [CommandPLL1R] if spurcheck = 1 then print #main.spurbutton, "Spur Test is OFF":spurcheck=0:gosub [CalculateAllStepsForLO1Synth]:gosub [CreateCmdAllArray]:wait [Showvar] if haltsweep = 1 then goto [Halted] 'ver111-26 if varwindow=1 then goto [Closevarwin] WindowWidth = 200 WindowHeight = 450 'ver111-26 UpperLeftX = 590 UpperLeftY = 5 BackgroundColor$ = "darkblue" ForegroundColor$ = "white" statictext #varwin.variable1, "this step = ";thisstep, 5, 5, 180, 15 'ver111-35 statictext #varwin.variable2, "dds1output = ";DDS1array(thisstep,46);" MHz", 5, 20, 180, 15 statictext #varwin.variable3, "LO 1 = ";PLL1array(thisstep,43);" MHz", 5, 35, 180, 15 statictext #varwin.variable4, "pdf1 = ";PLL1array(thisstep,40);" MHz", 5, 50, 180, 15 statictext #varwin.variable5, "ncounter1 = ";PLL1array(thisstep,45), 5, 65, 180, 15 statictext #varwin.variable6, "Bcounter1 = ";PLL1array(thisstep,48), 5, 80, 180, 15 statictext #varwin.variable7, "Acounter1 = ";PLL1array(thisstep,47), 5, 95, 180, 15 statictext #varwin.variable8, "fcounter1 = ";PLL1array(thisstep,46), 5, 110, 180, 15 statictext #varwin.variable9, "rcounter1 = ";rcounter1, 5, 125, 180, 15 statictext #varwin.variable10, "LO2 = ";LO2;" MHz", 5, 140, 180, 15 statictext #varwin.variable11, "pdf2 = ";pdf2;" MHz", 5, 155, 180, 15 statictext #varwin.variable12, "ncounter2 = ";ncounter2, 5, 170, 180, 15 statictext #varwin.variable13, "Bcounter2 = ";Bcounter2, 5, 185, 180, 15 statictext #varwin.variable14, "Acounter2 = ";Acounter2, 5, 200, 180, 15 statictext #varwin.variable15, "rcounter2 = ";rcounter2, 5, 215, 180, 15 statictext #varwin.variable16, "LO3 = ";PLL3array(thisstep,43);" MHz", 5, 230, 180, 15 statictext #varwin.variable17, "pdf3 = ";PLL3array(thisstep,40);" MHz", 5, 245, 180, 15 statictext #varwin.variable18, "ncounter3 = ";PLL3array(thisstep,45), 5, 260, 180, 15 statictext #varwin.variable19, "Bcounter3 = ";PLL3array(thisstep,48), 5, 275, 180, 15 statictext #varwin.variable20, "Acounter3 = ";PLL3array(thisstep,47), 5, 290, 180, 15 statictext #varwin.variable21, "fcounter3 = ";PLL3array(thisstep,46), 5, 305, 180, 15 statictext #varwin.variable22, "rcounter3 = ";rcounter3, 5, 320, 180, 15 statictext #varwin.variable23, "dds3output = ";DDS3array(thisstep,46), 5, 335, 180, 15 statictext #varwin.variable24, "Magdata = ";magarray(thisstep,3);" magpower= ";datatable(thisstep,2), 5, 350, 195, 15 'raw magdata bits, MSA input power(massaged) 'ver111-39b statictext #varwin.variable25, "Phadata = ";phaarray(thisstep,3);" PDM = ";phaarray(thisstep,4), 5, 365, 180, 15 'ver111-39d statictext #varwin.variable26, "Real Final I.F. = ";LO2 - (PLL1array(thisstep,45)*DDS1array(thisstep,46)/rcounter1) + datatable(thisstep,1), 5, 380, 180, 15 'ver112-2b 'real final IF = LO2-(LO1-thisfreq) open "Variables Window" for dialog as #varwin:varwindow = 1 print #varwin, "trapclose [Closevarwin]" 'goto [Closevarwin] if xit is clicked print #main.showvar, "Close Variables" wait [updatevar] print #varwin.variable1, "this step = ";thisstep 'ver111-35 print #varwin.variable2, "dds1output = ";DDS1array(thisstep,46);" MHz" print #varwin.variable3, "LO 1 = ";PLL1array(thisstep,43);" MHz" print #varwin.variable4, "pdf1 = ";PLL1array(thisstep,40);" MHz" print #varwin.variable5, "ncounter1 = ";PLL1array(thisstep,45) print #varwin.variable6, "Bcounter1 = ";PLL1array(thisstep,48) print #varwin.variable7, "Acounter1 = ";PLL1array(thisstep,47) print #varwin.variable8, "fcounter1 = ";PLL1array(thisstep,46) print #varwin.variable9, "rcounter1 = ";rcounter1 print #varwin.variable10, "LO2 = ";LO2;" MHz" print #varwin.variable11, "pdf2 = ";pdf2;" MHz" print #varwin.variable12, "ncounter2 = ";ncounter2 print #varwin.variable13, "Bcounter2 = ";Bcounter2 print #varwin.variable14, "Acounter2 = ";Acounter2 print #varwin.variable15, "rcounter2 = ";rcounter2 print #varwin.variable16, "LO3 = ";PLL3array(thisstep,43);" MHz" print #varwin.variable17, "pdf3 = ";PLL3array(thisstep,40);" MHz" print #varwin.variable18, "ncounter3 = ";PLL3array(thisstep,45) print #varwin.variable19, "Bcounter3 = ";PLL3array(thisstep,48) print #varwin.variable20, "Acounter3 = ";PLL3array(thisstep,47) print #varwin.variable21, "fcounter3 = ";PLL3array(thisstep,46) print #varwin.variable22, "rcounter3 = ";rcounter3 print #varwin.variable23, "dds3output = ";DDS3array(thisstep,46) print #varwin.variable24, "Magdata = ";magarray(thisstep,3);" magpower= ";datatable(thisstep,2)'raw magdata bits, MSA input power(massaged) 'ver111-39b print #varwin.variable25, "Phadata = ";phaarray(thisstep,3);" PDM = ";phaarray(thisstep,4) 'ver111-39d print #varwin.variable26, "Real Final I.F. = ";LO2 - (PLL1array(thisstep,45)*DDS1array(thisstep,46)/rcounter1) + datatable(thisstep,1) 'ver112-2b return [Closevarwin] close #varwin:varwindow = 0 'close out variables window print #main.showvar, "Show Variables" wait [Calfwd] 'this will sweep one time, from step 0 to steps, beep and halt. 'it will fill the calarray with present sweep data, mag and pha if haltsweep = 1 then goto [Halted] 'ver111-26 calfwd = 1 print #main.calibfwd, "Calibrating" goto [Restart] [CalculateAllStepsForLO1Synth] haltstep = thisstep 'remember where we were in the sweep when halted for thisstep = 0 to steps magarray(thisstep,0) = thisstep * x/steps 'establishes "thispointx" (on x-axis of graph) (0 to 720)ver111-25 thisfreq = startfreq + (stepfreq * thisstep) 'calculates input freq. at this new step LO1 = thisfreq + LO2 - finalfreq 'calculates the actual LO1 frequency:thisfreq,LO2,finalfreq are actuals datatable(thisstep,0) = thisstep 'put current step number into the array, row value= thisstep 'moved ver111-18 datatable(thisstep,1) = thisfreq 'put current frequency into the array, row value= thisstep 'moved ver111-18 '[CalculateThisStepPLL1] appxVCO=LO1 : reference=appxdds1 : rcounter=rcounter1 if PLL1mode = 0 then gosub [CreateIntegerNcounter]'needed:appxVCO,reference,rcounter ; creates:ncount,ncounter,fcounter(0) 'returns with ncount,ncounter,fcounter(0),pdf if PLL1mode = 1 then gosub [CreateFractionalNcounter]'needed:appxVCO,reference,rcounter ; creates:ncount,ncounter,fcounter,pdf 'returns with ncount,ncounter,fcounter,pdf dds1output = pdf * rcounter 'actual output of DDS1(input Ref to PLL1) if PLL1mode = 1 then gosub [AutoSpur]'needed:LO2,finalfreq,dds1output,rcounter1,finalbw,appxdds1,fcounter,ncounter ver111-8 '[AutoSpur] is a continuation of [CreateFractionalNcounter], used only in MSA when PLL 1 is Fractional 'returns with possibly new: ncounter,fcounter,pdf,dds1output if PLL1mode = 1 then gosub [ManSpur]'ver111-10 '[ManSpur] is a continuation of [CreateFractionalNcounter], used only in MSA when PLL 1 is Fractional 'if Spur Test Button On, will return with new ncounter,fcounter,pdf,dds1output gosub [CreatePLL1N]'needs:ncounter,fcounter,PLL1mode,PLL1 ; creates PLL NBuffer N0-Nx gosub [FillPLL1array]'need:N0-Nx,pdf,dds1output,LO1,ncount,ncounter,Fcounter,Acounter,Bcounter;creates samePLL1 '[endCalculateThisStepPLL1] '[CalculateThisStepDDS1]'need:dds1output,masterclock,appxdds1,dds1filbw ddsoutput = dds1output : ddsclock = masterclock if dds1output-appxdds1>dds1filbw/2 then beep:error$="DDS1output too high for filter":print #main.msgbox,error$:wait 'ver111-37e if appxdds1-dds1output>dds1filbw/2 then beep:error$="DDS1output too low for filter":print #main.msgbox,error$:wait 'ver111-37e gosub [CreateBaseForDDSarray]'needed:ddsoutput,ddsclock ; creates: base,sw0thrusw39,w0thruw4 gosub [FillDDS1array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock '[endCalculateThisStepDDS1] next thisstep thisstep = haltstep 'return to the step in the sweep, where we halted, if needed return '[endCalculateAllStepsForLO1Synth] [CalculateAllStepsForLO3Synth]'for hybrid, and orig (fixed freq) TG 'if TGtop = 0 then skip all this (return), actually we should not have even entered this subroutine. haltstep = thisstep 'remember where we were in the sweep when halted for thisstep = 0 to steps 'ver111-17 thisfreq = startfreq + (stepfreq * thisstep) 'calculates input freq. at this new step if TGtop = 1 then LO3 = LO2 - finalfreq - offset 'for orig, fixed freq TG ver111-15a 'or LO3 = LO1 - thisfreq - offset if TGtop = 2 and gentrk = 1 and normrev = 0 then LO3 = LO2 + thisfreq + offset 'for new TG, Trk Gen mode, normal ver111-18 if TGtop = 2 and gentrk = 1 and normrev = 1 then LO3 = LO2 + (centfreq - (stepfreq * (thisstep - (steps/2))) + offset) if TGtop = 2 and gentrk = 0 then LO3 = LO2 + sgout 'for new TG, Sig Gen mode ver111-18 '[CalculateThisStepPLL3] appxVCO=LO3 : reference=appxdds3 : rcounter=rcounter3 if appxdds3 = 0 then reference=masterclock 'for orig, fixed freq TG with no DDS3 steering. ver111-17 if PLL3mode = 0 then gosub [CreateIntegerNcounter]'needed:appxVCO,reference,rcounter ; creates:ncount,ncounter,fcounter(0) 'returns with ncount,ncounter,fcounter(0),pdf if PLL3mode = 1 then gosub [CreateFractionalNcounter]'needed:appxVCO,reference,rcounter ; creates:ncount,ncounter,fcounter,pdf 'returns with ncount,ncounter,fcounter,pdf dds3output = pdf * rcounter 'actual output of DDS3(input Ref to PLL3) gosub [CreatePLL3N]'needs:ncounter,fcounter,PLL3mode,PLL3 ; creates PLL NBuffer N0-Nx gosub [FillPLL3array]'need thisstep,N0thruN23,pdf3(40),dds3output(41),samePLL3(42)see dim PLL3array for slot info 'ver111-14 '[endCalculateThisStepPLL3] '[CalculateThisStepDDS3]'need:dds3output,masterclock,appxdds3,dds3filbw if appxdds3 = 0 then goto [endCalculateThisStepDDS3] 'there is no DDS, skip this section ver111-17 ddsoutput = dds3output : ddsclock = masterclock if dds3output-appxdds3>dds3filbw/2 then beep:error$="DDS3output too high for filter":print #main.msgbox,error$:wait 'ver111-37e if appxdds3-dds3output>dds3filbw/2 then beep:error$="DDS3output too low for filter":print #main.msgbox,error$:wait 'ver111-37e gosub [CreateBaseForDDSarray]'needed:ddsoutput,ddsclock ; creates: base,sw0thrusw39,w0thruw4 gosub [FillDDS3array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock ver111-15 [endCalculateThisStepDDS3] 'del.ver112-2b phaarray(thisstep,0) = 0 'this will set all pdmstates, to 0 'ver112-1a phaarray(thisstep,0) = 0 'this will set all pdmstates, to 0 'undeleted, ver113-7e next thisstep thisstep = haltstep 'return to the step in the sweep, where we halted, if needed lastpdmstate = 2 'this will guarantee that the PDM will get commanded 'ver112-1a return '[endCalculateAllStepsForLO3Synth] [FillPLL1array]'need thisstep,N0thruN23,pdf1(40),dds1output(41),samePLL1(42)see dim PLL1array for slot info 'ver111-1 'reversed sequence for N23 to be first. ver111-31a PLL1array(thisstep,23) = N0:PLL1array(thisstep,22) = N1 PLL1array(thisstep,21) = N2:PLL1array(thisstep,20) = N3 PLL1array(thisstep,19) = N4:PLL1array(thisstep,18) = N5 PLL1array(thisstep,17) = N6:PLL1array(thisstep,16) = N7 PLL1array(thisstep,15) = N8:PLL1array(thisstep,14) = N9 PLL1array(thisstep,13) = N10:PLL1array(thisstep,12) = N11 PLL1array(thisstep,11) = N12:PLL1array(thisstep,10) = N13 PLL1array(thisstep,9) = N14:PLL1array(thisstep,8) = N15 PLL1array(thisstep,7) = N16:PLL1array(thisstep,6) = N17 PLL1array(thisstep,5) = N18:PLL1array(thisstep,4) = N19 PLL1array(thisstep,3) = N20:PLL1array(thisstep,2) = N21 PLL1array(thisstep,1) = N22:PLL1array(thisstep,0) = N23 PLL1array(thisstep,40) = pdf PLL1array(thisstep,43) = LO1 PLL1array(thisstep,45) = ncounter PLL1array(thisstep,46) = fcounter PLL1array(thisstep,47) = Acounter PLL1array(thisstep,48) = Bcounter return [FillPLL3array]'need thisstep,N0thruN23,pdf3(40),dds3output(41),samePLL3(42)see dim PLL3array for slot info 'ver111-14 'reversed sequence for N23 to be first. ver111-31a PLL3array(thisstep,23) = N0:PLL3array(thisstep,22) = N1 PLL3array(thisstep,21) = N2:PLL3array(thisstep,20) = N3 PLL3array(thisstep,19) = N4:PLL3array(thisstep,18) = N5 PLL3array(thisstep,17) = N6:PLL3array(thisstep,16) = N7 PLL3array(thisstep,15) = N8:PLL3array(thisstep,14) = N9 PLL3array(thisstep,13) = N10:PLL3array(thisstep,12) = N11 PLL3array(thisstep,11) = N12:PLL3array(thisstep,10) = N13 PLL3array(thisstep,9) = N14:PLL3array(thisstep,8) = N15 PLL3array(thisstep,7) = N16:PLL3array(thisstep,6) = N17 PLL3array(thisstep,5) = N18:PLL3array(thisstep,4) = N19 PLL3array(thisstep,3) = N20:PLL3array(thisstep,2) = N21 PLL3array(thisstep,1) = N22:PLL3array(thisstep,0) = N23 PLL3array(thisstep,40) = pdf PLL3array(thisstep,43) = LO3 PLL3array(thisstep,45) = ncounter PLL3array(thisstep,46) = fcounter PLL3array(thisstep,47) = Acounter PLL3array(thisstep,48) = Bcounter return [FillDDS1array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock 'ver111-12 DDS1array(thisstep,0) = sw0:DDS1array(thisstep,1) = sw1 DDS1array(thisstep,2) = sw2:DDS1array(thisstep,3) = sw3 DDS1array(thisstep,4) = sw4:DDS1array(thisstep,5) = sw5 DDS1array(thisstep,6) = sw6:DDS1array(thisstep,7) = sw7 DDS1array(thisstep,8) = sw8:DDS1array(thisstep,9) = sw9 DDS1array(thisstep,10) = sw10:DDS1array(thisstep,11) = sw11 DDS1array(thisstep,12) = sw12:DDS1array(thisstep,13) = sw13 DDS1array(thisstep,14) = sw14:DDS1array(thisstep,15) = sw15 DDS1array(thisstep,16) = sw16:DDS1array(thisstep,17) = sw17 DDS1array(thisstep,18) = sw18:DDS1array(thisstep,19) = sw19 DDS1array(thisstep,20) = sw20:DDS1array(thisstep,21) = sw21 DDS1array(thisstep,22) = sw22:DDS1array(thisstep,23) = sw23 DDS1array(thisstep,24) = sw24:DDS1array(thisstep,25) = sw25 DDS1array(thisstep,26) = sw26:DDS1array(thisstep,27) = sw27 DDS1array(thisstep,28) = sw28:DDS1array(thisstep,29) = sw29 DDS1array(thisstep,30) = sw30:DDS1array(thisstep,31) = sw31 DDS1array(thisstep,32) = sw32:DDS1array(thisstep,33) = sw33 DDS1array(thisstep,34) = sw34:DDS1array(thisstep,35) = sw35 DDS1array(thisstep,36) = sw36:DDS1array(thisstep,37) = sw37 DDS1array(thisstep,38) = sw38:DDS1array(thisstep,39) = sw39 DDS1array(thisstep,40) = w0 DDS1array(thisstep,41) = w1 DDS1array(thisstep,42) = w2 DDS1array(thisstep,43) = w3 DDS1array(thisstep,44) = w4 DDS1array(thisstep,45) = base 'base is decimal command DDS1array(thisstep,46) = base*ddsclock/2^32 'actual dds 1 output freq return [FillDDS3array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock 'ver111-15 DDS3array(thisstep,0) = sw0:DDS3array(thisstep,1) = sw1 DDS3array(thisstep,2) = sw2:DDS3array(thisstep,3) = sw3 DDS3array(thisstep,4) = sw4:DDS3array(thisstep,5) = sw5 DDS3array(thisstep,6) = sw6:DDS3array(thisstep,7) = sw7 DDS3array(thisstep,8) = sw8:DDS3array(thisstep,9) = sw9 DDS3array(thisstep,10) = sw10:DDS3array(thisstep,11) = sw11 DDS3array(thisstep,12) = sw12:DDS3array(thisstep,13) = sw13 DDS3array(thisstep,14) = sw14:DDS3array(thisstep,15) = sw15 DDS3array(thisstep,16) = sw16:DDS3array(thisstep,17) = sw17 DDS3array(thisstep,18) = sw18:DDS3array(thisstep,19) = sw19 DDS3array(thisstep,20) = sw20:DDS3array(thisstep,21) = sw21 DDS3array(thisstep,22) = sw22:DDS3array(thisstep,23) = sw23 DDS3array(thisstep,24) = sw24:DDS3array(thisstep,25) = sw25 DDS3array(thisstep,26) = sw26:DDS3array(thisstep,27) = sw27 DDS3array(thisstep,28) = sw28:DDS3array(thisstep,29) = sw29 DDS3array(thisstep,30) = sw30:DDS3array(thisstep,31) = sw31 DDS3array(thisstep,32) = sw32 'x4 multiplier DDS3array(thisstep,33) = sw33 'control bit DDS3array(thisstep,34) = sw34 'power down bit DDS3array(thisstep,35) = sw35 '35-39 are Phase DDS3array(thisstep,36) = sw36:DDS3array(thisstep,37) = sw37 DDS3array(thisstep,38) = sw38:DDS3array(thisstep,39) = sw39 DDS3array(thisstep,40) = w0 'word 0, 8 bits, mult, control and phase DDS3array(thisstep,41) = w1 'word 1, 8 bits DDS3array(thisstep,42) = w2 'word 2, 8 bits DDS3array(thisstep,43) = w3 'word 3, 8 bits DDS3array(thisstep,44) = w4 'word 4, 8 bits DDS3array(thisstep,45) = base 'base is decimal command DDS3array(thisstep,46) = base*ddsclock/2^32 'actual dds 3 output freq return [CreateCmdAllArray] 'for SLIM CB only 'ver-31b 'a DDS serial command, will begin with LSB (W0), thru MSB (W31), ending with Phase bit 4 (W39) 'a PLL serial command, will begin with MSB (N23), thru LSB (N0, the address bit) rememberthisstep = thisstep 'remember where we were when entering this subroutine for thisstep = 0 to steps for clmn = 0 to 15 cmdallarray(thisstep,clmn) = DDS1array(thisstep,clmn)*4 + DDS3array(thisstep,clmn)*16 next clmn for clmn = 16 to 39 cmdallarray(thisstep,clmn) = PLL1array(thisstep,clmn-16)*2 + DDS1array(thisstep,clmn)*4 + PLL3array(thisstep,clmn-16)*8 + DDS3array(thisstep,clmn)*16 next clmn next thisstep thisstep = rememberthisstep return [CommandPLL]' comes here during PLL R Initializations and PLL 2 N command ver111-28 if cb = 0 then gosub [CommandPLLorig] 'ver111-28 if cb = 2 then gosub [CommandPLLslim] 'ver111-28 return 'to [InitializePLL2]or[CommandXPllRbuffer] [CommandPLLorig]'needs:N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,old ControlBoard ver111-28 'used during initialization of PLL1, PLL2, and PLL3. PDM will get set to "0". 'when PLL1 or PLL2 then Jcontrol=SELT. when PLL3 the Jcontrol=INIT out control, Jcontrol 'enable Control Board J connector out port, N23:out port, N23 + 2 out port, N22:out port, N22 + 2:out port, N21:out port, N21 + 2 out port, N20:out port, N20 + 2:out port, N19:out port, N19 + 2 out port, N18:out port, N18 + 2:out port, N17:out port, N17 + 2 out port, N16:out port, N16 + 2:out port, N15:out port, N15 + 2 out port, N14:out port, N14 + 2:out port, N13:out port, N13 + 2 out port, N12:out port, N12 + 2:out port, N11:out port, N11 + 2 out port, N10:out port, N10 + 2:out port, N9:out port, N9 + 2 out port, N8:out port, N8 + 2:out port, N7:out port, N7 + 2 out port, N6:out port, N6 + 2:out port, N5:out port, N5 + 2 out port, N4:out port, N4 + 2:out port, N3:out port, N3 + 2 out port, N2:out port, N2 + 2:out port, N1:out port, N1 + 2 out port, N0:out port, N0 + 2:out port, LEPLL:out port, 0 'Latch buffer out control, contclear 'Disable the Control Board J connector return 'to [CommandPLL] [CommandPLLslim]'needs:datavalue,levalue,N23-N0,control,Jcontrol,port,contclear,LEPLL ; commands N23-N0,SLIM ControlBoard ver111-28 'used during initialization of PLL1, PLL2, and PLL3. PDM will get set to "0" during Initializations 'selt word = 1 common clock, 4 datas, plus 3 (filtbank). entering this sub, selt word should = filtbank only 'init word = 5 latch lines plus 2 pdm commands. entering this sub, init word should = pdmcmd + pdmclk only.ver111-39d 'two steps to do: command data and clock without disturbing Filter Bank, then send LE without disturbing PDM 'step 1. Command the PLL without changing the filter bank. 'For PLL1,datavalue=2, for PLL2,datavalue=16, for PLL3,datavalue=8 'following code lines changed in ver113-3c a=filtbank + N23*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N22*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N21*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N20*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N19*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N18*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N17*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N16*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N15*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N14*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N13*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N12*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N11*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N10*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N9*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N8*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N7*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N6*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N5*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N4*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N3*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N2*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N1*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear a=filtbank + N0*datavalue:out port, a:out control, SELT:out control, contclear:out port, a+1:out control, SELT:out control, contclear out port, filtbank:out control, SELT:out control, contclear 'leaving lines latched to filter bank out port, 0 'step 2. Command the PLL without changing the PDM pdmcommand = phaarray(thisstep,0)*64 'do not disturb PDM state, this may be used during Spur Test out port, pdmcommand + levalue 'levalues: PLL1=1, PLL2=16, PLL3=4 out control, INIT out port, pdmcommand out control, contclear 'leaving lines latched, and unchanged, to PDM out port, 0 return 'to [CommandPLL] [DetermineModule] 'ver111-28 'All "glitchXX's" are "0" when entering this subroutine. Either from "fresh RUN" or [WaitStatement] 'if a module is not present, or if it doesn't need commanding, return with it's "glitchXX = 0" '[DDS1] dds1output = DDS1array(thisstep,46) 'ver111-16 if dds1output = lastdds1output then goto [PLL1] 'dds 1 is same, don't waste time commanding 'ver111-28 glitchd1 = 1 'ver111-36h lastdds1output = dds1output [PLL1] ncounter1=PLL1array(thisstep,45):fcounter1=PLL1array(thisstep,46) 'ver111-16 if ncounter1=lastncounter1 and fcounter1=lastfcounter1 then goto [PLL3] 'don't waste time commanding 'ver111-28 glitchp1 = 1 'add 1 msec delay. ver111-28 lastncounter1=ncounter1:lastfcounter1=fcounter1 'ver111-16 [PLL3] if TGtop = 0 then return 'there is no PLL 3, no DDS 3,and no PDM for VNA ncounter3=PLL3array(thisstep,45):fcounter3=PLL3array(thisstep,46) if ncounter3=lastncounter3 and fcounter3=lastfcounter3 then goto [DDS3] 'don't waste time commanding 'ver111-28 glitchp3 = 1 'add 1 msec delay. ver111-28 lastncounter3=ncounter3:lastfcounter3=fcounter3 [DDS3] if appxdds3 = 0 then goto [PDM] 'if 0, there is no DDS3, but, there can be VNA ver111-28 dds3output = DDS3array(thisstep,46) if dds3output = lastdds3output then goto [PDM] 'dds 3 is same, don't waste time commanding 'ver111-29 glitchd3 = 1 'ver111-36h lastdds3output = dds3output [PDM] if vna = 0 then return ' not in VNA mode, skip the PDM 'ver111h pdmcmd = phaarray(thisstep,0) 'ver111-39d if pdmcmd = lastpdmstate then return 'don't waste time commanding glitchpdm = 10 'ver111-36h lastpdmstate = pdmcmd 'ver111-39d return 'to [CommandThisStep] [CommandOrigCB]' correct modules have been determined in [DetermineModule] 'Command necessary modules, independently, from Original Control Board if glitchd1 > 0 then gosub [CommandDDS1OrigCB] if glitchp1 > 0 then gosub [CommandPLL1OrigCB] if glitchd3 > 0 and TGtop > 0 then gosub [CommandDDS3OrigCB] if glitchp3 > 0 and TGtop > 0 then gosub [CommandPLL3OrigCB] if glitchpdm > 0 and vna = 1 then gosub [CommandPDMOrigCB] return 'to [CommandThisStep] [CommandDDS1OrigCB] 'needed:DDS1array 'ver111-21 if dds1parser = 1 then goto [CommandDDS1OrigCBserial] 'ver111-21 '(CommandDDS1OrigCBparallel)'needed:DDS1array(w0-w4),port,control,AUTO,STRB,contclear ; commands DDS1 on J5, parallel. ver111-21 'note, a DDS commanded parallel, will begin with Control Word (W0), then MSB Word (W1), ending with LSB Word (W4) 'set word 0 'set 8 bit word, W0 (0), phase info out port,DDS1array(thisstep,40) ' a "1" here would activate the x4 internal multiplier, but not recommended out control, AUTO 'wclk line goes high out control, contclear 'wclk line goes low 'set word 1 out port,DDS1array(thisstep,41) 'set 8 bit word, W1, MSB freq out control,AUTO:out control, contclear 'set word 2 out port,DDS1array(thisstep,42) 'W2 out control,AUTO:out control, contclear 'set word 3 out port,DDS1array(thisstep,43) 'W3 out control,AUTO:out control, contclear 'set word 4 out port,DDS1array(thisstep,44) 'set 8 bit word, W4, LSB freq out control,AUTO:out control, contclear out port, 0 'return the output port data lines to 0 'send fqud out control, STRB 'set fqud to 1, freq changes now out control, contclear 'set fqud to 0 and all others to 0 return 'to [CommandOrigCB] [CommandDDS1OrigCBserial]'needed:DDS1array(sw0-sw39),control,AUTO,STRB,contclear ; commands DDS1 on J5, serially ver111-21 'note: once the DDS1 has been reset into serial mode, the D0 thru D6 data lines are "don't care". 'note, a DDS serial command, will begin with LSB (W0), thru MSB (W31), ending with Phase bit 4 (W39) for clmn = 0 to 39 'ver111-21 out port, DDS1array(thisstep,clmn)*128 'apply data bit to DDS1pin25, D7 data line out control, AUTO:out control, contclear 'retain data bit while wclk up, then down next clmn 'next bit in 40 bit serial data transfer out port, 0 out control, STRB:out control, contclear 'fqud up, fqud down return 'to [CommandOrigCB] '[endCommandDDS1OldRevA] [CommandPLL1OrigCB]'needed:PLL1array(N23-N0),SELT,lastncounter1,lastfcounter1 'ver111-21 'ver111-28a makes the SELT buffer "see" the pdm state before commanding PLL1, to prevent orig PDM from changing states. Jcontrol = SELT : LEPLL = 4 'ver111-21 'Command PLL1,oldControl using N23-N0,control,Jcontrol,port,contclear,LEPLL ver111-21 'note, a PLL will serially command beginning with N23 and end with N0 (address bit) pdmcmd = phaarray(thisstep,0) 'ver111-39d out port, pdmcmd*128 'ver111-28a out control, Jcontrol 'enable Control Board J connector for clmn = 0 to 23 'reversed order 'ver111-31a out port, pdmcmd*128 + PLL1array(thisstep,clmn):out port, pdmcmd*128 + PLL1array(thisstep,clmn) + 2 'ver111-21 'ver111-28a next clmn 'ver111-21 out port, pdmcmd*128 + LEPLL:out port, pdmcmd*128 'Latch buffer 'ver111-28a out control, contclear 'Disable the Control Board J connector out port, 0 'ver111-28a return 'to [CommandOrigCB] [CommandDDS3OrigCB]'needed:DDS3array,lastdds3output,INIT 'ver111-18 Jcontrol = INIT:swclk = 32:sfqud = 2 'for Orig Control Bd,J4,DDS3 ver111-16 'Command DDS3,serially,oldControl using sw0-sw39,swclk,sfqud,control,Jcontrol,port,contclear,LEPLL ver111-21 'note, a DDS commanded serially, will begin with LSB, continue to MSB, and end with Control Word MSB Phase Bit 'present filter bank data while commanding DDS3, so as not to change filter bank ver111-29 out port, filtbank 'ver111-29 out control, Jcontrol 'enable Control Board J connector for clmn = 0 to 39 'ver111-21 out port, filtbank + DDS3array(thisstep,clmn) 'apply data bit to DDS, and also filter lines 'ver111-29 out port, filtbank + DDS3array(thisstep,clmn) + swclk 'apply data bit and wclk 'ver111-29 next clmn out port, filtbank:out port, filtbank + sfqud:out port, filtbank 'last sw down and swclk down, sfqud up, sfqud down 'ver111-29 out control, contclear 'disable J connector out port, 0 'ver111-29 return 'to [CommandOrigCB] [CommandPLL3OrigCB]'needed:PLL3array(N23-N0),INIT,lastncounter3,lastfcounter3 ver111-18 Jcontrol = INIT : LEPLL = 16 'ver111-21 'Command PLL3,Orig Control using N23-N0,control,Jcontrol,port,contclear,LEPLL ver111-21 'note, a PLL will serially command beginning with N23 and end with N0 (address bit) 'present filter bank data while commanding PLL3, so as not to change filter bank ver111-29 out port, filtbank 'ver111-29 out control, Jcontrol 'enable Control Board J connector for clmn = 0 to 23 'reversed order 'ver111-31a out port, filtbank + PLL3array(thisstep,clmn) 'ver111-29 out port, filtbank + PLL3array(thisstep,clmn) + 2 'ver111-21 'ver111-29 next clmn 'ver111-21 out port, filtbank + LEPLL:out port, filtbank 'Latch buffer 'ver111-29 out control, contclear 'Disable the Control Board J connector out port, 0 'ver111-29 return 'to [CommandOrigCB] [CommandPDMonly] 'ver111-28 if cb = 0 then goto [CommandPDMOrigCB] 'ver111-28 if cb = 2 then goto [CommandPDMSlimCB] 'ver111-28 return 'to [InvertPDmodule] [CommandPDMOrigCB]'Set original PDM phase for last known mode, since a PLL1 or PLL2 command will reset the PDM to Norm. out port, phaarray(thisstep,0)*128: out control, SELT: out control, contclear: out port, 0 'pdmcmd is determined in [InvertPDmodule] 'ver111-20 return 'to [CommandOrigCB]or[CommandPDMonly] [CommandPDMSlimCB]'also sending a "latch signal", used by orig PDM module out port, phaarray(thisstep,0)*64 out control, INIT out port, phaarray(thisstep,0)*64 + 32 out port, phaarray(thisstep,0)*64 out control, contclear out port, 0 return 'to [CommandPDMonly] 'delver113-3b[CommandPLL1SlimCB]'independently.(not used) 'delver113-3b[CommandPLL3SlimCB]'independently.(not used) 'delver113-4a[CommandDDS1SlimCB]'independently.(not used) 'delver113-4a[CommandDDS3SlimCB]'independently.(not used) [CommandAllSlims]'for SLIM Control and SLIM modules. Old PDM and old Filt Bank can be used 'ver111-31c '(send data and clocks without changing Filter Bank) '0-15 is DDS1bit*4 + DDS3bit*16, data = 0 to PLL 1 and PLL 3. see[CreateCmdAllArray]. 'present new Data with no clock,latch high,latch low,present new data with clock,latch high,latch low. ver113-2a 'repeat for each bit. (40 data bits and 40 clocks for each module, even if they don't need that many) 'this format guarantees that the common clock will not transition with a data transition, preventing crosstalk in LPT cable. ver111-32c for clmn = 0 to 39 'ver113-3c a= cmdallarray(thisstep,clmn)+ filtbank out port, a : out control, SELT:out control, contclear 'a is the data, without clock out port, a+1:out control, SELT:out control, contclear 'a+1 is data, plus clock next clmn out port, filtbank 'remove data, leaving filtbank data to filter bank. out control, SELT:out control, contclear 'disable buffer. filtbank signals will be latched to filter bank assembly 'send LE's to PLL1, PLL3, FQUD's to DDS1, DDS3, and command PDM 'begin by setting up init word=LE's and Fquds + PDM state for thisstep pdmcmd = phaarray(thisstep,0)*64 'ver111-39d out port, le1 + fqud1 + le3 + fqud3 + pdmcmd 'present data to buffer input'ver111-39d out control, INIT: out control, contclear 'latch the buffer, moving the signals to the 5 modules'ver113-2a out port, pdmcmd + 32 'remove LEs and Fquds, leaving PDM data, but add a latch signal P2D5 for old PDM if used.'ver111-39d out control, INIT: out control, contclear 'sends latch signal to old PDM'ver113-2a out port, pdmcmd 'remove the added latch signal to PDM, leaving just the PDM's static data'ver111-39d out control, INIT: out control, contclear 'ver113-2a out port, 0 'bring all Data lines low. PDM data remains static return 'to [CommandThisStep] [finished]'this is the end of the software, close any open window if special = 1 then close #special 'close out Special Tests window. ver113-5a if varwindow = 1 then close #varwin 'close out variable window if datawindow = 1 then close #datawin 'close out data window. ver113-5a if calManWindHndl$<>"" then close #calManWindHndl$ 'close window for calibration manager, SEWcal3 ver113-7g if configWindHndl$<>"" then close #configWindHndl$ 'close window for configuration manager, SEWcal3 ver113-7g close #main 'close out working window close #handle 'close out graph window end '------------ ' The following are error messages and are not compiled: '"PLL 1" '"PLL 2" '"PLL 3" ' and: ' "2325 Rcounter is < 3" ' "2325 Rcounter is > 16383" ' "2325 Bcounter < 3" ' "2325 Bcounter > 2047" ' "2325 Bcounter16383" ' "2326 Bcounter <3" ' "2326 Bcounter >8191" ' "2326 Bcounter32767" ' "2350 Bcounter <3" ' "2350 Bcounter >1023" ' "2350 Bcounter 32767" ' "2353 Bcounter is < 3" ' "2353 Bcounter is > 1023" ' "2353 Bcounter < Acounter+2" ' "4112 R counter >16383" ' "4112 N counter <3" ' "4112 N counter >8191" ' "4112 B counter .5 ddsclock" 'ver112-2c '-------------------------------- [SpecialTests]'ver111-36b if haltsweep = 1 then goto [Halted] if special=1 then goto [CloseSpecial] WindowWidth = 200 WindowHeight = 300 UpperLeftX = 380 UpperLeftY = 5 BackgroundColor$ = "darkblue" ForegroundColor$ = "white" TextboxColor$ = "red" 'the following textboxes will be red ver113-7e button #special.DDS1, "Command DDS 1", [CommandDDS1], UL, 5, 5, 100, 20 textbox #special.dds1out, 105, 5, 75, 20 'create DDS 1 frequency output box statictext #special.dds1txt, "with DDS Clock at ", 5, 30, 100, 15 textbox #special.masclkf, 105, 30, 75, 20 'create master clock frequency box button #special.DDS3, "Command DDS 3", [CommandDDS3], UL, 5, 55, 100, 20 'ver111-38a textbox #special.dds3out, 105, 55, 75, 20 'create DDS 1 frequency output box 'delver113-3a button #special.testglitch, "Test Glitchtime var", [TestGlitchtime], UL, 5, 80, 100, 20 'ver111-36c 'delver113-3a textbox #special.glitchbox, 105, 80, 75, 20 'create glitchbox 'ver111-36c button #special.dds3track, "DDS 3 Track", [DDS3Track], UL, 5, 105, 75, 20 'ver111-39d statictext #special.dds3trktxt, "0-32", 80, 107, 25, 15 'ver112-2c button #special.dds1track, "DDS 1 Sweep", [DDS1Sweep], UL, 115, 105, 75, 20 'ver112-2c button #special.pdminv, "Change PDM", [ChangePDM], UL, 5, 130, 90, 20 'ver112-2a if vna = 1 then button #special.insert, "Sync Test PDM", [SyncTestPDM], UL, 5, 155, 90, 20 'ver112-2f if vna = 1 then button #special.prevnalin, "Preset VNA Linearity", [PresetVNAlin], UL, 5, 180, 120, 20 'ver112-2f open "Special Tests Window" for dialog as #special:special = 1 print #special.dds1out, "";DDS1array(thisstep,46) 'insert DDS1 output frequency at thisstep 'ver112-2d print #special.masclkf, "";masterclock 'insert masterclock frequency print #special.dds3out, "";DDS3array(thisstep,46) 'insert DDS3 output frequency at thisstep 'ver112-2d 'delver113-3a print #special.glitchbox, "";glitchtime 'insert last glitchtime into glitchbox 'ver112-2d print #special, "trapclose [CloseSpecial]" 'goto [CloseSpecial] if xit is clicked print #main.special, "Close Special" wait [CloseSpecial]'ver111-36b syncsweep = 0 'ver112-2b setpdm = 0 'makes sure the PDM returns to automatic operation ver112-2a convdatapwr = 0 'ver112-2b vnalintest = 0 'ver112-2f test = 0 'ver112-2g close #special:special = 0 'close out Special Tests window print #main.special, "Special Tests" if returnflag = 1 then return 'ver112-2f wait [OpenDataWindow]'ver113-5a if haltsweep = 1 then goto [Halted] 'ver113-7a 'if the "Array Data Window" is already open, close it. if datawindow = 1 then close #datawin:datawindow = 0 'create window called, Data Window, to display all data for each step WindowWidth = 300 'ver113-5b WindowHeight = 300 UpperLeftX = 180 UpperLeftY = 5 BackgroundColor$ = "white" ForegroundColor$ = "black" open "Data Window" for text as #datawin:datawindow = 1 'delver113-5b print #datawin, "trapclose [CloseDataWindow]" 'goto [CloseDataWindow] if xit is clicked return [CloseDataWindow] close #datawin:datawindow = 0 wait [MagnitudeMSAinput]'ver113-5a gosub [OpenDataWindow] enterthisstep = thisstep print #datawin,"Freq Magnitude (dBm)" for thisstep = 0 to steps print #datawin, datatable(thisstep,1);" "; datatable(thisstep,2) 'Magnitude input to MSA next thisstep thisstep = enterthisstep wait [MagBitsAtoD]'ver113-5a gosub [OpenDataWindow] enterthisstep = thisstep print #datawin,"Freq Mag A/D Bits" for thisstep = 0 to steps print #datawin, datatable(thisstep,1);" "; magarray(thisstep,3) 'Magnitude AtoD, in Bits next thisstep thisstep = enterthisstep wait [MagCalTable]'ver113-5a gosub [OpenDataWindow] enterthisstep = thisstep print #datawin,"Freq Mag Cal Correction" for thisstep = 0 to steps print #datawin, datatable(thisstep,1);" "; calarray(thisstep,2) 'Magnitude, Calibration Table next thisstep thisstep = enterthisstep wait [PhaProcessed]'ver113-5a gosub [OpenDataWindow] enterthisstep = thisstep print #datawin,"Freq Phase (deg)" for thisstep = 0 to steps print #datawin, datatable(thisstep,1);" "; datatable(thisstep,3) 'Phase, processed next thisstep thisstep = enterthisstep wait [PhaBitsAtoD]'ver113-5a gosub [OpenDataWindow] enterthisstep = thisstep print #datawin,"Freq Phase Bits" for thisstep = 0 to steps print #datawin, datatable(thisstep,1);" "; phaarray(thisstep,3) 'Phase A/D. Bits next thisstep thisstep = enterthisstep wait [PhaCalTable]'ver113-5a gosub [OpenDataWindow] enterthisstep = thisstep print #datawin,"Freq Phase Cal Correction" for thisstep = 0 to steps print #datawin, datatable(thisstep,1);" "; calarray(thisstep,2) 'Phase Claibration Table next thisstep thisstep = enterthisstep wait [MagPhaS21]'ver113-5b gosub [OpenDataWindow] xclm$="!" print #datawin,"!insert xclm$ +" print #datawin,"S21 Data for VNA" print #datawin,"!select 1 2" print #datawin,"!insert xclm$ +" print #datawin, "Data taken: ";date$("mm/dd/yyyy");" ";time$() print #datawin,"!select 1 3" print #datawin,"!insert xclm$ +" print #datawin, "Touchstone Format, space delimited" print #datawin, "# MHZ S DB R 50" 'changed MV to DB, ver113-6a print #datawin,"!select 1 5" print #datawin,"!insert xclm$ +" print #datawin, "Freq Mag Ang" enterthisstep = thisstep for thisstep = 0 to steps print #datawin, datatable(thisstep,1);" ";datatable(thisstep,2);" ";datatable(thisstep,3) 'S21 Parameters: Frequency, Magnitude, and Phase Angle next thisstep thisstep = enterthisstep wait [CommandDDS1]'ver111-36b. ver113-4a 'this will recalculate DDS1, using the values in the Command DDS 1 Box, and "with DDS Clock at" Box. 'it will insert the new DDS 1 frequency into the command arrays for all steps, leaving others alone 'it will initiate a re-command at thisstep (where the sweep was halted) 'if Original Control Board is used, only the DDS 1 is re-commanded. ver113-4a 'if SLIM Control Board is used, all 4 modules will be re-commanded. ver113-4a 'using One Step or Continue will retain the new DDS1 frequency. 'PLO1 will be non-functional until [Restart] button is clicked. PLL1 will break lock and "slam" to extreme. '[Restart] will reset arrays and begin sweeping at step 0. Special Tests Window will not be updated. 'Signal Generator or Tracking Generator output will not be effected. 'caution, do not enter a frequency that is higher than 1/2 the masterclock frequency (ddsclock) print #special.dds1out, "!contents? dds1out$"; 'grab contents of Command DDS 1 Box ddsoutput = val(dds1out$) 'intended output frequency of DDS 1 print #special.masclkf, "!contents? msclk$"; 'grab contents of "with DDS Clock at" box msclk = val(msclk$) 'if "with DDS Clock at" box was not changed, this is the real MasterClock frequency ddsclock = msclk 'caution: if ddsoutput >= to .5 ddsclock, the program will error out gosub [CreateBaseForDDSarray]'needed:ddsoutput,ddsclock ; creates: base,sw0thrusw39,w0thruw4 remember = thisstep 'remember where we were when entering this subroutine for thisstep = 0 to steps 'ver112-2a gosub [FillDDS1array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock next thisstep 'ver112-2a thisstep = remember 'ver112-2a gosub [CreateCmdAllArray] 'ver112-2a if cb = 0 then gosub [CommandDDS1OrigCB]'will command DDS 1, only 'delver113-4a if cb = 2 then gosub [CommandDDS1SlimCB]'will command DDS 1, only if cb = 2 then gosub [CommandAllSlims]'will command all 4 modules. ver113-4a wait [CommandDDS3]'ver111-38a 'this will recalculate DDS3, using the values in the Command DDS 3 Box, and "with DDS Clock at" Box. 'it will insert the new DDS 3 frequency into the command arrays for all steps, leaving others alone 'it will initiate a re-command at thisstep (where the sweep was halted) 'only the DDS 3 is re-commanded 'using One Step or Continue will retain the new DDS3 frequency. 'PLO3 will be non-functional until [Restart] button is clicked. PLL3 will break lock and "slam" to extreme. '[Restart] will reset arrays and begin sweeping at step 0. Special Tests Window will not be updated. 'Signal Generator or Tracking Generator output will be non functional. 'Spectrum Analyzer function is not effected 'caution, do not enter a frequency that is higher than 1/2 the masterclock frequency (ddsclock) print #special.dds3out, "!contents? dds3out$"; 'grab contents of Command DDS 3 Box ddsoutput = val(dds3out$) 'intended output frequency of DDS 3 print #special.masclkf, "!contents? msclk$"; 'grab contents of "with DDS Clock at" box msclk = val(msclk$) 'if "with DDS Clock at" box was not changed, this is the real MasterClock frequency ddsclock = msclk 'caution: if ddsoutput >= to .5 ddsclock, the program will error out gosub [CreateBaseForDDSarray]'needed:ddsoutput,ddsclock ; creates: base,sw0thrusw39,w0thruw4 remember = thisstep 'remember where we were when entering this subroutine for thisstep = 0 to steps gosub [FillDDS3array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock next thisstep thisstep = remember gosub [CreateCmdAllArray] if cb = 0 then gosub [CommandDDS3OrigCB]'will command DDS 3, only 'delver113-4a if cb = 2 then gosub [CommandDDS3SlimCB]'will command DDS 3, only if cb = 2 then gosub [CommandAllSlims]'will command all 4 modules. ver113-4a wait [DDS3Track]'ver111-39d 'This uses DDS3 as a Tracking Generator, but is limited to 0 to 32 MHz, when MasterClock is 64 MHz 'DDS3 spare output is rich in harmonics and aliases. 'Tracks the values in Working Window, Center Frequency and Sweep Width (already in the command arrays) 'The Spectrum Analyzer function is not effected. 'PLO3, Normal Tracking Generator, and Phase portion of VNA will be non-functional 'Operation: 'In Working Window, enter Center Frequency to be within 0 to 32 (MHz), or less than 1/2 the MasterClock 'In Working Window, enter Sweep Width (in MHz). But, do not allow sweep to go below 0 or abov 1/2 MasterClock 'Click [Restart], then halt. 'In Special Tests Window, click [DDS 3 Track]. DDS 3 will, immediately, re-command to new frequency. 'Click [Continue]. Sweep will resume, but with DDS 3 tracking the Spectrum Analalyzer '[One Step] and [Continue] and halting operates normally until [Restart] button is pressed. '[Restart] will reset arrays, and leave the DDS 3 Track Mode. ie, normal sweeping. ddsclock = masterclock remember = thisstep for thisstep = 0 to steps ddsoutput = datatable(thisstep,1) 'caution: if ddsoutput >= to .5 ddsclock, the program will error out gosub [CreateBaseForDDSarray]'needed:ddsoutput,ddsclock ; creates: base,sw0thrusw39,w0thruw4 gosub [FillDDS3array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock next thisstep thisstep = remember gosub [CreateCmdAllArray] if cb = 0 then gosub [CommandDDS3OrigCB]'will command DDS 3, only 'delver113-4a if cb = 2 then gosub [CommandDDS3SlimCB]'will command DDS 3, only if cb = 2 then gosub [CommandAllSlims]'will command all 4 modules. ver113-4a wait [DDS1Sweep]'ver112-2c 'This forces the DDS 1 to the values in Working Window: Center Frequency and Sweep Width (already in the command arrays) 'DDS1 spare output is rich in harmonics and aliases. 'PLO1, and thus, the Spectrum Analyzer will be non-functional in this mode. 'Signal Generator or Tracking Generator output will not be effected. 'Operation: 'In Working Window, enter Center Frequency to be within 0 to 32 (MHz), or less than 1/2 the MasterClock 'In Working Window, enter Sweep Width (in MHz). But, do not allow sweep to go below 0 or abov 1/2 MasterClock 'Click [Restart], then halt. 'In Special Tests Window, click [DDS 1 Sweep]. DDS 1 will, immediately, re-command to new frequency. 'Click [Continue]. Sweep will resume, but with DDS 1 sweeping. '[One Step] and [Continue] and halting operates normally until [Restart] button is pressed. '[Restart] will reset arrays, and will leave the DDS 1 Sweep Mode. ie, normal sweeping. ddsclock = masterclock remember = thisstep for thisstep = 0 to steps ddsoutput = datatable(thisstep,1) 'caution: if ddsoutput >= to .5 ddsclock, the program will error out gosub [CreateBaseForDDSarray]'needed:ddsoutput,ddsclock ; creates: base,sw0thrusw39,w0thruw4 gosub [FillDDS1array]'need thisstep,sw0-sw39,w0-w4,base,ddsclock next thisstep thisstep = remember gosub [CreateCmdAllArray] if cb = 0 then gosub [CommandDDS1OrigCB]'will command DDS 1, only 'delver113-4a if cb = 2 then gosub [CommandDDS1SlimCB]'will command DDS 1, only if cb = 2 then gosub [CommandAllSlims]'will command all 4 modules. ver113-4a wait 'delver113-3a [TestGlitchtime]'this subroutine is deleted for ver113 [ChangePDM]'ver112-2a 'enters from Special Tests Window Button setpdm = setpdm + 1 if setpdm > 2 then setpdm = 0 if setpdm = 0 then print #special.pdminv, "PDM is Auto" if setpdm = 1 then print #special.pdminv, "PDM in Normal":gosub [PdmNorm] if setpdm = 2 then print #special.pdminv, "PDM in Inverted":gosub [PdmInv] wait [PdmNorm]'this commands the pdm to Normal, for all steps rememberthisstep = thisstep for thisstep = 0 to steps phaarray(thisstep,0) = 0 next thisstep thisstep = rememberthisstep gosub [CommandPDMonly] return [PdmInv]'this commands the pdm to Invert, for all steps rememberthisstep = thisstep for thisstep = 0 to steps phaarray(thisstep,0) = 1 next thisstep thisstep = rememberthisstep gosub [CommandPDMonly] return [SyncTestPDM] 'ver112-2b 'enters from Special Tests Window Button, only if in VNA Mode 'this will set up defaults and begin sweeping to measure phase steps 'when CF=0 and SW=0, the PDM will measure "rolling" phase of two different frequencies, 'although the difference is less than 1 Hz.PDM is fixed at Norm(0) syncsweep = 1 'ver112-2b convdatapwr = 1 'ver112-2b print #main.centerfreqbox, 0 'default center freq print #main.sweepwidthbox, 0 'default sweep width print #main.marker1box, "";steps + 3 'insert marker1 default in Marker1 box print #main.marker2box, "";steps + 3 'insert marker2 default in Marker2 box print #main.marker3box, "";steps + 3 'insert marker3 default in Marker3 box print #main.waitbox, 3 'insert wate default, or last "wate" into wait box print #main.toprefbox, 5 'insert default top reference line print #main.botrefbox, -5 'insert default bottom reference line print #main.phasetopbox,360 print #main.phasebotbox,0 setpdm = 1 : print #special.pdminv, "PDM in Normal":gosub [PdmNorm] goto [Restart] wait [SyncSweep]'comes here at end of sweep if syncsweep = 1 'ver112-2b 'it will not continue sweeping until the phase data is between 80 and 90% of maxpdmout 'hopefully, it will "trigger" a sweep at 81% gosub [ReadPhase] scan 'this is a fail safe. Click any button to get out of this loop. ver113-6e if phadata > .8*maxpdmout and phadata < .9*maxpdmout then return goto [SyncSweep] [ConvertDataToPower] 'ver112-2b 'this routine is a traffic director when the blue Magnitude trace is used for other data. 'enters from [CalcMagpowerPixel] if convdatapwr = 1 if syncsweep = 1 then goto [ConvertSync] goto [ConvertPDMlin] [ConvertSync] 'ver112-2b 'this will take the phase difference of the previous step's and this step's phase 'and convert it to power, for display 'enters from [ConvertDataToPower] if syncsweep = 1 if thisstep = 0 then return 'the last step in the sweep - step 0 is bogus data 'grab raw phase bits from previous sweep and create deltabits deltabits = phaarray(thisstep-1,3) - phaarray(thisstep,3) 'convert deltabits to delta phase deltaphase = 360 * deltabits/maxpdmout power = deltaphase return [PresetVNAlin] 'ver112-2b print #special.prevnalin, "Test VNA Linearity" 'change the button name if vnalintest = 1 then goto [VNAlinTest] vnalintest = 1 redim calarray(800,2) 'clear out the calibration array to zeros print #main.centerfreqbox, 500 'default center freq. in MHz print #main.sweepwidthbox, 1000 'default sweep width. in MHz print #main.waitbox, 22 'insert wate default into wait box print #main.phasetopbox,180 print #main.phasebotbox,-180 'afix the PDM to "Normal" (0). It will remain fixed as long as the Special Tests Window is open. setpdm = 1 : print #special.pdminv, "PDM in Normal":gosub [PdmNorm] 'set up magnitude limits, prolly +/- 5 degrees(db) print #main.toprefbox, 5 'insert default top reference line. This is now "degrees" print #main.botrefbox, -5 'insert default bottom reference line. This is now "degrees" goto [Restart] 'the sweep will begin, and display several sawtooths, the number depending on the length 'of the cable between the TG output and the MSA input. 'There will be extreme glitches near the center of each sawtooth, indicating the 'zero degree crossovers. This is due to the PDM being fixed at "Normal" [VNAlinTest]'for testing PDM Linearity 'ver112-2b 'make sure pdm is fixed at norm or invert before entering. Accomplished by previously clicking [PresetVNAlin] Button. 'before entering this routine, make sure the sweep is displaying one full segment that ' is greater than 360 degrees and less than 720 degrees. 'before entering this routine, pick a step point to be the zero phase error refpoint. It has: 'step #, frequency, and phase. It must be within the 0 degree crossover boundries. 'we use it as a reference zero degrees error. Use the Mouse's left click to select the step. 'then, click the Special Tests Window [Test VNA Linearity] Button. 'a very long line, between TG out and MSA in, will reduce the error created by Mixer 4, AM to PM conversion convdatapwr = 1 'used in [CalcMagpowerPixel] to skip processing Mag Data 'determine the "real" slope factor for this band segment, in degrees per MHz 'retrieve raw phase data bits. Bits0, Bits400 'ver112-2g phabits0 = phaarray(0,3) 'ver112-2g phabits400 = phaarray(steps,3) 'ver112-2g 'if phabits0 is less than or equal to phabits400, add 360 degrees(in bits) to phabits0 'ver112-2g 'maxpdmout is the bit value of 360 degrees, for any AtoD Module if phabits0 <= phabits400 then phabits0 = phabits0 + maxpdmout 'ver112-2g 'add maxpdmout (65535 bits) to phabits0 and take difference 'ver112-2g 'delta bits = maxpdmout + phabits0 - phabits400 'ver112-2g 'change to phase: 360 * (delta bits/maxpdmout) 'ver112-2g delpha = 360*((maxpdmout + phabits0 - phabits400)/maxpdmout) 'ver112-2g 'freq at step 0 - freq at last step = delta freq (551.8 - 829 = -277.2) delfreq = datatable(0,1) - datatable(steps,1) 'SEWgraph The following line avoids a crash with zero span if delfreq=0 then notice "Sweep must be preset to show 360-720 degrees." :wait 'SEWgraph 'realslopefactor (in deg per MHz) = delta phase / delta freq = (393.7 / -277.2) = -1.42 d/m realslopefactor = delpha/delfreq '(in -degrees/MHz) refstep = leftstep 'the processed phase for refstep is in datatable(refstep,3),always for previous sweep refstepphase = datatable(refstep,3) 'the frequency of refstep is in datatable(refstep,1),always for previous sweep refstepfreq = datatable(refstep,1) 'print the slope factor in the Message Box next time sweep is halted test=realslopefactor 'this will be cleared when leaving Spec Test Window. ver112-2g goto [Restart] [ConvertPDMlin] 'ver112-2b 'enters here from [CalcMagpowerPixel]. We are processing the previous step but it 'is still called "thisstep" 'the blue line will show how far off the real slope is from a theoritical slope, in degrees 'the processed phase for thisstep is in datatable(thisstep,3) 'the frequency of thisstep is in datatable(thisstep,1) 'this step will have a theoritical phase equal to: ' theoryphase = thisstep freq - refstep freq times realslopefactor + refstep phase theoryphase = ((datatable(thisstep,1)- refstepfreq) * realslopefactor) + refstepphase 'in wide band sweeps, theoryphase can get greater than 360 degrees 'ver112-2g 'therefore, change theoryphase to decimal number compared to 360 degrees 'ver112-2g theoryphase = theoryphase/360 'example theoryphase = 1.324 or -1.226 'ver112-2g 'cast out whole number and use decimal equivalent 'ver112-2g theoryphase = theoryphase - int(theoryphase) 'theoryphase = .324 or -.226 'ver112-2g 'reconvert back to phase 'ver112-2g theoryphase = 360*theoryphase 'ver112-2g if theoryphase < -180 then theoryphase = theoryphase + 360 if theoryphase > 180 then theoryphase = theoryphase - 360 'at this line, I could make power = theoryphase and display blue over red error 'the error will be equal to: phaseerror = thisstep phase - theoryphase phaseerror = datatable(thisstep,3) - theoryphase if phaseerror < -180 then phaseerror = phaseerror + 360 if phaseerror > 180 then phaseerror = phaseerror - 360 'using the blue magpower line as phase error, the processed magpower becomes phaseerror power = phaseerror return '--SEW Added the following routines to save/copy the graph image 'These routines are invoked through the File and Edit menus 'Scotty: I created additional variables here, all of which begin with captial X 'to avoid any conflicts with your variables. '=====================Start Routines to Save/Copy Image=========================== [SaveImage] 'Get Image size by finding center positions and doubling them #handle "home" #handle "posxy CenterX CenterY" clientWidth = CenterX * 2-1 clientHeight = CenterY * 2-1 print #handle, "getbmp graphbmp 0 0 ";clientWidth;" ";clientHeight filedialog "Save As...", "*.bmp", graphFileName$ 'will have buttons that say SAVE and CANCEL if graphFileName$<>"" then open graphFileName$ for output as #outFile bmpsave "graphbmp", graphFileName$ close #outFile end if unloadbmp "graphbmp" wait [CopyImage] 'Get Image size by finding center positions and doubling them #handle "home" #handle "posxy CenterX CenterY" clientWidth = CenterX * 2-1 clientHeight = CenterY * 2-1 print #handle, "getbmp graphbmp 0 0 ";clientWidth;" ";clientHeight hBitmap=hbmp("graphbmp")'get bmp handle 'open clipboard: calldll #user32, "OpenClipboard",h as long, result as long calldll #user32, "EmptyClipboard", ret as long 'put bmp data on clipboard: calldll #user32, "SetClipboardData",_CF_BITMAP as long,_ hBitmap as long, rethandle as long calldll #user32, "CloseClipboard", r as boolean unloadbmp "graphbmp" wait '@==================End of Save/Copy Image================ '--SEW End additions for save/copy image '--SEW Deleted [CalTablePath1],[CalTablePath2],[CalTablePath3],[CalTablePath4],[CalTableFreqError] '--SEW That initialization is now handled in the mag/freq calibration module. 'SEW2--Replaced everything below: Configuration, Calibration and Utilities Modules '--SEW Added the following Configuration Module to use a configuration file ' '=================================================================== '@===============Configuration Manager Module======================= '=================================================================== 'Configuration Manager Version 1.03, as of 2-28-09 'This module combines the user interface of the Configuration Manager and the 'underlying routines, which previously were a separate module. 'All the user needs to do is call configRunManager. The window will be opened and 'the existing config.txt file will be read. If that file or its folder, MSA_Info, 'does not exist, they will be created, using default values for the file. 'The user enters configuration data in the window. When the user reads or saves the 'file, the data is also loaded into the MSA variables, so upon completion those 'variables will reflect the state of the configuration file. If the user closes the 'window without saving the file, the data will reflect the state of the window, 'but the existing file will not be up to date. ' 'All variables, functions and subroutines in this module begin with the prefix "config". 'The only other variables affected are the MSA variables being configured. Those can 'be seen in configReadFile$(). global configDisplayHasTG 'configDisplayedFilters$ is a list of final filters displayed in the Manager window. 'zero entry of first dimension is used. Limit is 38, but more than 10 is highly unlikely. dim configDisplayedFilters$(40) global configNumDisplayedFilters 'Number of filters in configDisplayedFilters$ 'delver113.7g global configWindHndl$ 'Handle to our main window SEWcal3 moved to beginning 'The following arrays are to initialize listboxes or comboboxes dim configPLLtypes$(5) dim configPLLpol$(1) dim configPLLmodes$(1) dim configParsers$(1) dim configADCs$(3) dim configTGtops$(2) dim configControlBoards$(2) 'The following two lines are used to run the Configuration Manager 'as a stand-alone program. Within the MSA software an equivalent call will be 'made upon startup 'call configRunManager 0 'end '------------------Begining of Routines-------------------- '@configRunManager function configRunManager(autoRun) 'Run the Configuration Manager 'returns 1 if changes were cancelled; otherwise 0 'This subroutine creates the interface window and is in control for the entire 'period during which the window is open, though other functions and subroutines 'are called from here. 'autoRun=1 if we were called automatically on startup due to the absence 'of the config.txt file. It determines how we display save/return buttons. WindowWidth = 750 WindowHeight = 500 UpperLeftX = 5 UpperLeftY = 5 BackgroundColor$ = "lightgray" ForegroundColor$ = "black" TextboxColor$ = "white" ComboboxColor$="white" statictext #config.Title, "ENTER CONFIGURATION DATA FOR YOUR MSA", 200,1,400,20 configPLLtop=60: configPLLleft=30 staticText #config.PLL1label, "PLL1",configPLLleft+20, configPLLtop-35,50,20 staticText #config.PLL2label, "PLL2",configPLLleft+120, configPLLtop-35,50,20 staticText #config.PLL3label, "PLL3",configPLLleft+220, configPLLtop-35,50,20 staticText #config.PLLtypes, "--------------------Type-------------------------------",PLLleft+60, configPLLtop-20,200,20 configPLLtypes$(0)="0" : configPLLtypes$(1)="2325": configPLLtypes$(2)="2326" configPLLtypes$(3)="2350":configPLLtypes$(4)="2353":configPLLtypes$(5)="4112" comboBox #config.PLL1type,configPLLtypes$(),[configNil],configPLLleft,configPLLtop,70,120 comboBox #config.PLL2type,configPLLtypes$(),[configNil],configPLLleft+100,configPLLtop,70,120 comboBox #config.PLL3type,configPLLtypes$(),[configSelPLL3],configPLLleft+200,configPLLtop,70,120 staticText #config.PLLpols, "--------------------Polarity----------------------------",PLLleft+60, configPLLtop+35,200,20 configPLLpol$(0)="0(non-inv)":configPLLpol$(1)="1(invert)" comboBox #config.PLL1pol,configPLLpol$(),[configNil],configPLLleft,configPLLtop+55,70,120 comboBox #config.PLL2pol,configPLLpol$(),[configNil],configPLLleft+100,configPLLtop+55,70,120 comboBox #config.PLL3pol,configPLLpol$(),[configNil],configPLLleft+200,configPLLtop+55,70,120 staticText #config.PLLrefs, "---------------Reference (MHz)------------------",PLLleft+60, configPLLtop+85,200,20 textBox #config.PLL1Ref,configPLLleft,configPLLtop+105,70,20 textBox #config.PLL2Ref,configPLLleft+100,configPLLtop+105,70,20 textBox #config.PLL3Ref,configPLLleft+200,configPLLtop+105,70,20 staticText #config.PLLmodes, "--------------------Mode-------------------------------",PLLleft+60, configPLLtop+135,200,20 configPLLmodes$(0)="0(Integer)" : configPLLmodes$(1)="1(Fract)" comboBox #config.PLL1mode,configPLLmodes$(),[configNil],configPLLleft,configPLLtop+155,70,120 comboBox #config.PLL3mode,configPLLmodes$(),[configNil],configPLLleft+200,configPLLtop+155,70,120 'DDS configDDStop=configPLLtop+250 :configDDSleft=configPLLleft staticText #config.DDS1label, "DDS1",configDDSleft+20, configDDStop-40,50,20 staticText #config.DDS3label, "DDS3",configDDSleft+220, configDDStop-40,50,20 staticText #config.DDScenters, "--------------Center Freq (MHz)------------------",configDDSleft+60, configDDStop-20,200,20 TextboxColor$ = "cyan" textBox #config.DDS1freq,configDDSleft,configDDStop,70,20 textBox #config.DDS3freq,configDDSleft+200,configDDStop,70,20 staticText #config.DDSbws, "---------------Bandwidth (MHz)------------------",configDDSleft+60, configDDStop+30,200,20 textBox #config.DDS1bw,configDDSleft,configDDStop+50,70,20 textBox #config.DDS3bw,configDDSleft+200,configDDStop+50,70,20 TextboxColor$ = "white" configParsers$(0)="0(parallel)" : configParsers$(1)="1(serial)" comboBox #config.DDS1parse,configParsers$(),[configNil],configDDSleft,configDDStop+100,70,60 staticText #config.DDS1parseLabel, "DDS1 Parser",configDDSleft, configDDStop+85,90,15 staticText #config.LO2Label, "LO2 (MHz)",configDDSleft+105, configDDStop+85,70,15 staticText #config.mastLabel, "Mast Clock (MHz)",configDDSleft+190, configDDStop+85,90,15 textBox #config.LO2,configDDSleft+100,configDDStop+100,70,22 TextboxColor$ = "cyan" textBox #config.mast,configDDSleft+200,configDDStop+100,70,22 'Defaults changeable at runtime configSweepLeft=340: configSweepTop=40 staticText #config.t1,"Sweep Center(MHz)",configSweepLeft,configSweepTop-3,65,30 staticText #config.t2,"Sweep Width(MHz)",configSweepLeft,configSweepTop+27,65,30 staticText #config.t3,"Top Ref",configSweepLeft,configSweepTop+63,65,20 staticText #config.t4,"Bottom Ref",configSweepLeft,configSweepTop+93,65,20 TextboxColor$ = "yellow" textBox #config.cent,configSweepLeft+65,configSweepTop,70,20 textBox #config.width,configSweepLeft+65,configSweepTop+30,70,20 textBox #config.top,configSweepLeft+65,configSweepTop+60,70,20 textBox #config.bot,configSweepLeft+65,configSweepTop+90,70,20 configMiscLeft=340: configMiscTop=configSweepTop+140 staticText #config.x1,"Wait (ms)",configMiscLeft,configMiscTop+2,65,20 staticText #config.x2,"GlitchTime",configMiscLeft,configMiscTop+32,65,20 staticText #config.SGLabel,"Sig Gen Preset",configMiscLeft,configMiscTop+57,65,30 staticText #config.TGOffLabel,"Track Gen Offset",configMiscLeft,configMiscTop+87,65,30 staticText #config.PDMLabel,"Max PDM out",configMiscLeft-5,configMiscTop+122,68,20 staticText #config.InvDegLabel,"Inv Deg",configMiscLeft,configMiscTop+152,65,20 textBox #config.wate,configMiscLeft+65,configMiscTop,70,20 textBox #config.glitch,configMiscLeft+65,configMiscTop+30,70,20 textBox #config.SG,configMiscLeft+65,configMiscTop+60,70,20 textBox #config.TGoff,configMiscLeft+65,configMiscTop+90,70,20 TextboxColor$ = "white" textBox #config.PDM,configMiscLeft+65,configMiscTop+120,70,20 TextboxColor$ = "cyan" textBox #config.Inv,configMiscLeft+65,configMiscTop+150,70,20 'ADC TextboxColor$ = "white" configADCs$(0)="8(orig 8-bit)" : configADCs$(1)="12(ladder)" : configADCs$(2)="16(serial 16-bit)" configADCs$(3)="22(serial 12-bit)" staticText #config.y1,"ADC type",configMiscLeft,configMiscTop+202,65,20 comboBox #config.adconv,configADCs$(),[configSelADconv],configMiscLeft+65,configMiscTop+200,110,120 'TG topology configTGtops$(0)="0(None)" : configTGtops$(1)="1(orig)" : configTGtops$(2)="2(DDS3/PLL3)" staticText #config.TGTopLabel,"TG Topology",configMiscLeft-2,configMiscTop+232,65,20 comboBox #config.TGtop,configTGtops$(),[configSelTGtop],configMiscLeft+65,configMiscTop+230,110,120 'Control Board configControlBoards$(0)="0(Old)" : configControlBoards$(1)="1(Old, new harness)" : configControlBoards$(2)="2(SLIM original)" staticText #config.y3,"Control Board",configMiscLeft-2,configMiscTop+262,65,20 comboBox #config.cb,configControlBoards$(),[configNil],configMiscLeft+65,configMiscTop+260,110,120 'Buttons to load, save, help, change TG and VNA configButtonTop=40 : configButtonLeft=550 button #config.SLIMDefault "Set to SLIM Defaults",[configDoDefaults],UL,configButtonLeft-50,configButtonTop,110,25 button #config.TG "Delete TG",[configDoTG],UL,configButtonLeft-50,configButtonTop+30,110,25 button #config.VNA "Delete VNA", [configDoVNA],UL,configButtonLeft-50,configButtonTop+60,110,25 button #config.test "Re-Load File",[configDoLoad],UL,configButtonLeft+70,configButtonTop,110,25 'delver113-7c button #config.save "Save File", [configBtnSave],UL,configButtonLeft+70,configButtonTop+30,110,25 button #config.help "Help", [configDoHelp],UL,configButtonLeft+70,configButtonTop+60,110,25 button #config.saveReturn "Save Configuration", [configSaveAndReturn],UL,configButtonLeft-15,configButtonTop+90,170,35 button #config.noSaveReturn "Return to MSA Without Saving", [configNoSave],UL,configButtonLeft-15,configButtonTop+130,170,35 'Final Filters configFiltTop=configButtonTop+218 : configFiltLeft=configButtonLeft TextboxColor$ = "cyan" ListboxColor$="cyan" staticText #config.filtInstruct "List your final filters: frequency bandwidth",configFiltLeft-7,configFiltTop-35,130,35 'ver113-7c listBox #config.filt,configDisplayedFilters$(),configFilterSelected,configFiltLeft-10,configFiltTop,140,50 staticText #config "Freq(MHz) BW(KHz)",configFiltLeft-5,configFiltTop+50,130,15 textBox #config.filtFreq configFiltLeft-5,configFiltTop+65,50,20 textBox #config.filtBW configFiltLeft+55,configFiltTop+65,50,20 button #config.AddFiltPrior "AddPrior", configDoFilt,UL,configFiltLeft,configFiltTop+89,50,20 button #config.AddFiltAfter "AddAfter", configDoFilt,UL,configFiltLeft+51,configFiltTop+89,50,20 button #config.DeleteFilt "Delete", configDoFilt,UL,configFiltLeft,configFiltTop+110,50,20 button #config.ReplaceFilt "Replace", configDoFilt,UL,configFiltLeft+51,configFiltTop+110,50,20 'Port Address ComboboxColor$="cyan" statictext #config.LPTinstruct "LPT Port Address",configButtonLeft+3,configMiscTop+215,130,15 configLPTs$(0)="Hex 378" : configLPTs$(1)="Hex 175" combobox #config.LPT,configLPTs$(),[configNil],configButtonLeft,configMiscTop+230,100,100 button #config.LPThelp "How do I find out?", [configDoLPTHelp],UL,configButtonLeft,configMiscTop+255,100,20 'Open window call configInitFirstUse 'Call before opening window so configVersion is correct open "MSA/VNA Configuration Manager Version "; using("##.##",configVersion()) for Dialog_modal as #config print #config, "trapclose [configClosed]" configWindHndl$="#config" #config.PLL1label "!font arial 12 bold" #config.PLL2label "!font arial 12 bold" #config.PLL3label "!font arial 12 bold" #config.DDS1label "!font arial 12 bold" #config.DDS3label "!font arial 12 bold" #config.filtInstruct "!font 9" #config.filt "font courier_new 9" #config.Title, "!font arial 12 bold" #config.PLL1type,"select 2326" #config.PLL1type,"select 2325" #config.LPT, "select Hex 378" #config.filt, "singleclickselect" if autoRun=1 then #config.noSaveReturn, "!hide" configHelpHandle$="" configLPThelpHandle$="" configNumDisplayedFilters=0 call configCreateLoadFile 'Load file data. Creates one if necessary call configDisplayData wait 'wait for user action [configNoSave] 'Return without save button clicked 'This button is displayed only when we are invoked by the user, 'not automatically on startup if configHelpHandle$<>"" then close #configHelpHandle$ if configLPThelpHandle$<>"" then close #configLPThelpHandle$ 'We need to reload the data from the file to make it active call configCreateLoadFile close #config : configWindHndl$="" configRunManager=1 'signal cancellation exit function 'exits configRunManager and returns to MSA [configClosed] 'Close box clicked wait 'Don't allow closing via the close box [configSaveAndReturn] 'Save Config button clicked if configHelpHandle$<>"" then close #configHelpHandle$ if configLPThelpHandle$<>"" then close #configLPThelpHandle$ 'We want to leave with all variables and the file updated call configGetDisplayData errStr$=configDataError$() if errStr$<>"" then notice "File Error: "+errStr$+ " File not saved." wait 'Cancel the return to MSA due to error; wait for user action end if if autoRun=0 then 'We were invoked by the user, so allow cancellation msg$="You are about to change the MSA configuration file." _ + chr$(13) + "MSA will close. The changed file will be loaded" _ + chr$(13) + "the next time you run the MSA." ans$=uPrompt$("Notice", msg$,0,1) 'Post message with OK and cancel if ans$="cancel" then wait end if call configSaveFile close #config : configWindHndl$="" configRunManager=0 'signal no cancellation exit function 'exits configRunManager and returns to MSA [configDoLoad] 'Read existing file errStr$=configLoadData$() 'SEW5--somehow got deleted in original if errStr$<>"" then notice "File Error: "+errStr$ else if TGtop=0 then configDisplayHasTG=0 else configDisplayHasTG=1 end if call configAdjustDisplayedItems call configDisplayData end if wait [configDoDefaults] 'Defaults for standard SLIM build call configAdjustDisplayedItems call configInitializeDefaults call configDisplayData wait [configDoTG] 'Add or delete TG 'Restore defaults even if we are hiding them, because 'we may end up saving the file call configGetDisplayData errStr$=configDataError$() if errStr$<>"" then notice errStr$ : wait call configInitializeTGDefaults call configInitializeVNADefaults if configDisplayHasTG=1 then 'Reverse state of configDisplayHasTG configDisplayHasTG=0: hasVNA=0 else configDisplayHasTG=1 end if if configDisplayHasTG=0 then TGtop=0:PLL3=0 'Indicate no TG and no PLL3 call configDisplayTGData call configDisplayVNAData call configAdjustDisplayedItems wait [configDoVNA] 'Add or delete VNA 'Restore defaults even if we are hiding them, because 'we may end up saving the file call configGetDisplayData errStr$=configDataError$() if errStr$<>"" then notice errStr$ : wait hadVNA=hasVNA call configInitializeVNADefaults if hadVNA=1 then 'Reverse state of hasVNA hasVNA=0 'turn VNA off else if configDisplayHasTG=0 then call configInitializeTGDefaults 'add default TG hasVNA=1: configDisplayHasTG=1 end if if configDisplayHasTG=0 then TGtop=0:PLL3=0 'Indicate no TG and no PLL3 call configDisplayTGData call configDisplayVNAData call configAdjustDisplayedItems wait [configDoHelp] if configHelpHandle$<>"" then close #configHelpHandle$ 'don't want two helpTop=10 : helpLeft=15 statictext #help.L1,"Enter configuration data for your machine.", helpLeft+40, helpTop, 350,20 statictext #help.L2,"With a standard SLIM build, the items in WHITE likely need no change.", helpLeft, helpTop+25, 350,15 statictext #help.L3,"YELLOW items are default values that can be changed at runtime.", helpLeft, helpTop+45, 350,15 statictext #help.L4,"CYAN items generally must be customized.", helpLeft, helpTop+65, 350,15 button #help.OK, "OK", [configHelpClosed], UL, 350, 120, 50,25 configHelpHandle$="#help" BackgroundColor$="white" WindowHeight=200: WindowWidth=450 UpperLeftX=200 : UpperLeftY=200 open "Configuration Assistance" for window_nf as #help #help.L1, "!font Arial 10 bold" #help, "trapclose [configHelpClosed]" wait [configHelpClosed] close #configHelpHandle$ configHelpHandle$="" wait [configDoLPTHelp] if configLPThelpHandle$<>"" then close #configLPThelpHandle$ 'don't want two helpTop=10 : helpLeft=15 statictext #LPThelp.L1,"The LPT port address is needed to access the parallel port.", helpLeft, helpTop, 550,20 statictext #LPThelp.L2,"This information is maintained for each port by the Device Manager.", helpLeft, helpTop+20, 550,20 statictext #LPThelp.L3,"You can locate the Device Manager through a series of selections similar", helpLeft, helpTop+40, 550,20 statictext #LPThelp.L4,"to Start/Settings/Control Panel/System/Device Manager. From there make", helpLeft, helpTop+60, 550,20 statictext #LPThelp.L5,"selections similar to Ports/Printer Port(LPT1)/Properties/Resources.", helpLeft, helpTop+80, 550,20 statictext #LPThelp.L6,"Look for the item Input/Output Range, which will display a range of numbers", helpLeft, helpTop+100, 550,20 statictext #LPThelp.L7,"in hexidecimal. The first number in that range is the port address you need.", helpLeft, helpTop+120, 550,20 statictext #LPThelp.L8,"Enter the number as it is in hexidecimal; do not convert to base 10.", helpLeft, helpTop+140, 550,20 statictext #LPThelp.L9,"If you have multiple parallel ports, you will have to determine which to use.", helpLeft, helpTop+160, 550,20 button #LPThelp.OK, "OK", [configLPTHelpClosed], UL, 350, 190, 50,25 configLPThelpHandle$="#LPThelp" BackgroundColor$="white" WindowHeight=250: WindowWidth=470 UpperLeftX=200 : UpperLeftY=200 open "Finding LPT information" for window_nf as #LPThelp #LPThelp, "trapclose [configLPTHelpClosed]" #LPThelp.L1, "!font 9" : #LPThelp.L2, "!font 9" #LPThelp.L3, "!font 9" : #LPThelp.L4, "!font 9" #LPThelp.L5, "!font 9" : #LPThelp.L6, "!font 9" #LPThelp.L7, "!font 9" : #LPThelp.L8, "!font 9" #LPThelp.L9, "!font 9" wait [configLPTHelpClosed] close #configLPThelpHandle$ configLPThelpHandle$="" wait [configNil] wait [configSelPLL3] #config.PLL3type, "selection? i" if i=0 then goto [configDoTG] 'no PLL3; turn off TG wait [configSelADconv] 'Select ADC and automatically change maxPDMout to match #config.adconv "selectionindex? i" select case i case 1 '8 bit maxP=2^8-1 case 2 '12 bit maxP=2^12-1 case 3 '16 bit maxP=2^16-1 case else '12 bit maxP=2^12-1 end select print #config.PDM, maxP 'change displayed value, not maxPDMout itself wait [configSelTGtop] 'TGtop changed. If changed to "no TG" then we want to delete 'all the TG items. Note it can't be changed from "no TG" to something 'else, because the combobox would be hidden. #config.TGtop "selectionindex? i" if i=1 then goto [configDoTG] 'Changed to TGtop=0, so we delete TG if i=2 then appxdds3=0 else appxdds3=10.7 '2=orig TG which has no DDS3 wait end function 'End of configRunManager sub configCloseWindows 'Close any windows that are open if configLPThelpHandle$<>"" then close #configLPThelpHandle$ : configLPThelpHandle$="" if configHelpHandle$<>"" then close #configHelpHandle$ : configHelpHandle$="" if configWindHndl$<>"" then close #configWindHndl$ : configWindHndl$="" end sub '@configDoFilt sub configDoFilt btn$ 'Add, delete or replace filter in list #config.filt "selectionIndex? ind" 'Note that the box index runs from 1..., but the array it is loaded from, 'configDisplayedFilters$() runs from zero. So the Nth index of the array ends up in 'the (N+1)th index of the box. if btn$="#config.DeleteFilt" then 'Delete selected filter if ind=0 then exit sub 'no selection for i=ind to configNumDisplayedFilters configDisplayedFilters$(i-1)=configDisplayedFilters$(i) 'shift filters down one position next i configDisplayedFilters$(configNumDisplayedFilters-1)="" configNumDisplayedFilters=max(0,configNumDisplayedFilters-1) #config.filt "reload" call configFilterSelected "" exit sub end if if btn$="#config.ReplaceFilt" then 'Replace selected filter if ind=0 then exit sub 'No selection addPos=ind-1 'Mark to add at current spot in configDisplayedFilters$() else 'Here we have to add a filter if configNumDisplayedFilters>=39 then notice "Too many filters." : exit sub if ind=0 then addPos=configNumDisplayedFilters 'No selection; add to end else if btn$="#config.AddFiltAfter" then addPos=ind else addPos=ind-1 if addPos<0 then addPos=0 for i=configNumDisplayedFilters-1 to addPos step -1 'shift filters up one configDisplayedFilters$(i+1)=configDisplayedFilters$(i) next i end if configNumDisplayedFilters=configNumDisplayedFilters+1 end if 'Here we need to put the filter into into entry number addPos #config.filtFreq, "!contents? freq$" #config.filtBW, "!contents? bw$" freq=val(freq$) : bw=val(bw$) 'Make sure values aren't crazy if freq<5 or freq>15 or bw<.01 or bw>5000 then notice "Invalid Values" : exit sub s$=configFormatFilter$(freq, bw) 'Assemble freq and bw configDisplayedFilters$(addPos)=s$ #config.filt "reload" call configFilterSelected "" end sub '@configFormatFilter$ function configFormatFilter$(freq, bw) 'Assemble filter freq and bw into a string for the list freq$=str$(freq) freq$=freq$+Space$(max(0,7-len(freq$))) 'makes freq$ a fixed width if bw=0 then bwPad$=" " else _ bwPad$=Space$(5-int(Log(bw)/Log(10))) 'Aligns bw at decimal; bw$=bwPad$+str$(bw) configFormatFilter$=freq$+bw$ end function '@configFilterSelected sub configFilterSelected btn$ 'Called when a filter in the list has been selected 'Put the buttons in the proper state and display filter values in text boxes. #config.filt "selectionIndex? ind" if ind=0 then 'No selection; restricts options #config.AddFiltPrior "Add" #config.AddFiltAfter "!hide" #config.DeleteFilt "!hide" #config.ReplaceFilt "!hide" else #config.AddFiltAfter "!show" #config.DeleteFilt "!show" #config.ReplaceFilt "!show" #config.AddFiltPrior "AddPrior" #config.AddFiltAfter "AddAfter" #config.DeleteFilt "Delete" #config.ReplaceFilt "Replace" end if 'Doesn't work to get selected text from the box, so get it 'from the array if ind=0 then thisFilt$="" else thisFilt$=configDisplayedFilters$(ind-1) #config.filtFreq, Word$(thisFilt$,1) 'first word is frequency #config.filtBW, Word$(thisFilt$,2) 'second word is bandwidth end sub '@configDataError$ function configDataError$() 'Return error message if retrieved data has error if configDisplayHasTG=0 then hasDDS3=0 else #config.TGtop, "selectionindex? i" 'if TGtop=0, i will be 1, etc. if i=3 then hasDDS3=1 else hasDDS3=0 'Only SLIM TG has DDS3 end if configDataError$="" 'For some variables, we try to catch crazy values. 'delver113-7f if masterclock<=20 or masterclock>200 then _ 'delver113-7f configDataError$="Invalid Master Clock freq." : exit function if appxLO2<=100 or appxLO2>3000 then _ configDataError$="Invalid LO2 freq." : exit function 'delver113-7f if appxdds1<=10.6 or appxdds1>=10.8 then _ 'delver113-7f configDataError$="Invalid DDS1 center freq." : exit function 'delver113-7f if hasDDS3=1 and (appxdds3<=10.6 or appxdds3>=10.8) then _ 'delver113-7f configDataError$="Invalid DDS3 center freq." : exit function 'delver113-7f if dds1filbw<=0.005 or dds1filbw>=0.1 then _ 'delver113-7f configDataError$="Invalid DDS1 bandwidth." : exit function 'delver113-7f if configDisplayHasTG=1 and (dds3filbw<=0.005 or dds3filbw>=0.1) then _ 'delver113-7f configDataError$="Invalid DDS3 bandwidth." : exit function 'delver113-7f if PLL1phasefreq<=0.1 or PLL1phasefreq>=10 then _ 'delver113-7f configDataError$="Invalid PLL1 reference freq." : exit function 'delver113-7f if PLL2phasefreq<=0.1 or PLL2phasefreq>=10 then _ 'delver113-7f configDataError$="Invalid PLL2 reference freq." : exit function 'delver113-7f if configDisplayHasTG=1 and (PLL3phasefreq<=0.1 or PLL3phasefreq>=10) then _ 'delver113-7f configDataError$="Invalid PLL3 reference freq." : exit function if appxLO2<>PLL2phasefreq*int(appxLO2/PLL2phasefreq) then _ configDataError$="LO2 is not a multiple of PLL2phasefreq." : exit function 'delver113-7f if invdeg<-180 or invdeg>180 then _ 'delver113-7f configDataError$="Invalid Inv Deg." : exit function 'delver113-7f if maxpdmout<255 or maxpdmout>2^16 then _ 'delver113-7f configDataError$="Invalid Max PDM out." : exit function end function '@configAdjustDisplayedItems sub configAdjustDisplayedItems 'Adjust displayed items to reflect state of TG and VNA if configDisplayHasTG then #config.SG, "!show" #config.TGoff, "!show" #config.PLL3type, "show" #config.PLL3pol, "show" #config.PLL3mode, "show" #config.PLL3Ref, "!show" #config.DDS3freq, "!show" #config.DDS3bw, "!show" #config.TG, "Delete TG" #config.TGOffLabel, "!show" #config.SGLabel, "!show" #config.DDS3label, "!show" #config.PLL3label, "!show" #config.SGLabel, "!show" #config.TGOffLabel, "!show" else #config.SG, "!hide" #config.TGoff, "!hide" '#config.TGtop, "!hide" #config.PLL3type, "hide" #config.PLL3pol, "hide" #config.PLL3mode, "hide" #config.PLL3Ref, "!hide" #config.DDS3freq, "!hide" #config.DDS3bw, "!hide" #config.PDM, "!hide" #config.Inv, "!hide" #config.TG, "Add TG" #config.TGOffLabel, "!hide" '#config.TGTopLabel, "!hide" #config.SGLabel, "!hide" #config.DDS3label, "!hide" #config.PLL3label, "!hide" #config.SGLabel, "!hide" #config.TGOffLabel, "!hide" end if if hasVNA then #config.PDMLabel, "!show" #config.InvDegLabel, "!show" #config.PDM, "!show" #config.Inv, "!show" #config.VNA, "Delete VNA" else #config.PDMLabel, "!hide" #config.InvDegLabel, "!hide" #config.PDM, "!hide" #config.Inv, "!hide" #config.VNA, "Add VNA" end if end sub '@configDisplayData sub configDisplayData 'Enter data from MSA variables into window #config.PLL1type, "select "; str$(PLL1) #config.PLL2type, "select "; str$(PLL2) #config.PLL1pol, "select ";configPLLpol$(PLL1phasepolarity) #config.PLL2pol, "select ";configPLLpol$(PLL2phasepolarity) #config.PLL1Ref, PLL1phasefreq #config.PLL2Ref, PLL2phasefreq #config.PLL1mode, "select ";configPLLmodes$(PLL1mode) #config.DDS1freq, appxdds1 #config.DDS1bw, dds1filbw #config.DDS1parse, "select ";configParsers$(dds1parser) #config.LO2, appxLO2 #config.mast,masterclock #config.cent, centfreq #config.width, sweepwidth #config.top, topref #config.bot, botref #config.wate, wate #config.glitch, globalGlitchtime select case adconv case 8 #config.adconv, "select ";configADCs$(0) case 12 #config.adconv, "select ";configADCs$(1) case 16 #config.adconv, "select ";configADCs$(2) case else #config.adconv, "select ";configADCs$(3) end select #config.cb, "select ";configControlBoards$(cb) portHex$="Hex "+DecHex$(globalPort) #config.LPT, "!"; portHex$ #config.LPT, "setfocus" 'Note configDisplayedFilters$() runs from index 0,...; MSAFilters() runs from 1.... configNumDisplayedFilters=configFilterCount() for i=1 to 40 'refresh filter list call configGetFilter i, freq, bw if i<=configNumDisplayedFilters then configDisplayedFilters$(i-1)=configFormatFilter$(freq, bw) 'Assemble freq and bw else configDisplayedFilters$(i-1)="" 'Blank if no filter end if next #config.filt, "reload" 'Loads new data to display call configFilterSelected "" 'Arrange buttons call configDisplayVNAData 'Do this even if they are hidden call configDisplayTGData end sub '@configDisplayVNAData sub configDisplayVNAData 'Enter VNA related variables into window #config.Inv, invdeg #config.PDM, maxpdmout end sub '@configDisplayTGData sub configDisplayTGData 'Enter TG related variables into window #config.PLL3type, "select "; str$(PLL3) #config.PLL3pol, "select ";configPLLpol$(PLL3phasepolarity) #config.PLL3Ref, PLL3phasefreq #config.PLL3mode, "select ";configPLLmodes$(PLL1mode) #config.DDS3freq, appxdds3 #config.DDS3bw, dds3filbw #config.SG, sgpreset #config.TGoff,offset #config.TGtop, "select ";configTGtops$(TGtop) if TGtop=0 then configDisplayHasTG=0 else configDisplayHasTG=1 end sub '@configGetDisplayData sub configGetDisplayData 'Transfer data from display to MSA variables #config.PLL1type, "selection? PLL1" #config.PLL2type, "selection? PLL1" #config.PLL3type, "selection? PLL3" #config.PLL1pol, "selectionindex? PLL1phasepolarity" : PLL1phasepolarity=PLL1phasepolarity-1 #config.PLL2pol, "selectionindex? PLL2phasepolarity" : PLL2phasepolarity=PLL2phasepolarity-1 #config.PLL3pol, "selectionindex? PLL3phasepolarity" : PLL3phasepolarity=PLL3phasepolarity-1 #config.PLL1Ref, "!contents? PLL1phasefreq" #config.PLL2Ref, "!contents? PLL2phasefreq" #config.PLL3Ref, "!contents? PLL3phasefreq" #config.PLL1mode, "selectionindex? PLL1mode":PLL1mode=PLL1mode-1 #config.PLL3mode, "selectionindex? PLL3mode":PLL3mode=PLL3mode-1 #config.DDS1freq, "!contents? appxdds1" #config.DDS3freq, "!contents? appxdds3" #config.DDS1bw, "!contents? dds1filbw" #config.DDS3bw, "!contents? dds3filbw" #config.DDS1parse, "selectionindex? dds1parser" : dds1parser=dds1parser-1 #config.LO2, "!contents? appxLO2" #config.mast,"!contents? masterclock" #config.cent, "!contents? centfreq" #config.width, "!contents? sweepwidth" #config.top, "!contents? topref" #config.bot, "!contents? botref" #config.wate, "!contents? wate" #config.glitch, "!contents? globalGlitchtime" #config.SG, "!contents? sgpreset" #config.TGoff, "!contents? offset" 'Note we don't change hasVNA, because it always reflects the state of the display #config.PDM, "!contents? maxpdmout" #config.Inv, "!contents? invdeg" #config.adconv, "selectionindex? i" select case i case 1 adconv=8 case 2 adconv=12 case 3 adconv=16 case else adconv=22 end select #config.LPT, "contents? port$" globalPort=HexDec(Word$(port$,2)) 'e.g. port$ is "Hex 378") call configClearFilters for i=1 to configNumDisplayedFilters 'Put filter freq and bw into MSAFilters() thisFilt$=configDisplayedFilters$(i-1) 'get string for this filter freq=val(Word$(thisFilt$,1)) 'first word is frequency bw=val(Word$(thisFilt$,2)) 'bandwidth is second word call configAddFilter freq, bw next finalfreq=freq : finalbw=bw 'use values of first filter #config.TGtop, "selectionindex? TGtop" : TGtop=TGtop-1 'e.g. index 1 is value of 0 #config.cb, "selectionindex? cb" : cb=cb-1 'e.g. index 1 is value of 0 end sub '------------From here to the end of the Configuration Manager Module is---------- '------------the original Configuration Module, which lacked the user interface--- ' ---------Globals for Config Module---- global configModuleVersion 'Version of configuration module global configFileFullName$ 'path name for configuration file dim configFileInfo$(10,3) 'Used to get file info global configFileVersion 'File version of data input from file '@configInitFirstUse sub configInitFirstUse 'Call this before using any other routines configModuleVersion=1.03 configFileFullName$=DefaultDir$+"\MSA_Info\config.txt" end sub '@configVersion function configVersion() 'Version of this module configVersion=configModuleVersion end function '@configFileVersion function configFileVersion() 'Version of the file we have loaded configFileVersion=configFileVersion end function '@configCreateDefaultFile sub configCreateDefaultFile 'Create default file. Replaces any existing file 'Creates a file with default values. Assumes we know the MSA_Info folder exists. call configInitializeDefaults call configSaveFile end sub '@configFileExists function configFileExists() 'Return 1 if config.txt file exists On Error goto [configNoFile] open configFileFullName$ for input as #configIn close #configIn configFileExists=1 exit function [configNoFile] 'Error means it isn't there configFileExists=0 end function '@configCreateLoadFile sub configCreateLoadFile 'Open config file. Create folder and file if necessary 'Find out whether the necessary folders exist for config and calibration 'information. If no proper config.txt file exists, then create one with 'with default values. 'First see if we have the folder MSA_Info files DefaultDir$, "", configFileInfo$() numFolders=val(configFileInfo$(0,1)) haveFolder=0 for i=1 to numFolders if configFileInfo$(i,1)="MSA_Info" then haveFolder=1: exit for next i if haveFolder=0 then 'Create MSA_Info folder if 0<>mkDir("MSA_Info") then notice "Cannot access files." call configCreateDefaultFile else 'We have the MSA_Info folder. See if it has proper file files DefaultDir$+"\MSA_Info", "config.txt", configFileInfo$() if configFileInfo$(0,0)="0" then call configCreateDefaultFile 'No file. Create one. end if end if 'Get data from file if ""<>configLoadData$() then 'File is there, but has a problem Confirm "File error: "+errStr$+"; Replace with default file?"; response$ if response$="no" then notice "Default values displayed. File not replaced." call configInitializeDefaults exit sub end if call configCreateDefaultFile 'Try once more. Any error now is a system error if ""<>configLoadData$() then notice "Cannot access file" : exit sub end if if configFileVersion>configModuleVersion then _ notice "Warning: Config file format is later version than the software" 'Here we should update the file if configFileVersion is old. But at this 'time we have no old file versions end sub '@configSaveFile sub configSaveFile 'Save file from config variables open configFileFullName$ for output as #configOut print #configOut, "ConfigVersion=";using("##.##", configModuleVersion) for i=1 to MSANumFilters 'for each filter, print a line with frequency and bandwidth print #configOut, "Filter=";str$(MSAFilters(i,0));" ";str$(MSAFilters(i,1)) next print #configOut, "LPT=&H";DecHex$(globalPort) 'save port as hexidecimal print #configOut,"masterclock=";masterclock print #configOut,"centfreq=";centfreq print #configOut,"sweepwidth=";sweepwidth print #configOut,"wate=";wate print #configOut,"glitchtime=";globalGlitchtime print #configOut,"adconv=";adconv print #configOut,"topref=";topref print #configOut,"botref=";botref print #configOut,"cb=";cb print #configOut,"dds1parser=";dds1parser print #configOut,"appxdds1=";appxdds1 print #configOut,"dds1filbw=";dds1filbw print #configOut,"PLL1=";PLL1 print #configOut,"PLL1phasefreq=";PLL1phasefreq print #configOut,"PLL1mode=";PLL1mode print #configOut,"PLL1phasepolarity=";PLL1phasepolarity print #configOut,"PLL2=";PLL2 print #configOut,"appxLO2=";appxLO2 print #configOut,"PLL2phasefreq=";PLL2phasefreq print #configOut,"PLL2phasepolarity=";PLL2phasepolarity print #configOut,"TGtop=";TGtop print #configOut,"PLL3=";PLL3 print #configOut,"appxdds3=";appxdds3 print #configOut,"dds3filbw=";dds3filbw print #configOut,"PLL3phasepolarity=";PLL3phasepolarity print #configOut,"PLL3mode=";PLL3mode print #configOut,"PLL3phasefreq=";PLL3phasefreq print #configOut,"sgpreset=";sgpreset print #configOut,"offset=";offset print #configOut,"hasVNA=";hasVNA print #configOut,"maxpdmout=";maxpdmout print #configOut,"invdeg=";invdeg print #configOut,"EndConfigFile=" close #configOut end sub '@configLoadData$ function configLoadData$() 'Open and read file. Return error message 'This is called only after we know the file exists open configFileFullName$ for input as #configIn startLine=1 configLoadData$=configReadFile$("#configIn",startLine) close #configIn end function '@configGetFilter sub configAddFilter freq, bw 'Add a filter if MSANumFilters>38 then notice "Too many filters" : exit sub MSANumFilters=MSANumFilters+1 MSAFilters(MSANumFilters,0)=freq MSAFilters(MSANumFilters,1)=bw end sub '@configGetFilter sub configGetFilter N, byref freq, byref bw 'Get freq and bw for Nth filter if N<1 or N>40 then freq=0 : bw=0 : exit sub freq=MSAFilters(N,0) : bw=MSAFilters(N,1) end sub '@configClearFilters sub configClearFilters 'Clear list of filters MSANumFilters=0 for i=1 to 40 MSAFilters(i,0)=0 : MSAFilters(i,1)=0 next end sub function configFilterCount() 'Return number of filters configFilterCount=MSANumFilters end function '@configInitializeDefaults sub configInitializeDefaults 'Enter default values for configuration variables masterclock = 64 centfreq = 0 sweepwidth=0.04 wate = 0 globalGlitchtime = 0 adconv = 16 topref = 0 botref = -100 cb = 2 dds1parser = 1 appxdds1 = 10.7 dds1filbw = .015 PLL1 = 2326 PLL1phasefreq = .974 PLL1mode = 0 PLL1phasepolarity = 0 PLL2 = 2326 appxLO2 = 1024 PLL2phasefreq = 4 PLL2phasepolarity = 1 for i=1 to 40 'clear filter freq and bw MSAFilters(i,0)=0: MSAFilters(i,1)=0 next i MSAFilters(1,0)=10.7: MSAFilters(1,1)=15 'Add one filter MSANumFilters=1 globalPort = hexdec("&H378") 'parallel port call configInitializeVNADefaults call configInitializeTGDefaults end sub '@configInitializeVNADefaults sub configInitializeVNADefaults 'Enter default values for variables relating to VNA hasVNA=1 maxpdmout = 65535 invdeg = 180 end sub '@configInitializeTGDefaults sub configInitializeTGDefaults 'Enter default values for variables relating to TG TGtop = 2 PLL3 = 2326 appxdds3 = 10.7 dds3filbw = .015 PLL3phasepolarity = 0 PLL3mode = 0 PLL3phasefreq = .974 sgpreset = 10 offset = 0 end sub '@configReadFile$ function configReadFile$(configFile$, byRef startLine) 'Read data from already opened file 'Reads configuration data. 'The data is read from a file already opened, whose handle is in configFile$. 'We start with line startLine and continue until we find the tag 'EndConfigFile= (case insensitive). We update startLine to be one past the 'final line containing that tag 'The data is in the following format; comments are allowed and are marked 'by fileCommentChar$. 'Each data tag ends with "=", and is case insensitive. Items may appear in any 'order and may be ommitted (default values will be used) ' 'Each variable in configInitializeDefaults, configInitializeTGDefaults and 'configInitializeVNADefaults can be used as a tag, 'such as Masterclock=63.99; note case does not matter 'If error, we return a string describing the error 'If no error, we return "" call configInitializeDefaults 'Omitted variables will end up with default values numFiltersFound=0 fileLine=startLine 'Keeps track of which line of file we are on while EOF(#configFile$)=0 startLine=fileLine+1 'one past where we are Line Input #configFile$, tLine$ 'Read one line tLine$=Trim$(tLine$) 'drop extra blanks startChar$=Left$(tLine$,1) 'first real character of line if startChar$=fileCommentChar$ then isComment=1 else isComment=0 if startChar$<>fileCommentChar$ AND startChar$<>"" then 'valid non-comment line equalPos=instr(tLine$,"=") 'equal sign marks end of tag if equalPos=0 then configReadFile$="Line "+str$(fileLine) 'tag without equal sign call configInitializeDefaults exit function end if tag$=Upper$(Left$(tLine$, equalPos-1)) item$=Mid$(tLine$, equalPos+1) 'stuff after equal sign commentPos=instr(item$, fileCommentChar$) if commentPos>0 then item$=Left$(item$, commentPos-1) 'drop comments item$=Trim$(item$) isErr=0 val=val(item$) select case tag$ case "CONFIGVERSION" configFileVersion=val case "FILTER" numFiltersFound=numFiltersFound+1 filtFreq=val(Word$(item$,1)) : filtBW=val(Word$(item$,2)) if filtFreq<=0 then isErr=1 else if numFiltersFound=1 then 'If we have only one filter now, it is the default filter 'and we replace it with the first real one we find MSAFilters(1,0)=filtFreq : MSAFilters(1,1)=filtBW else call configAddFilter filtFreq, filtBW end if end if case "LPT" globalPort = HexDec(item$) 'parallel port; saved as hex case "MASTERCLOCK" masterclock=val: if val<=0 then isErr=1 case "CENTFREQ" centfreq=val: if val<0 then isErr=1 case "SWEEPWIDTH" sweepwidth=val: if val<0 then isErr=1 case "WATE" wate=val: if val<0 then isErr=1 case "GLITCHTIME" globalGlitchtime=val: if val<0 then isErr=1 case "ADCONV" adconv=val: if val<=0 then isErr=1 case "TOPREF" topref=val case "BOTREF" botref=val case "CB" cb=val: if configValidCB(val)=0 then isErr=1 case "DDS1PARSER" dds1parser=val: if val<>0 and val<>1 then isErr=1 case "APPXDDS1" appxdds1=val: if val<=0 then isErr=1 case "DDS1FILBW" dds1filbw=val: if val<=0 then isErr=1 case "PLL1" PLL1=val: if configValidPLL(val)=0 then isErr=1 case "PLL1PHASEFREQ" PLL1phasefreq=val: if val<=0 then isErr=1 case "PLL1MODE" PLL1mode=val: if val<>0 and val<>1 then isErr=1 case "PLL1PHASEPOLARITY" PLL1phasepolarity=val: if val<>0 and val<>1 then isErr=1 case "PLL2" PLL2=val: if configValidPLL(val)=0 then isErr=1 case "APPXLO2" appxLO2=val: if val<=0 then isErr=1 case "PLL2PHASEFREQ" PLL2phasefreq=val: if val<=0 then isErr=1 case "PLL2PHASEPOLARITY" PLL2phasepolarity=val: if val<>0 and val<>1 then isErr=1 case "TGTOP" TGtop=val: if configValidTGtop(val)=0 then isErr=1 case "PLL3" PLL3=val: if val<>0 and configValidPLL(val)=0 then isErr=1 case "APPXDDS3" appxdds3=val: if val<=0 then isErr=1 case "DDS3FILBW" dds3filbw=val: if val<=0 then isErr=1 case "PLL3PHASEPOLARITY" PLL3phasepolarity=val: if val<>0 and val<>1 then isErr=1 case "PLL3MODE" PLL3mode=val: if val<>0 and val<>1 then isErr=1 case "PLL3PHASEFREQ" PLL3phasefreq=val: if val<=0 then isErr=1 case "SGPRESET" sgpreset=val case "OFFSET" offset=val case "HASVNA" if val=0 then hasVNA=0 else hasVNA=1 case "MAXPDMOUT" maxpdmout=val: if val<=0 then isErr=1 case "INVDEG" invdeg=val case "ENDCONFIGFILE" 'This marks the end of the configuration file configReadFile$="" 'no error startLine=lineNum+1 'set to next line after this tag exit function case else isErr=true end select if isErr=1 then configReadFile$="Line "+str$(fileLine) 'inValid tag or data call configInitializeDefaults exit function end if end if fileLine=fileLine+1 wend 'go to next file line 'We can only get here if we did not find the EndConfigFile tag configReadFile$="Proper end of data not found" 'no error end function '@configValidCB function configValidCB(cb) 'Return 1 if cb is configValid; otherwise 0 select case cb case 0,1,2 configValidCB=1 case else configValidCB=0 end select end function '@configValidPLL function configValidPLL(PLL) 'Return 1 if PLL is configValid; otherwise 0 select case PLL case 0, 2325, 2326, 2350, 2353, 4112 configValidPLL=1 case else configValidPLL=0 end select end function '@configValidTGtop function configValidTGtop(top) 'Return 1 if top is configValid; otherwise 0 select case top case 0,1,2 configValidTGtop=1 case else configValidTGtop=0 end select end function '@================End Configuration Manager Module================= '================================================================== ' 'SEW Added the following Calibration Module to load magnitude and frequency calibration from files ' '=================================================================== '@==============Calibration Manager Module========================== '@ Version 1.03 'This module displays a window for viewing and editing files for calibration-over-signal-level '("mag cal") and calibration-over-frequency ("freq cal"). The former records actual power levels 'corresponding to given ADC readings. For VNA use, it also includes errors in phase 'measurement over frequency. ' 'To perform calibration call calManRunManager. While it is running, calManWindHndl$ will be non-blank. 'To check whether a freq and mag path 1 file exist, use "calFileExists()". 'Before calling anything other than calManRunManager, call InitFirstUse maxMagPoint, maxFreqPoints 'to initialize and to set the max number of arrays. Call calCloseWindows if the calling program quits when 'there may still be a cal manager window open. ' 'To apply the calibration tables to a measurement, use calConvertMagData or calConvertFreqError. '==============Start Test Program================= global calEditorPathNum '0 for freq; 1-N for magnitude dim calManFileList$(40) 'List of active paths; zero entry is used global calManFiles$ 'Indicates which files exist (marked by "1") 'First char is freq cal file, Nth (1...41) is mag cal file N-1 dim calFileInfo$(10,3) 'Used internally to request file info global calManEntryIsRef 'Used to keep track of whether data entry is on first (reference) point global calManRefPhase, calManRefFreq, calManRefPower 'Used during entry of data global calManOldText$ 'original text or text at time of last Save. global calManLastAutoPoint 'Previous point number entered for freq cal from the user sweep 'SEW8 'The following are used to test the Calibration Module as a freestanding program ' MSAFilters(1,0)=10.7 : MSAFilters(1,1)=15 ' MSAFilters(2,0)=10.695 : MSAFilters(2,1)=7 ' MSAFilters(3,0)=10.71 : MSAFilters(3,1)=1000 ' MSANumFilters=3 ' gosub [calManRunManager] ' wait '@calManRunManager 'This is a gosub subroutine rather than a true subroutine so that it can call [Measure] which 'in turn can call the non-subroutines that currently run the MSA hardware. [calManRunManager] 'Open window and let user proceed. WindowWidth = 575 WindowHeight =600 UpperLeftX = 200 UpperLeftY = 50 BackgroundColor$ = "lightgray" ForegroundColor$ = "black" 'Text Editor texteditor #calman.te 45, 45,220,220 statictext #calman.teLabel,"Frequency Calibration Table", 68, 30, 150,15 'ver113-7e 'delver113-7e statictext #calman.xLabel,"Frequency", 68, 30, 50,15 'delver113-7e statictext #calman.yLabel," Power", 135, 30, 50,15 'delver113-7e statictext #calman.pLabel,"Phase", 195, 30, 50,15 'File buttons calTEbot=260 : calButtonLeft=300 :calTop=30 button #calman.Reload, "Re-Load File", calManBtnFile, UL, calButtonLeft, calTop+15, 100, 25 button #calman.Save, "Save File", calManBtnFile, UL, calButtonLeft, calTop+45, 100, 25 button #calman.Return, "Return to MSA", [calManBtnReturn], UL, calButtonLeft, calTop+75, 100, 25 'The following checkbox can be implemented for testing 'checkbox #calman.phase, "Include Phase", [calManSetPhase], [calManResetPhase], calButtonLeft+120, calTop+15, 100, 25 'File List statictext #calman.fileLabel,"Available Files", calButtonLeft+25, calTop+115, 80,13 calManFileList$(0)="0 (Frequency)" listbox #calman.pathList calManFileList$(), calManSelectPath, calButtonLeft, calTop+130, 120, 100 'Data Entry items calTextLeft=10 : calTextTop=calTEbot+60 button #calman.Clean, "Clean Up", calManClean, UL, 50, calTEbot+10, 90, 25 'SEW8 changed .Default to .DispDefault so Return key doesn't activate it button #calman.DispDefault, "Display Defaults", calManDisplayDefault, UL, 150, calTEbot+10, 90, 25 TextboxColor$="cyan" textbox #calman.data1, calTextLeft,calTextTop+15, 75,20 'create label and box, will also be "Input (dBm)" ver113-7d statictext #calman.Ldata1, "Freq (MHz)",calTextLeft+5,calTextTop+3, 75,13 textbox #calman.data2, calTextLeft+90,calTextTop+15, 75,20 'create label and box, will also be "ADC value" ver113-7d statictext #calman.Ldata2, "Power (dbm)",calTextLeft+95,calTextTop+3, 75,13 textbox #calman.data3, calTextLeft+180,calTextTop+15, 75,20 'create label and box, will also be "Phase (deg)" ver113-7d statictext #calman.Ldata3, "Raw ADC",calTextLeft+185,calTextTop+3, 75,13 textbox #calman.ref, calTextLeft+430,calTextTop+15, 75,20 'create label and box, will also be "Ref Freq (MHz)" ver113-7d statictext #calman.Lref, "Ref ADC",calTextLeft+435,calTextTop+3, 90,13 textbox #calman.ref2, calTextLeft+430,calTextTop-20, 75,20 'create label and box, will also be "Ref Phase (deg)" ver113-7d statictext #calman.Lref2, "Ref Phase (deg)",calTextLeft+430,calTextTop-32, 90,13 button #calman.Measure, "Measure", [calManMenuMeasure], UL, calTextLeft+265,calTextTop+10, 75,25 'SEW8 Added NextPoint and PrevPoint to replace Measure for freq cal. button #calman.NextPoint, "Next Point", [calManBtnNextFreqPoint], UL, calTextLeft+265,calTextTop-5, 75,20 button #calman.PrevPoint, "Prev Point", [calManBtnPrevFreqPoint], UL, calTextLeft+265,calTextTop+15, 75,20 button #calman.EnterAll, "Enter All", [calManEnterAll], UL, calTextLeft+345,calTextTop-5, 75,20 'SEW8 For freq cal button #calman.Enter, "Enter", calManEnter, UL, calTextLeft+345,calTextTop+15, 75,20 button #calman.StartEntry, "Start Data Entry", calManEnterInstructions, UL, calTextLeft+150,calTextTop+10, 150,25 graphicbox #calman.enterInstruct, calTextLeft,calTextTop+40, 550,190 call calInitFirstUse 100,800 '100 mag points, 800 freq points; do before opening window 'Open Window SEW8 changed to use window rather than modal dialog open "Calibration File Manager ver. "+using("##.##", calVersion()) for window_nf as #calman calManWindHndl$="#calman" 'So MSA can close it if it is left open #calman, "trapclose [calManFinished]" #calman.te, "!cls" #calman.te, "!font courier_new 9" #calman.ref, "!disable" 'So user doesn't change it #calman.enterInstruct, "font Times_New_Roman 11" #calman.pathList, "singleclickselect" 'Set to handle phase based on MSA global hasVNA. When we are not in the MSA, 'this is undefined and we implement checkbox control, so set the checkbox call calSetDoPhase hasVNA 'if hasVNA=0 then #calman.phase "set" else #calman.phase "reset" call calManEnterAvailablePaths 'Loads list of filter files #calman.pathList, "selectindex 1" 'Select frequency file calEditorPathNum=0 'SEW6 ver113-7c dum=calManFile("Load") 'Loads frequency file (creates if necessary) 'delver113-7e #calman.pLabel, "!hide" 'hide phase heading wait 'wait for user action in cal window [calManSetPhase] 'Only relevant when checkbox is implemented call calSetDoPhase 1 if calEditorPathNum<>0 then 'delver113-7e #calman.pLabel, "!show" call calManClean "" call calManPrepareEntry end if wait [calManResetPhase] 'Only relevant when checkbox is implemented call calSetDoPhase 0 if calEditorPathNum<>0 then 'delver113-7e #calman.pLabel, "!hide" call calManClean "" call calManPrepareEntry end if wait [calManBtnReturn] doCan=calManWarnToSave(1) 'Warn to save if data changed. Allow cancel. if doCan=1 then return 'cancelled Exit calManRunManager call calInstallFile 0 'Leave with freq file installed call calInstallFile 1 'Leave with path 1 installed call calCloseWindows haltsweep=0 'SEW6 return 'Returns to caller of calManRunManager [calManFinished] dum=calManWarnToSave(0) 'Warn to save if data changed. No cancel allowed. call calCloseWindows call calInstallFile 0 'Leave with freq file installed call calInstallFile 1 'Leave with path 1 installed haltsweep=0 'SEW6 return 'Returns to caller of calManRunManager sub calCloseWindows 'Close any windows that are open if calManWindHndl$<>"" then close #calman : calManWindHndl$="" end sub 'SEW8 added CalManEnterAll [calManEnterAll] 'button to Enter all sweep points for freq cal 'chngver113-7e for i=1 to steps for i=0 to steps 'ver113-7e call calManGetFreqInput i 'Put data into boxes if i=steps then call calManEnter "xx" else call calManEnter "" 'Enter data into table; clean up on last one scan 'In case things are going badly and user wants to quit next i wait '@calManEnter sub calManEnter btn$ 'Handle Enter button 'If called by button click, btn$ will not be blank and we do clean up at the end. 'If btn$ is blank, that is a signal to skip the clean up because we are entering 'a mass of points. #calman.data1, "!contents? s1$" #calman.data2, "!contents? s2$" #calman.data3, "!contents? s3$" if calEditorPathNum=0 then 'Frequency cal. data2 is freq, data3 is power; 'if first point, need to put freq in ref freq=val(s2$) if freq<0 or freq>10000 then notice "Invalid frequency." : exit sub pow=val(s3$) f$=using("####.######",freq) p$=using("####.##",pow) if pow<-200 or pow>100 then notice "Invalid dbm value." : exit sub if calManEntryIsRef then 'Get ref freq and power first time only calManRefFreq=freq calManRefPower=pow print #calman.ref, p$ print #calman.ref2,f$ end if 'delver113-7d p$=using("####.##",pow-calManRefPower) p$=using("####.##",calManRefPower-pow) 'SEW9 reversed the subtraction.ver113-7d print #calman.te, f$;" ";p$ else 'Mag cal. data 1 is power, data2 is ADC, data3 is phase (if we are doing phase); 'if first point, need to be sure freq is in ref and put phase in ref2 pow=val(s1$) if pow<-200 or pow>100 then notice "Invalid dbm value." : exit sub adc=val(s2$) if adc<0 then notice "Invalid adc value." : exit sub if calGetDoPhase()=0 then phase=0 else phase=val(s3$) if phase<-180 or phase>180 then notice "Invalid phase value." : exit sub adc$=using ("#######", adc) v$=using ("####.##", pow) p$=using ("####.##", phase) if calManEntryIsRef then 'Get freq first time only; after that it is fixed #calman.ref, "!contents? freq$" freq=val(freq$) if freq<=0 or freq>10000 then notice "Invalid frequency." : exit sub print #calman.ref2, using("####.##", phase) 'Fix reference phase first time only calManRefPhase=phase calManRefFreq=freq calManRefPower=pow end if 'The power correction factor is phase-calManRefPhase, put into normal range if calGetDoPhase()=1 then pCor=phase-calManRefPhase while pCor<=-180 : pCor=pCor+360: wend while pCor>180 : pCor=pCor-360: wend p$=using ("####.##", pCor) 'Enter the mag cal data, with phase print #calman.te, adc$;" ";v$;" ";p$ else 'Enter the mag cal data, without phase print #calman.te, adc$;" ";v$ end if end if 'SEW8 made the following conditional 'We have now entered the data, whether mag or freq. Now clean things up. if btn$<>"" or calManEntryIsRef then fErr$=calLoadFromEditor$("#calman.te", calEditorPathNum) 'Load variables from editor if fErr$<>"" then 'Error in existing data, so we won't mess with formatting or fixing the comments notice "Error in data: " + fErr$ if calManEntryIsRef then call calManEnterInstructions "" calManEntryIsRef=0 exit sub end if end if if calManEntryIsRef=1 then 'First point--Enter info into comments c2$="Calibrated " + Date$("mm/dd/yy") + " at " if calEditorPathNum=0 then 'Freq c1$="Calibration over frequency" c2$=c2$ + Trim$(using ("####.##", calManRefPower)) + " dbm." else 'Mag filtFreq=MSAFilters(calEditorPathNum,0) : filtBW=MSAFilters(calEditorPathNum,1) c1$="Filter Path " + str$(calEditorPathNum) + ": CenterFreq=" _ + Trim$(using("###.######",filtFreq)) +" MHz; Bandwidth=" _ + Trim$(using("####.######",filtBW)) +" KHz" c2$=c2$ + Trim$(using("####.######", calManRefFreq)) + " MHz." end if calFileComments$(1)=c1$ calFileComments$(2)=c2$ calManEntryIsRef=0 call calManEnterInstructions "" end if 'SEW8 made the following conditional if btn$<>"" or calManEntryIsRef then #calman.te, "!cls" call calSaveToEditor "#calman.te", calEditorPathNum 'Restore data, now with comments end if if calEditorPathNum=0 then 'SEW8 created this if... block call calManGetFreqInput calManLastAutoPoint 'Display last retrieved point else 'Path calibration #calman.data1, "" 'SEW6 Clear data boxes #calman.data2, "" 'SEW6 #calman.data3, "" 'SEW6 end if end sub '@calFileExists function calFileExists() 'Return 1 if both the freq file and path 1 mag file exist On Error goto [calNoFile] open calFilePath$()+calFileName$(0) for input as #calIn 'Frequency cal file close #calIn open calFilePath$()+calFileName$(1) for input as #calIn 'Path 1 mag cal close #calIn calFileExists=1 exit function [calNoFile] 'Error means it isn't there calFileExists=0 end function 'SEW8 added calManBtnNextFreqPoint [calManBtnNextFreqPoint] 'Handles button to retrieve next point in automated freq cal. #calman.data1, "!contents? measPoint$" 'get point number measPoint=val(measPoint$) if measPoint<0 or measPoint>steps-1 then notice "Invalid point number" : wait measPoint=measPoint+1 'Next point #calman.data1, str$(measPoint) 'Display point number call calManGetFreqInput measPoint 'Get point data into boxes and wait wait 'SEW8 added calManBtnPrevFreqPoint [calManBtnPrevFreqPoint] 'Handles button to retrieve previous point in automated freq cal. #calman.data1, "!contents? measPoint$" 'get point number measPoint=val(measPoint$) if measPoint<1 or measPoint>steps then notice "Invalid point number" : wait measPoint=measPoint-1 'Next point #calman.data1, str$(measPoint) 'Display point number call calManGetFreqInput measPoint 'Get point data into boxes and wait wait 'SEW8 added calManGetFreqInput 'SEW replaced sub calManGetFreqInput with this new version: sub calManGetFreqInput measStep 'Enter user scanned data for point measStep (0...steps) 'The user has performed a scan covering the desired range with the desired number of points. 'We enter the points from the MSA arrays into the calibration table. 'This is valid if the Path calibration for the currently installed filter is current. 'We retrieve freq and power (dbm) for each point and put it into calman.data2 (freq) 'and calman.data3 (power). We put point number into calman.data1. calManLastAutoPoint=measStep 'SEW8 Record number of point of the user-established sweep #calman.data1, using("####", measStep) 'Enter step number into box #calman.data2, using("####.######", datatable(measStep,1)) 'Enter frequency into box #calman.data3, using("####.##", datatable(measStep, 2)) 'Enter power into box end sub [calManMenuMeasure] 'enters here when the "Measure" button is clicked. ver113-7d gosub [calManMeasure] wait 'SEW8 rewrote calManMeasure [calManMeasure] 'Measure a point for calibration over signal strength (mag cal) 'data 1 is power, data2 is ADC, data3 is phase (if we are doing phase); 'freq is in ref. We measure power and phase at this frequency and enter into boxes. 'It is assumed that the user has set up the scan at the desired frequency.Scotty-yes, in zero sweep width 'delver113-7d #calman.data2, "!contents? measS1$" 'Actual power level (we use measPow just for temp convenience) 'delver113-7d measPow=val(measS1$) 'We do nothing with this other than verify its validity 'delver113-7d if measPow<-200 or measPow>100 then notice "Invalid dbm value." : return 'delver113-7d #calman.ref, "!contents? measRefFreq$" 'delver113-7d centfreq=val(measRefFreq$) 'All our measurements are made at the reference frequency 'delver113-7d if centfreq<=0 or centfreq>10000 then notice "Invalid frequency." : return 'go to the main MSA software and grab the Center Frequency variable, centfreq #calman.ref, centfreq 'ver113-7d if centfreq<0 or centfreq>1000 then notice "Invalid frequency." : return 'ver113-7d if centfreq=0 then notice Chr$(13);"Center Frequency of 0 is not allowed.";Chr$(13);"Return to MSA and Change Center Frequency" : return 'ver113-7d if sweepwidth>0 then notice Chr$(13);"Sweep Width is not 0.";Chr$(13);"Return to MSA and Change Sweep Width to 0" : return 'ver113-7d 'We have to average 10 readings. For mag, we just average ADC, since we are 'just now determining the calibration factors needed to convert ADC to power. 'For phase, if needed, we convert from ADC bits to phase and average that. 'Averaging phase is a little tricky. 'A -179 degree angle and a 179 degree angle should average to 180, not 0 degrees. 'We expect only a few degrees variation in phase. We save the first phase reading and 'average the difference (this reading-first reading). If a difference exceeds 180 degrees, 'we decrease it by 360 because we know we must take the difference in the opposite 'direction. E.g. 179 minus -179 gives a difference of 358; we subtract 360 to get the true difference. 'of -2 degrees. Likewise, if the difference is less than -180 degrees, we add 360. measADCSum=0 : measPhaseDifSum=0 'Average the mag ADC readings and the phase degrees. saveVNA=vna 'Save MSA current setting vna= calGetDoPhase() 'Set vna to 1 if the MSA has the vna feature 'ver113-7d 'chngver113-7d for measStep=0 to steps for measStep=0 to 9 'ver113-7d gosub [ReadStep] 'Read phase and mag 'magdata now has ADC bits for magnitude; if MSA can measure phase phadata has ADC bits for phase. measADCSum=measADCSum+magdata if vna=1 then '(vna=1 is fudged, we are here from the SA Mode) 'phaarray(measStep,0) is 1 if inverted otherwise 0; phadata is phase ADC reading measPhase=360*phadata/maxpdmout-invdeg*phaarray(measStep,0) if measStep=0 then measFirstPhase=measPhase 'Save first phase reading measPhaseDif=measPhase-measFirstPhase 'phase dif if measPhaseDif<-180 then measPhaseDif=measPhaseDif+360 if measPhaseDif>180 then measPhaseDif=measPhaseDif-360 measPhaseDifSum=measPhaseDifSum+measPhaseDif 'Accumulate phase difference end if next measStep #calman.data2, using("######", measADCSum/10) 'Enter averaged ADC into box if vna=1 then measPhase=measFirstPhase + measPhaseDifSum/10 'First phase measurement plus average difference while measPhase<=-180 : measPhase=measPhase+360 : wend 'Put into range -180 to 180 while measPhase>180 : measPhase=measPhase-360 : wend else measPhase=0 end if #calman.data3, using("####.##", measPhase) 'Enter averaged phase into box vna=saveVNA 'Restore MSA setting return 'SEW8 deleted calDoBackgroundSweep '@calManClean sub calManClean btn$ 'Format and Sort list 'We just get the data and put it back fErr$=calLoadFromEditor$("#calman.te", calEditorPathNum) 'This also sorts if fErr$<>"" then notice "Bad Data. "+fErr$ : exit sub if calEditorPathNum=0 then nPoints=calNumFreqPoints() else nPoints=calNumMagPoints() #calman.te, "!cls" call calSaveToEditor "#calman.te", calEditorPathNum if nPoints=0 then 'If there are no data points, start over with a clean header call calCreateDefaults calEditorPathNum,"#calman.te", 0 'zero signals no points end if end sub sub calManDisplayDefault btn$ if calManWarnToSave(1)=1 then exit sub call calCreateDefaults calEditorPathNum,"#calman.te", 1 '1 signals to do points call calManClean "" call calManPrepareEntry end sub '@calManSelectPath sub calManSelectPath btn$ 'Handle user selection of calibration file 'Set current path number. Will be negative if there is no selection prevPathNum=calEditorPathNum #calman.pathList, "selectionindex? sel" if sel=0 then notice "No File Selected." : exit sub 'Must be error calEditorPathNum=sel-1 'SEW7 moved; sel starts at 1 if valid selection; calEditorPathNum starts at 0 can=calManFile("Reload") if can=1 then 'User cancelled the switch #calman.pathList, "selectindex ";prevPathNum+1 'index is one more than path number calEditorPathNum=prevPathNum end if if calEditorPathNum=0 then #calman.teLabel, "Frequency Calibration Table" 'delver113-7e #calman.xLabel, "Frequency" 'delver113-7e #calman.yLabel " Power" 'delver113-7e #calman.pLabel, "!hide" else #calman.teLabel, "Path Calibration Table" 'delver113-7e #calman.xLabel, " ADC" 'delver113-7e #calman.yLabel "Power" 'delver113-7e if calGetDoPhase()=1 then #calman.pLabel, "!show" else #calman.pLabel,"!hide" end if end sub '@calManEnterAvailablePaths sub calManEnterAvailablePaths 'Create list of available paths 'The list is based on the MSA info in MSAFilters(), which lists 'freq and bw for each calibration path, starting at path 1=index 1 'We create a list where index 0 is the frequency cal file, and index N (1...) 'is the Nth mag cal path. for i=0 to 40: calManFileList$(i)="": next i 'Clear list calManFileList$(0)="0 (Frequency)" for i=1 to MSANumFilters freq$=str$(MSAFilters(i,0)) : bw=MSAFilters(i,1) : bw$=str$(bw) freq$=freq$+Space$(max(0,7-len(freq$))) 'makes freq$ a fixed width if bw=0 then bwPad$=" " else _ bwPad$=Space$(5-int(Log(bw)/Log(10))) 'Aligns bw$ at decimal; bw$=bwPad$+str$(bw) configFormatFilter$=freq$+bw$ thisFilt$=freq$+bw$ calManFileList$(i)=str$(i) + " (" + Trim$(thisFilt$) + ")" 'Path num plus freq and bw next #calman.pathList, "reload" 'Loads new strings into listbox end sub '@calManPrepareEntry sub calManPrepareEntry 'hide all entry boxes, labels and buttons #calman.Lref, "!hide" #calman.ref, "!hide" #calman.ref2, "!hide" #calman.Lref2, "!hide" #calman.data1, "!hide" #calman.Ldata1, "!hide" #calman.data2, "!hide" #calman.Ldata2, "!hide" #calman.data3, "!hide" #calman.Ldata3, "!hide" #calman.Measure, "!hide" #calman.Enter, "!hide" #calman.NextPoint, "!hide" 'SEW8 #calman.PrevPoint, "!hide" 'SEW8 #calman.EnterAll, "!hide" 'SEW8 #calman.StartEntry, "!show" #calman.enterInstruct, "cls" #calman.enterInstruct, "place 10 15" #calman.enterInstruct, "\To begin entry of calibration data, click Start Entry." #calman.enterInstruct, "\Alternatively, you may enter, alter and delete data in the text editor." calManEntryIsRef=1 'We are set for the first point end sub '@calManEnterInstructions 'SEW8 changed several details fo calManEnterInstructions for new cal method '@calManEnterInstructions sub calManEnterInstructions btn$ 'Display instructions for entering data 'calManEntryIsRef=1 for entering the first (reference) point; =0 for other points #calman.enterInstruct, "cls" #calman.enterInstruct, "place 10 15" #calman.StartEntry, "!hide" #calman.Enter, "!show" #calman.Lref, "!hide" 'Reference and its label hide #calman.ref, "!hide" #calman.data1, "!show" 'data 1 and its label show #calman.Ldata1, "!show" #calman.data2, "!show" 'data2 and its label show #calman.Ldata2, "!show" #calman.data3, "!show" 'data3 and its label show #calman.Ldata3, "!show" #calman.ref2, "!hide" 'ref2 and its label hide #calman.Lref2, "!hide" #calman.data2, "" 'Clear data boxes #calman.data3, "" if calEditorPathNum=0 then 'Here we are doing freq cal. We need frequency and measured power for each point. #calman.Lref, "Ref Power(dbm)" #calman.Ldata1, "Point Number" 'SEW8 #calman.Ldata2, "Freq (MHz)" #calman.Ldata3, "Power (dbm)" #calman.ref, "!disable" #calman.ref2, "!disable" #calman.Measure, "!hide" 'SEW8 Hide Measure and show NextPoint, PrevPoint instead #calman.NextPoint, "!show" #calman.PrevPoint, "!show" #calman.EnterAll, "!show" 'ver113-7e altered the following instructions for each "#calman.enterInstruct" #calman.enterInstruct, "\Frequency Calibration should be performed with an input power of -32 dBm to -37 dBm." #calman.enterInstruct, "\A calibration list has been created from the previous sweep, with the number of Points" #calman.enterInstruct, "\equaling the number of steps in the sweep, +1. Data of each Point can be accessed by" #calman.enterInstruct, "\clicking the Next Point button. You must change the value in the Power(dBm) box to" #calman.enterInstruct, "\the Known Input Power. You may modify any data by highlighting it and retyping it." #calman.enterInstruct, "\You may insert data from a single Point by clicking the Enter button. You may insert" #calman.enterInstruct, "\the data of every Point in the sweep by clicking the Enter All button. You may insert" #calman.enterInstruct, "\data by typing the data directly into the Frequency Calibration Table, after the last" #calman.enterInstruct, "\data Point. Data may be entered in any order. Clean Up to sort the data at any time." #calman.enterInstruct, "\The Magnitude Error vs Frequency Correction Factor = Ref Power - Known Input Power." if calManEntryIsRef=1 then 'first point for frequency cal 'SEW8 Rewrote the following message notice "Notice" +chr$(13)+"Automatic entry of points assumes you have performed " _ +chr$(13)+"a sweep over the desired frequency range before entering the" _ +chr$(13)+"Calibration Mangager. Numbers (0...) refer to points of that sweep." #calman.ref, "" #calman.ref2, "" call calManGetFreqInput 0 'SEW8 Display data for point 0 else '2nd+ points for frequency cal #calman.ref, "!show" 'show power ref #calman.Lref, "!show" end if else 'Here we are doing mag cal. We need Input power, ADC and possibly phase for each point 'For first point we need frequency. #calman.data1, "" 'Clear data box #calman.Lref2, "Ref Phase" #calman.Ldata2, "ADC value" #calman.Ldata3, "Phase (deg)" #calman.Ldata1, "Input (dbm)" #calman.ref2, "!disable" 'Don't allow reference phase to be changed if calGetDoPhase() =0 then #calman.data3, "!hide" 'data3 and its label hide (not doing phase) #calman.Ldata3, "!hide" end if #calman.ref, "!show" 'ref will hold reference frequency #calman.Lref, "!show" #calman.Lref, "Ref Freq (MHz)" #calman.Measure, "!show" 'SEW8 Hide Measure and show NextPoint, PrevPoint instead #calman.Measure, "!enable" #calman.NextPoint, "!hide" #calman.PrevPoint, "!hide" #calman.EnterAll, "!hide" if calGetDoPhase() =0 then #calman.enterInstruct, "\For each point, enter the input power level and the ADC reading, then click Enter." #calman.enterInstruct, "\For the first point also enter the reference frequency at which the measurements" #calman.enterInstruct, "\made. The power level may be entered manually or automatically measured with Measure." #calman.enterInstruct, "\or automatically measured with Measure." #calman.enterInstruct, "\Data may be entered in any order; to sort the data click Clean Up" #calman.enterInstruct, "\You may add, alter or delete lines directly in the text editor if desired." else 'ver113-7 changed the following instructions: #calman.enterInstruct, "\The Spectrum Analyzer must be configured for zero sweep width. Center Frequency must" #calman.enterInstruct, "\be higher than 0 MHz. The first data Point will become the Reference data for all" #calman.enterInstruct, "\other data Points. Click Measure button to display the data measurements for ADC" #calman.enterInstruct, "\value and Phase. Manually, enter the Known Power Level into the Input (dBm) box." #calman.enterInstruct, "\Click the Enter button to insert the data into the Path Calibration Table." #calman.enterInstruct, "\Subsequent Data may be entered in any order, and sorted by clicking Clean Up. ADC" #calman.enterInstruct, "\bits MUST increase in order and no two can be the same. You may alter the Data in" #calman.enterInstruct, "\the table, or boxes, by highlighting and retyping. The Phase Data (Phase Error vs" #calman.enterInstruct, "\Input Power) = Measured Phase - Ref Phase, is Correction Factor used in VNA." #calman.enterInstruct, "\Phase is meaningless for the Basic MSA, or MSA with TG." end if if calManEntryIsRef=1 then 'first point for mag cal #calman.ref, "!enable" 'Allow ref freq to be changed on first point only #calman.ref, "" #calman.ref2, "" 'Measure can be used only if this mag file matches active filter path f=MSAFilters(calEditorPathNum,0) : bw=MSAFilters(calEditorPathNum,1) if f=finalfreq and bw=finalbw then haveProperFilt=1 _ else haveProperFilt=0 if haveProperFilt=1 then #calman.Measure, "!enable" else #calman.Measure, "!disable" notice "Notice"+chr$(13)+"Measurements made at this time will not be accurate, because " _ +chr$(13)+"the selected filter is not the currently installed filter." end if else '2nd+ points for mag cal #calman.ref, "!disable" 'Allow ref freq to be changed on first point only if calGetDoPhase() =1 then #calman.ref2, "!show" #calman.Lref2, "!show" 'ref2 and its label show (phase ref) #calman.Lref2, "Ref Phase (deg)" end if end if end if #calman.enterInstruct, "flush" 'Make graphics stick end sub '@calManWarnToSave function calManWarnToSave(allowCancel) 'Give warning to save if data has changed. Return 1 to cancel 'calManOldText$ contains the old data to compare against. This method is used 'because the !modified? command cannot be reset at the time of a Save. 'If allowCancel=1, the message box will allow the user to cancel can=0 #calman.te, "!contents? curr$" 'get current data if calManOldText$=curr$ then calManWarnToSave=0: exit function 'Put up a message box. msg$="Unsaved calibration changes will be lost. Do you want to SAVE first?" ans$=uPrompt$("Warning", msg$,1,allowCancel) 'yes, no, possibly cancel if ans$="no" then calManWarnToSave=0: exit function 'Proceed, no save if ans$="cancel" then calManWarnToSave=1 : exit function 'Cancel call calSaveToFile calEditorPathNum 'User wants to save so do it call calInstallFile calEditorPathNum 'Re-read to check for errors SEWcal2,ver113-7g #calman.te, "!contents? calManOldText$" 'Save for future compare calManWarnToSave=0 'No cancel end function '@calManBtnFile sub calManBtnFile btn$ 'Handle file buttons pos=instr(btn$,".") if pos>0 then btn$=Mid$(btn$, pos+1) 'Drop part before period r=calManFile(btn$) 'r indicates whether cancelled; we don't care. end sub '@calManFile function calManFile(btn$) 'Load/save/create files returns 0, except 1 if user cancels 'All file loads must be done through this function 'If data is changed, ask whether to save it. But obviously not if this command is a Save. 'Also, the Load command is only generated internally so no need to ask there. calManFile=0 if btn$<>"Save" and btn$<>"Load" then if calManWarnToSave(1)=1 then calManFile=1 : exit function 'Cancelled end if select case btn$ case "Load", "Reload" if calEditorPathNum<0 then notice "You must select a calibration file to save." if calEditorPathNum=0 then 'Before loading the frequency file we must be sure that the mag cal 'data is valid for the MSA's active filter match=0 for i=1 to MSANumFilters f=MSAFilters(i, 0) : bw=MSAFilters(i,1) if f=finalfreq and bw=finalbw then match=i : exit for next i if match=0 then notice "Can't find active filter; don't use Measure." 'only possible in debugging call calInstallFile match 'Loads mag cal file end if call calInstallFile calEditorPathNum #calman.te, "!cls" call calSaveToEditor "#calman.te", calEditorPathNum 'display data call calManPrepareEntry 'Prepare buttons and instructions for data entry case "Save" if calEditorPathNum<0 then notice "You must select a calibration file to save." errMsg$=calLoadFromEditor$("#calman.te", calEditorPathNum) if errMsg$<>"" then notice "Data Error: "+errMsg$+ "; file not saved." : exit function call calSaveToFile, calEditorPathNum dum=calManFile("Load") 'Reload to update editor and verify data case "Default" if calEditorPathNum<0 then notice "You must first select a calibration file." call calCreateDefaults calEditorPathNum, "", 1 call calManPrepareEntry case else end select #calman.te, "!contents? calManOldText$" 'Save for future compare end function '@====================Original Calibration Manager Ended Here===================== '========================================================================================= '@==========================Start of Mag/Freq Calibration Module========================== 'Mag/Freq Calibration module version 1.03 ' 'This module is now a subset of the Configuration Manager Module. This portion 'manages calibration files and applies them upon request to raw data. 'calInitFirstUse must be called before any other routines, but that is 'taken care of if calManRunManager has already been run. 'The principal routines of interest to the user are: ' 'function calConvertMagError(magdata) 'Returns dbm level given raw ADC reading 'function calConvertFreqError(freq) 'Returns correction factor for this freq, 'to be added to raw power to get final ' calCubicInterpolation is a general purpose cubic interpolation routine ' that will properly handle angles 'function calCubicInterpolation(val,isAngle, favorFlat,x0,y0,x1,y1,x2,y2,x3,y3) ' calLinearInterpolation is a general purpose cubic interpolation routine ' that will properly handle angles 'sub calLinearInterpolation freq, isPolar, f1,R1,I1,f2,R2,I2,byref p1, byref p2 ' '---------------Start Global Variables for Mag/Freq Calibration Module--------- 'calMagTable contains calibration data for the current signal path 'The zero entry for the first dimension is not used. 'magCalTable(i, v) gives the ith entry; v=0 gives ADC reading; v=1 gives actual db value. global calMaxMagPoints, calMaxFreqPoints dim calMagTable(100,2) 'Size can be changed dynamically 'calMagTable contains calibration data for the current signal path 'The zero entry for the first dimension is not used. 'calMagTable(i, v) gives the ith entry; v=0 gives freq (in MHz); v=1 gives dbm magnitude; 'v=2 gives phase correction to be subtracted from raw phase readings, used only for VNA. 'Each entry of calMagCoeffTable() will have 8 numbers. 0-3 are the A,B,C,D 'coefficients for interpolating the real part; 4-7 are for the imag part. dim calMagCoeffTable(100,7) 'SEWcal Cubic coefficients for interpolating in calMagTable global calMagPoints 'Number of actual points in calMagTable global calMagFileHadPhase 'Set to 1 if file data had third data element (for VNA) 'Otherwise, 0. global calDoPhase 'Set to 1 to treat mag cal data as including phase; otherwise phase ignored. 'calFreqTable contains calibration data for response over frequency 'The zero entry for the first dimension is not used. 'calFreqTable(i, v) gives the ith entry; v=0 gives freq (in MHz); 'v=1 gives magnitude correction. dim calFreqTable(800,1) 'Size can be changed dynamically 'calFreqCoeffTable has the A,B,C,D coefficients for interpolating in the calFreqTable() dim calFreqCoeffTable(800,3) 'SEWcal Cubic interpolation coefficients for calFreqTable() global calFreqPoints 'Number of actual points in calFreqTable dim calFileComments$(2) 'Up to 2 lines of comments from files global calFileCommentChar$ 'Character marking comments in data files global calModuleVersion 'Version of this module; set in calInitFirstUse global calFileVersion 'Version of last opened file dim calFileInfo$(10,3) 'Used internally to request file info '------------Routines------------------ '@calInitFirstUse sub calInitFirstUse maxMagPoints, maxFreqPoints 'Call to initialize before using other routines calMaxMagPoints=max(800, maxMagPoints) calMaxFreqPoints=max(800, maxFreqPoints) calFileCommentChar$="*" 'Use asterisk as comment char redim calMagTable(calMaxMagPoints,2) redim calFreqTable(calMaxFreqPoints,1) redim calMagCoeffTable(calMaxMagPoints,7) 'SEWcal redim calFreqTable(calMaxFreqPoints,1) 'SEWcal calMagFileHadPhase=0 calDoPhase=0 calModuleVersion=1.03 'Change this code to update version end sub '@calVersion function calVersion() 'Version of this module calVersion=calModuleVersion end function '@calSetMaxPoints sub calSetMaxPoints maxMagPoints, maxFreqPoints 'Call to change max points; data is lost calMaxMagPoints=max(800, maxMagPoints) calMaxFreqPoints=max(800, maxFreqPoints) calFileCommentChar$="*" 'Use asterisk as comment char redim calMagTable(calMaxMagPoints,2) redim calMagCoeffTable(calMaxMagPoints,7) 'SEWcal redim calFreqTable(calMaxFreqPoints,1) redim calFreqCoeffTable(calMaxFreqPoints,3) 'SEWcal end sub '@calClearMagPoints sub calClearMagPoints 'Clear calMagTable() to zero points 'It's not necessary to zero the points, but it keeps things clean for i=1 to calMaxMagPoints calMagTable(i,0)=0 :calMagTable(i,1)=0:calMagTable(i,2)=0 next i calMagPoints=0 end sub '@calClearFreqPoints sub calClearFreqPoints 'Clear calFreqTable() to zero points 'It's not necessary to zero the points, but it keeps things clean for i=1 to calMaxFreqPoints calFreqTable(i,0)=0 :calFreqTable(i,1)=0 next i calFreqPoints=0 end sub '@calDataHadPhase function calDataHadPhase() 'Returns 1 if last file or editor data had phase correction data calDataHadPhase=calMagFileHadPhase end function '@calSetDoPhase sub calSetDoPhase doPhase 'Set calDoPhase to 1 or 0, indicating whether output should include phase calDoPhase=doPhase end sub 'calGetDoPhase function calGetDoPhase() 'Get calDoPhase:or 0, indicating whether output should include phase calGetDoPhase=calDoPhase end function '@calClearComments sub calClearComments calFileComments$(1)="" calFileComments$(2)="" end sub '@calNumMagPoints function calNumMagPoints() 'Get number of points in calMagTable calNumMagPoints=calMagPoints end function '@calNumFreqPoints function calNumFreqPoints() 'Get number of points in calFreqTable calNumFreqPoints=calFreqPoints end function '@calGetMagPoint sub calGetMagPoint N, byref adc, byref db, byref phase 'Get mag data for point N if N<=0 or N>calMagPoints then notice "Invalid mag cal point number." adc=calMagTable(N,0) db=calMagTable(N,1) phase=calMagTable(N,2) end sub '@calGetFreqPoint sub calGetFreqPoint N, byref f, byref db 'Get mag data for point N if N<=0 or N>calFreqPoints then notice "Invalid frequency cal point number." f=calFreqTable(N,0) db=calFreqTable(N,1) end sub '@calAddMagPoint function calAddMagPoint(adc, db, phase) 'Add mag cal point; return 1 if error if calMagPoints>=calMaxMagPoints then calAddFreqPoint=1: exit function calMagPoints=calMagPoints+1 calMagTable(calMagPoints,0)=adc calMagTable(calMagPoints,1)=db calMagTable(calMagPoints,2)=phase calAddMagPoint=0 'No error end function '@calAddFreqPoint function calAddFreqPoint(f, db) 'Add freq point; return 1 if error if calFreqPoints>=calMaxFreqPoints then calAddFreqPoint=1: exit function calFreqPoints=calFreqPoints+1 calFreqTable(calFreqPoints,0)=f calFreqTable(calFreqPoints,1)=db calAddFreqPoint=0 'No error end function '@calSortMag sub calSortMag 'Sort mag cal table in ascending order of ADC reading sort calMagTable(),1, calMagPoints,0 end sub '@calSortFreq sub calSortFreq 'Sort freq cal table in ascending order of frequency. sort calFreqTable(),1, calFreqPoints,0 end sub 'SEWcal created calCreateMagCubicCoeff sub calCreateMagCubicCoeff 'Create table of cubic coefficients for mag cal table 'Each entry of the mag coefficient table will have 8 numbers. 0-3 are the A,B,C,D 'coefficients for interpolating the real part; 4-7 are for the imag part. for i=1 to calMagPoints 'First do mag 'Signal that this is not an angle, and not to "favor flat", because 'we expect the db as a function of ADC to become vertical near the ends. partNum=1 : favorFlat=0 : isAngle=0 call calMagOrFreqCoeff 0,i,partNum,isAngle,favorFlat,A,B,C,D calMagCoeffTable(i,0)=A :calMagCoeffTable(i,1)=B calMagCoeffTable(i,2)=C :calMagCoeffTable(i,3)=D 'Next do phase 'Signal that this is an angle, and to "favor flat", because 'we expect the phase correction as a function of ADC to be fairly flat. partNum=2 : favorFlat=1 : isAngle=1 call calMagOrFreqCoeff 0,i,partNum,isAngle,favorFlat,A,B,C,D calMagCoeffTable(i,4)=A :calMagCoeffTable(i,5)=B calMagCoeffTable(i,6)=C :calMagCoeffTable(i,7)=D next i end sub 'SEWcal created calCreateFreqCubicCoeff sub calCreateFreqCubicCoeff 'Create table of cubic coefficients for mag cal table 'Each entry of the freq coefficient table will have 4 numbers. 0-3 are the A,B,C,D 'coefficients for interpolating the frequency power correction, which is a scalar. for i=1 to calFreqPoints 'Signal that this is not an angle, and to "favor flat", because 'we expect the freq response not to become near-vertical partNum=1 : favorFlat=1 : isAngle=0 call calMagOrFreqCoeff 1,i,partNum,isAngle,favorFlat,A,B,C,D calFreqCoeffTable(i,0)=A :calFreqCoeffTable(i,1)=B calFreqCoeffTable(i,2)=C :calFreqCoeffTable(i,3)=D next i end sub 'SEWcal created calMagOrFreqCoeff sub calMagOrFreqCoeff calTable, pointNum, partNum, isAngle, favorFlat,byref A,byref B,byref C,byref D 'Calculate the cubic interpolation coefficients to apply to a point 'lying between (possibly including) points pointNum-1 and pointNum of 'the calibration table specified by calTable (0=mag; 1=freq). 'partNum=1 to process real part and =2 to process imag part. 'If isAngle=1 then we are interpolating an angle, otherwise not. 'The coefficients will approximate y values in the interval from pointNum-1 to pointNum 'as a cubic equation, such that it passes through the endpoints with the desired slope. 'To determine the desired slope, we use the points to the left and right of the interval. 'This gives us four points, 0-3, of which pointNum is number 2. The interval in which data 'will be interpolated with these coefficients is from point 1 to point 2. We determine what ' slopes we want at the endpoints and then fit a cubic equation to the interval. In ' general, at each point we want the curve on each side to have a common slope equal ' to some sort of average of the interval slopes on each side. We do a straight ' arithmetic average, except that if favorFlat=1 then we average the inverses of the ' slopes and invert that average. The latter tends to make the averaged slope flatter, ' which is useful to avoid overshoot/undershoot. ' Assume the cubic function ' y=A + B(x-x2) + C(x-x2)^2 + D(x-x2)^3 ' passes through points (x1, y1) and (x2, y2), with f12 then x0=calMagTable(pointNum-2,0) : y0=calMagTable(pointNum-2,partNum) if pointNum2 then x0=calFreqTable(pointNum-2,0) : y0=calFreqTable(pointNum-2,partNum) if pointNum200+y3 then y3=y3+360 if y2b<-90 and y3>200+y2b then y2b=y2b+360 end if if y2a<-90 and y1b>200+y2a then y2a=y2a+360 if y1b<-90 and y2a>200+y1b then y1b=y1b+360 if pointNum>2 then if y1a<-90 and y0>200+y1a then y1a=y1a+360 if y0<-90 and y1a>200+y0 then y0=y0+360 end if end if '(4) Find m1, the desired slope of the cubic at point 1 if pointNum>2 then if x0=x1 then inSlope=0 'should not happen else inSlope=(y1a-y0)/(x1-x0) 'slope from point 0 to point 1 end if else inSlope=(y2a-y1b)/(x2-x1) 'slope from point 1 to point 2 end if outSlope=(y2a-y1b)/(x2-x1) 'slope from point 1 to point 2 prod=inSlope*outSlope if prod <=0 then 'if slope on either side is zero, or is positive on one side 'and negative on the other, we want a zero slope m1= 0 else 'Calculate an average slope for point 1 based on connecting lines 'We average the inverses of the slopes, then invert m1= 2*prod/(inSlope+outSlope) end if '(5) Find m2, the desired slope of the cubic at point 2 inSlope=outSlope 'slope from point 1 to point 2 if pointNum200+I2 then I2=I2+360 if I1<-90 and I2>200+I1 then I1=I1+360 ang=I1+ratio*(I2-I1) if ang>180 then ang=ang-360 else if ang<=-180 then ang=ang+360 p2=ang else p2=I1+ratio*(I2-I1) end if end sub 'SEW8 revised entire calBinarySearch to eliminate recursion '@calBinarySearch function calBinarySearch(dataType, searchVal) 'Perform search to find the lowest entry whose lookup value is >=searchVal 'If dataType=0 then the lookup is for ADC value in calMagTable; otherwise it is for freq in in calFreqTable 'Uses primarily a binary search with recursive calls. When initially called, bot should equal 1 'and top should equal calFreqPoints; these mark the bounds of the entries to be searched. 'If searchVal is beyond the highest entry, we will return top+1 if dataType=0 then nPoints=calMagPoints else nPoints=calFreqPoints top=nPoints bot=1 span=top-bot+1 while span>4 'Do preliminary search to narrow the search area halfSpan=int(span/2) mid=bot+halfSpan if dataType=0 then thisVal=calMagTable(mid,0) else thisVal=calFreqTable(mid,0) if thisVal=searchVal then calBinarySearch=mid : exit function 'exact hit if thisVal= entry bot-1 but <= entry top, and we have a span of less than 4 'Start with bot entry and find first entry >= searchVal ceil=bot if dataType=0 then thisVal=calMagTable(ceil,0) else thisVal=calFreqTable(ceil,0) if thisVal>=searchVal then calBinarySearch=ceil : exit function ceil=ceil+1 : if ceil>nPoints then calBinarySearch=ceil : exit function if dataType=0 then thisVal=calMagTable(ceil,0) else thisVal=calFreqTable(ceil,0) if thisVal>=searchVal then calBinarySearch=ceil : exit function ceil=ceil+1 : if ceil>nPoints then calBinarySearch=ceil : exit function if dataType=0 then thisVal=calMagTable(ceil,0) else thisVal=calFreqTable(ceil,0) if thisVal>=searchVal then calBinarySearch=ceil : exit function calBinarySearch=ceil+1 'searchVal is off the top of the table end function 'SEWcal modified calConvertMagPhase sub calConvertMagPhase magdata, wantPhase, byref magDB, byref phaseCorrect 'This function returns the magnitude (magDB) and the phase correction (phaseCorrect) 'based on the ADC signal strength reading magdata. The phase correction is returned 'only if wantPhase=1; otherwise zero is returned. 'It uses cubic interpolation on the calibration entries of calMagTable. 'Note: calMagTable is organized with the smallest ADC values first 'SEW8 revised call to calBinarySearch index=calBinarySearch(0,magdata) 'search calMagTable 'index now is the first entry >= magdata, except that if no entry meets that test, 'index will be one past the end. phaseCorrect=0 if index>calMagPoints then 'Off top end;use largest mag and phase correction for largest ADC entry magDB=calMagTable(calMagPoints,1) phaseCorrect=calMagTable(calMagPoints,2) exit sub end if if index=1 then 'Off bottom end;use mag and phase correction for smallest ADC entry magDB=calMagTable(1,1) phaseCorrect=calMagTable(1,2) exit sub end if 'Evaluate cubic at x=magdata dif=magdata-calMagTable(index,0) A=calMagCoeffTable(index,0) : B=calMagCoeffTable(index,1) C=calMagCoeffTable(index,2) : D=calMagCoeffTable(index,3) magDB = A+dif*(B+dif*(C+dif*D)) if wantPhase=1 then A=calMagCoeffTable(index,4) : B=calMagCoeffTable(index,5) C=calMagCoeffTable(index,6) : D=calMagCoeffTable(index,7) phaseCorrect = A+dif*(B+dif*(C+dif*D)) if phaseCorrect<=-180 then phaseCorrect=phaseCorrect+360 'ver113-7e if phaseCorrect>180 then phaseCorrect=phaseCorrect-360 'ver113-7e end if end sub 'SEWcal modified calConvertFreqError function calConvertFreqError(freq) 'Find power correction for frequency error contribution. 'needed: datatable, frequency error calibration table; creates average freqerror 'This routine uses cubic interpolation on calFreqTable to determine the frequency 'error for thisfreq. The calibration table consists of entries numbered from 1, each 'containing a frequency and the error at that frequency. The entries must be in order of 'increasing, with the first entry being the lowest frequency. If the frequency is less than the 'first entry, or greater than the final entry,the error for that entry will be used. 'The final entry need not be for the maximum possible frequency. 'SEW8 revised call to calBinarySearch index=calBinarySearch(1,freq) 'Search calFreqTable 'index now is the first entry >= freq, except that if no entry meets that test, 'index will be one past the end. if index>calFreqPoints then _ calConvertFreqError=calFreqTable(calFreqPoints,1): exit function 'use largest value if index=1 then _ calConvertFreqError=calFreqTable(1,1): exit function 'Use smallest value '(5)Evaluate cubic at x=magdata dif=freq-calFreqTable(index,0) A=calFreqCoeffTable(index,0) : B=calFreqCoeffTable(index,1) C=calFreqCoeffTable(index,2) : D=calFreqCoeffTable(index,3) calConvertFreqError = A+dif*(B+dif*(C+dif*D)) end function '@calCreateDefaults sub calCreateDefaults pathNum, editor$, doPoints 'Create default data in file or text editor. 'if editor$<>"", it contains the destination text editor; otherwise we do a file, 'which replaces any existing file. For a file, we assume any necessary folders exist. 'If pathNum=0 we create a freq cal file; othwerwise a mag cal file for path pathNum 'if doPoints=1 we create two data points; otherwise no points if editor$="" then doFile=1 open calFilePath$()+calFileName$(pathNum) for output as #calOut editor$="#calOut" else doFile=0 #editor$, "!cls" 'Clear existing data in text editor end if 'Start with comments if pathNum=0 then 'Freq c1$="Calibration over frequency" c2$="Calibrated " + Date$("mm/dd/yy") + " at -zz dbm." else 'Mag c1$="Path"+str$(pathNum)+" CenterFreq= xxx; Bandwidth=yyy" c2$="Calibrated " + Date$("mm/dd/yy") + " at zz MHz." end if calFileComments$(1)=c1$ : calFileComments$(2)=c2$ 'Save comments in our array print #editor$, calFileCommentChar$+c1$ print #editor$, calFileCommentChar$+c2$ 'print comments print #editor$, "CalVersion=";using("##.##", calModuleVersion) if pathNum=0 then print #editor$, "FreqTable=" print #editor$, calFileCommentChar$+" MHz db in increasing order of MHz" if doPoints=1 then print #editor$, "0 0" print #editor$, "1000 0" end if else print #editor$, "MagTable=" print #editor$, calFileCommentChar$+" ADC dbm in increasing order of ADC" if calDoPhase=1 then p$=" 0" else p$="" if doPoints=1 then print #editor$, "4850 -120" 'Numbers from Verif. unit, narrow filter print #editor$, "4900 -110" print #editor$, "5500 -100" print #editor$, "7600 -90" print #editor$, "23600 -30" print #editor$, "26300 -20" print #editor$, "29100 -10" print #editor$, "31400 0" end if end if 'For now, we don't use the EndCalFile tag, and don't require it on input either 'print #editor$, "EndCalFile=" if doFile then close #calOut end sub '@calManAvailableFiles function calAvailableFiles$() 'Return string indicating which cal files exist 'Returned string will have only as many characters as needed to flag existing files. 'The first is for the frequency cal file. 'The Nth character, for N=1 to 41, relates to the (N-1)th mag cal file. If the file exists, 'the character is 1; otherwise the character is 0. p$=calFilePath$() sLen=0 'This will be length needed to handle all the files we have files p$, "MSA_CalFreq.txt", calFileInfo$() if calFileInfo$(0,0)<>"0" then s$="1" 'enter 1 if freq file exists; else 0 sLen=1 else s$="0" end if files p$, "MSA_CalPath*.txt", calFileInfo$() 'search for mag cal files numFiles=val(calFileInfo$(0,0)) for j=1 to 40 'Test for 40 possible file numbers j$=str$(j)+".txt" thisFlag$="0" for i=1 to numFiles n$=calFileInfo$(i,0) n$=Mid$(n$,12) 'get name without "MSA_CalPath" if j$=n$ then thisFlag$="1": sLen=j+1: exit for next i s$=s$+thisFlag$ 'append a 1 if this file exists; 0 otherwise next j 'We have determined that we need no more than sLen characters; all 'the extras would be 0. calAvailableFiles$=Left$(s$,sLen) end function '@calInstallFile sub calInstallFile pathNum 'Open cal file and load data. Create folder and file if necessary 'If pathNum=0 we want a freq cal file; otherwise a mag cal file for path pathNum 'Find out whether the necessary folders exist for config and calibration 'information. If no proper cal file exists, then create one with 'default values, but ask user before replacing an existing file 'SEWcal Also calculates cubic interpolation coefficients for the newly loaded file 'Create the name of the desired file fileName$=calFileName$(pathNum) 'See if we have the folder MSA_Info files DefaultDir$, "", calFileInfo$() numFolders=val(calFileInfo$(0,1)) haveFolder=0 for i=1 to numFolders if calFileInfo$(i,1)="MSA_Info" then haveFolder=1: exit for next i 'Create folders and file if necessary, or just open file if haveFolder=0 then 'Create MSA_Info folder if 0<>mkDir("MSA_Info") then notice "Cannot access files." end if 'We have the MSA_Info folder. See if we have MSA_Cal folder files DefaultDir$+"\MSA_Info", "", calFileInfo$() numFolders=val(calFileInfo$(0,1)) haveFolder=0 for i=1 to numFolders if calFileInfo$(i,1)="MSA_Cal" then haveFolder=1: exit for next i if haveFolder=0 then 'Create MSA_Cal folder if 0<>mkDir("MSA_Info\MSA_Cal") then notice "Cannot access files." end if 'We have the MSA_Info\MSA_CAL folder. See if it has proper file files calFilePath$(), fileName$, calFileInfo$() if calFileInfo$(0,0)="0" then call calCreateDefaults pathNum, "",1 'No file. Create one. end if 'Get data from file fErr$=calLoadFromFile$(pathNum) if fErr$<>""then 'File is there, but has a problem Confirm "File error: "+fErr$+"; Replace with default file?"; response$ if response$="no" then notice "File not replaced. Internal cal data cleared." call calClearComments if pathNum=0 then call calClearFreqPoints else call calClearMagPoints exit sub end if call calCreateDefaults pathNum, "", 1 'Try once more. Any error now is a system error if ""<>calLoadFromFile$(pathNum) then notice "Cannot access file" : exit sub end if if calFileVersion>calfigModuleVersion then _ notice "Warning: Calibration file format is later version than the sofware" 'Here we should update the file if calFileVersion is old. But at this 'time we have no old file versions 'SEWcal Calculate interpolation coefficients for this file if pathNum=0 then call calCreateFreqCubicCoeff else call calCreateMagCubicCoeff end sub '@calSaveToFile sub calSaveToFile pathNum 'Save to file 'Save a cal file for path number pathNum. We assume the necessary 'folders are already in place 'If pathNum=0 we are dealing with a freq cal file. 'File output replaces any existing file of the same name. 'calFileComments$() are placed at the beginning of the file, marked 'with calFileCommentChar$ calFile$=calFilePath$() + calFileName$(pathNum) open calFile$ for output as #outFile startLine=1 call calOutputData "#outFile", 1 ,pathNum,startLine close #outFile end sub '@calSaveToEditor sub calSaveToEditor editor$, pathNum 'Save to text editor 'Save variables and point array into text editor, in same format as a file 'calFileComments$() are placed at the beginning of the data, marked 'with calFileCommentChar$ startLine=1 call calOutputData editor$, 0 ,pathNum,startLine #editor$, "!select 1,1" #editor$, "!copy" : #editor$, "!paste" 'This scrolls the window to the top end sub '@calOutputData sub calOutputData calFile$, isFile, pathNum, byRef startLine 'Output data to file or text editor 'Save data as a frequency cal file. Replaces any existing file. 'The data is sent to a file already opened, whose handle is in calFile$ 'or from a text editor whose handle is in calFile$. The type of source is 'indicated by isFile (1 for file, 0 for textEditor). 'calFileComments$() are placed at the beginning of the file, marked 'with calFileCommentChar$ 'We update startLine to one past the last line we write 'Start with comments for i=1 to 2 com$=calFileComments$(i) if com$<>"" then print #calFile$, calFileCommentChar$+com$ next i print #calFile$, "CalVersion=";using("##.##", calModuleVersion) if pathNum=0 then print #calFile$, "FreqTable=" print #calFile$, calFileCommentChar$+" MHz db in increasing order of MHz" for i=1 to calFreqPoints f=calFreqTable(i,0) 'this line sometimes causes floating exception error f$=using ("####.######", calFreqTable(i,0)) v$=using ("####.##", calFreqTable(i,1)) print #calFile$, f$;" ";v$ 'output data line next i else print #calFile$, "MagTable=" if calDoPhase=0 then print #calFile$, calFileCommentChar$+" ADC dbm in increasing order of ADC" else print #calFile$, calFileCommentChar$+" ADC dbm Phase in increasing order of ADC" end if for i=1 to calMagPoints adc$=using ("#######", calMagTable(i,0)) v$=using ("####.##", calMagTable(i,1)) p$=using ("####.##", calMagTable(i,2)) if calDoPhase=0 then print #calFile$, adc$;" ";v$ 'output data line else print #calFile$, adc$;" ";v$;" ";p$ 'output data line end if next i end if 'For now, we don't print the end tag, nor do we require it on input 'print #calFile$, "EndCalFile=" end sub '@calOpenFile$ function calOpenFile$(pathNum) 'Open calibration file for path number pathNum; return its handle 'if pathNum=0 then we want freq cal file 'If file does not exist, return "". fName$=calFileName$(pathNum) On Error goto [noFile] open fName$ for input as #calFile calOpenFile$="#calFile" exit function [noFile] fName$="" calOpenMagFile$="" end function '@calFileName$ function calFileName$(pathNum) 'Return file name for the specified pathNum 'If pathNum=0 we want the freq cal file; otherwise mag cal for path number pathNum if pathNum=0 then calFileName$="MSA_CalFreq.txt" else calFileName$="MSA_CalPath" + str$(pathNum) + ".txt" end if end function '@calFilePath$ function calFilePath$() 'Return path name for cal files, ending in "\" calFilePath$=DefaultDir$ + "\MSA_Info\MSA_Cal\" end function '@calLoadFromEditor$ function calLoadFromEditor$(editor$,pathNum) 'Read data from text editor. Return error message 'editor$ is the handle of the text editor. We also sort. startLine=1 : isFile=0 fErr$=calReadFile$(editor$,isFile,pathNum,startLine) if pathNum=0 then call calSortFreq else call calSortMag calLoadFromEditor$=fErr$ if pathNum<>0 then finalfreq=MSAFilters(pathNum, 0) : finalbw=MSAFilters(pathNum, 1) 'SEW7 made conditional end function '@calLoadFromFile$ function calLoadFromFile$(pathNum) 'Open and read file. Return error message 'This is called only after we know the file exists fileName$=calFilePath$() + calFileName$(pathNum) open fileName$ for input as #calIn startLine=1 : isFile=1 calLoadFromFile$=calReadFile$("#calIn",isFile,pathNum,startLine) close #calIn if pathNum<>0 then finalfreq=MSAFilters(pathNum, 0) : finalbw=MSAFilters(pathNum, 1) 'SEW7 made conditional end function '@calReadFile$ function calReadFile$(calFile$, isFile, pathNum, byRef startLine) 'Reads calibration data, starting at line startLine and continuing until 'we find the tag "EndCalFile=" (case insensitive). We update startLine 'to one past the line containing that tag. 'If pathNum=1... we read magnitude calibration data for a 'particular signal path. There is one path for each RBW filter. if pathNum=0 then 'we read frequency calibration data, for which there is only one data set. 'The data is read from a file already opened, whose handle is in calFile$ 'or from a text editor whose handle is in calFile$. The type of source is 'indicated by isFile (1 for file, 0 for textEditor). 'The data is in the following format; comments are allowed and are marked 'by calFileCommentChar$. First two comment lines preceding tags are put into calFileComments$ 'Each data tag ends with "=", and is case insensitive. '---Magnitude calibration file format--- 'VERSION=xxx 'Version of the module that wrote the file 'MagTable= 'Start of magnitude cal data; no data on this line 'xxxx xxxx 'Up to calMaxMagPoints lines of data pairs: ADC reading(increasing) and mag(db) 'xxxx xxxx 'Table is put into calMagTable, with ADC reading as x value 'ENDCALFILE= 'marks end of data ' '---Frequency calibration file format--- 'VERSION=xxx 'Version of the module that wrote the file 'FreqTable= 'Start of frequency cal data; no data on this line 'xxxx xxxx 'Up to to calMaxPoints lines of data pairs:frequency(MHz)(increasing) and magitude(db) 'xxxx xxxx 'Table is put into calFreqTable with frequency as x value 'ENDCALFILE= 'marks end of data '---end of file formats ' 'The number of entries in calMagTable is put into calMagPoints 'The number of entries in calFreqTable is put into calFreqPoints 'If error, we return a string describing the error 'If no error, we return "" doMag=0 '=1 while we are processing mag cal data doFreq=0 '=1 while we are processing freq cal data 'didName=0: didBW=0: didFreq=0 'SEW7 deleted if pathNum>0 then 'Reset number of points call calClearMagPoints else call calClearFreqPoints end if ncalFileComments=0:accumComments=1 calFileComments$(1)="": calFileComments$(2)="" if isFile=0 then #calFile$, "!lines nLines" else nLines=100000 prevXVal=-100000 'SEW7; Used to check for increasing values p$="Path "+str$(pathNum)+": " 'For error messages for fileLine=startLine to nLines 'Loop until we reach nLines (if text editor) or end of file (if file) if isFile then if EOF(#calFile$)<>0 then exit for Line Input #calFile$, tLine$ 'Read one line else print #calFile$, "!line ";fileLine;" tLine$" 'Get line number fileLine end if startLine=startLine+1 'one past where we are tLine$=Trim$(tLine$) 'drop extra blanks startChar$=Left$(tLine$,1) 'first real character of line if startChar$=calFileCommentChar$ then isComment=1 else isComment=0 if isComment or startChar$="" then 'Save first two comment lines, w/0 the comment character if accumComments and isComment and ncalFileComments<2 then ncalFileComments=ncalFileComments+1 calFileComments$(ncalFileComments)=Mid$(tLine$,2) end if else 'valid non-comment line accumComments=0 'no more comments put into calFileComments$$ equalPos=instr(tLine$,"=") 'equal sign marks end of tag if equalPos<>0 then 'Equal sign found tag$=Upper$(Left$(tLine$, equalPos-1)) item$=Mid$(tLine$, equalPos+1) 'stuff after equal sign commentPos=instr(item$, calFileCommentChar$) if commentPos>0 then item$=Left$(item$, commentPos-1) 'drop comments item$=Trim$(item$) doMag=0: doFreq=0:isErr=0 select case tag$ case "CALVERSION" if val(item$)>calModuleVersion then _ calReadFile$="Warning: "+p$+"File format is later version than the sofware" case "MAGTABLE" if pathNum=0 then isErr=1 else doMag=1 case "FREQTABLE" if pathNum>0 then isErr=1 else doFreq=1 case "ENDCALFILE" 'This marks the end of the file 'SEW7 deleted check to see that data points existed calReadFile$="" 'no error exit function case else isErr=true end select if isErr then calReadFile$=p$+"Line "+str$(fileLine):exit function 'invalid tag else 'No equal sign; must be data 'Now retrieve the numbers from this data line. There will always 'be at least two numbers; for mag calibration of VNA there may also be phase. 'Numbers are separated by comma, tab or space delims$=" ," + chr$(9) 'space, comma and tab are delimiters isErr=uExtractNumericItems(2, tLine$, delims$,data1, data2, data3) 'If not numeric, signal error if isErr=1 then calReadFile$=p$+"Line "+str$(fileLine): exit function if doMag then calMagDataHadPhase=0 if tLine$<>"" then 'If there is data left, we must have a third number isErr=uExtractNumericItems(1, tLine$, delims$,data3, data4, data5) if isErr=1 then calReadFile$=p$+"Line "+str$(fileLine): exit function calMagDataHadPhase=1 else data3=0 end if end if 'SEWcal2 modified the next approx 17 lines to eliminate 'duplicate entries in some cases. ver113-7g skipData=0 if data1<=prevXVal then 'SEWcal2 created this if...else block 'Data in file must have increasing x values; in text editor we let it slide 'If we have absolutely identical entries, we skip the duplicates. if data1=prevXVal and data2=prevY1 and data3=prevY2 then skipData=1 else if isFile=1 then calReadFile$=p$+"Line "+str$(fileLine): exit function 'not increasing end if end if prevXVal=data1 : prevY1=data2 : prevY2=data3 'SEWcal2 tooMany=0 if doMag then 'Add mag point; quit if error (i.e. too many points) if skipData=0 then tooMany=calAddMagPoint(data1, data2, data3) 'SEWcal2 else 'Add frequency point if skipData=0 then tooMany=calAddFreqPoint(data1, data2) 'SEWcal2 end if if tooMany=1 then calReadFile$=p$+"Line "+str$(fileLine)+"; Too many points.": exit function end if end if 'end of processing non-comment line next fileLine 'We can only get here if we did not find the EndCalFile tag, which is really 'only needed if this file is embedded in another. So for now we let it go. 'calReadFile$="Proper end of data not found." calReadFile$="" end function '@=================End Mag/Freq Calibration Module=================== '@=================End Calibration Manager Module=================== ' ' '--SEW Added the following module to provide utility routines used by other modules ' '==========================UTILITIES MODULE=========================================== 'Utilities Module Version 1.01 ' ' This module contains miscellaneous math and text processing routines 'sub uInitFirstUse 'call before using other routines 'function uRadsPerDegree() 'Return radians per degree 'function uDegreesPerRad() 'Return degrees per radan 'function uPi() 'Return Pi 'function uNatLog10() 'Return natural log of 10 'function uE() 'Return e, the base of nat log system 'function uSafeLog10(aVal) 'Return base 10 log of aVal; special rule for non-positive arguments 'function uLog10(aVal) 'Return base 10 log of aVal; special rule for non-positive arguments 'function uRoundDown(x) 'Round to integer<= x. -2.1 rounds to -3 'function uRoundUp(x) 'Round to integer>= x. -2.1 rounds to -2 'function uTenPower(pow) 'Raise 10 to power pow; avoid hangup if pow is large integer 'function uPower(x,pow) 'Raise x to power pow; avoid hangup if pow is large integer 'function uATan2(r, i) 'Return angle (degrees) of r+j*i whose tangent is i/r 'function uIsNumeric(data$) 'Returns 1 if data seems valid numeric 'function uRepeat$(s$, n) 'Return s$ repeated n times 'function uExtractTextItem$(byref data$,delim$) 'Remove and return first delimited item from data$ 'function uExtractNumericItems(nItems, byref data$, delims$, byRef val1, byref val2, byref val3) 'function uExtractDataItem$(byref data$, delims$) 'Remove and return first delimited item ' ----Format numbers as string 'function uFormatByDig$(v, maxWhole, maxDec, maxSig) 'Format v based on numbers of allowed digits 'function uFormatted$(v, form$) 'Format vbased on form$ 'sub uGetMultiplier byref v, byref mult$ 'Return appropriate multiplier and scale v global uKRadsPerDegree, uKDegreesPerRad, uKPi, uKE, uKNatLog10 'Constants sub uInitFirstUse 'call before using other routines uKRadsPerDegree=0.0174532925199433 uKDegreesPerRad=57.2957795130823 uKPi=3.14159265358979 uKNatLog10=log(10) uKE=exp(1) end sub function uRadsPerDegree() 'Return radians per degree uRadsPerDegree=uKRadsPerDegree end function function uDegreesPerRad() 'Return degrees per radan uDegreesPerRad=uKDegreesPerRad end function function uPi() 'Return Pi uPi=uKPi end function function uNatLog10() 'Return natural log of 10 uNatLog10=uKNatLog10 end function function uE() 'Return e, the base of nat log system uE=uKE end function function uSafeLog10(aVal) 'Return base 10 log of aVal; special rule for non-positive arguments if aVal<=0.00001^4 then 'Might be negative due to rounding; avoid crazy values uSafeLog10=-20 else uSafeLog10=log(aVal)/uKNatLog10 'Nat log divided by nat log of 10 end if end function 'SEWcal2 deleted uLog10, which was the same as uSafeLog10 'delver113-7gfunction uLog10(aVal) 'Return base 10 log of aVal; special rule for non-positive arguments 'delver113-7g if aVal<=0.00001^4 then 'Might be negative due to rounding; avoid crazy values 'delver113-7g uLog10=-20 'delver113-7g else 'delver113-7g uLog10=log(aVal)/uKNatLog10 'Nat log divided by nat log of 10 'delver113-7g end if 'delver113-7gend function function uRoundDown(x) 'Round to integer<= x. -2.1 rounds to -3 if x>=0 then uRoundDown=int(x) else if int(x)=x then uRoundDown=x else uRoundDown=int(x-1) end if end function function uRoundUp(x) 'Round to integer>= x. -2.1 rounds to -2 if x>=0 then if int(x)=x then uRoundUp=x else uRoundUp=int(x+1) else uRoundUp=int(x) end if end function 'SEWcal2 added uRoundUpToMultiple 'ver113-7g ' RoundUpToMultiple--Round up to next higher multiple of mult if value ' is not already a multiple of mult. E.g. if mult=5 then ' 3.2-->5 -3.2-->0 function uRoundUpToMultiple(X ,mult) 'ver113-7g div = uRoundUp(X / mult) '3.2-->1 -3.2-->0 uRoundUpToMultiple = div * mult '3.2-->5 -3.2-->0 end function 'SEWcal2 added uRoundDownToMultiple 'ver113-7g ' uRoundDownToMultiple--Round down to next lower multiple of mult if value ' is not already a multiple of mult. E.g. if mult=5 then ' 3.2-->0 -3.2-->-5 function uRoundDownToMultiple(X, mult) 'ver113-7g div = uRoundDown(X / mult) '3.2-->0 -3.2-->-1 uRoundDownToMultiple = div * mult '3.2-->0 -3.2-->-5 end function 'SEWcal2 added uRoundUpToPower 'ver113-7g ' uRoundUpToPower--Round up to next higher integral(+/-) power of base if value ' is not already a power of base. Negative numbers are rounded to an algebraically ' larger number ' E.g. if base is 10 then ' 50-->100 -50-->-10 0.5-->1 0.005-->0.01 function uRoundUpToPower(X ,base) 'Round up to power of base'ver113-7g if X = 0 then uRoundUpToPower = 0 : exit function if base <= 0 then uRoundUpToPower = X : exit function if X > 0 then absX = X else absX = 0-X / base end if pow = Log(absX) / Log(base) 'power=log of X, using base of "base" trunc = Int(pow) 'can reduce positive pow or increase negative pow If trunc <> pow and pow > 0 then trunc = trunc + 1 'It is possible for trunc to be off by one due to rounding errors 'in the log calculation. So we adjust if necessary ceil = base^trunc 'Should be >= absX but <= absX*base if ceil < absX then trunc = trunc + 1 else if ceil / base >= absX then trunc = trunc - 1 end if if X<0 then uRoundUpToPower=0-base^trunc else uRoundUpToPower=base ^ trunc end function 'SEWcal2 added uRoundDownToPower 'ver113-7g ' uRoundDownToPower--Round down to next lower integral(+/-) power of base if value ' is not already a power of base. Negative numbers are rounded as though ' positive, with the result then being negated ' E.g. if base is 10 then ' 50-->10 -50-->-10 0.5-->0.1 0.005-->0.001 function uRoundDownToPower(X, base) 'Round down to power of base 'ver113-7g if X = 0 then uRoundDownToPower = 0 : exit function if base <= 0 then uRoundDownToPower = X : exit function if X > 0 Then absX = X else absX = 0-X * base end if pow = Log(absX) / Log(base) 'power=log of X, using base of "base" trunc = Int(pow) 'can reduce positive pow or increase negative pow if trunc <> pow and pow < 0 then trunc = trunc-1 'It is possible for trunc to be off by one due to rounding errors 'in the log calculation. So we adjust if necessary flr = base^trunc 'Should be <= absX but >= absX/base if flr > absX then trunc = trunc - 1 else if flr * base <= absX then trunc = trunc + 1 end if if X<0 then uRoundDownToPower=0-base^trunc else uRoundDownToPower=base ^ trunc end function function uTenPower(pow) 'Raise 10 to power pow; avoid hangup if pow is large integer 'LB does not seem to use divide and conquer for large integral powers, 'so we force use of floating point math absPow=abs(pow) if absPow<5 then uTenPower=10^pow :exit function 'this covers most cases if int(pow)<>pow then uTenPower=10^pow :exit function uTenPower=10^(pow-0.1)*10^0.1 end function function uPower(x,pow) 'Raise x to power pow; avoid hangup if pow is large integer 'LB does not seem to use divide and conquer for large integral powers, 'so we force use of floating point math absPow=abs(pow) if absPow<5 then uPower=x^pow :exit function 'this covers most cases if int(pow)<>pow then uPower=x^pow :exit function uPower=x^(pow-0.1)*x^0.1 end function function uATan2(r, i) 'Return angle (degrees) of r+j*i whose tangent is i/r if r=0 then if i=0 then ang=0 else if i>0 then ang=90 else ang=-90 end if else ang = uKDegreesPerRad*atn(i/r) 'Gives angle between ±90 if r < 0 then if i < 0 then ang = ang - 180 else ang = ang + 180 end if 'Put angle within bounds; rounding may have put it outside if ang>180 then ang=ang-360 else if ang<=-180 then ang=ang+360 end if end if uATan2=ang end function function uIsNumeric(data$) 'Returns 1 if data seems valid numeric 'We don't check precisely. We check to be sure there is at least one digit, and 'no non-digits other than "-", "+", "." "E" or "e" 'An empty string will return 0 dataLen=len(data$):foundDig=0 for i=1 to dataLen thisChar$=Mid$(data$, i,1) if instr("0123456789", thisChar$) then foundDig=1 else if instr("+-.eE", thisChar$)=0 then uIsNumeric=0: exit function 'Bad character end if next uIsNumeric=foundDig 'True if we found a digit, otherwise false end function function uRepeat$(s$, n) 'Return s$ repeated n times r$="" while n>0: r$=r$+s$ : n=n-1 : wend uRepeat$=r$ end function function uExtractTextItem$(byref data$,delim$) 'Remove and return first delimited item from data$ 'Locates first delimited item in data$, returns it, and removes the item and the 'delimiter from data$. If delim$ is more than one character, the entire sequence is 'considered to be the required delimiter. Leading/trailing blanks are not removed. dataLen=len(data$) :pos=1 delimChar$=Left$(delim$,1) : delimLen=len(delim$) if dataLendataLen then uExtractTextItem$=data$ : data$="": exit function 'We now need to see if the full delimiter string is present delimFound=1 if delimLen>1 then if Mid$(data$,pos, delimLen)<>delim$ then delimFound=0 'full delimiter must be present end if item$=Left$(data$,pos-1) 'Our desired item is everything preceding the delimiter if delimFound=1 then data$=Mid$(data$, pos+delimLen) 'Remaining data is everything following the delimiter uExtractTextItem$=item$ exit function end if 'We get here if we found the first delimiter character but not the whole thing. 'We use recursion to keep searching data$=Mid$(data$, pos) 'chop off what we alredy have in item$, plus first delimiter character uExtractTextItem$=item$ + delimChar$+ uExtractTextItem$(data$, delim$) end function function uExtractNumericItems(nItems, byref data$, delims$, byRef val1, byref val2, byref val3) 'Removes first nItems (1-3) delimited items per uExtractDataItem$ 'Returns their values in item1$, item2$. Missing items are returned as "" 'Returns 1 if either item is blank or non-numeric if nItems<1 or nItems>3 then uExtractNumericItems=1: exit function uExtractNumericItems=0 'No error yet item1$=uExtractDataItem$(data$, delims$) if item1$="" or uIsNumeric(item1$)=0 then uExtractNumericItems=1: exit function val1=val(item1$) if nItems=1 then exit function item2$=uExtractDataItem$(data$, delims$) if item2$="" or uIsNumeric(item2$)=0 then uExtractNumericItems=1: exit function val2=val(item2$) if nItems=2 then exit function item3$=uExtractDataItem$(data$, delims$) if item3$="" or uIsNumeric(item3$)=0 then uExtractNumericItems=1 val3=val(item3$) end function function uExtractDataItem$(byref data$, delims$) 'Remove and return first delimited item 'Locates first item in data$, returns it, and removes from data$ the 'item and any successive delimiter characters up to the next non-delimiter 'Data is separated by any character in delims$. data$ may begin with spaces. 'Several delimiters in succession will be treated as one delimiter data$=Trim$(data$) :item$="" dataLen=len(data$) :pos=1 for i=1 to dataLen 'will continue until a delimiter is found thisChar$=Mid$(data$,pos,1) 'next character of data$ if instr(delims$,thisChar$)>0 then exit for pos=pos+1 next i 'pos is now the position of the first delimiter found, or dataLen+1 if none found uExtractDataItem$=Left$(data$,pos-1) 'Our desired item is everything preceding the delimiter if pos>=dataLen then data$="" : exit function 'Nothing except maybe delimiter left for further processing for i=pos+1 to dataLen 'will continue until a non-delimiter is found if instr(delims$,thisChar$)=0 then exit for pos=pos+1 thisChar$=Mid$(data$,pos,1) 'next character of data$ next i 'pos is now the position of the next data item, or possibly one past the end data$=Mid$(data$,pos) 'deletes everything preceding the next data item end function function uFormatByDig$(v, maxWhole, maxDec, maxSig) 'Return a formatted string for v 'maxWhole is the max number of whole digits allowed; maxDec is the max number of 'decimal digits. Both are limited to a max of 20, for sanity. Overriding maxDec is 'maxSig, the max number of total significant digits. maxSig only affects the number of 'decimal places; it does not force any whole digits to zero. 'If v is too big, we return scientific notation signv$="" if v<0 then signv$="-": v=0-v if v<0.00001^4 then uFormatByDig$="0": exit function 'zero and tiny values are "0" if maxWhole>20 then maxWhole=20 :if maxWhole<0 then maxWhole=0 if maxDec>20 then maxDec=20 :if maxDec<0 then maxDec=0 if maxSig<1 then maxSig=1 'First find the number of whole digits; for v<1 this will be zero or negative 'and will be the number of zeroes between the decimal point and the first significant digit nWhole=int(uLog10(v)) : if v>1 then nWhole=nWhole+1 'It is possible to be off by one due to rounding, so check it shiftv=v*0.1^nWhole 'This should make value: 0.1<=value<1 if shiftv>=1 then nWhole=nWhole+1 : shiftv=shiftv/10 if shiftv<0.1 then nWhole=nWhole-1: shiftv=shiftv*10 'We have now established nWhole if v>=1 then 'max decimal places is reduced if whole part uses up allowed sig dig maxDec=min(maxDec,max(0,maxSig-nWhole)) else 'for v<0, leading zeroes won't count as sig dig. We know how many there are, 'so we can figure out the extent to which maxSig limits maxDec sigDigForMaxDec=maxDec+nWhole 'We will have this many sig dig if we use maxDec decimal places if sigDigForMaxDec>maxSig then maxDec=maxDec-(sigDigForMaxDec>maxSig) end if if nWhole>maxWhole then 'Value is too big; use scientific notation with only a few significant digits f$=signv$+uFormatByDig$(shiftv*10, 2,3,4) uFormatByDig$=f$+"e"+str$(nWhole-1) exit function end if 'We now know how many whole and decimal places to use, except for one issue, arising from 'the fact that formatting involves rounding, which can create an extra digit. The total 'number of significant digits we plan to have is nWhole+maxDec. For numbers in the form '99999d * 10^N (N any integer), where the 9's fill nWhole+maxDec positions and the "d" is 'therefore the digit where we add the "5" to round, rounding will create an extra digit which 'messes up our previous calculations. For such numbers, shiftv is of the 'form 0.99999d. So if we round this off and get 1, we know we have a problem number, but we 'also know it rounds to an exact power of 10, so we can construct its string representation. roundFactor=0.5*0.1^(nWhole+maxDec) if roundFactor>=1 then 'This occurs only if the rounding factor would be added to a fractional v which doesn't 'have any digits until after the place where we would add the "5", and so we 'know it will produce zero even after rounding uFormatByDig$="0": exit function end if roundedShiftv=shiftv+roundFactor if roundedShiftv>=1 then 'SEWcal2 fixed this and the comment above regarding 0.99999d ver113-7g 'The value we need to represent is +/- 10^nWhole. 'If nWhole>=0 we want a 1 followed by nWhole zeros if nWhole>=0 then uFormatByDig$=signv$+"1"+uRepeat$("0",nWhole) : exit function 'If nWhole<0 we want a zero and decimal, then -1-nWhole zeroes, then the digit 1 uFormatByDig$=signv$+"0."+uRepeat$("0",-1-nWhole)+"1" exit function end if 'Create format string. Add 1 to nWhole in case of some overflow problem we didn't cover formatStr$=uRepeat$("#",max(0,nWhole)+1)+"."+uRepeat$("#",maxDec) f$=Trim$(using(formatStr$,v)) 'now we have to affix the sign and possibly a leading 0 if v<0 and maxWhole>0 and leadingZero=0 then f$="0"+f$ 'If whole dig allowed, use "0.xxxx" f$=signv$+f$ 'affix sign 'now we have to delete trailing zeroes from the fractional part if required decPos=instr(f$,".") lenF=len(f$) if decPos>0 then 'Do only if we have a decimal point for i=1 to 100 'Do until we are done endChar$=Right$(f$,1) if endChar$="." then uFormatByDig$=Left$(f$, lenF-1) : exit function 'Delete decimal and end if endChar$<>"0" then uFormatByDig$=f$ : exit function 'non-zero found; end f$=Left$(f$, lenF-1): lenF=lenF-1 'Delete zero and continue next end if uFormatByDig$=f$ end function 'SEWcal2 made many changes to uFormatted$ ver113-7g function uFormatted$(v, form$) 'Return formatted string for v, based on form$ 'form$ is a formatting string, which can be the usual ##.## style string 'for the using() function, or can be a series of three numbers separated 'by spaces or commas. The first is the max number of whole digits allowed, the second is the max number 'of decimal digits. The third is the max number of significant digits, which is used 'only to restrict the actual number of decimal places. 'Following the format specifier there may be additional info, in which case each 'item of info is separated from that before it by "//". Allowed info: 'Prefix=xxx Text to be prepended to formatted value 'Suffix=yyy Text to be appended to formatted value 'UseMultiplier This tag is present to use P,T,G,M,K,m,u,n,p or f to scale the number 'Scale=ddd value is multiplied by this scale value before formatting 'TrimUsing This tag signals to trim leading blanks and trailing decimal zeroes left by "using" function doUsing=1 'default; may change upperForm$=Upper$(form$) 'Upper case is used to search for tags 'See if we need to scale the number pos=instr(upperForm$,"SCALE=") if pos>0 then f2$=Mid$(form$, pos+6) 'Everything right of equal sign scale$=uExtractTextItem$(f2$,"//") scaleFactor=val(scale$) : if scaleFactor=0 then scaleFactor=1 v=v*scaleFactor end if 'See if we need to use a multiplier character if instr(upperForm$, "USEMULTIPLIER")>0 then 'check for UseMultiplier call uGetMultiplier v, mult$ 'Returns multiplier and scales v mult$=" "+mult$ 'prepend space to multiplier character, even if there is none end if if form$="" then f$="" 'No format provide so we will use str$() else if Left$(form$,1)="#" then 'form$ is in format needed for "using()", so use it directly f$=uExtractTextItem$(form$, "//") 'get everything up to double slash. f$=Trim$(f$) else 'Here the format must be a series of 3 numbers separated by spaces or commas. doUsing=0 'we won't use the using() function formText$=uExtractTextItem$(form$, "//") isErr=uExtractNumericItems(3, formText$, " ,", maxWhole, maxDec, maxSig) if isErr then doUsing=1 : f$="" 'Use str() if format is invalid end if upperForm$=Upper$(form$) 'Used to search for tags end if if doUsing=1 then 'format with the using() function or str$() function if f$="" then s$=str$(v) else s$=using(f$, v) if instr(upperForm$, "TRIMUSING")>0 then 'check for TrimUsing 'trim leading blanks and trailing decimal zeroes s$=Trim$(s$) : sLen=len(s$) decPos=instr(s$,".") if decPos>0 then 'If we have a decimal we have to trim trailing zeroes, and maybe the decimal for j=sLen to 1 step -1 'iterate back from end of string thisChar$=Mid$(s$, j, 1) if thisChar$<>"0" then 'keep going as long as we have zeroes 'j is now the position before the zeroes needing deletion if thisChar$="." then j=j-1 'Make j the position before the decimal s$=Left$(s$,j) 'Keep everything through the jth position end if next j end if end if else s$=uFormatByDig$(v, maxWhole, maxDec, maxSig) end if 'The number itself is now formatted 'Now see if a suffix or prefix is specified pre$="" : suf$="" pos=instr(upperForm$,"PREFIX=") if pos>0 then f2$=Mid$(form$, pos+7) 'Everything right of equal sign pre$=uExtractTextItem$(f2$,"//") end if pos=instr(upperForm$,"SUFFIX=") if pos>0 then f2$=Mid$(form$, pos+7) 'Everything right of equal sign suf$=uExtractTextItem$(f2$,"//") end if uFormatted$=pre$+s$+mult$+suf$ 'Put it all together end function 'SEWcal2 added uCompact$ ver113-7g function uCompact$(s$) 'Return s$ with all blanks deleted 'This is useful before using the val() function on user supplied data, 'because a space between a negative sign and the number causes val to produce zero. s2$="" : sLen=len(s$) for i=1 to sLen thisChar$=Mid$(s$,i, 1) if thisChar$<>" " then s2$=s2$+thisChar$ 'copy all but spaces next uCompact$=s2$ end function sub uGetMultiplier byref v, byref mult$ 'Return appropriate multiplier and scale v 'For example, this converts 2000 to 2 K. if v=0 then mult$="" : exit sub if v>=0 then absV=v else absV=0-v if absV>=1 then 'SEWcal2 changed >1 to >=1 and made other changes if absV<1000 then mult$="" : exit sub if absV<1000000 then mult$="K" : v=v/1000 : exit sub if absV<1000000000 then mult$="M" : v=v/1000000 : exit sub if absV<1000000000000 then mult$="G" : v=(v/1000000)/1000 : exit sub if absV<1000000000000000 then mult$="T" : v=(v/1000000)/1000000 : exit sub mult$="P" : v=v/100000^3 : exit sub else if absV>=0.001 then mult$="m" : v=v*1000 : exit sub if absV>=0.000001 then mult$="u" : v=v*1000000 : exit sub if absV>=0.000000001 then mult$="n" : v=(v*1000000)*1000 : exit sub if absV>=0.000000000001 then mult$="p" : v=(v*1000000)*1000000 : exit sub mult$="f" : v=v*100000^3 : exit sub end if end sub function uPrompt$(caption$, msg$, doYesNo, allowCancel) 'Post message and return user response 'yes and no are allowed or alternatively OK 'Cancel may be allowed with either 'msg$ is the message to post. caption$ is the caption of the message box 'Returns "yes", "no", "ok" or "cancel" 'This code is modified from LB Workshop calldll #user32, "MessageBeep", 0 as long, beepResult as boolean if doYesNo=0 then if allowCancel=1 then mbflags = 0 OR _MB_OKCANCEL else mbflags = 0 OR _MB_OK else if allowCancel=1 then mbflags = 0 OR _MB_YESNOCANCEL else mbflags = 0 OR _MB_YESNO end if calldll #user32, "MessageBoxA", 0 as long, msg$ as ptr, _ caption$ as ptr, mbflags as long, mbResult as long 'mbResult CODES: 1=ok 2=cancel 3=abort 4=retry 5=ignore 6=yes 7=no if mbResult=1 then uPrompt$="ok" : exit function if mbResult=2 then uPrompt$="cancel": exit function if mbResult=6 then uPrompt$="yes": exit function if mbResult=7 then uPrompt$="no": exit function end function '@=================End Utilities Module======================= 'Notes on PDM Calibration 'With PDM Cal at 200 MHz, the high degree cal point 'Inp Pwr, Raw 0, Raw 1 invdeg '-30 dBm 289.406, 108.695 179.29 deg '-40 dBm 291.274, 110.585 179.28 deg raw phase change due to Sam Atten Switch '-50 dBm 301.104, 120.308 179.29 deg 'With PDM Cal at 327 MHz, low degree cal point '-30 dBm 74.835, 253.947 179.12 deg '-40 dBm 78.032, 257.144 179.11 deg raw phase change due to Sam Atten Switch '-50 dBm 93.525, 272.635 179.11 deg 'With PDM Cal at 832 MHz, the high degree cal point 'Inp Pwr, Raw 0, Raw 1 invdeg '-30 dBm 275.398, 94.088 178.69 deg '-40 dBm 285.121, 103.805 178.68 deg raw phase change due to Sam Atten Switch '-50 dBm 320.899, 139.572 178.67 deg 'With PDM Cal at 950 MHz, low degree cal point '-30 dBm 68.929, 247.647 178.72 deg '-40 dBm 79.789, 258.512 178.72 deg raw phase change due to Sam Atten Switch '-50 dBm 120.686, 299.382 178.70 deg