'spectrumanalyzer.bas (and.tkn) 'Officially released as MSA_version 116 Rev 0, Release date 12-18-12 ' Any further change will be Beta MSA_version 117-xx.bas. '------------Changes and additions ------------ 'MSA_version 116 Release date 12-18-12 'Same as 116-4sLPT without any changes '116-4sLPT. Modified from version 116-4s 'fix Special Test LPT errors. Changes shown as '116-4sLPT. All are inside of [LPTportTest] '116-4s was released as the 9th beta '116-4s ' Change Revision to I ' Fixes regarding plane extension ' Rename FreqMode to freqBand ' Add automatic band selection, signalled by freqBand=0 ' Add ability to cycle through three trace colors in Stick modes. ' In Filter Analysis, allow insertion loss to be negative if there is actually gain ' When in stick modes, don't call gRestoreErasure after redrawing. '116-4r, 12-28-2011 ' tested with parallel LPT and USB to LPT, both 16 bit and 12 bit serial ADC's ' changes marked as 'ver116-4q ' Deleted all of the "if" and "else" in [StartSweep], dealing with creating the struct. for USB reading of the ADC's, and ' moved the structure assignments to the area, '------Start items for USB interface---------- ' Deleted the use of [Read22wSlimCBUSB]and[Read16wSlimCBUSB]. Replaced with [ReadADCviaUSB] ' Changes in [ReadMagnitude] and [ReadPhase] ' Modified [LPTportTest] to accomodate USB ' when using 12 bit, the default magnitude in the path cal table should be changed from 4095 to about half that, or, 2048 for +10 dBm '116-4q was released as the 8th beta '116-4q ' Change revision to H ' Change boolean to long in Windows API calls (but not USB driver calls). ' Adjust AutoWait box. ' Add call to CoInitialize to fix tooltip crash in File Dialog '116-4p was released as the 7th beta '116-4p ' Remove debug code for testing OSL ' Fix sig gen. It does not need to be in band. Whatever it is, we generate as LO3-LO2, LO3+LO2 or plain LO3, whichever ' one works for the given sgout. '116-4o ' Add Scotty changes for USB without control board, per his Lrev1 ' (Set-up the USB using the N bits rather than assuming none of them will ever change. They will if user plays with the LB code.) '116-4n ' Restore Reference to OSL. It is needed for Update Cal. ' Apply OSL even with series and shunt fixture--just create default values for the missing cal items. ' Change display of OSL data window to delete tiny values. ' OSLBandApplyFull, OSLApplyFull and OSLBaseApply are no longer be used. We always do full OSL. '116-4m ' Change revision to G ' Change some window text to use sans serif 9 rather than default values. ' Fix group delay calc in uBestFitLine ' Fix to CopyModeDataToVNAData to get freq correct ' Fix very original startup data type ' Fix MouseOver in Two Port. Various Two Port tweaks. ' Fix application of line cal Through delay ' Remove TwoPort Matrix multiply and invert, which were not used. ' When leaving Two Port, minimize array size only if we have no entries. ' 'Note: 116-4L was released as the 6th beta '116-4L ' Change revision to F ' Change text sizes in PDM cal ' When trace preference is loaded, set axis label to match trace color. ' Change some colors and text in interface windows. ' Move point at which phase is negated in 3G so it occurs after adjustment for PDM and difPhase. ' Fix LO3 calculation regarding use of baseFrequency ' 'Note: 116-4k was released as the fifth beta '116-4k ' Modify reference cal in Reflection mode so the Open or Short does not have to be ideal. ' When doing full OSL, treat all fixtures as Bridges. ' Fixes to interpolation of angles. In graph modules, angles are kept in the graph range. Elsewhere they ' are kept in the range -180 to +180. ' Fix Smith Chart interpolation to match method for main graph. This means the interpolated point may not quite ' match the graph on the Smith Chart, which linearly interpolates pixels. ' Round markers to integral point if they are manually placed very close to an integral point. ' Allow log sweeps to go to zero or negative, but only Y-axis can cross zero. ' Add baseFrequency, which gets added to the current frequency when commanding the hardware. ' Change Y pixel calculations for log scale to use gConvertYxToPix ' In Reflection mode, delete printing of bridge/series/shunt in the setup info. ' Add warning if number of steps exceeds 2000. Show hourglass after while calculating steps after restart. ' Relocate printing of sweep time so it does not immediately get erased by refresh action. ' In config manager, clarify listing of PLL types. For example, there is now an entry for 2326,4118 which ' includes both types, though internally it is still stored as simply 2326. ' Fix [CreateCmdAllArray]--last line got incorporated into a comment ' '116-4j ' Change revision to E ' When restoring VNA data in reflection mode, re-calculate all data derived from S11 ' We now set both S11BridgeR0 and S21JigR0 to the same value in reflection mode. When doing full OSL, the user does not choose the ' fixture type so we wouldn't know which one to set if we didn't set both. Certain routines refer to one or the other, ' depending on fixture type, but they will get the same value either way. ' Fixes to use of [RestoreVNAData] regarding application of R0 transform and plane extension. ' Adjust AutoWait to use max of mag and phase time constants ' Fix PLL configuration labels ' Fix crash when placing marker with Variables window open ' Turn RBW filter selection into subroutines, and call when necessary from DetectChanges. Previously, necessary ' recalculations were not always done when filter changed. Now we require [Restart] or do [PartialRestart]. ' Change Initial Cal so wait time is based on video time constants, and in Measure do a one-time [CommandCurrentStep] ' to be sure we are properly commanded per current path frequency. Otherwise we get messed up when ' changing paths. ' Make filter A0 and A1 into globals, renamed FiltA0 and FiltA1. ' Remove surplus code at end of sweep loop relating to haltAtEnd=0. It followed similar code that prevented ' it from ever being executed. ' Change mag cal to average fewer points gathered over a longer time. ' Add item in Initial Cal to allow user to force phase correction to a set value (normally 0 or 180) ' 'Note: 116-4i was posted as the fourth beta '116-4i ' Change OSL standards specs to use regular RLC specs. ' Add MouseOver to TwoPort window ' '116-4h ' Revise transmission mode RLC analysis to allow user choice as to whether to analyze notches at top or bottom. ' Modify latched switches for USB. ' When saving bitmaps with BMPSAVE, don't open and close file. ' Modify transmission mode RLC Analysis ' Add routine to calc RLC values from impedances at two frequencies ' Delete lossy inductor option from RLC analysis ' Add "mouse over" feature to show marker at current mouse frequency and allow setting of ' markers at that frequency from the keyboard. ' Fixes to doSpecialGraph so its phase does not get overridden by phase adjustments that apply to normal graphs. ' Add Default Graph option to Y-axis window ' '116-4g ' changed revision to D ' Clear markers when altering Two-Port data ' Revise transmission RLC analysis for notches to use points 3 dB above the notch. ' Clarify filter analysis instructions. ' Delete autoWaitSettlingTime routine; it is no longer used ' 'Note: 116-4f was posted as the third beta '116-4f ' When selecting video filter, be sure capacitor values are not zero ' When loading config file, be sure we have a Wide filter ' Don't initialize relays if suppressHardware=1 ' Move a USB command line from DDS3Track to DDS1Sweep ' '116-4e ' change revision to C ' Add latch numbers to latch enable pins in LPT tester. ' Fix filter analysis reference to #handle.g ' Fix [ReadStep] so phase is not read unnecessarily, and zero phase array if not doing phase. ' Fixes to selection of auto wait when auto wait is disabled. ' Change two port matching instructions. ' Fix axis ranges in Two Port when changing data types ' Save Two-Port params as .s2p rather than .s1p. ' Provide for single port matching in AutoMatch. Start Two-Port with default parameter values. ' 'Note: 116-4d was posted as the second beta version '116-4d ' Make changes so hardware initilization always occurs on [PartialRestart] unless ' suppressHardwareInitOnRestart is expressly set to 1. Set it to 1 only when ' hardware init is pointless and we want to save time. ' Fix uSaveFileDialog and uOpenFileDialog ' Add switchTR to sweep context for saving and restoring ' In display, abbreviate Sig Gen= to SG= ' '116-4c ' Changed Revision to B ' Fix reference to "handle" in Filter function ' Add Coaxial Cavity Sweep Test in Special Tests window 'Note: 116-4b was posted as beta software '116-4b ' Deleted option to graph Z parameters. Z parameters aren't that helpful. Instead, ' we have added the ability to graph S11 and S22 as impedance and other items. ' Moved Two Port module so it is above smith chart module. ' Add resizing to Two Port Window. ' Various improvements to Two Port module ' Deleted comments on version 115 changes. File got too big for LB Workshop. ' Add AutoMatch feature to Two-Port Window ' Add display of mouse info on Smith Chart when left button is down ' Allow trace widths of 0. ' Modify refresh at end of each scan ' Have functions and calibrations use AutoWait ' Delete commented-out code for GraphCoaxLossAndZ0 to get more file space. ' Fix to gGetCustomPresetColors ' When saving grid context, put LastPresets at end, after the options have been recorded. ' Add colors for two supplemental sets of traces: 1A, 2A, 1B and 2B ' Tie reference trace colors to the 1A and 2A colors. ' Don't set suppressHardware=1 if we have USB control board ' Show "Show Variables" menu item for basic MSA build ' Modify uOpenFileDialog to use up-to-date struct. Made no difference to occassional crash ' that occurs when tool tips are displayed the second time through. Turns out it only ' occurs when the target file (that mouse is hovering over) is on the desktop. '116-4a ' Change constDatatable to constModeData because it is not always data from datatable. ' Change touchWriteParameters to touchWriteOnePortParameters because it only writes a single parameter, ' and have it save data from VNAData as an intermediary rather than from specific scan data arrays. ' Various improvements to Two Port module ' Add ability to graph Z parameters in Two Port ' '116-3a ' Incorporate USB changes since 116-1b from Dave Roberts' version 116-1g ' ' USB:02-08-2010 USB:05/12/2010 ' USB:15/08/10 'USB:06-08-2010 '116-2a ' Reorganize order of routines to put them in logical groups ' Expand Two Port module to display performance with specified impedance matching. ' Scotty's changes to fix to use ADF4112. Changes marked '12-3-10 ' Fix uExtractDataItem so multiple delimiters are not deleted at once ' Adjust marker routines so markers work on Two Port Window '116-1b ' Add extra element to configControlBoards for cb=3 (USB) ' Change Data Window to display only the actual number of steps actually scanned. ' Physically select path filter in Calibration Manager ' Fix setup info so when reference line is turned off, no reference info is displayed. ' Change interpolation of path calibration so use of 180 degree phase correction to mark "phase invalid" ' does not mess up the interpolation. ' When saving graph or smith chart image, don't try to unload bitmap if operation cancelled. ' When Initial Cal Manager is invoked, do nothing if already running. ' Fix file saving when leaving Initial Cal Manager ' Fix saving of PLL1 and PLL2 in Configuration Manager ' Fix 12-bit ADC reading ' Add switching of video filter, band switch, forward/reverse and transmission/reflection switches. ' create validPhaseThreshold so PDM inversion is not done at low levels where phase is forced to zero. ' Add features for Auto Wait Time. ' Add TwoPort module ' change topref, botref, topphase,botphase to Y2Top, Y2Bot, Y1Top and Y1Bot ' Multiply raw phase by -1 in 3G mode ' Force sig gen to be in-band when mode is changed ' For doSpecialGraph=3(noisy sine), increase transmission values of dB ' Fix clearing of ReflectArray before installing a step of data--step 0 was always cleared. ' '116-1a ' Change Version to 116 and Revision to A ' USB test version 01/08/2010 copied from Dave Roberts ' all USB changes tagged with code "USB:date" ' so search for the string "USB:" to find changes ' Additional USB changes 02-08-2010 by S. Wetterlin '115-9f ' Change Revision to H ' Fix calc of power and voltage for graphing. '115-9e ' Change Revision to G ' When resizing window, don't require restart if sweep is not in progress. ' Fix display of Initial Cal Manager in non-VNA modes 'Note: 115-9d was released as Revision F '115-9d ' Add routines for front-end adjustments of SA readings. ' Fix saving of reflection Test Setups to include R0 '115-9c ' Change Revision to F. ' Adjust Zoom in crystal analysis. ' Change crystal Cm to fF and Lm to mH 'Note: 115-9b was released as Revision E. '--------------------------------------------------------------------------------------------- global msaVersion$, msaRevision$ 'Version and revision numbers of this release msaVersion$="116" 'ver116-1a msaRevision$="I" 'ver116-4s '-------------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 resetting 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 Y1Top, Y1Bot 'Top and bottom of Y1 (right) axis global Y2Top, Y2Bot 'Top and bottom of Y2 (right) axis 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 'delver114-4h 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 at a finalfreq of 10.7 MHz. Nominally, 180. ver116-1b global doingPDMCal '=1 when PDM cal in progress to determine invdeg ver114-5L global CalInvDeg 'set to value of invdeg determined by cal ver114-5L global cftest '=1 when doing cavity filter sweep test (Special Tests window) 'ver116-4b '--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 'Used to pass new port value back from config routine w/o making port global. ver113.7c 'ver114-5k deleted globalGlitchtime, which was no longer used global globalSteps 'SEWgraph; Number of steps set by user. Set in calcWindoInfo. global version of steps. global varwindow, datawindow '=1 when indicated window is open 'ver115-1b global doSpecialGraph '=0 for normal operation; for other values see [doSpecialGraph] global doSpecialRandom 'Random number generated at start of each sweep, for doSpecialGraph ver 114-3g global doSpecialRLCSpec$ 'RLC spec for doSpecialGraph global doSpecialCoaxName$ 'Name of coax last used in RLC spec ver115-4b global finalfreq, finalbw 'freq and bandwidth of current final filter global LO2 'actual LO2 frequency ver115-1c global hasVNA '=1 if the build includes VNA; otherwise 0 global hGraphWindow 'Windows handle to the graph window; set when created ver115-5d global hGraphMenuBar 'Windows handle to menu bar in graph window; set when created ver115-5d global suppressPhase '=1 to force phase to zero without measuring it ver116-1b global hFileMenu, hOptionsMenu,hDataMenu,hFunctionsMenu,hOperatingCalMenu, hMultiscanMenu 'Windows handles to some graph window submenus ver115-5d global hTwoPortMenu 'ver116-1b global menuOperatingCalShowing '=1 when the operating cal menu is shown; otherwise 0 global menuMultiscanShowing, menuTwoPortShowing 'same for multiscan and two-port menus ver116-1b 'zero-based index of menu positions in menu bar global menuOptionsPosition, menuDataPosition, menuFunctionsPosition, menuOperatingCalPosition, menuMultiscanPosition global menuTwoPortPosition, menuModePosition 'ver116-1b 'IDs of various listed menu items that may need to be hidden/shown in certain modes global menuDataS21ID, menuDataLineCalID, menuDataS11ID, menuDataS11DerivedID 'ver115-5d global menuDataLineCalRefID, menuDataLineCalOSLID 'ver115-5d global menuOptionsSmithID 'ver115-5d global menuFunctionsFilterID, menuFunctionsCrystalID, menuFunctionsMeterID, menuFunctionsRLCID 'ver115-5d global menuFunctionsCoaxID,menuFunctionsGenerateS21ID, menuFunctionsGroupDelayID 'ver115-8b global twoPortWinHndl$ 'handle of open Two-Port window, or blank if not open ver116-1b 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 global componentWindHndl$ 'Handle to component measurement window global crystalListHndl$ 'Handle to crystal list windows; blank if not open 'ver115-5c deleted crystalWindHndl$ global crystalWindHndl$ 'Handle to crystal window global crystalLastUsedID 'Last ID of crystal added to crystal list global tranRLCLastRLCWasSeries, tranRLCLastNotchWasTop 'most recent settings for tran mode RLC analysis global imageSaveLastFolder$ 'Folder in which last graph image was saved, regular or Smith chart ver115-2a dim Appearances$(10) 'Names of Appearances dim customPresetNames$(5) 'User names for custom color presets (1-5) ver115-2a '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 'ver114-4e deleted global graphAppearance$ global currGraphBoxHeight, currGraphBoxWidth 'Actual current height, width, adjusted when resizing 'ver115-1c global clientHeightOffset, clientWidthOffset 'Difference between window size and client area size; set from test window 'ver115-1c global smithLastWindowHeight, smithLastWindowWidth 'Determines size of smith chart; initialized and later adjusted when resizing global graphMarLeft, graphMarRight, graphMarTop, graphMarBot 'margins from graph box edge to grid global haltAtEnd 'Flag set to 1 to cause a halt at end of current sweep 'SEWgraph global hasMarkPeakPos, hasMarkPeakNeg, hasMarkL, hasMarkR, hasAnyMark 'Marker flags dim markerIDs$(9) 'IDs of markers, used to fill combo box. marker numbers run from 1 so ID of marker N is markerIDs$(N-1) global selMarkerID$ 'ID of marker selected by user global doGraphMarkers 'Set/cleared by user to show or hide markers on graph global doPeaksBounded '=1 to limit peak search between L and R markers; otherwise 0 global doLRRelativeTo$ 'marker ID of reference marker when L and R are relative to another marker; otherwise blank global doLRRelativeAmount 'db offset when L,R are relative to another marker; otherwise 0 global doLRAbsolute '=1 when LR are placed around another marker, but at an absolute db level ver115-3f global continueCode 'Checked after "scan" command; 0=continue; 1=halt via [Halted]; 2=immediate wait; 3=restart. global axisPrefHandle$ 'handle variable for axis preference window; non-blank when window is open global graphBox$ 'handle variable containing handle for current graph box. ver 114-3c global TwoPortGraphBox$ 'Handle to graph box for two-port graphs, or blank if no window open ver116-1b global displaySweepTime '=1 to display sweep time in message area 'ver114-4f global interpolateMarkerClicks '=1 to enable placing marker at exact click point; =0 to round to nearest step. ver115-1a dim axisGraphData$(40) : dim axisDataType(40) 'Graph data for dialog selecting graph types ver116-1b 'ver114-4k variables allowing forward or reverse sweep 'The following 3 variables are not global, but are used in connection with reverse sweeps 'sweepDir '+1 for left-right sweep; -1 for right-left sweep 'sweepStartStep, sweepEndStep 'start and end steps for current sweep. Note "startfreq" is the x-axis start (left), 'but sweepStartStep will be at the x-axis right end if we are going in reverse. global alternateSweep '=1 to alternate forward and reverse sweeps; =0 if direction is set by sweepDir ver114-5a global componStopAtEnd '=1 to stop component Measure and end of measure sweep. ver115-1f global RefRLCLastNumPoints,RefRLCLastConnect$ 'For continuity calling ReflectionRLC global analyzeQLastNumPoints 'For continuity in AnalyzeQ global GDLastNumPoints 'Number of points last used for group delay analysis global refreshEachScan 'Set/cleared by user to control screen refresh. =1 means refresh each scan. global refreshForceRefresh 'Forces refresh at end of scan even though refreshEachScan=0 global refreshOnHalt 'normally =1 to redraw when we halt. Set to 0 internally for some purposes. 'The following globals determine whether we redraw various components from scratch or by a faster method. global refreshGridDirty 'Forces grid (and labels, title) and setup info to redraw from scratch in RefreshGraphs global refreshTracesDirty 'Forces traces to be redrawn from raw Y1 and Y2 values in RefreshGraph global refreshMarkersDirty 'Forces recalc of marker positions based on their frequency global refreshAutoScale 'Do auto scaling on refresh; also implies refreshRedrawFromScratch ver114-7a global refreshRedrawFromScratch 'Forces complete redraw from scratch in RefreshGraph global doingInitialization 'Set to 1 during startup initialization of context variables; then to 0 ver114-3f global haltsweep 'Set to 1 when scan is running 'global vna ' =1 when we are in vna mode delver114-5n 'Y1DisplayMode, Y2DisplayMode: 0=off 1=NormErase 2=NormStick 3=HistoErase 4=HistoStick global Y1DisplayMode, Y2DisplayMode 'Type of phase and mag graphing. Made global for sub use. global isStickMode ' =1 when Y1DisplayMode or Y2DisplayMode are in a "stick" mode global specialOneSweep '=1 when [Restart] is called to do one sweep and then return, rather than wait. ver 114-5f global returnBeforeFirstStep '=1 to initialize on Restart and return to caller before taking any data ver115-1d global haltedAfterPartialRestart '=1 after halting as a result of returnBeforeFirstStep. Set to 0 when scan continues. ver1166-1b global msaMode$ '=SA, ScalarTrans, VectorTrans or Reflection global menuMode$ 'msaMode$ to which the graph window menus currently conform global autoScaleY1, autoScaleY2 '=1 to autoscale the axes global restartTimeStamp$ 'Date/time of last restart global primaryAxisNum '1 or 2, to indicate primary Y axis (e.g. where mag dBm defaults to) ver115-3b global Y1DataType, Y2DataType 'data component constant to determine Y1 and Y2 graph data 'The following component constants are used to specify the data component needed to graph global constGraphS11DB, constGraphS11Ang, constTheta global constMagDBM,constMagWatts,constMagDB,constMagRatio,constMagV global constRho,constAngle,constRawAngle,constGD,constSerReact,constParReact 'ver115-1b global constSerR,constSerC,constSerL,constParR,constParC,constParL global constSWR, constReturnLoss, constInsertionLoss 'ver114-8d global constImpedMag, constImpedAng 'ver115-1d global constReflectPower, constComponentQ 'ver115-2d global constAdmitMag, constAdmitAng, constConductance, constSusceptance 'ver115-4a global constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 'for auxGraphData(,) ver115-4a global constNoGraph 'ver115-2c used to suppress data 'The following identify slots in ReflectArray() but are not used for graphing. They hold 'S11 prior to the final adjustment for plane extension and graph R0, and are saved to make 'it easier to recalculate S11 when those values change. global constIntermedS11DB, constIntermedS11Ang 'ver115-2d 'The following constants are for two-port graphs. They do not have values 'distinct from those for regular graphs ver116-1b global constTwoPortS11DB, constTwoPortS21DB, constTwoPortS12DB, constTwoPortS22DB global constTwoPortS11Ang, constTwoPortS21Ang, constTwoPortS12Ang, constTwoPortS22Ang global constTwoPortMatchedS21DB, constTwoPortMatchedS12DB 'For/Rev gain dB with impedance-matching terminations ver116-2a global constTwoPortMatchedS21Ang, constTwoPortMatchedS12Ang 'angle of gain global constTwoPortMatchedS11DB, constTwoPortMatchedS22DB 'For/Rev RL dB with specified terminations ver116-2a global constTwoPortMatchedS11Ang, constTwoPortMatchedS22Ang 'angle of return loss global constTwoPortKStability, constTwoPortMuStability 'ver116-2a 'Amplifier stability factors 'The following constant values are used to specify graph data, 'and assigned in such a way that the first ones can be 'used as the index into ReflectArray(), which holds a bunch of pre-calculated values for reflection mode. 'Note if these are changed, FilterDataType may have to be changed. 'ver115-1b altered these 'We start with 1, because entry 0 of ReflectArray is frequency constGraphS11DB=1 'S11 db re S11GraphR0 constGraphS11Ang=2 'S11 angle re S11GraphR0 constRho=3 'S11 data with mag made linear constImpedMag=4 'impedance magnitude (linear, not db) constImpedAng=5 'impedance angle constSerR=6 'Series Resistance constSerReact =7 'Series Reactance constParR=8 'Equiv parallel resistance constParReact=9 'Equiv parallel reactance constSerC=10 'Equiv series capacitance constSerL=11 'Equiv series inductance constParC=12 'Equiv parallel capacitance constParL=13 'Equiv parallel inductance constSWR=14 'SWR constIntermedS11DB=15 'Not a graph item ver115-2d constIntermedS11Ang=16 'Not a graph item ver115-2d 'The above are in ReflectArray(); the below are either not reflection related 'or are other names for reflection data, or simple calculations from that data. constMagDBM=17 'Magnitude dBM for SA mode constMagWatts=18 'Magnitude watts (linear) for SA mode constMagV=19 'Magnitude volts (linear) for SA mode constMagDB=20 'Magnitude dB for S21 constMagRatio=21 'Magnitude ratio (linear) for S21 constAngle=22 'Angle for S21 constTheta=23 'Theta for reflection constGD=24 'Group Delay for S21 constReturnLoss=25 'Return Loss for reflection ver114-8d constInsertionLoss=26 'Insertion Loss for S21 ver114-8d constReflectPower=27 'Percent reflected power ver115-2d constComponentQ=28 'component Q (not resonance Q) ver115-2d constAdmitMag=29 'ver115-4a constAdmitAng=30 constConductance=31 constSusceptance=32 constRawAngle=33 'Transmission angle without cal adjustment 'constAuxN represent the data in auxGraphData(step, N). They must be consecutively numbered. ver115-4a constAux0=34 'N=0 for accessing auxGraphData constAux1=35 constAux2=36 constAux3=37 constAux4=38 constAux5=39 constNoGraph=40 'Don't graph and don't label the axis 'The following can be used directly to index TwoPortArray to retrieve the data 'Note that the constant for an angle is always one more than that for its corresponding DB constTwoPortS11DB=1 constTwoPortS21DB=3 constTwoPortS12DB=5 constTwoPortS22DB=7 constTwoPortS11Ang=2 constTwoPortS21Ang=4 constTwoPortS12Ang=6 constTwoPortS22Ang=8 'The following can be used directly (after subtracting constTwoPortMatchedS11DB-1) to index TwoPortMatchedSParam to retrieve the data 'Note that the constant for an angle is always one more than that for its corresponding DB constTwoPortMatchedS11DB=9 'ver116-2a constTwoPortMatchedS11Ang=10 'ver116-2a constTwoPortMatchedS21DB=11 'ver116-2a constTwoPortMatchedS21Ang=12 'ver116-2a constTwoPortMatchedS12DB =13 'ver116-2a constTwoPortMatchedS12Ang =14 'ver116-2a constTwoPortMatchedS22DB=15 'ver116-2a constTwoPortMatchedS22Ang=16 'ver116-2a 'The following do not directly index an array; they need to be calculated constTwoPortKStability=17 'ver116-2a constTwoPortMuStability=18 'ver116-2a dim ReflectArray(800,16) 'Actual signal freq (0),GraphS11DB(1), GraphS11Ang(2),linearMag(3), 'Impedance Mag(4), Impedance Angle(5),Rs(6), Xs(7), Rp(8), ' Xp(9), Cs(10), Ls(11), Cp(12), Lp(13), SWR(14), 'intermedDB(), intermedAng(15) (intermed= w/o R0 transform or plane ext) 'ver115-2d dim uWorkReflectData(16) 'Same data as ReflectArray, but for only one entry 'ver115-1b 'ver115-2d dim S21DataArray(800,3) 'Frequency (actual input freq) (0), mag(1), phase(2) and intermed phase(3) for VectorTrans and ScalarTrans modes. ver116-1b 'Intermed phase is phase before plane extension, saved in case of recalculation 'The following auxGraphDataXXX arrays have info on auxiliary graphs, which are numbered 0 to 5; the 'graph number is the first index of the array. If the graphs are specified as data types constAux0, etc., then 'the graph number is the constant for the desired graph minus constAux0. dim auxGraphData(800, 5) 'Used to hold specially calculated data, such as from Q analysis, which can be retrieved and graphed. 'auxGraphDataInfo$ Info for UpdateGraphDataFormat for auxGraphData. ver115-4a '(,0) is graph Name, (,1) is formatting string, (,2) is axis label, (,3) is marker label dim auxGraphDataFormatInfo$(5,3) 'auxGraphDataInfo is numeric info about each item in auxGraphData. (,0) is 1 if the data is an angle '(,1) and (,2) are the axis min and max to use as defaults for graphing. dim auxGraphDataInfo(5,2) 'ver115-4a 'SEWgraph; The following hold parameters used to perform filter analysis when requested by the user global doFilterAnalysis '=1 to perform filter analysis; 0 otherwise SEWgraph global x1DBDown, x2DBDown 'positive db values for x1 and x2 points SEWgraph global filterPeakMarkID$ 'Marker that indicates filter peak 'SEWgraph The following are used to manage a "working array" in the Utilities Module. This array is used for very 'temporary processing to deal with the fact that in LB you can't pass arrays as arguments. So some routines, 'such as saving/retrieving data points to/from strings or files, utilize this specific array. The user is 'responsible for transferring data in and out of this array. Data can't be left in the array for long, because 'another operation might utilize the array. dim uWorkArray(800,8) 'Initially 800 points with up to 9 (0...8) data items per point global uWorkMaxPoints, uWorkNumPoints 'max points and actual used points in uWorkArray global uWorkMaxPerPoint, uWorkNumPerPoint 'max and actual number of data items per entry of uWorkArray dim uWorkFormats$(8) 'Format strings for each data item, in form suitable for "using" function, 'or blank to cause str$() function to be used. global maxNumSteps 'Absolute max number of steps allowed for sweep or in arrays of points (num points=num steps+1) ver114-3e maxNumSteps=40000 'ver114-3e global maxPointExtraLines 'max lines in a file or string with point data, not including the numeric point data itself ver 114-3e maxPointExtraLines=100 'ver116-4k dim uWorkTitle$(6) 'Title info extracted when processing uTextPointArray$; 0 not used ver114-3e; ver114-5m increased to 6 dim uTextPointArray$(maxNumSteps+maxPointExtraLines+5) 'Array of points as string; used as short-term 'intermediary in saving/retrieving arrays of points ver114-3e dim VNAData(1,2) 'For temporary storage of data to be restored to the graph. Resized when needed. ver116-1b global VNADataNumSteps 'Number of steps of data in VNAData. Data runs from (0,x) to (VNADataNumSteps, x) ver116-1b global VNADataLinear '=1 if the data in VNAData has linear spacing, =0 for log. ver116-4a global VNADataZ0 'Reference impedance of data in VNAData ver116-4a dim VNADataTitle$(4) 'Title of data in VNAData ver116-1b global VNARestoreDoR0AndPlaneExt 'Tells VNARestoreData whether to perform R0 conversion and plane extension ver116-4j dim contextTypes(30) 'Used in connection with save and retrieve context files 'indicating which contexts are involved ver114-3a 'Constants to specify context types in contextTypes() global constHardware, constGrid, constTrace, constSweep, constMarker, constBand, constBase, constGraphData, constModeData constHardware=0 : constGrid=1 : constTrace=2 : constSweep=3 : constMarker=4 : constBand=5 constBase=6 : constGraphData=7 : constModeData=8 '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 moved here by ver115-1d 'calFreqCoeffTable has the A,B,C,D coefficients for interpolating in the calFreqTable() dim calFreqCoeffTable(800,3) 'SEWcal Cubic interpolation coefficients for calFreqTable() moved here by ver115-1d '---Variables relating to touchstone data files--- ver115-5f global touchFreq$, touchForm$, touchRef 'Touchstone format specs global touchFreqMult 'Frequency multiplier corresponding to touchFreq$. E.g. 1e6 for MHZ. global touchBadLine 'Line number of Touchstone file error; zero if no error global dataLoadLastFolder$ 'Folder from which parameter data was last loaded global touchMaxData 'Max data lines in our touchstone files when reading touchMaxData=10000 'ver116-1b global touchLastFolder$ 'Last folder accessed for save or load of parameter files. global touchSParamType$ 'Type of params in sParam: "", "Reflection", Transmission" or "TwoPort" dim touchComments$(10) 'Up to 10 lines of comments from parameter file. Zero entry not used global touchCommentCount 'Number of comment lines in touchComments$ '---End variables for data files---- 'Additional variables that need to be available to subroutines 'Note "startfreq" is the x-axis start (left), 'but sweepStartStep will be at the x-axis right end if we are going in reverse. 'baseFrequency is added when commanding the hardware, but does not affect graph display or file frequencies. global startfreq, endfreq, baseFrequency 'ver116-4k global wate, planeadj global freqBand '1, 2 or 3, indicating bands 1G, 2G and 3G, or zero to use auto-band mode ver116-4s global bandEnd1G, bandEnd2G 'Final frequencies for 1G and 2G when in auto-band mode. ver116-4s global lastSetBand 'set to 1,2 or 3 each time the band switch is set, so we know its state ver116-4s global sgout 'signal generator output freq when in plain SA mode global test 'SEWgraph Contents get printed to message box on halt global spurcheck '=1 to turn spur test on 'ver114-4f global gentrk '=1 when TG is being used (depends on mode); 0 if SG is used or build does not have TG hardware global normrev '=0 if TG is normal, =1 if TG is in reverse. global offset 'TG offset frequency moved ver115-5f global path$ 'Currently active filter path (1...); a number as a string in form "Path N" ver114-1d global FiltA0, FiltA1 'low and high bits of RBW filter address 'ver116-4j dim fileInfo$(1,1) 'array for use with Files() command ver114-3f global message$ 'Message to print in graph window global varwindow '=1 if variables window is open ver115-1a global suppressPDMInversion '=1 to suppress inversion in [ReadStep] ver115-1a global leftstep 'Used to hold a marker step number for [preupdatevar] ver115-1a global userFreqPref '0 if user last used Center/Span method; 1 if user last used Start/Stop ver115-1d 'When loading a path calibration file, we determine lowest ADC value for magdata for which phase is considered valid global validPhaseThreshold 'ver116-1b '------------Items for auto wait time----------'ver116-1b 'When loading a path calibration file, we divide the response into three sections and calculate approximate slopes: 'For ADCcalHighADCofCenterSlope the slope is calHighEndSlope calculated from a segment at top end 'The slope is delta ADC/delta dB global calCanUseAutoWait '=1 if cal table is suitable for auto wait time calculations global useAutoWait '=1 if user specified to use auto wait times global autoWaitPrecision$ '"Fast", "Normal" or "Precise" meaningless if useAutoWait=0 global calADCofLowFringe 'ADC below which the ADC/dB slope is tiny global calLowADCofCenterSlope, calHighADCofCenterSlope global calLowEndSlope, calCenterSlope, calHighEndSlope global autoWaitTC 'max time constant for video filters of mag and phase (where applicable) ver116-4j 'The max db error is converted to a max ADC error for the three regions 'of the path calibration table. 'With auto wait time, we do repeated readings after waiting a certain time, 'and determine when the change in readings falls below a maxChange level 'The maximum allowed change in ADC values, to keep the error at the allowed limit, global autoWaitMaxChangeLowEndADC, autoWaitMaxChangeCenterADC, autoWaitMaxChangeHighEndADC global autoWaitMaxChangePhaseADC '------------End items for auto wait time---------- '------------Items for transitions between Reflection and VectorTrans modes ver116-1b-------- 'Sweep parameters of last transmission sweep global transLastSteps, transLastStartFreq, transLastEndFreq, transLastIsLinear, transLastGraphR0 'most recent Y axis settings for transmission global transLastY1Type, transLastY1Top, transLastY1Bot, transLastY1AutoScale 'data type and axis top and bottom global transLastY2Type, transLastY2Top, transLastY2Bot, transLastY2AutoScale 'Sweep parameters of last reflection sweep global refLastSteps, refLastStartFreq, refLastEndFreq, refLastIsLinear, refLastGraphR0 'most recent Y axis settings for reflection global refLastY1Type, refLastY1Top, refLastY1Bot, refLastY1AutoScale global refLastY2Type, refLastY2Top, refLastY2Bot, refLastY2AutoScale 'most recent titles dim refLastTitle$(4), transLastTitle$(4) '------------------------------------------------------------------------------------------- 'Variables for saving/restoring context files via gosub routines, where these are used as parameters global restoreFileName$, restoreFileHndl$, restoreContext$, restoreIsValidation, restoreErr$,restoreLastLineNum 'ver115-8c 'There can be 1 to four video filter settings, with different capacitor values. 'ver116-1b 'They each have a name. Mag and phase capacitors can be different, but the names and number 'of filters are the same. The names must be Wide, Mid, Narrow or XNarrow, but not all those names must be used. 'Names and capacitor values are set in hardware configuration. global videoFilter$ 'Selected video filter: Wide, Mid, Narrow or XNarrow 'ver116-1b dim videoFilterCaps(4,1) 'Capacitance(uf) for Wide(1), Mid(2), Narrow(3) and XNarrow(4) video filters 'ver116-1b 'Second index is 0 for magnitude and 1 for phase filters. dim videoFilterNames$(4) 'Names of each video filter, or blank if no filter. Index matches videoFilterCaps 'ver116-1b global videoFilterAddress, videoMagCap, videoPhaseCap 'current video filter address (0-3) and cap values (uF) for mag and phase ver116-1b global videoMagTC, videoPhaseTC 'Time constants (ms) of video mag and phase filters 'ver116-1b global switchFR, switchTR 'current or desired state of forward/reverse (0=forward) and transmission/reflection (0=transmission) switches ver116-1b 'Globals used to remember state info to allow detection of user changes; added by ver114-6e 'See RememberState and DetectChanges global prevMSAMode$ 'msaMode$ global prevPath$ 'Filter path. ver115-1a global prevFreqMode 'frequency mode and auto band switch ver116-4s global prevStartF, prevEndF, prevBaseF 'ver116-4k global prevXIsLinear, prevY1IsLinear, prevY2IsLinear global prevSteps, prevSweepDir, prevAlternate global prevStartY1, prevEndY1, prevStartY2, prevEndY2 global prevHorDiv, prevVertDiv global prevY1Disp,prevY2Disp global prevGenTrk, prevSpurCheck 'ver114-6k global prevPath$ 'ver116-4j global prevTGOff, prevSGFreq 'ver115-1a global prevPlaneAdj 'ver114-7f global prevY1DataType, prevY2DataType 'ver115-1b deleted source constants global prevAutoScaleY1, prevAutoScaleY2 'ver114-7a global prevDataChanged 'This must be set to 1 when data is loaded from a context global prevS21JigAttach$ '"Series" or "Shunt" to indicate the Transmission jig used ver114-6k global prevS21JigR0 'Source and load impedances of Transmission global prevS21JigShuntDelay 'Delay of shunt fixture connector global prevS11BridgeR0, prevS11GraphR0 'Bridge reference and graph reference for S11 'ver114-6k global prevS11JigType$ 'Jig previously used for reflection mode ver115-1b global prevSwitchFR 'Previous setting of forward/reverse switch ver116-1b 'Functions may need to redo the sweep with new parameters. The following are used to save/restore the 'pre-existing parameters, using SaveAndChangeSweepParameters and [RestoreSweepParameters] ver115-5c global functSaveAlternate,functSaveSweepDir,functSavePlaneAdj,functSaveWate, functSaveVideoFilter$ 'ver116-4b global functSaveAutoWait, functSaveAutoWaitPrecision$ 'ver116-1b global functSaveSteps, functSaveStartFreq, functSaveEndFreq global functSaveAutoY1, functSaveAutoY2 global functSaveY1Mode, functSaveY1Mode global functSaveY1DataType, functSaveY2DataType global functSaveXIsLinear, functSaveY1IsLinear, functSaveY2IsLinear global functSaveNumHorDiv, functSaveNumVertDiv global functSaveDesiredCalLevel 'ver114-5e added these cal items. Full Line cal is a calibration of through response with the current sweep settings. 'Baseline cal is a cal of through response with a generic wideband sweep. 'desiredCalLevel is the user-specified level. applyCalLevel is the level we are actually applying global desiredCalLevel, applyCalLevel '2=band Cal (if exists); 1=Base Cal(if exists); 0=None 'We keep track of the parameters for the last cal. Number of steps is set to -1 to indicate no valid cal 'Following are Full Line cal sweep params ver114-5e global bandLineStartFreq, bandLineEndFreq, bandLineNumSteps, bandLineLinear, bandLinePath$, bandLineTimeStamp$ 'Following are Base Line cal sweep params ver114-5e global baseLineStartFreq, baseLineEndFreq, baseLineNumSteps, baseLineLinear, baseLinePath$, baseLineTimeStamp$ global baseLineS21JigAttach$, bandLineS21JigAttach$ 'S21JigAttach$ for applicable cal 'ver115-1B global baseLineS21JigR0, bandLineS21JigR0 'S21 jig R0 for applicable cal ver115-1b global installedBandLineTimeStamp$ 'Time stamp of the band cal that was installed; not when it was installed ver115-2d 'Following are sweep params at which Base Line Cal was last installed ver114-5f global installedBaseLineStartFreq, installedBaseLineEndFreq, installedBaseLineNumSteps global installedBaseLineLinear global installedBaseLineTimeStamp$ 'Time stamp of the base cal that was installed; not when it was installed ver115-2d dim lineCalArray(800,2) 'calibration data for each step#: (0)freq (tuning),(1)magpower during cal,(2)phaseofpdm during cal dim bandLineCal(800,2) 'Bandsweep line calibration data; transferred to lineCalArray when needed ver 114-5f 'Note baseLineCal is fixed sized dim baseLineCal(2000,2) 'Baseline line calibration data; transferred to lineCalArray when needed ver 114-5f 'Impedance can be measured via S21 in a test jig, or via S11 in a reflection bridge 'We need to know the reference impedance (a resistance) of each, and for the jig 'we need to know if the DUT is in series, or shunted to ground. The S21 jig is actually used only in reflection mode. 'ver114-6g added these global S21JigAttach$ '"Series" or "Shunt" to indicate the Transmission jig used ver114-6k global S21JigR0 'Source and load impedances of Transmission jig global S21JigShuntDelay 'One-way delay of connector from shunt fixture through line to the DUT, in ns. ver115-1e global S11BridgeR0, S11GraphR0 'Bridge reference and graph reference for S11 'ver114-6k global S11JigType$ '="Trans" if S21Jig is being used for reflection mode; "Reflect" if reflection bridge is used ver115-1b global lineCalThroughDelay 'Delay (ns) of line cal through connection. Used for continuity between lineCal dialog sessions 'and to inform [BandLineCal]. need not be saved as a preference item. 'ver114-7f added these dialog variables global DialogCancelled, DialogRLCConnect$ 'Used to pass values to/from some dialogs global DialogRValue, DialogLValue, DialogCValue 'Used to pass values to/from some dialogs global DialogQLValue, DialogQCValue 'ver115-4b global DialogCoaxSpecs$, DialogCoaxName$ 'Used to pass values to/from some dialogs ver115-4a global referenceLineSpec$, referenceLineType 'Spec and type of reference line ver114-7f 'type: 0=none; 1=use data when ref was selected; 2=use RLC in spec; 3=use fixed value ver115-5d global referenceTrace 'which ref lines, based on bits: 1 bit=do trace 1; 2 bit=do trace 2; 4 bit=do Smith trace 'ver115-6b global referenceSourceNumPoints 'Number of valid points in referenceSource() dim referenceSource(801,2) 'freq(0), db(1) and angle() of source data for reference lines. First entry is 1 dim referenceTransform(801,2) 'Actual graph data for reference lines Entries are by point number, 1... (not step num) global referenceColor1$, referenceWidth1,referenceColor2$, referenceWidth2 'Reference Trace color and width global referenceColorSmith$, referenceWidthSmith 'color/width for smith chart reference line 'The reference line may be graphed or combined with the scan data. 'The math transform is in the form A*Ref + B*Data, A and B generally being 1 or -1 'Math is done if referenceDoMath=1 or 2; otherwise reference is just graphed. 'If referenceDoMath=1 then math is done on the dBm values that would be graphed with the default graphs. 'referenceDoMath=1 is allowed only for SA mode; too complicated and not very useful for VNA modes, which use calibration instead. 'If referenceDoMath=2 then math is done on the current graph values (e.g. capacitance) global referenceDoMath, referenceOpA, referenceOpB 'ver114-7b dim setupList$(15) 'List of current test setups; used in test setup dialog only '-----OSL cal variables----- 'ver115-1b added the following OSL items global OSLdoneO, OSLdoneS, OSLdoneL 'For communicating with [PerformOSLCal] 'These items are the currently active data for reflection dim OSLa(800,1), OSLb(800,1),OSLc(800,1) 'OSL coefficients a, b, c, at same frequencies as ReflectArray() ver115-1b global OSLRefType$ 'Open, Short or Load ver116-4n global OSLcalLastUsedFull '=1 if cal window last used full OSL; 0 if last used reference. 'global OSLApplyFull 'delver116-4n We now always apply OSL in reflection mode if applyCalLevel=0. 'These items are used only during the OSL calibration procedure to calculate coefficients. dim OSLstdOpen(800,1) 'Actual refco of open standard at each step, real/imaginary dim OSLstdLoad(800,1) 'Actual refco of load standard at each step, real/imaginary dim OSLstdShort(800,1) 'Actual refco of short standard at each step, real/imaginary dim OSLcalOpen(800,1) 'Measured (during cal) open at each step, db/angle converted to real/imag in ProcessOSLCal dim OSLcalLoad(800,1) 'Measured (during cal) load at each step, db/angle converted to real/imag in ProcessOSLCal dim OSLcalShort(800,1) 'Measured (during cal) short at each step, db/angle converted to real/imag in ProcessOSLCal global OSLLastSelectedCalSet 'Standard cal set selected last time dialog was open global OSLOpenSpec$, OSLShortSpec$, OSLLoadSpec$ 'RLC specs for currently selected OSL standards ver116-4i global OSLFileOpenSpec$, OSLFileShortSpec$, OSLFileLoadSpec$ 'RLC specs for OSL standards, used to transfer to and from files. ver116-4i global OSLFileCalSetName$, OSLFileCalSetDescription$ 'ver116-4i dim OSLCalSetNames$(10) 'List of OSL cal sets; zero entry is used. Entries correspond to OSLCalSetFileNames ver115-7a dim OSLCalSetFileNames$(10) 'List of OSL cal set descriptions (long); zero entry is used. redim'd as necessary ver115-7a global OSLCalSetNumber 'Number of entries in list of cal set names and file names ver115-7a 'These items are the result of calibration and allow either base or band cal to be installed 'The OSLBasex arrays are fixed size; the others are expanded as necessary dim OSLBaseA(2000,1), OSLBaseB(2000,1), OSLBaseC(2000,1) 'Base coefficients; used to fill OSLx() dim OSLBandA(800,1), OSLBandB(800,1), OSLBandC(800,1) 'Band coefficients (matches current frequencies) dim OSLBaseRef(2000,2), OSLBandRef(800,2) 'Freq(0) and dB(1) and angle(2) update info. Ref is 0 until cal update is run. global OSLBandRefType$, OSLBaseRefType$ 'Open, Short or Load ver116-4n 'We keep track of the parameters for the last cal. Number of steps is set to -1 to indicate no valid cal global OSLError '=1 if math error occurred in calculating OSL coeff; used to nullify the cal ver115-4j global OSLBaseStartFreq, OSLBaseEndFreq, OSLBaseNumSteps, OSLBaseLinear, OSLBasePath$ 'Params for last base OSL calibration global OSLBandStartFreq, OSLBandEndFreq, OSLBandNumSteps, OSLBandLinear, OSLBandPath$ 'Params for last band OSL calibration global OSLBandS11JigType$, OSLBaseS11JigType$ 'Jig type--"Reflect" or "Trans"-- for last cal global OSLBaseS21JigAttach$, OSLBandS21JigAttach$ 'S21 jig for last OSL cal; relevant only if jig type is "Trans" global OSLBaseS11BridgeR0, OSLBandS11BridgeR0 'Bridge R0 for last OSL cal; relevant only if jig type is "Reflect" global OSLBaseS21JigR0, OSLBandS21JigR0 'S21 jig R0 for last OSL cal; relevant only if jig type is "Trans" global OSLBaseTimeStamp$ 'Time stamp for last base open, load, short cal. global OSLBandTimeStamp$ 'Time stamp for last band open, load, short cal. global installedOSLBandTimeStamp$ 'Time stamp of the installed band cal; not when it was installed ver115-2d 'Following are sweep params at which base OSL cal coefficients were last installed 'We don't need these for installed Band cal, because they would all match the sweep params 'at the time of installation. global installedOSLBaseStartFreq, installedOSLBaseEndFreq, installedOSLBaseNumSteps global installedOSLBaseLinear, installedOSLBaseRefType$ 'ver116-4n global installedOSLBaseTimeStamp$ 'Time stamp of the installed base cal; not when it was installed ver115-2d '-------End OSL cal variables-------' 'If doing color cycling, the trace colors are changed at the start of each scan. If not cycling, cycleNumber is stuck at 1. dim cycleColorsAxis1$(3), cycleColorsAxis2$(3) 'colors for cycling in Stick mode. Index 1 is standard trace color ver116-4s global doCycleTraceColors, cycleNumber 'switch to signal cycling, and number (1-3) of current place in cycle ver116-4s global maxCoaxEntries, numCoaxEntries 'Maximum and actual number of entries in coax data arrays maxCoaxEntries=100 dim coaxNames$(maxCoaxEntries) 'Coax names; 0 entry not used dim coaxData(maxCoaxEntries, 4) 'Coax data: R0(,1), VF(,2), K1(,3), K2(,4) dim RLCDialogCoaxTypes$(maxCoaxEntries+10) 'For RLC specification dialog ver115-4a global calInProgress 'variable set to 1 before starting a cal sweep, then to 0 when done 'ver114-6b moved the following dim statements here 'SEWgraph; the following arrays may be expanded in ResizeArrays to accomodate more steps 'SEWgraph Pixel values are no longer kept in these arrays, so references to thispointx, thispointmag, thispointphase, 'oldmagpixwl and oldphapixel should be ignored. Eventually, the arrays could be compacted to eliminate those unused slots. global constMaxValue constMaxValue=1e12 'Max value for RLC components and certain calculations. ver115-1b 'Data is put into datatable() point by point as it is gathered. Its frequency is the 0-1 GHz "equivalent 1G frequency". 'In VectorTrans and ScalarTrans modes, the data is also saved to S21DataArray() with the actual sweep frequency, 'and if reflection mode convert to S11 and save to ReflectArray() dim datatable(800,4) 'data from most current sweep, (0)thisstep,(1)thisfreq(hardware freq),(2)processed magpower,(3)processed phase, (4)band (1G-3G) ver116-4s 'Note: magarray(x,1) is no longer used; magarray(x,2) is never actually used to store magnitude ver116-1b dim magarray(800,3) 'magni pixels for each step#: (0)thispointx, (1)oldmagpixel,(2)thispointmag(3)magdata 'Note: phaarray(x,1) is no longer used; phaarray(x,2) is never actually used to store phase ver116-1b dim phaarray(800,4) '(0)pdmcmd; phase pixels for each step#:(1)oldphapixel,(2)thispointphase,(3)phadata,(4)pdmread ver111-39d 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 freqCorrection(800) 'freq correction factors for frequency of each step in current sweep; added to raw data 'frontEndCalData is the raw data, freq and dBm, for the current front end. It is interpolated to frontEndCorrection 'on Restart to match the current scan points. It is resized if necessary when a front end file is loaded 'first index is 1-based. For second index: 0=freq; 1=dBm ver115-9d 'The data is the value to be subtracted from the raw power readings. Subtraction is used so a front end file 'can be created by a transmission measurement of the front end, after calibrating with a through connection. dim frontEndCalData(800,1) dim frontEndCorrection(800) 'correction for front end in use for each step in current sweep; subtracted from raw data global frontEndCalNumPoints 'Number of valid points in frontEndCalData global frontEndActiveFilePath$ 'Path name for active front end file. Only relevant in SA modes.ver115-9c global frontEndLastFolder$ 'path to Last folder from which front end was loaded 'ver114-2d combined config arrays into one, and deleted configarray dim cmdallarray(800,39) '(0-15)DDS1+DDS3, (16-39)PLL1+DDS1+PLL3+DDS3 global suppressHardware '=1 to suppress hardware operations, otherwise 0 'ver115-6c global suppressHardwareInitOnRestart '=1 to skip hardware re-initialization to speed up Restart or [PartialRestart]. 'ver116-4d deleted wantHardwareInitOnPartialRestart '-------Items for multi-scanning----------- ver115-8c 'In SA mode only, it is possible to rotate through several different scan settings; this 'is called multi-scanning. One sweep is completed with one setting, then we move to the next. 'When one is completed, its graphic is displayed in its own window. 'The settings are saved, as is the datatable info. The datatable info for a scan can be reloaded 'into the main window when scanning is stopped. 'Multiscan entries are numbered from 1 through multiscanMaxNum 'Entry zero is info for the main graph. global multiscanCurrNum 'Current entry number global multiscanMaxNum 'Maximum entry number global multiscanIsOpen '=1 when multiscan windows are open, even if scan not in progress. global multiscanInProgress '=1 when actually scanning in multiscan mode global multiscanHaltAtEnd 'set to non-zero during multiscan to cause halt at end, value depends on window selected global multiscanSaveRefreshEachScan 'Saves for restoration when quitting multiscan multiscanMaxNum=4 'This is fixed 'This array holds the context strings for the multiscan entries 'Blank for grid context means this entry is not to be used 'Zero entry of first index not used dim multiscanContexts$(multiscanMaxNum, 3) 'second index= grid(0), trace(1), sweep(2), marker(3) 'multiscanDBM holds the magnitude in dBm for each multiscan entry. Main graph is entry 0. '2000 steps are allowed for each entry, so the second index for entry N 'runs from 2001*N to 2001*(N+1)-1 'multiscanRefData holds reference data arranged similarly dim multiscanTitles$(multiscanMaxNum, 4) 'Four title lines for each multiscan entry ver115-9a dim multiscanDBM((multiscanMaxNum+1)*2001) 'Reference data is always to be added/subtracted with graph data, based on the math type dim multiscanRefData((multiscanMaxNum+1)*2001) 'The only reference type allowed in multiscans is reference math with data: the reference 'data and current data are added or subtracted based on two values OpA and OpB, which are each '1 or -1 (see referenceDoMath), but are zero if reference is not to be used. 'OpA for entry N is at 2*N. OpB is at 2*N+1. dim multiscanRefOps((multiscanMaxNum+1)*2) dim multiscanGraphHandles$(multiscanMaxNum) 'LB handles to the graphics box for each multiscan; blank if inactive dim multiscanWindowHandlesLB$(multiscanMaxNum) 'LB handles to windows for each multiscan; blank if inactive dim multiscanWindowHandlesWind(multiscanMaxNum) 'Windows handles to windows for each multiscan global multiscanMainWidth, multiscanMainHeight 'Dimensions of main graph box when multiscan was started global multiscanWindowsPosition, multiscanSettingsPosition 'positions of multiscan windows that need to be hidden/shown global multiscanControlPosition multiscanControlPosition=0 multiscanWindowsPosition=1 'Windows menu is number 1, indexed from 0 multiscanSettingsPosition=2 'Settings menu is number 2, indexed from 0 dim multiscanMenuBarHandles(multiscanMaxNum) 'Windows handles to menu bar for each scan dim multiscanWindowsMenuHandles(multiscanMaxNum) 'Windows handles to "Windows" menu for each scan dim multiscanSettingsMenuHandles(multiscanMaxNum) 'Windows handles to "Settings" menu for each scan dim multiscanControlMenuHandles(multiscanMaxNum) 'Windows handles to "Control" menu for each scan dim multiscanSkip(multiscanMaxNum) '=1 to skip this graph when scanning '-------End Items for multi-scanning----------- '--------Items for auto switches----------- 'Indicates whether we have software-controlled switches: RBW filter, video filter, xG Band switch, Transmit/Reflect, and Forward/Reverse global switchHasRBW, switchHasVideo, switchHasBand, switchHasTR, switchHasFR '--------End items for auto switches----------- '------Start items for USB interface---------- ' USB interface dll 'USB:01-08-2010 ' this is used as a form of handle used by the USB interface ' it is necessary because of the limitations of liberty basic ' and it is actually a memory pointer to a USB device class object ' we set it to zero when the interface is not initialised global USBdevice 'USB:01-08-2010 ' this is a boolean flag used to control when the USB interfcae dll is open (I hate basic) global UsbInterfaceOpen 'USB:01-08-2010 ' set this flag to != 0 for usb interface active global bUseUsb 'USB:01-08-2010 global bUsbAvailable 'USB:01-08-2010 ' these are string buffers used in USB I/O operations global USBwrbuf$ 'USB:01-08-2010 ' used in ADC input functions; the number of ADC readings made and the results read 'ver116-4r deleted (since not used) global UsbAdcCount 'USB:01-08-2010 'ver116-4r deleted global UsbAdcResult1 'USB:01-08-2010 'ver116-4r deleted global UsbAdcResult2 'USB:01-08-2010 USBdevice = 0 'USB:01-08-2010 UsbInterfaceOpen = 0 'USB:01-08-2010 bUseUsb = 0 'USB:01-08-2010 struct USBrBuf, numreads as ulong, magnitude as ulong , phase as ulong 'USB:01-08-2010 ' the next 3 are used to create a memory buffer for the dll to use to save scan time ' it contains a char[][] version of cmdallarray global AllArrayBlockSize ' current size of memory block allocated for AllArrays global hSAllArray ' handle for memory block global ptrSAllArray ' pointer to memory block global hSDDS1Array 'USB:05/12/2010 global ptrSDDS1Array 'USB:05/12/2010 global hSDDS3Array 'USB:05/12/2010 global ptrSDDS3Array 'USB:05/12/2010 global hSPLL1Array 'USB:05/12/2010 global ptrSPLL1Array 'USB:05/12/2010 global hSPLL3Array 'USB:05/12/2010 global ptrSPLL3Array 'USB:05/12/2010 struct Int64N, msLong as ulong, lsLong as ulong ' USB:15/08/10 struct Int64SW, msLong as ulong, lsLong as ulong ' USB:15/08/10 ' This structure is used to minimize time spent forming commands to send to the USB DLL ' the values correspond to the parameters of the same name (or similar description) in the parallel function ' we aim to try not to set them each time to save processing time in basic code struct UsbAllSlimsAndLoadData, thisstep as short, filtbank as short, latches as short, pdmcommand as short, pdmcmdmult as short, pdmcmdadd as short ' USB:15/08/10 ' The following struct is used to control ADC reading configuration. struct UsbAdcControl, Adcs as short, Clocking as short, Delay as short, Bits as short, Average as short ' USB:15/08/10 ' Placed here to save liberty basic from having to fill it in each time it goes to read the ADC's ' The parameters map to the parameters in the ADC convert commands in fw-msa ' Adcs takes values 1 or 3 normally ( 1 = magnitude ADC only, 3 = both ) but will also do 2 (phase only) 'it will always be =3 'ver116-4r ' Clocking is the clocking option - 0 for AD7685 and 1 for LT1860. Use same clocking option for either 12 or 16 bit serial ADC. =1 'ver116-4r ' Delay is the ADC Convert clock high time delay - 2 for AD7684, 4 for LT1960. Use same delay for both. =4 (about 5.4 usec) 'ver116-4r ' Bits is the number of data bits - 16 for AD7685, 10 for LT1860. Will always use 16. When 12 bit ADC is used, we delete the last 4 serial bits. 'ver116-4r ' Average is normally 1 - set to higher number if you want the interface to do multiple readings and average. Always use 1. 'ver116-4r UsbAdcControl.Adcs.struct = 3 'ver116-4r UsbAdcControl.Clocking.struct = 1 'ver116-4r UsbAdcControl.Delay.struct = 4 'ver116-4r UsbAdcControl.Bits.struct = 16 'ver116-4r UsbAdcControl.Average.struct = 1 'ver116-4r '---------End items for USB interface------------ '---------------END OF VARIABLES DECLARATIONS------- nomainwin Open "OLE32.dll" for dll as #DLL.OLE 'ver116-4q CallDLL #DLL.OLE, "CoInitialize", 0 as ULong, res as ULong 'To avoid tooltips crash in file dialog ver116-4q 'Suppress parallel port if we don't have the DLLs if uVerifyDLL("ntport") then suppressHardware=0 else suppressHardware=1 'may change when we have cb info if uVerifyDLL("msadll") then bUsbAvailable = 1 else bUsbAvailable = 0 'USB:01-08-2010 ' attempt to initialise the USB interface. Can be called even when open if bUsbAvailable then call UsbOpenInterface 'USB:01-08-2010 if USBdevice <> 0 then 'USB:16-08-2010 CALLDLL #USB, "UsbMSAGetVersions", USBdevice as long, result as ushort 'USB:16-08-2010 if int( result / 256) < 2 then 'USB:16-08-2010 call UsbCloseInterface 'USB:16-08-2010 notice "The version number of msadll is too old for me to use" 'USB:05/12/2010 end if 'USB:05/12/2010 if int( result and 255 ) < 36 then 'USB:16-08-2010 call UsbCloseInterface 'USB:16-08-2010 notice "The USB interface is either not plugged in or is too old a version for me" 'USB:05/12/2010 end if 'USB:05/12/2010 end if 'USB:16-08-2010 ' needs to be more complex - this flag uses USB if it is available ' do not set it if bUsbAvailable is not set ' create a memory block for holding dds data (akin to cmdallarray[][] but accessible within dll) AllArrayBlockSize = 801*40 'USB:01-08-2010 DeviceArrayBlockSize = 801 * 8 'USB:06-08-2010 hSAllArray = GlobalAlloc( AllArrayBlockSize ) 'USB:01-08-2010 ptrSAllArray = GlobalLock( hSAllArray ) 'USB:01-08-2010 hSDDS1Array = GlobalAlloc( DeviceArrayBlockSize ) 'USB:06-08-2010 ptrSDDS1Array = GlobalLock( hSDDS1Array ) 'USB:06-08-2010 hSDDS3Array = GlobalAlloc( DeviceArrayBlockSize ) 'USB:06-08-2010 ptrSDDS3Array = GlobalLock( hSDDS3Array ) 'USB:06-08-2010 hSPLL1Array = GlobalAlloc( DeviceArrayBlockSize ) 'USB:06-08-2010 ptrSPLL1Array = GlobalLock( hSPLL1Array ) 'USB:06-08-2010 hSPLL3Array = GlobalAlloc( DeviceArrayBlockSize ) 'USB:06-08-2010 ptrSPLL3Array = GlobalLock( hSPLL3Array ) 'USB:06-08-2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceSetAllArrayPtr", USBdevice as long, ptrSAllArray as long, 800 as short, 40 as short, result as boolean 'USB:01-08-2010 interpolateMarkerClicks=0 'Note user has no way to change this ver115-1a steps = 400 globalSteps=400 'SEWgraph call gSetNumDynamicSteps steps 'ver114-1f graphBox$="" 'ver115-1a markerIDs$(0)="1" : markerIDs$(1)="2" : markerIDs$(2)="3" : markerIDs$(3)="4" 'SEWgraph markerIDs$(4)="5" : markerIDs$(5)="6" : markerIDs$(6)="L" : markerIDs$(7)="R" 'SEWgraph markerIDs$(8)="P+" : markerIDs$(9)="P-" 'SEWgraph '-------Initialize Modules--------- call uInitFirstUse 'Initialize Utilities Module call configInitFirstUse 'Initialize Configuration Module 'call calInitFirstUse 201, 1001, hasVNA 'delver116-1b This is done a few lines below '----------------Load Configuration File--------- 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 'Will quit program when finished 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 else 'Be sure we have the Wide filter. This line is needed for smooth transition from 'ver115 to ver116. ver1116-4f if VideoFilterNames$(1)<>"Wide" then VideoFilterNames$(1)="Wide" : VideoFilterCaps(1,0)=0.002 : VideoFilterCaps(1,1)=0.011 call configSaveFile 'Save config file in current format ver114-5i end if end if 'Convert Configuration Globals into Locals port=globalPort 'SEW5 add ver113-7c glitchtime=0 'SEW5 add ver113-7c; ver114-5k deleted globalGlitchtime status=port+1 'SEW5 add ver113-7c control=port+2 'SEW5 add ver113-7c bandEnd1G=1000 : bandEnd2G=2000 'good for now ver116-4s if cb=3 then suppressHardware=0 '3 means USB. suppressHardware relates only to parallel port ver116-4b 'An initial low on the PS bit that controls latched switches may be draining switch capacitors 'Set it high and allow some recharge time. At this point we don't care what the switches get set to, 'and if the capacitors are discharging the switches won't change state at all. freqBand=1 : call SelectLatchedSwitches 1 'ver116-4h ver116-4s call uSleep 1000 'Wait 1 second for capacitor recharge. There will be additional software delays before PS is used. 'The following was moved here by ver115-1a so that hasVNA is set first call calInitFirstUse 201, 1001, hasVNA 'Initialize Mag/Freq Calibration Module--201 max mag cal points; 1001 max freq cal points ver114-4b 'ResizeArrays needs TGtop, so we do it after loading config file call ResizeArrays 2001 'Make all arrays big enough for 2001 points; also loads BaseLineCal file 'ver114-5m '---------Load path and freq calibration info------ 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 MSAFiltStrings$(i-1)="P"+str$(i)+" "+configFormatFilter$(MSAFilters(i,0), MSAFilters(i,1)) 'ver113-7c next i 'The below are not actually the desired states. See step 3 (initialization) for explanation. 'The latched filter addresses will be asserted by SelectVideoFilter because the video filter 'shares the same latch. But the PS bit will not be toggled, so this will not actually affect 'latched switches that rely on PS, and won't drain capacitors. But this will help initialize 'latched switches that generate the latching pulse from a change of address. 'This is done after loading config file so capacitor info is available, and after 'loading cal files so auto wait info is available. videoFilter$="Wide" : freqBand=2 : switchTR=1 : switchFR=1 : call SelectVideoFilter 'ver116-4s '---------Create OperatingCal Folder------------- if TGtop>0 then isErr=CreateOperatingCalFolder() 'Create OperatingCal folder if it does not exist if isErr then notice "Unable to create OperatingCal folder." end if '-----Load or create coax data file----- call CoaxLoadDataFile 'ver115-4a '2.Establish hard "Global" variables 'For speed, most of the following are not declared global, and they are not accessible 'within true subroutines. But a couple have true global versions. contclear = 11 'to take all LPT control lines low STRB = 10 'to take LPT-pin 1 high. (SLIM Latch 4) AUTO = 9 'to take LPT-pin 14 high. (SLIM Latch 3) INIT = 15 'to take LPT-pin 16 high. (SLIM Latch 2) SELT = 3 'to take LPT-pin 17 high. (SLIM Latch 1) INITSELT = 7 'to take both LPT-pins 16 & 17 high. (INIT,SELT)(was enapt) ver111-22 STRBAUTO = 8 'to take both LPT-pins 1 & 14 high. (FQUD,WCLK)(was wclkfqud) ver111-22 global globalSTRB, globalINIT, globalSELT, globalContClear 'ver116-1b globalSTRB=STRB : globalINIT=INIT : globalSELT=SELT : globalContClear=contclear 'ver116-1b 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 cb=3 then le1=1:le2=16:le3=4:fqud1=2:fqud3=8:bUseUsb = 1 'USB:01-08-2010 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 '3.Initialize for whatever mode we will start up in 'Some of these initializations may be changed when the preferences file 'is loaded in [LoadPreferenceFile] doingInitialization=1 'ver114-3f suppressPhase=0 'Turns phase on ver116-1b suppressHardwareInitOnRestart=0 'Normally we do hardware initialization on each restart. refreshOnHalt=1 'We normally redraw the graph when we halt. multiscanIsOpen=0 multiscanInProgress=0 baseFrequency=0 'ver116-4k cftest=0 'cavity filter sweep test off ver116-4b message$="" 'ver115-1a msaMode$="SA" 'ver115-3b planeadj=0 'ver114-4i gentrk=0 : normrev=0 : sweepDir=1 'ver 114-4k refreshEachScan=1 'ver114-3f videoFilter$="Wide" 'ver116-1b useAutoWait=0 'ver116-1b autoWaitPrecision$="Normal" 'ver116-1b call TwoPortInitVariables 'initialize variables including default Y axis ranges for Two-Port ver116-1b call SelectVideoFilter 'Sets videoFilterAddress and outputs it ver116-1b 'Note the latched switches--Band, FR and TR--may actually not be "latching" (because they may just 'rely on the control board latch, and they may or may not use the Pulse Start (Latch Pulse) to trigger latching. 'If they generate their own pulse for latching based on a change of required state, we have to be sure 'that on startup they do so. For example, just setting the frequency band switch to 01 for 1G may not create 'a latch pulse, if the control board latch already had that value. We need to initialize those switches to 'two successive values. We have to wait in between to allow for some recharging of the capacitors. 'The first state was set at the very beginning of the program, to utilize the time delays of initializtion. 'Video Filter is not a latched switch, but it has to be output along with the other data 'This should work if the switch capacitors discharge only about 10% and recharge time constant is 1 second or less 'Note that SelectLatchedSwitches adds some time delay also switchTR=0 : switchFR=0 : call SelectLatchedSwitches lastSetBand 'ver116-1b ver116-4s call uSleep 500 'wait again because latching will occur again when preferences are loaded. returnBeforeFirstStep=0 'ver115-1d haltedAfterPartialRestart=0 'ver116-1b specialOneSweep=0 'ver115-1d crystalLastUsedID=0 imageSaveLastFolder$=DefaultDir$ 'Folder in which image was last saved ver115-2a touchLastFolder$=DefaultDir$ 'Folder from which param data was last loaded ver115-5f doSpecialRLCSpec$="RLC[P, R1000,C1n,L1u]" 'default for doSpecialGraph of simulated RLC RefRLCLastNumPoints=0 RefRLCLastConnect$="" 'For continuity calling ReflectionRLC analyzeQLastNumPoints=0 'For continuity in AnalyzeQ GDLastNumPoints=0 'Number of points last used for group delay analysis frontEndCalNumPoints=0 'No front end adjustment frontEndActiveFilePath$="" frontEndLastFolder$=DefaultDir$ 'ver114-3f moved the call to gInitFirstUse here from [CreateGraphWindow] gosub [FindClientOffsets] 'set clientWidthOffset and clientHeightOffset from test window ver115-1b smithLastWindowHeight=430 : smithLastWindowWidth=400 'ver115-5d currGraphBoxHeight=600-clientHeightOffset-44 'ver115-1b 'ver115-1c 44 allows for button area below box? currGraphBoxWidth=800-clientWidthOffset 'ver115-1b 'ver115-1c graphMarLeft=70 : graphMarRight=180 : graphMarTop=55 : graphMarBot=140 'SEWgraph Graph margins from edge of graphicbox call gInitFirstUse "#handle.g", currGraphBoxWidth, currGraphBoxHeight, graphMarLeft, graphMarRight, _ 'ver115-1c graphMarTop, graphMarBot 'SEWgraph Initialize graphing module gosub [InitGraphParams] 'SEWgraph 'Initialize parameters to set up the graphing module ver114-3f moved gosub [ChangeMode] 'create Graph Window in mode of msaMode$ desiredCalLevel=0 'Desire no cal ver114-6b call SignalNoCalInstalled bandLineNumSteps=-1 'Indicate cal does not exist ver114-5f; baseLine cal was handled above ver114-5mb OSLBandNumSteps=-1 'ver115-1b OSLBaseNumSteps=-1 'ver115-1b OSLLastSelectedCalSet=0 'Indicates there was no prior selection ver115-7a OSLOpenSpec$="" : OSLShortSpec$="" : OSLLoadSpec$="" 'ver116-4i OSLS11JigType$="Reflect" 'ver115-1b 'Defaults are now in place. Read the preferences file and save it. If there is no preference file 'this has the effect of creating one with the default values. If there is one, saving it updates a 'possibly old preferences file to the current format. 'ver114-3f added instructions to load and save preference file restoreFileName$=DefaultDir$+"\MSA_Info\MSA_Prefs\Prefs.txt" 'tells [LoadPreferenceFile] what to load gosub [LoadPreferenceFile] 'ver115-8c 'call uSleep 500 'Loading Preferences may re-latch switches; allow some recharge time ver116-1b delver116-4d if restoreErr$<>"" then 'ver115-1b 'Error. If error was that file does not exist at all, that is OK; we'll create one fileHndl$=OpenContextFile$(restoreFileName$,"IN") if fileHndl$<>"" then 'A file exists and it is bad close #fileHndl$ notice "Error in Preference File: ";restoreErr$ 'ver114-7n else restoreErr$="" 'Clear error if problem was file does not exist. ver115-3c end if end if 'Resave preferences only if no serious error if restoreErr$="" then call SavePreferenceFile restoreFileName$ 'Save Preference file in current format ver115-4a if gGetXIsLinear() then userFreqPref=0 else userFreqPref=1 'Start with Center/Span for linear, Start/Stop for log 'ver115-1d call mClearMarkers 'Clear all graph markers '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. '5.Command Filter Bank [InitializeHardware] 'These hardware initializations are performed on startup and usually repeated on Restart. The reason 'they are repeated on Restart is to fix any hardware glitches that might occur. Whenever it is known 'that a hardware change is made, such as filter selection changing, it is best to take action immediately, 'and not rely on the Restart process. In some cases, Restart skips these initializations for speed. if suppressHardware=0 and cb<3 then 'ver115-6c USB:02-08-2010 added cb test out port, 0 'begin with all data lines low if cb = 2 then 'ver116-1b out control, INITSELT 'latch "0" into SLIM Control Board Buffers 1 and 2 out control, AUTO 'latch "0" into SLIM Control Board Buffers 3 'We don't clear SLIM Buffer 4, because it controls among other things the latched switches 'It was initialized near the beginning to make the PS line high. end if out control, contclear 'begin with all control lines low end if if (cb = 3) and (bUseUSB<>0) then 'USB:01-08-2010 USBwrbuf$ = "A5010000" ' reset all lines low 'USB:01-08-2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 4 as short, result as boolean 'USB:01-08-2010 end if 'USB:01-08-2010 'the following are meaningless values to guarantee first time commanding. Used in subroutine, [DetermineModule] lastdds1output = appxdds1:lastdds3output = appxdds3:lastpdmstate = 2 'ver111-28 lastncounter1 = 0 : lastncounter3 = 0 'to guarantee Original MSA will command PLL's after init. ver114-6c error$="" : errora$="" 'ver115-1c 'Initialize Final Filter path. call CommandFilter filtbank 'Commands and sets filtbank. Does nothing if suppressHardware=1. ver115-6c call SelectVideoFilter 'reselect video filter in case a glitch got it 'ver116-1b 'Note we don't reset the latched switches on Restart (for startup, they are set when prefs are loaded), 'because it can get obnoxius and requires a time delay. 'Plus, we don't want to set them when the user makes a change, and immediately set again on Restart. 'These switches are properly set whenever DetectChanges is called, which should take care of them. 'ver116-4d deleted call to SelectLatchedSwitches '6.if configured, initialize DDS3 by reseting to serial mode. Frequency is commanded to zero if suppressHardware then goto [SkipHardwareInitialization] 'In case there is no hardware ver115-6c 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 if cb = 3 then gosub [ResetDDS3serUSB] 'USB:01-08-2010 '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] 'skips to here if no TG '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 'ver115-1c LO2 is now global '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 'Create rcounter1 ver114-2e rcounter1=int(appxdds1/PLL1phasefreq) 'ver114-2e if (appxdds1/PLL1phasefreq) - rcounter1 >= 0.5 then rcounter1 = rcounter1 + 1 'rounds off rcounter ver114-2e if spurcheck=1 and PLL1mode=0 then rcounter1 = rcounter1 +1 'only do this for IntegerN PLL ver114-2e '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 resetting. 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 if cb = 3 then gosub [ResetDDS1serUSB]'reset serial DDS1 without disturbing Filter Bank or PDM 'USB:01-08-2010 [SkipHardwareInitialization] 'Skips to here if there is no hardware (suppressHardware=1) ver115-6c cb=cb 'to avoid two labels in a row '11.[BeginScanSeries] get info from windows and update variables [BeginScanSeries] 'Start a new series of scans, which requires some initialization '12.[InitializeGraphModule] suppressPDMInversion=0 'ver115-1a 'ver115-8d moved test for specialOneSweep to step 14 gosub [UpdateGraphParams] 'SEWgraph Update graph module for any changes made by the user firstScan=1 'Signal that the next scan is the first after Restart 'ver114-5f moved some items to UpdateGraphParams 'Note x values must be calculated first (in [UpdateGraphParams]) ; modVer115-1c 'If calInProgress=1, InstallSelectedxxx will just set applyCal=0 and installed base steps=-1 'ver116-4b if msaMode$="Reflection" then call InstallSelectedOSLCal else if msaMode$<>"SA" then call InstallSelectedLineCal 'ver115-8c end if cycleNumber=1 : call gSetTraceColors cycleColorsAxis1$(1),cycleColorsAxis2$(1) 'ver116-4s call gGetTextColors xText$, dum1$, dum1$, gridText$ 'ver116-4s call gSetTextColors xText$, cycleColorsAxis1$(1),cycleColorsAxis2$(1), gridText$ 'match text to trace ver116-4s doCycleTraceColors=0 'start with cycling off. No preference file item for this. ver116-4s call gInitDynamicDraw 'Set up for first scan of dynamic draw/erase/redraw... call ImplementDisplayModes 'Done in [UpdateGraphParams] but gInitDynamicDraw overrode it 'ver115-4e 'In multiscan, we don't want to update the time stamp on every redraw, which sometimes happens without scanning. if multiscanIsOpen=0 or multiscanInProgress=1 then 'ver115-9a restartTimeStamp$=date$("mm/dd/yy"); "; ";time$() 'ver115-2c call gSetTitleLine 3, restartTimeStamp$ 'SEWgraph Put date and time in line 3 of title if gGetXIsLinear() then call gSetTitleLine 4, "MSA Linear Sweep ";path$ _ else call gSetTitleLine 4, "MSA Log Sweep ";path$ 'Save linear/log and path info ver116-1b end if 'For multiscan, the redraw of the background is done prior to scanning via [PartialRestart], and on refresh if multiscanInProgress=0 then 'Redraw background stuff on first scan of a series. ver115-8d 'ver115-8d deleted calc of centerstep, which is no longer used call gDrawGrid 'SEWgraph; Clear graphics area and draw the background grid and labels. Wipes out all prior flushes. call DrawSetupInfo 'SEWgraph Draw info describing the sweep setup if smithGraphHndl$()<>"" then 'ver115-1b draw smith chart if we have one ver115-1e call smithRedrawChart 'Draw blank chart ver115-2c end if if referenceLineType<>0 then 'Draw reference lines ver114-8a if referenceLineType>1 then call CreateReferenceSource 'RLC or fixed value call CreateReferenceTransform 'Generate actual reference graph data call gClearAllReferences if referenceDoMath=0 then 'don't draw ref if we are using ref for math if (referenceTrace and 2) then call gAddReference 1,CreateReferenceTraces$(referenceColor2$,referenceWidth2,2) 'Do Y2 reference if (referenceTrace and 1) then _ call gAddReference 2,CreateReferenceTraces$(referenceColor1$,referenceWidth1,1) 'Do Y1 reference call gDrawReferences refHeadingColor1$=referenceColor1$ : refHeadingColor2$=referenceColor2$ 'ver115-5d else call gGetTraceColors refHeadingColor1$, refHeadingColor2$ 'Use trace colors for "REF" if math is used end if call PrintReferenceHeading 'Print above axis to indicate which line matches which axis 'ver115-5d end if #graphBox$, "flush" 'Make the setup info stick end if useExpeditedDraw=gCanUseExpeditedDraw() 'SEWgraph; For normal SA use, [gDrawSingleTrace] will be used. 'ver115-1a deleted printing of glitchtime doingInitialization=0 'We are done with initialization on startup 'ver114-4g moved if calInProgress=1 then 'ver114-5g message$="Calibration in progress." : call PrintMessage 'ver114-4g else message$="" : call PrintMessage 'ver114-4f end if if msaMode$="SA" and gentrk=0 and multiscanInProgress=0 then 'ver115-4f if (endfreq-startfreq)/steps >finalbw/1000 then 'compare as MHz message$= "Frequency step size exceeds RBW; signals may be missed." call PrintMessage end if end if '13.Calculate the command information for first step through last step of the sweep and put in arrays cursor hourglass 'ver116-4k 'ver116-4s changed this so datatable and phaarray are set up here whether or not suppresshardware=1. for i=0 to steps thisfreq=gGetPointXVal(i+1) 'Point number is 1 greater than step number SEWgraph if msaMode$<>"SA" then 'Store actual signal freq in VNA arrays ver116-1b if msaMode$="Reflection" then ReflectArray(thisstep,0)=thisfreq _ else S21DataArray(thisstep,0)=thisfreq end if if freqBand=0 then 'ver116-4s thisBand=1 if thisfreq>bandEnd2G then thisBand=3 else if thisfreq>bandEnd1G then thisBand=2 'set band if auto-band else thisBand=freqBand end if if thisBand<>1 then thisfreq=Equiv1GFreq(thisfreq, thisBand) 'Convert from actual freq to equivalent 1G frequency ver116-4s datatable(i,0) = thisstep 'put current step number into the array, row value= thisstep 'moved ver111-18 datatable(i,1) = thisfreq datatable(i,4)=thisBand 'ver116-4s phaarray(i,0) = 0 'pdm state next i if suppressHardware=0 then 'Do these only if we are using the hardware 'ver115-6c ver116-4s gosub [CalculateAllStepsForLO1Synth] 'ver111-18 if TGtop > 0 then gosub [CalculateAllStepsForLO3Synth] 'ver111-18 gosub [CreateCmdAllArray] 'ver111-31b end if call CalcFreqCorrection 'Calculate power correction at each frequency SEWgraph1 cursor normal 'ver116-4k if msaMode$="SA" and frontEndActiveFilePath$<>"" then call frontEndInterpolateToScan 'Calculate corrections for front end ver115-9d continueCode=0 'SEWgraph Set to other values by subroutines to cause halt, wait or restart scanResumed=0 'used to indicate whether we start with a new scan(0) or resume where we left off(1)SEW haltedAfterPartialRestart=0 'May get set to 1 a few lines below. 116-1b 'ver114-6e Normally, refresh will occur at end of scan only if halted or refreshEachScan=1, 'and will be done by expedited methods. But if the user makes certain changes, the following 'variables are used to force more extensive redrawing. call mDeleteMarker "Halt" 'ver114-4h moved the -4d version suppressSweepTime=1 'to suppress it for the first scan ver114-4h 'if we just want to go through the initialization procedure we set returnBeforeFirstStep 'and invoke [Restart] with a gosub; here we return to the caller 'Save some sweep settings for reflection and transmission for use when changing 'back to a previously used mode, so we know the nature of the last gathered data if msaMode$="Reflection" then 'ver116-1b refLastSteps=steps : refLastStartFreq=startfreq : refLastEndFreq=endfreq : refLastIsLinear=gGetXIsLinear() refLastGraphR0=S11GraphR0 refLastY1Type=Y1DataType : refLastY1Top=Y1Top : refLastY1Bot=Y1Bot : refLastY1AutoScale=autoScaleY1 refLastY2Type=Y2DataType : refLastY2Top=Y2Top : refLastY2Bot=Y2Bot : refLastY2AutoScale=autoScaleY2 for i=1 to 4 : refLastTitle$(i)=gGetTitleLine$(i) : next i else if msaMode$="VectorTrans" then transLastSteps=steps : transLastStartFreq=startfreq : transLastEndFreq=endfreq : transLastIsLinear=gGetXIsLinear() transLastGraphR0=S21JigR0 transLastY1Type=Y1DataType : transLastY1Top=Y1Top : transLastY1Bot=Y1Bot : transLastY1AutoScale=autoScaleY1 transLastY2Type=Y2DataType : transLastY2Top=Y2Top : transLastY2Bot=Y2Bot : transLastY2AutoScale=autoScaleY2 for i=1 to 4 : transLastTitle$(i)=gGetTitleLine$(i) : next i end if end if if returnBeforeFirstStep then 'ver115-2a thisstep=sweepStartStep returnBeforeFirstStep=0 haltedAfterPartialRestart=1 'ver116-1b gosub [CleanupAfterSweep] return 'ver115-1d end if '14.[StartSweep]'Begin sweeping from step 0 'StartSweep begins the outer loop that repeats the entire scan process until halted. 'The scan loop continues until a user action which aborts the scan, or in the case of 'OneStep it continues only for a single point. If specialOneSweep=1 or HaltAtEnd=1, it 'automatically stops at the end of a single sweep. [StartSweep]'enters from above, or [IncrementOneStep]or[FocusKeyBox]([OneStep][Continue]) if specialOneSweep then haltAtEnd=1 else haltAtEnd=0 'ver115-8d moved this here if haltedAfterPartialRestart=0 and scanResumed=1 then 'ver116-1b 'For a resumed scan, a halt occurred after the previous step and that step was fully processed. 'haltsweep will equal 0. If alternateSweep=1 and the halt occurred at the end of a sweep, we need to 'repeat the last point as the first point of the new sweep. But in the case where we are continuing 'after a halt resulting from partial restart, we returned before the first step was taken and need to 'start with that step. call mDeleteMarker "Halt" 'ver114-4h moved the -4d version if thisstep = sweepStartStep and syncsweep = 1 then gosub [SyncSweep] 'ver112-2b; ver114-4k if alternateSweep=0 or haltWasAtEnd=0 then 'ver114-5c Go to next step unless we need to repeat this one if sweepDir=1 then if thisstepsweepEndStep then thisstep = thisstep - 1 else thisstep=sweepStartStep end if end if else 'ver114-5c No longer need to retest scanResumed thisstep=sweepStartStep 'ver114-4k end if haltedAfterPartialRestart=0 'Reset. Will stay zero until next partial restart. 116-1b scanResumed=0 'Reset flag '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 [CommandCurrentStep] 'ver116-4j made this a separate routine '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 call DisplayButtonsForHalted 'ver114-4f replaced call to [UpdateBoxes] call mAddMarker "Halt", thisstep+1, "1" 'ver114-4d 'If marker is shown on graph, we need to redraw the whole graph 'Otherwise just redraw the marker info if doGraphMarkers then call RefreshGraph 0 else call mDrawMarkerInfo 'No erasure gap in redraw ver114-5m if thisstep=sweepEndStep then 'Note reversal is after graph is redrawn if alternateSweep then gosub [ReverseSweepDirection] 'ver114-4m; ver114-5e haltWasAtEnd=1 'ver114-5c else haltWasAtEnd=0 'ver114-5c end if 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 in middle of sweep. process and print the previous step, then read this step gosub [ProcessAndPrintLastStep] gosub [ReadStep]'read this step 'ver113-6d end if 'ver116-4k moved sweep time here, so it prints after any refresh action from the prior scan if displaySweepTime and thisstep=sweepStartStep then currTime=Time$("ms") if suppressSweepTime=0 then _ message$= "Sweep Time=";using("####.##", (currTime-startTime)/1000);" sec." : call PrintMessage 'ver114-4h suppressSweepTime=0 'Only suppress on first scan 'ver114-4h startTime=currTime 'SEWgraph timer for testing end if '17.[Scan] Check to see if a button has been pushed 'SEWgraph Note that on any user action, if haltsweep=1 the action must have been detected 'during the following "scan". But if haltsweep=0 the action occurred during a wait state. 'Exception: Window resizing is detected when it happens, not during "scan". [Scan] 'ver113-6d scan 'check for any button push and go there. ver111-26 'otherwise, continue sweeping. [PostScan] 'SEWgraph. Label is used to return here after a button action handled by a [xyz] routine. 'SEWgraph Note: after a button handler in the form of a true subroutine, control will exit sub back 'to this point. We do not want a "wait" to occur in such a subroutine, because that will suspend 'control in a non-global namespace, and the user will be unable to take actions that require access 'to [xyz] routines. To cause a halt, wait or restart in such a subroutine, the subroutine should set 'the global variable continueCode to 1, 2 or 3. if continueCode<>0 then ' =0 means continue normally if continueCode=1 then continueCode=0 : goto [Halted] '=1 means halt immediately if continueCode=2 then continueCode=0 : haltsweep=0 : wait '=2 means wait immediately continueCode=0 : haltsweep=0 : goto [Restart] 'Anything else means restart end if '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 = sweepEndStep and syncsweep = 1 then gosub [SyncSweep] 'ver112-2b 'ver114-4k 'ver114-5a modified the following if sweepDir=1 then 'ver114-4k added this block to handle possible reverse sweeps if thisstepsweepEndStep then thisstep = thisstep - 1 :goto [CommandThisStep] 'ver114-4k end if 'If we are here, we have just read the final step of a sweep if haltAtEnd=0 then 'Alternate sweep directions if required. When we switch direction, thisstep 'was the final point of one sweep and becomes the first point of the next. 'We process and print it immediately as the last point of this sweep; then reverse 'direction and start with the same point. To avoid re-processing it at the next step we 'set haltsweep=0. if alternateSweep then 'ver114-5c gosub [ProcessAndPrint] gosub [ReverseSweepDirection] haltsweep=0 end if goto [StartSweep] 'SEWgraph Repeat loop over scans if halt flag not set end if 'SEWgraph We fall out of this loop only when haltAtEnd=1 and we reach thisstep=sweepEndStep '[EndSweepSeries] 'This label marks the end of the scan loops. '19.[Halted] [Halted] 'SEWgraph moved guts of this to FinishSweeping, which can also be called from elsewhere if desired. gosub [FinishSweeping]'get raw data, process, print to the computer monitor ver111-22 if specialOneSweep then specialOneSweep=0 return 'Sweep process was called by gosub; we return to caller. end if wait 'wait for operator action 'SEWgraph created FinishSweeping; 'ver114-6e split the non-graphing cleanup into [CleanupAfterSweep] [FinishSweeping] 'SEWgraph0 Do cleanup to end sweeping but return for further actions 'This is a modified version of the former [Halted], without the wait at the end gosub [ProcessAndPrint]'process, print to the computer monitor ver111-22 if haltAtEnd=0 then call mAddMarker "Halt", thisstep+1, "1" 'Add Halt marker ver114-4d haltsweep=0 'do now so RefreshGraph will "flush" ver115-1a if isStickMode=0 then if refreshOnHalt then 'ver115-8c refreshGridDirty=1: call RefreshGraph 1 'SEWgraph; redraw and show erasure gap; don't do if stick mode ver114-7d else 'We sometimes don't want to waste time redrawing, such as when we are loading a data file, 'but we at least need to flush to make the graphics stick. #graphBox$, "flush" end if end if if specialOneSweep and thisstep <> sweepEndStep then beep: message$="Sweep Aborted" 'ver115-4b else if calInProgress then beep: message$="Calibration Complete" 'ver115-4b end if 'test 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. if test<>0 then message$=str$(test) if message$<>"" then call PrintMessage 'ver115-4b 'Alternate sweep directions if required; added by ver114-5a if thisstep=sweepEndStep then if alternateSweep then gosub [ReverseSweepDirection] 'ver114-5a goto [CleanupAfterSweep] [CleanupAfterSweep] 'Do cleanup after a sweep to be sure flags are set/reset properly 'Called by [FinishSweeping]. Can also be called by other routines to immediately 'terminate a sweep when they will be Restarting so they don't care about finishing the plotting. call DisplayButtonsForHalted 'ver114-4f replaced call to [UpdateBoxes] if thisstep=sweepEndStep then haltWasAtEnd=1 else haltWasAtEnd=0 'ver114-5c haltAtEnd=0 'SEWgraph In case we got here from auto halt at end of sweep calInProgress=0 'ver114-5h haltsweep = 0 'this says the sweep has been halted, so don't print the first command of the next sweep step 'ver111-20 return [ReverseSweepDirection] 'Reverse direction of sweep 'This is called after sweepEndStep has been fully processed, but only if alternateSweep=1 if sweepDir=1 then sweepDir=-1 sweepStartStep=steps : sweepEndStep=0 else sweepDir=1 sweepStartStep=0 : sweepEndStep=steps end if call gSetSweepDir sweepDir 'Notify graph module of new direction return 'ver116-4j made [CommandCurrentStep] a separate gosub from the old [CommandThisStep] so it can be called not only during regular scanning, 'but on in combination with [ReadStep] to command and read a particular step, once all info is set up. [CommandCurrentStep]'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 if suppressHardware=0 then 'ver115-6c thisBand=datatable(thisstep,4) : if thisBand<>lastSetBand then call SelectLatchedSwitches thisBand 'Set band switch ver116-4s 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 if cmdneeded > 0 and cb = 3 then gosub [CommandAllSlimsUSB] 'USB:01-08-2010 if cftest=1 then gosub [CommandLO2forCavTest] 'cav ver116-4c end if return [FindClientOffsets] 'set clientWidthOffset and clientHeightOffset from test window ver115-1b 'Open a small test window so we can find the client area to determine how much 'smaller it is than the full window size. WindowWidth = 150 : WindowHeight = 150 UpperLeftX = 1 : UpperLeftY = 1 menu #handle, "File", "Save Image", [SaveImage] 'We need a menu to get the size right open "Test" for window as #handle 'Now that we have a window, find the actual client area--ver114-7o hWind = hWnd(#handle) 'Windows handle of graph window STRUCT Rect, leftX as long, upperY as long, rightX as long, lowerY as long 'To hold the returned data calldll #user32,"GetClientRect", hWind as ulong, Rect as struct, r as long 'Fill Rect with size info 'The offsets will be the size difference between the full window and the client area clientWidthOffset = 150-(Rect.rightX.struct-Rect.leftX.struct) clientHeightOffset = 150-(Rect.lowerY.struct-Rect.upperY.struct) close #handle 'We don't need the test window anymore return [ResizeGraphHandler] 'Called when graph window resizes #handle, "hide" 'hide window to avoid multiple system redraws ver115-1b #graphBox$ "home" #graphBox$ "posxy CenterX CenterY" currGraphBoxWidth = CenterX * 2-1 'ver115-1c currGraphBoxHeight = CenterY * 2-1 'ver115-1c 'Note: On resizing, all non-buttons seem to end up a few pixels higher than the original spec, 'so the Y locations are adjusted accordingly via markTop 'Note WindowHeight when window is created is entire height; on resizing, it is the client area only markTop=currGraphBoxHeight+15 : markSelLeft=5 'ver115-1b 'ver115-1c markEditLeft=markSelLeft+55 markMiscLeft=markEditLeft+185 configLeft=markMiscLeft+80 #handle, "refresh" #handle.Cover, "!show" 'Cover the crap that can appear from resizing #handle.Cover, "!hide" 'Uncover and the crap is gone #handle, "show" 'show window ver115-1b 'The graphicbox auto resizes but we have to update the graph module 'to let it know the new size call gUpdateGraphObject graphBox$, currGraphBoxWidth, currGraphBoxHeight, _ 'ver115-1c graphMarLeft, graphMarRight, graphMarTop, graphMarBot call gCalcGraphParams 'Calculate new scaling. May change min or max. call gGetXAxisRange xMin, xMax : if startfreq<>xMin or endfreq<>xMax then call SetStartStopFreq xMin, xMax call gGenerateXValues gPointCount() 'recreate x values and x pixel locations; keep same number of points call gRecalcPix 0 '0 signals not to recalc x pixel coords, which we just did in gGenerateXValues. 'If a sweep is in progress, we don't want to redraw from here, because that can cause a crash. 'So we just clear the graph and signal to wait for the user to redraw. This crash may have to 'do with the fact that we don't know where we are in the sweep process when resizing is invoked, 'because it is not synchronous with the scan command. Or it may simply have something to do with 'the fact that no button has yet been pushed on the graph window, which somehow affects the 'LB resizing process. The crash still sometimes occurs, so it is best to halt before resizing. if haltsweep=1 then #graphBox$, "cls" notice "Warning: Halt before resizing to avoid LB bug." call RequireRestart 'ver115-9e Otherwise old graph still appears, in wrong place. else refreshRedrawFromScratch=1 'To redraw from scratch ver115-1b call RedrawGraph 0 'Redraw at new size end if 'call RequireRestart 'ver115-9e Not sure why we should require restart wait sub ImplementDisplayModes 'calculate the various items from Y1DisplayMode and Y2DisplayMode 'Y1DisplayMode, Y2DisplayMode: 0=off 1=NormErase 2=NormStick 3=HistoErase 4=HistoStick 'ver115-2c added checks for constNoGraph if (Y1DataType<>constNoGraph and (Y1DisplayMode=2 or Y1DisplayMode=4)) or _ (Y2DataType<>constNoGraph and (Y2DisplayMode=2 or Y2DisplayMode=4)) then isStickMode=1 else isStickMode=0 call gSetDoAxis Y1DataType<>constNoGraph, Y2DataType<>constNoGraph 'Turn graph data on or off ver115-3b 'Note that gActivateGraphs won't activate a graph if we just set its data existence to zero ver115-3b call gActivateGraphs Y1DisplayMode<>0,Y2DisplayMode<>0 'Turn actual graphing on or off ver115-3b if (Y1DataType<>constNoGraph and Y1DisplayMode>2) or (Y2DataType<>constNoGraph and Y2DisplayMode>2) then _ call gSetDoHist 1 else call gSetDoHist 0 'Set histogram or normal trace ver115-3b call gGetTraceWidth t1Width, t2Width 'ver114-4n Erase eraseLead points ahead of drawing. The more steps, the larger eraseLead if globalSteps<=50 then 'ver114-4n reduced eraseLead eraseLead=1 else eraseLead=2+int(steps/400) if ((Y1DataType<>constNoGraph and t1Width>2) or _ (Y2DataType<>constNoGraph and t2Width>2)) _ and globalSteps>200 then eraseLead=eraseLead+1 end if if Y2DisplayMode<>1 and Y2DisplayMode<>3 then doErase2=0 else doErase2=1 'ver114-2f if Y1DisplayMode<>1 and Y1DisplayMode<>3 then doErase1=0 else doErase1=1 'ver115-3b call gSetErasure doErase1, doErase2, eraseLead end sub 'SEWgraph added UpdateGraphParams; ver114-4n made it a gosub to allow use of non-globals [UpdateGraphParams] 'Set up graphs for drawing, but don't draw anything if alternateSweep then sweepDir=1 : call gSetSweepDir 1 'Start out forward if alternating ver114-5a sweepDir=gGetSweepDir() 'ver114-4k if sweepDir=1 then 'ver114-4k added this if... block 'Forward direction sweepStartStep=0 : sweepEndStep=steps else 'Reverse direction sweepStartStep=steps : sweepEndStep=0 end if 'ver115-3b deleted settings related to Y2DisplayMode and Y1DisplayMode. They were overridden in ImplementMagPhaDisp, 'which is called by UpdateGraphDataFormat 'ver115-1d deleted the separate call for linear mode. startfreq and endfreq are now valid in all modes. call gInitGraphRange startfreq, endfreq, _ Y1Bot, Y1Top, Y2Bot, Y2Top 'min and max values for x, y1 and y2; calls gCalcGraphParams call gCalcGraphParams 'Calculate new scaling. May change min or max. call gGetXAxisRange xMin, xMax 'in case gCalcGraphParams changed axis limits ver116-4k if startfreq<>xMin or endfreq<>xMax then call SetStartStopFreq xMin, xMax 'ver116-4k 'ver114-5f moved the following here from step 12 call gGenerateXValues 0 'Precalculate x values for steps+1 points; reset number of points to 0; ver114-1f deleted parameter call UpdateGraphDataFormat 0 return sub UpdateGraphDataFormat doTwoPort 'Update graph module for the type of data we are graphing, and set data source and component 'If doTwoPort, we are dealing with two-port graphs ver116-1b call gSetGridStyles "EndsAndCenter", "All", "All" 'For linear sweep we display frequency in MHz; for log we do 1, 1 K, 1 M, or 1 G if gGetXIsLinear() then 'ver114-6d modified this block to use startfreq/endfreq for log sweeps xForm$= "4,6,9//suffix= M" else xForm$= "3,4,5//UseMultiplier//DoCompact//Scale=1000000" 'ver115-1e end if 'ver115-2c caused the full procedure to be executed for both dataNum. 'Also eliminated default setting of yForm$ 'ver115-3a moved the select block to DetermineGraphDataFormat so others can use it for dataNum=1 to 2 if doTwoPort then 'ver116-1b if dataNum=1 then componConst=TwoPortGetY1Type() else componConst=TwoPortGetY2Type() else if dataNum=1 then componConst=Y1DataType else componConst=Y2DataType end if if componConst=constNoGraph then doData=0 'Indicates whether there is a graph ver115-2c yAxisLabel$="None" : yLabel$="None" yForm$="####.##" 'Something valid, in case it gets mistakenly used if dataNum=1 then y1AxisLabel$="None" : y1Label$="None" y1Form$="####.##" 'Something valid, in case it gets mistakenly used else y2AxisLabel$="None" : y2Label$="None" y2Form$="####.##" 'Something valid, in case it gets mistakenly used end if else doData=1 if dataNum=1 then if doTwoPort then call TwoPortDetermineGraphDataFormat componConst, y1AxisLabel$,y1Label$, y1IsPhase,y1Form$ else call DetermineGraphDataFormat componConst, y1AxisLabel$,y1Label$, y1IsPhase,y1Form$ end if else if doTwoPort then call TwoPortDetermineGraphDataFormat componConst, y2AxisLabel$,y2Label$, y2IsPhase,y2Form$ else call DetermineGraphDataFormat componConst, y2AxisLabel$,y2Label$, y2IsPhase,y2Form$ end if end if end if if dataNum=1 then doY1=doData else doY2=doData next dataNum call gSetIsPhase y1IsPhase, y2IsPhase 'Tell graph module whether data is phase call gSetAxisFormats xForm$, y1Form$, y2Form$ 'Formats for displaying the data values call gSetAxisLabels "", y1AxisLabel$, y2AxisLabel$ 'Labels for the axes; No label for freq call gSetDataLabels y1Label$, y2Label$ 'Shorter labels for marker info if doTwoPort then 'ver116-1b 'gSetDoAxis specifies whether data for the axis even exists. gActivateGraphs specifies whether 'to actually graph the data, based on display mode, which for two port is always On. call gSetDoAxis TwoPortGetY1Type()<>constNoGraph, TwoPortGetY2Type()<>constNoGraph 'Turn graph data on or off ver115-3b 'Note that gActivateGraphs won't activate a graph if we just set its data existence to zero ver115-3b call gActivateGraphs 1, 1 'Turn actual graphing on else call ImplementDisplayModes 'give effect to Y2DisplayMode and Y1DisplayMode end if end sub sub DetermineGraphDataFormat componConst, byref yAxisLabel$, byref yLabel$,byref yIsPhase,byref yForm$ 'Return format info 'componConst indicates the data type. We return 'yAxisLabel$ The label to use at the top of the Y axis 'yLabel$ A typically shorter label for the marker info table 'yIsPhase$ =1 if the value represents phase. This indicates whether we have wraparound issues. 'yForm$ A formatting string to send to uFormatted$() to format the data ' 'ver116-1b added code to display S12 or S22 instead of S21 or S11 when DUT is reversed. if switchFR=0 then Sref$="S11" : Strans$="S21" 'Forward DUT else Sref$="S22" : Strans$="S12" 'ReverseDUT end if yIsPhase=0 'Default, since most are not phase select case componConst 'ver116-4b shortened some labels case constGraphS11DB yAxisLabel$=Sref$;" Mag(dB)" : yLabel$=Sref$;" dB" yForm$="####.###" 'ver115-5d case constRawAngle 'Used for transmission mode only 'added by ver115-1i yAxisLabel$="Raw Deg" : yLabel$="Raw Deg" yIsPhase=1 yForm$="#####.##" 'ver115-5d case constAngle,constGraphS11Ang,constTheta,constImpedAng if componConst=constAngle then yAxisLabel$=Strans$;" Deg" : yLabel$=Strans$;" Deg" if componConst=constTheta then yAxisLabel$="Theta" : yLabel$="Theta" if componConst=constGraphS11Ang then yAxisLabel$=Sref$;" Deg" : yLabel$=Sref$;" Deg" if componConst=constImpedAng then yAxisLabel$="Z Deg" : yLabel$="Z Deg" yIsPhase=1 yForm$="#####.##" 'ver115-5d case constGD 'calc group delay yAxisLabel$="Grp Delay (sec)" : yLabel$="G.D." yForm$="3,2,4//UseMultiplier//DoCompact" case constSerReact yAxisLabel$="Xs" : yLabel$="Xs" yForm$="3,3,4//UseMultiplier//SuppressMilli//DoCompact" 'ver115-4e case constParReact yAxisLabel$="Xp" : yLabel$="Xp" yForm$="3,3,4//UseMultiplier//SuppressMilli//DoCompact" 'ver115-4e case constImpedMag yAxisLabel$="Z ohms" : yLabel$="Z ohms" yForm$="3,3,4//UseMultiplier//SuppressMilli//DoCompact" 'ver115-4e case constSerR yAxisLabel$="Rs" : yLabel$="Rs" yForm$="3,3,4//UseMultiplier//SuppressMilli//DoCompact" 'ver115-4e case constParR yAxisLabel$="Rp" : yLabel$="Rp" yForm$="3,3,4//UseMultiplier//SuppressMilli//DoCompact" 'ver115-4e case constSerC yAxisLabel$="Cs" : yLabel$="Cs" yForm$="3,3,4//UseMultiplier//DoCompact" case constParC yAxisLabel$="Cp" : yLabel$="Cp" yForm$="3,3,4//UseMultiplier//DoCompact" case constSerL yAxisLabel$="Ls" : yLabel$="Ls" yForm$="3,3,4//UseMultiplier//DoCompact" case constParL yAxisLabel$="Lp" : yLabel$="Lp" yForm$="3,3,4//UseMultiplier//DoCompact" case constMagDBM if msaMode$="SA" then yAxisLabel$="Magnitude (dBm)" : yLabel$="dBm" else yAxisLabel$="Power (dBm)" : yLabel$="dBm" 'ver115-1i end if yForm$="####.###" 'ver115-5d case constMagWatts yAxisLabel$="Magnitude (Watts)" : yLabel$="Watts" yForm$="3,3,4//UseMultiplier//DoCompact" case constMagDB 'Only done for Transmission if msaMode$="ScalarTrans" then 'ver115-1a yAxisLabel$="Transmission (dB)" : yLabel$="dB" else yAxisLabel$=Strans$;" dB" : yLabel$=Strans$;" dB" end if yForm$="####.###" 'ver115-1e case constMagRatio 'Only done for TG mode transmission if msaMode$="ScalarTrans" then 'ver115-4f yAxisLabel$="Trans (Ratio)" : yLabel$="Ratio" else yAxisLabel$="Mag (Ratio)" : yLabel$="Ratio" end if yForm$="3,3,4//UseMultiplier//SuppressMilli//DoCompact" 'ver115-4e case constMagV yAxisLabel$="Mag (Volts)" : yLabel$="Volts" yForm$="3,3,4//UseMultiplier//DoCompact" case constRho yAxisLabel$="Rho" : yLabel$="Rho" yForm$="#.###" case constReturnLoss 'ver114-8d yAxisLabel$="RL" : yLabel$="RL" yForm$="###.###" 'ver115-1e case constInsertionLoss 'ver114-8d yAxisLabel$="Insertion Loss(dB)" : yLabel$="IL" yForm$="###.###" 'ver115-1e case constReflectPower 'ver115-2d yAxisLabel$="Reflect Pow(%)" : yLabel$="Ref%" yForm$="###.##" case constComponentQ 'ver115-2d yAxisLabel$="Component Q" : yLabel$="Q" yForm$="#####.#" case constSWR 'ver114-8d yAxisLabel$="SWR" : yLabel$="SWR" yForm$="####.##" case constAdmitMag 'ver115-4a yAxisLabel$="Admit. (S)" : yLabel$="Y" yForm$="3,3,4//UseMultiplier//DoCompact" case constAdmitAng 'ver115-4a yAxisLabel$="Admit Deg" : yLabel$="Admit Deg" yIsPhase=1 yForm$="#####.##" case constConductance 'ver115-4a yAxisLabel$="Conduct. (S)" : yLabel$="Conduct" yForm$="3,3,4//UseMultiplier//DoCompact" case constSusceptance 'ver115-4a yAxisLabel$="Suscep. (S)" : yLabel$="Suscep" yForm$="3,3,4//UseMultiplier//DoCompact" case constNoGraph 'ver115-2c yAxisLabel$="None" : yLabel$="None" yForm$="####.##" 'Something valid, in case it gets mistakenly used case constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 auxNum=componConst-constAux0 'e.g. constAux4 produces 4 yAxisLabel$=auxGraphDataFormatInfo$(auxNum,2) : yLabel$=auxGraphDataFormatInfo$(auxNum,3) yForm$=auxGraphDataFormatInfo$(auxNum,1) case else yForm$="###.##" yAxisLabel$="Invalid" : yLabel$="Invalid" end select end sub 'SEWgraph added InitGraphParams; ver114-4n made it a gosub to allow use of non-globals [InitGraphParams] 'Initial setup for graphs 'This is called one time early on, or to re-initialize default values 'The following intialize a lot of variables that the user may subsequently override wate=0 : offset=0 : sgout=10 'ver114-3c ver114-4h gentrk=0 : normrev=0 msaMode$="SA" 'ver114-5L primaryAxisNum=2 'Primary Y axis. Eg. on restart in SA mode, mag dBm goes here moved ver116-4m call SetDefaultGraphData 'ver115-3b S21JigAttach$="Series" 'ver115-1b S21JigR0=50 : S21JigShuntDelay=0 S11BridgeR0=50 : S11GraphR0=50 S11JigType$="Reflect" 'ver115-1b call UpdateGraphDataFormat 0 'Updates from graphDataType$ planeadj=0 'ver 114-4k 'freqBand=1 'delver116-1b this is done elsewhere on startup 'call gSetMode msaMode$ delver116-1b call SetCenterSpanFreq 0, finalbw/100 'Note finalbw is in kHz, others are in MHz call gSetNumDivisions 10,10 'Number of Hor and Vert divisions call gSetTraceWidth 1, 1 'Set width of both graph traces call gUsePresetColors "DARK" 'SEWgraph Activate the appearance ver114-3c call gSetIsLinear 1, 1,1 'SEWgraph default is linear sweep ver114-3c call gSetNumDynamicSteps globalSteps 'ver114-4k alternateSweep=0: sweepDir=1 'ver 114-5a call gSetSweepDir 1 'set sweep to forward and set start/end point nums specialOneSweep=0 'No special sweep in progress doGraphMarkers=1 refreshEachScan=1 referenceTrace=0 call gGetSupplementalTraceColors referenceColor1$, referenceColor2$, dum1$, dum2$ 'ver116-4b referenceWidth1=1 : referenceWidth2=1 referenceWidthSmith=1 referenceColorSmith$=referenceColor2$ 'ver116-4b lineCalThroughDelay=0 for i=1 to 5 'clear custom names ver115-2a customPresetNames$(i)="Empty" next i call FillAppearancesArray 'ver115-2a call gSetPrimaryAxis primaryAxisNum 'ver115-3c gosub [UpdateGraphParams] return [ReadStep]'and put raw data bits into arrays. 'heavily modified ver116-1b nonPhaseMode=(msaMode$="SA") or (msaMode$="ScalarTrans") 'ver116-4e doingPhase= (suppressPhase=0) and (nonPhaseMode=0) 'ver116-4e if useAutoWait then wate=int(autoWaitTC+0.5) 'wait this much between measurements ver116-4j magIsStable=0 if doingPhase then phaseIsStable=0 else phaseIsStable=1 changePhaseADC=0 changeMagADC=0 repeatOnceMore=0 end if for readStepCount=1 to 25 'ver116-1b added auto wait time procedures 'If doing auto wait, repeat up to 25 times until readings become stable, as shown by comparing two 'successive readings. If not doing auto wait, we bail out in the middle of the first pass. 'if readStepCount=1 then readTime=uTickCount() 'DEBUG gosub [WaitStatement]'needs:wate,glitch variables,glitchtime ;slows program before reading data 'ver111-20b prevReadMagData=magdata 'Note if we are starting a new step, but not first of sweep, this is last step final data magdata = 0 'reset this variable before reading data 'Read phase even in non-phase modes unless suppressPhase=1; we just don't process it in non-phase modes if suppressPhase=0 then 'ver116-4e 'ver116-4r deleted UsbAdcControl.Adcs.struct = 3 ' USB: 15/08/10 prevReadPhaseData=phadata gosub [ReadPhase] 'and return with phadata(in bits). Also installed into pharray(thisstep,3). ' If serial AtoD, magdata is returned, but not installed in any array 'if magdata is collected during [ReadPhase], skip Read Magnitude else phadata=0 'zero phase info if we are suppressing phase phaarray(thisstep,3)=0 'phadata phaarray(thisstep,4)=0 'pdm Read state end if 'prevReadTime=readTime 'DEBUG 'readTime=uTickCount() 'DEBUG if magdata = 0 then 'ver116-4r deleted UsbAdcControl.Adcs.struct = 1 ' USB: 15/08/10 gosub [ReadMagnitude]'and return with raw magdata bits end if 'USB:05/12/2010 magarray(thisstep,3) = magdata 'put raw data into array 'the phadata could be in dead zone, but magnitude is still valid. 'if in VNA Mode and PDM is in automatic, check for phasedata (bits) for limits 'If magnitude is so low that phase is not valid and will be forced to zero, don't do PDM inversion. readStepDidInvert=0 if doingPhase then if setpdm = 0 and suppressPDMInversion=0 and _ (phadata < pdmlowlim or phadata > pdmhighlim) then 'Invert PDM and re-read after waiting. But if mag reading is too low for phase 'to be valid, don't bother. if magdata>=validPhaseThreshold then readStepDidInvert=1 : gosub [InvertPDmodule] 'ver116-1b end if end if 'Note InvertPDmodule will impose some wait time, but not very much in auto wait mode. if useAutoWait=0 then exit for 'The rest of the loop is just for determining whether to repeat when doing auto wait if repeatOnceMore then ' if thisstep>=45 and thisstep<=55 then 'For DEBUG ' print "Final Repeat: ms=";magIsStable;" ps=";phaseIsStable;" magChange=";magdata-prevReadMagData;" phaChange=";phadata-prevReadPhaseData ' end if exit for 'we just finished the extra repeat end if 'Decide whether we need to repeat ' if readStepCount=1 and thisstep>=45 and thisstep<=55 then 'For DEBUG ' print "-----------";thisstep;"--------------" ' print "First Read: wait=";wate;" ms=";magIsStable;" ps=";phaseIsStable;" mag=";magdata;" pha=";phadata; " Delay=";readTime-prevReadTime ' end if 'We want to keep reading until two successive reads are close to each other, or until the direction reverses. 'We initially waited one half time constant of the magnitude filter, took a reading, waited, 'and took a second reading. We determine here whether the changes were less than a predetermined value 'Once mag or phase is determined to be stable, we flag it as stable so we don't have 'to re-evaluate after the next read. directionReversal=0 'flag for reversal of sign of change lowLevelADC=0 if thisstep<>sweepStartStep then 'For the first read, we generate the change in readings from the readings left over 'from the previous step, but only if this is not the first step. evaluateThisRead=1 else 'Always evaluate if not first read if readStepCount>1 then evaluateThisRead=1 else evaluateThisRead=0 end if if evaluateThisRead then if magIsStable=0 then 'Evaluate mag change if mag not already deemed stable prevMagADCChange=changeMagADC 'save previous change to compare direction changeMagADC=magdata-prevReadMagData select case case magdata"Wide" then repeatOnceMore=1 magIsStable=1 : phaseIsStable=1 'pretend. Note phase will be no good at this level so we don't evaluate it. case magdatacalHighADCofCenterSlope maxADCChange=autoWaitMaxChangeHighEndADC case else 'in center region if changeMagADC<0 then 'If in center on first read but headed for low end, we may end up 'in the low end, so may want to use the minimum allowed change for center and low end 'The low end allowed change is likely much smaller than that for center. if abs(changeMagADC)>(magdata-calLowADCofCenterSlope) then 'See whether another change like this gets us to low end maxADCChange=min(autoWaitMaxChangeCenterADC,autoWaitMaxChangeLowEndADC) else maxADCChange=autoWaitMaxChangeCenterADC end if else maxADCChange=autoWaitMaxChangeCenterADC end if end select if abs(changeMagADC)<=maxADCChange then magIsStable=1 if magIsStable=0 and lowLevelADC=0 and readStepCount>1 then 'Even if we don't have two close readings, we can stop when 'the direction of change reverses, which is a sign the change is being dominated by noise. if (prevMagADCChange<0 and changeMagADC>0) _ or (prevMagADCChange>0 and changeMagADC<0) then magIsStable=1 directionReversal=1 end if end if end if 'Now do phase if phaseIsStable=0 then 'evaluate phase change if phase not already deemed stable 'Note that if we just inverted phase, it is still valid to compare this phadata to the 'previous one, because settling time will still be based on that change. if magdata1 and _ ((prevPhaseADCChange<0 and changePhaseADC>0) or (prevPhaseADCChange>0 and changePhaseADC<0)) then phaseIsStable=1 directionReversal=1 end if end if end if end if ' if thisstep>=45 and thisstep<=55 then 'For DEBUG ' print "Analysis "; readStepCount; ": ms=";magIsStable;" ps=";phaseIsStable;" mag=";magdata;" pha=";phadata;" magChange=";changeMagADC;" phaChange=";changePhaseADC;" Delay=";readTime-prevReadTime ' end if if magIsStable and phaseIsStable then 'If Precise, repeat one more 'time and stop after that without comparing readings. 'low level is already set to repeat once more unless Wide filter if (autoWaitPrecision$="Precise") then repeatOnceMore=1 'For lowLevelADC, we already set repeatOnceMore (and phase is meaningless) if lowLevelADC=0 and repeatOnceMore=0 then exit for 'Also repeat once more if ending because of direction reversal, other than 'direction reversal on second read. if directionReversal and readStepCount<3 then repeatOnceMore=1 else exit for end if end if 'No point repeating if we aren't actually reading data. But we went through the motions above 'for possible debugging use. if suppressHardware then exit for next readStepCount 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 - sweepDir,data) if thisstep=sweepStartStep then 'Added by ver114-4m thisstep=sweepEndStep 'back up one and wrap around else thisstep=thisstep-sweepDir 'Back up one step; no wraparound to worry about end if 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 'number of ms we need to wait 'ver115-1i '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" if waittime>0 then 'ver115-1i added the use of the system sleep function if doingInitialization or waittime<15 then 'For short wait times we use our own timing loop 'Also for initialization, when we are measuring glitchtime waittime=waittime*glitchtime timecounter = 0 'ver111-27 [TimeLoop] 'ver111-27 if timecounter < waittime then timecounter = timecounter + 1:goto [TimeLoop] 'ver111-27 else 'It is preferable to use the system Sleep function, but it operates in increments of 10-15 ms. 'So it is only suitable for long wait times call uSleep waittime end if end if glitchp1=0:glitchd1=0:glitchp3=0:glitchd3=0:glitchpdm=0:glitchhlt=0 'reset glitch variables back to 0 'ver111-27 return [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 suppressHardware then magdata=0 : return 'ver115-6c if adconv = 8 then gosub [Read8Bitmag] 'and return here with magdata if adconv = 12 then gosub [Read12Bitmag] 'and return here with magdata if cb = 3 then gosub [ReadADCviaUSB] ' and return here with magdata and phadata 'ver116-4r if cb <> 3 and adconv = 16 then gosub [ReadAD16Status]:gosub [Process16Mag] 'ver116-4r 'and return here with just magdata 'ver111-33b if cb <> 3 and adconv = 22 then gosub [ReadAD22Status]:gosub [Process22Mag] 'ver116-4r '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 suppressHardware then 'ver115-6c phadata=0 else select case adconv 'ver116-1b case 8 gosub [Read8Bitpha] 'and return here with phadata only case 12 gosub [Read12Bitpha] 'and return here with phadata only case else if cb = 3 then gosub [ReadADCviaUSB] 'ver116-4r if cb <> 3 and adconv = 16 then gosub [ReadAD16Status]:gosub [Process16MagPha] 'ver116-4r if cb <> 3 and adconv = 22 then gosub [ReadAD22Status]:gosub [Process22MagPha] 'ver116-4r ' and return here with magdata and phadata end select end if if doSpecialGraph>0 then phadata=maxpdmout/4 + thisstep*30 'SEWgraph Force to a value not requiring constant inversion '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 doingPDMCal = 1 then return 'to [CalPDMinvdeg] 'ver111-29 ver114-5L 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 for this step and future steps 'ver111-28 'entered from [ReadStep], where it was determined that phadata was in, or close to "dead zone" 'this subroutine will re-command PDM, and return to [ReadStep] and read the phase again, 'but not test for dead zone again, just assumes data to be viable 'determine what the pdmstate was when entering, and "flip" it if suppressHardware then return 'ver115-6c if phaarray(thisstep,0) = 0 then newpdmstate = 1 'ver112-2a if phaarray(thisstep,0) = 1 then newpdmstate = 0 'ver112-2a 'change the pdm state for thisstep to the newpdmstate phaarray(thisstep,0) = newpdmstate 'now, go and command the PDM to the new state (Command PDM only!) gosub [CommandPDMonly] 'command just the PDM ver111-28 'this has just created a large glitch in the PDM output, so while it is settling down, 'change future PDM commands for all subsequent steps to end of sweep. for i = thisstep to sweepEndStep step sweepDir 'ver114-5a phaarray(i,0) = newpdmstate 'inverts pdmcmd for thisstep and subsequent steps to end of sweep. ver111-28 next i 'add appropriate wait time before reading the phase again gosub [VideoGlitchPDM]'calculates glitchpdm, depending on Video Selection and auto wait state gosub [WaitStatement] 'and use the new glitchpdm value 'now, go and read Phase, again. Use its "return" to return to [ReadStep] goto [ReadPhase] 're-read the phase and return to [ReadStep] 'when back in [ReadStep], it will not test for dead zone again. Assumes valid Phase. [VideoGlitchPDM]'entered from [InvertPDmodule],[PDM] 'changed by ver116-1b 'We want to wait 10 ms plus 12 time constants when inverting the PDM, but max of 5 seconds. 'If auto wait mode, we wait less time. For small time constants, we wait a certain minimum in auto wait because 'we need the PDM to become stable before we can rely on steady settling per the time constant. if useAutoWait then glitchpdm=glitchpdm + int(20+videoPhaseTC*5) else glitchpdm=glitchpdm + int(20+videoPhaseTC*12) 'in ms ver116-4j if glitchpdm>5000 then glitchpdm=5000 '5 sec max if useAutoWait=0 and glitchpdm 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 if cb = 3 then return ' not supportd on USB 'USB:01-08-2010 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]'For reading the 16 bit serial AtoD. Changed 4-27-10 ver115-9b 'This routine modified to help reject noise glitching caused by newer, faster, cheaply made computers. 'needed: port, control, 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, CVN is BD7. if cb = 2 then goto [Read16wSlimCB]' if SLIM Contol Board, jump over [Read16wOrigCB] [Read16wOrigCB] 'Using the Original Control Board. added by ver115-9b out port, 128 'take CVN high. Begins data capture inside AtoD out port, 128:out port, 128 'keep CVN high for 3 port commands to assure full AtoD conversion out port, 64 'CVN low and SCLK=1 'bit 15 is valid stat15 = inp(status) 'read data, statX is an 8 bit word for the Status Port out port, 0:out port, 64 'Status bit 14 is now valid stat14 = inp(status) out port, 0:out port, 64 'Status bit 13 is now valid stat13 = inp(status) out port, 0:out port, 64 'Status bit 12 is now valid stat12 = inp(status) out port, 0:out port, 64 'Status bit 11 is now valid stat11 = inp(status) out port, 0:out port, 64 'Status bit 10 is now valid stat10 = inp(status) out port, 0:out port, 64 'Status bit 9 is now valid stat9 = inp(status) out port, 0:out port, 64 'Status bit 8 is now valid stat8 = inp(status) out port, 0:out port, 64 'Status bit 7 is now valid stat7 = inp(status) out port, 0:out port, 64 'Status bit 6 is now valid stat6 = inp(status) out port, 0:out port, 64 'Status bit 5 is now valid stat5 = inp(status) out port, 0:out port, 64 'Status bit 4 is now valid stat4 = inp(status) out port, 0:out port, 64 'Status bit 3 is now valid stat3 = inp(status) out port, 0:out port, 64 'Status bit 2 is now valid stat2 = inp(status) out port, 0:out port, 64 'Status bit 1 is now valid stat1 = inp(status) out port, 0 'Status bit 0 is now valid stat0 = inp(status) 'we now have raw a/d status words in stat15-stat0 return 'to [ReadMagnitude]or[ReadPhase]with status words ' USB:15/08/10 ' the following code works fine but the structure version below is quicker ' ' Generic code for USB ADC input regardless of number of bits and ADC type 'USB:01-08-2010 '[Read22wSlimCBUSB] 'USB:01-08-2010 ' USBwrbuf$ = "B201040A01" ' goto [ReadCommonwSlimCBUSB] ' '[Read16wSlimCBUSB] 'USB:01-08-2010 ' USBwrbuf$ = "B200021001" ' ' fall through '[ReadCommonwSlimCBUSB] 'USB:01-08-2010 ' if USBdevice = 0 then return ' UsbAdcCount = 0 ' UsbAdcResult1 = 0 ' UsbAdcResult2 = 0 ' CALLDLL #USB, "UsbMSADeviceReadAdcs", USBdevice as long, USBwrbuf$ as ptr, 5 as short, USBrBuf as struct, result as boolean ' if( result ) then ' UsbAdcCount = USBrBuf.numreads.struct ' UsbAdcResult1 = USBrBuf.magnitude.struct ' UsbAdcResult2 = USBrBuf.phase.struct ' end if ' return 'to [ReadMagnitude]or[ReadPhase]with status words ' the main code has already set up the structure that defines the ADC conversion so just go for it ! [ReadADCviaUSB] 'This is new common subroutine for reading the ADC's with USB. 'ver116-4r 'This will read the ADC's and return the values for magdata and phadata if USBdevice = 0 then return 'ver116-4r deleted UsbAdcCount = 0 'since this is not used anywhere in the SW anyway 'ver116-4r deleted UsbAdcResult1 = 0 'ver116-4r deleted UsbAdcResult2 = 0 magdata = 0 phadata = 0 CALLDLL #USB, "UsbMSADeviceReadAdcsStruct", USBdevice as long, UsbAdcControl as struct, USBrBuf as struct, result as boolean 'USB:05/12/2010 if( result ) then UsbAdcCount = USBrBuf.numreads.struct 'this is not used anywhere, but I will leave it here as a reference 'ver116-4r magdata = USBrBuf.magnitude.struct 'ver116-4r phadata = USBrBuf.phase.struct 'ver116-4r 'Since the 12 bit serial ADC is read as 16 bits, throw away the last 4 bits 'ver116-4r if adconv = 22 then magdata = int(magdata/16) 'ver116-4r if adconv = 22 then phadata = int(phadata/16) 'ver116-4r end if return 'to [ReadMagnitude]or[ReadPhase]with status words [Read16wSlimCB] 'Using the SLIM Control Board. added by ver115-9b out port, 128:out control, AUTO:out control, contclear 'take CVN high. Begins data conversion inside AtoD, 'and is completed within 2.2 usec. out control, contclear 'keep CVN high for 3 port commands to assure full AtoD conversion out port, 64:out control, AUTO:out control, contclear 'CVN low and SCLK=1 'Status bit 15 'of the serial data is valid and can be read at any time. stat15 = inp(status) 'read data, statX is an 8 bit word for the Status Port out port, 0:out control, AUTO:out control, contclear 'SCLK=0 'bit 14 is valid, 'data (SDO) is incremented on the falling edge of SCLK out port, 64:out control, AUTO:out control, contclear 'SCLK=1 stat14 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 13 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat13 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 12 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat12 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 11 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat11 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 10 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat10 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 9 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat9 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 8 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat8 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 7 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat7 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 6 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat6 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 5 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat5 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 4 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat4 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 3 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat3 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 2 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat2 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 1 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat1 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 0 is valid 'a/d outputs would go high z on 16th SCLK trailing edge, but only 15 have been sent. stat0 = inp(status) 'read data, statX is 8 bit word 'U3 and P3 on SLIM Control Board is disabled. '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 if cb = 3 then return 'magdata and phadata is already processed. 'ver116-4r 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 if cb = 3 then return 'magdata is already processed (along with phadata) 'ver116-4r 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]'For reading the 12 bit serial AtoD. Changed 4-27-10 ver115-9b 'This routine modified to help reject noise glitching caused by newer, faster, cheaply made computers. '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 Control Board or Slim Control Board. ver111-33c 'good for serial, 12 Bit Original AtoD Module or SLIM-ADC-12 'serial data out is incremented on the falling SCLK edge. 'MAG is WAIT, PHASE is ACK, SCLK is BD6, CVN is BD7. if cb = 2 then goto [Read22wSlimCB]' if SLIM Contol Board, jump over routine [Read22wOrigCB] [Read22wOrigCB] 'Using the Original Control Board. added by ver115-9b out port, 128 'take CVN high. Begins data conversion inside AtoD, 'and is completed within 3.2 usec. out port, 128:out port, 128 'keep CVN high for 3 port commands to assure full AtoD conversion out port, 128 'More delay; first bit will appear without being clocked ver116-1b out port, 0 'CVN low, SCLK=0 Status bit 11 is now valid. out port, 64 'CVN low, SCLK=1 stat11 = inp(status) 'read data, statX is 8 bit word out port, 0:out port, 64 'Status bit 10 is now valid stat10 = inp(status) out port, 0:out port, 64 'Status bit 9 is now valid stat9 = inp(status) out port, 0:out port, 64 'Status bit 8 is now valid stat8 = inp(status) out port, 0:out port, 64 'Status bit 7 is now valid stat7 = inp(status) out port, 0:out port, 64 'Status bit 6 is now valid stat6 = inp(status) out port, 0:out port, 64 'Status bit 5 is now valid stat5 = inp(status) out port, 0:out port, 64 'Status bit 4 is now valid stat4 = inp(status) out port, 0:out port, 64 'Status bit 3 is now valid stat3 = inp(status) out port, 0:out port, 64 'Status bit 2 is now valid stat2 = inp(status) out port, 0:out port, 64 'Status bit 1 is now valid stat1 = inp(status) out port, 0 'Status bit 0 is now valid stat0 = inp(status) return 'to [ReadMagnitude]or[ReadPhase]with status words 'a/d outputs would go high z on 13th SCLK trailing edge, but only 12 have been sent. stat0 = inp(status) 'read data, statX is 8 bit word 'we have raw a/d status words in stat11-stat0 return 'to [ReadMagnitude]or[ReadPhase]with status words [Read22wSlimCB] 'Using the SLIM Control Board. added by ver115-9b out port, 128:out control, AUTO:out control, contclear 'take CVN high. Begins data conversion inside AtoD, 'and is completed within 3.2 usec. out control, contclear 'keep CVN high for 3 port commands to assure full AtoD conversion out control, contclear 'For time delay while CVN is high ver116-1b out control, contclear 'For time delay while CVN is high ver116-1b 'out port, 64:out control, AUTO:out control, contclear 'delver116-1b first bit appears without being clocked out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 Bit 11 is now valid. out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat11 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 10 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat10 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 9 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat9 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 8 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat8 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 7 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat7 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 6 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat6 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 5 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat5 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 4 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat4 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 3 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat3 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 2 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat2 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 1 is valid out port, 64:out control, AUTO:out control, contclear 'CVN low, SCLK=1 stat1 = inp(status) 'read data, statX is 8 bit word out port, 0:out control, AUTO:out control, contclear 'CVN low, SCLK=0 'bit 0 is valid 'a/d outputs would go high z on 13th SCLK trailing edge, but only 12 have been sent. stat0 = inp(status) 'read data, statX is 8 bit word 'U3 and P3 on SLIM Control Board is disabled. '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 if cb = 3 then return 'magdata and phadata already processed. 'ver116-4r 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 if cb = 3 then return 'magdata already processed. 'ver116-4r 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) if msaMode$<>"SA" then 'modver115-1e 'convert phadata (bits read) to phase (degrees) if we have phase, but not for special graphs, which set phase directly if msaMode$<>"ScalarTrans" and doSpecialGraph=0 then gosub [ConvertPhadata] 'ver116-4h gosub [ProcessDataArrays] 'Enter data in S21DataArray or ReflectArray end if gosub [PlotDataToScreen] return 'from [ProcessAndPrint] [ProcessDataArrays] 'process "thisstep" data for VNA/SNA, filling S21DataArray and/or ReflectArray 'ver115-8b separated this from ProcessAndPrint so it can be called separately. 'Data is transferred from datatable, stored as necessary and calculations made. 'For reflection mode; do jig calc and/or apply OSL calibration ver115-1b 'But data as is if we are doing calibration. ver115-1e gosub [TransferToDataArrays] if msaMode$="VectorTrans" or msaMode$="ScalarTrans" then if calInProgress=0 and planeadj<>0 then phaseToExtend=S21DataArray(thisstep,2) 'ver116-4s call uExtendCalPlane thisfreq, phaseToExtend, planeadj,0 'Do plane adjustment ver116-1b 'ver116-4s S21DataArray(thisstep,2)=phaseToExtend 'ver116-4s end if else if msaMode$="Reflection" then call ConvertRawDataToReflection thisstep 'Apply calibration and calculate all reflection related data; apply OSL if necessary ver116-4n end if end if return [TransferToDataArrays] 'Transfer datatable data to transmission or reflection array for thisstep thisfreq=datatable(thisstep,1) 'freq thisBand=datatable(thisstep,4) 'ver116-4s if thisBand<>1 then thisfreq=ActualSignalFrequency(thisfreq, thisBand) 'actual signal frequency, not equivalent 1G freq ver116-4s thisDB=datatable(thisstep,2) 'mag db thisAng=datatable(thisstep,3) 'phase 'We save data in S21DataArray for VectorTrans and ScalarTrans modes 'We save data in ReflectArray for Reflection Mode. 'Note that the actual signal frequency, not equivalent 1G freq, gets saved in these arrays 'as part of the restart process, but we repeat that here in case we are called outside the normal 'scanning process. 'Note data in datatable has no adjustment for planeadj, but these other arrays do if msaMode$="VectorTrans" or msaMode$="ScalarTrans" then S21DataArray(thisstep,0)=thisfreq 'actual signal freq S21DataArray(thisstep,1)=thisDB 'mag S21DataArray(thisstep,2)=thisAng 'phase--may be changed by plane extension S21DataArray(thisstep,3)=thisAng 'phase before plane extension ver116-1b end if if msaMode$="Reflection" then for i=1 to 16 : ReflectArray(thisstep,i)=0 : next i 'Clear all reflection data (except freq) for this point 'ver116-1b ReflectArray(thisstep,0)=thisfreq 'actual signal freq 'The following may be changed by applying OSL ReflectArray(thisstep,constGraphS11DB)=thisDB 'Save raw data in array that will hold reflection related data ReflectArray(thisstep,constGraphS11Ang)=thisAng ReflectArray(thisstep,constIntermedS11DB)=thisDB 'ConvertRawDataToReflection may override these intermed values ReflectArray(thisstep,constIntermedS11Ang)=thisAng end if return sub CalcFreqCorrection 'Calculate power correction factors for each frequency step. for s=0 to globalSteps currFreq=baseFrequency+gGetPointXVal(s+1) 'Point number is one more than step num ver116-4k added baseFrequency freqCorrection(s)=calConvertFreqError(currFreq) 'Put power correction into the array next s end sub [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 normal sweep, process phase by removing line calibration phase 'put final phase into datatable 'Do not do Reference Plane Extension here 'convert phase to +180 to -180 format and round off to .01 degree '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 = 360*phadata/maxpdmout 'converts phadata bits to absolute phase. ver15-2d moved rounding to later '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) 'ver116-4h prevented getting here when doSpecialGraph>0, so we don't need to test it here 'if PDM was inverted, subtract the inverted phase change 'The deviation in the PDM inversion from theoretical 180 deg is actually a fixed time period 'invdeg is maintained as the actual inversion that occurs at 10.7 MHz. With a different finalfreq, 'the deviation from 180 degrees will change. if phaarray(thisstep,0)=1 then 'ver116-1b PDMinversionDeviation=(invdeg-180)*finalfreq/10.7 phase = phase - (180+PDMinversionDeviation) end if phase=phase-difPhase 'SEW3: subtract correction for change of phase over signal level. thisBand=datatable(thisstep,4) 'ver116-4s if thisBand=3 then phase=0-phase 'For 3G mode, true phase is negative of measured phase, due to low side LO1 ver116-4L ver116-4s 'calculate phase with calibration table factored in 'ver114-5f Apply lineCalArray only if LineCal or BaseLineCal is active, and not when calibrating 'Note if calInProgress=1, applyCalLevel will have been set to 0 by cal installation routine if applyCalLevel>0 then phase = phase - lineCalArray(thisstep,2) 'subtract reference. if phase>=0 then phase=int(phase*100+0.5)/100 else phase=int(phase*100-0.5)/100 'round to two decimal places ver115-2d 'ver115-2b moved the application of planeadj. The data in datatable() never contains that adjustment. 'The phase correction is set to 180 degrees when the phase reading during initial calibration 'is suspect. In that case, we override all the foregoing and set the final phase to 0. 'validPhaseThreshold indicates the lowest magnitude level at which phase is valid. if magdata180 : phase = phase - 360 : wend 'ver114-5d fixed typo while phase <=-180 : phase = phase + 360 : wend '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 'Note that phase may have to be adjusted during graphing to fit the bounds of the display return '--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 '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 if msaMode$<>"SA" and msaMode$<>"ScalarTrans" then doPhaseCor=1 else doPhaseCor=0 'ver115-1a call calConvertMagPhase magdata, doPhaseCor, power, difPhase 'ver114-5n thisfreq = datatable(thisstep,1) freqerror=freqCorrection(thisstep) 'find freq cal adjustment SEWgraph1 'In SA mode, if there is an active front end file, we add the front end correction factor if msaMode$="SA" then if frontEndActiveFilePath$<>"" then freqerror=freqerror-frontEndCorrection(thisstep) 'ver115-9d end if else if calInProgress and msaMode$<>"Reflection" then 'ver116-4b 'If calibrating transmission, we want to use ideal results so when we display the actual doSpecialGraph 'it will come out the way we want. power=0 phase=0 datatable(thisstep,3) = phase else gosub [DoSpecialGraph] 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 = power 'ver115-2d 'Note if calInProgress=1, applyCalLevel will have been set to 0 by cal installation routine if applyCalLevel>0 then if (msaMode$<>"SA") then magpower = magpower - lineCalArray(thisstep,1) 'ver116-4n subtract reference. if magpower>=0 then magpower=int(magpower*100000+0.5)/100000 else magpower=int(magpower*100000-0.5)/100000 'round to five decimal places ver115-4d datatable(thisstep,2) = magpower 'put current power measurement into the array return 'to [ProcessAndPrint] [DoSpecialGraph] difPhase=0 : freqerror=0 'ver114-7e 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 testSlope=(maxADC-minADC)/steps magdata=minADC+testSlope*thisstep 'Apply mag calibration to get power, but forget phase correction call calConvertMagPhase magdata, 0, power, dum 'skip freq cal return end if if doSpecialGraph=2 then '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=freqCorrection(thisstep) 'find freq cal adjustment SEWgraph1 return end if if doSpecialGraph=3 then 'Generate random values for magdata superimposed on a sine wave centered midway in ADC 'Make Transmission values a little higher. call calGetMagPoint 1,minADC, calMag, calPhase 'ignore calMag and calPhase call calGetMagPoint calNumMagPoints(),maxADC, calMag, calPhase magdata=3*(1+RND(1)/20)*(maxADC)/4 + 3000*sin(10*datatable(thisstep,1)) 'ver114-7b if msaMode$="VectorTrans" or msaMode$="ScalarTrans" then magdata=1.1*magdata 'Increase transmission values ver116-1b 'Note: without being connected to MSA, which is when DoSpecialGraph is useful, 'phase will bounce between 0 and 180 and thus will show some graph action. call calConvertMagPhase magdata, 1, power, difPhase 'ver114-5n thisfreq = datatable(thisstep,1) freqerror=freqCorrection(thisstep) 'find freq cal adjustment SEWgraph1 phase=180-10*datatable(thisstep,1) 'linear change over frequency datatable(thisstep,3) = phase 'ver116-4h return end if if doSpecialGraph=4 then 'Generate a peak near 1 MHz currXVal=gGetPointXVal(thisstep+1)-1 'Upside down parabola centered near MHz ver 114-3g power=max(-6-((3000+doSpecialRandom*2000)*(currXVal+0.025-doSpecialRandom/20)^2),-100) phase=270-300*datatable(thisstep,1) 'ver115-1b datatable(thisstep,3) = phase 'ver116-4h return end if if doSpecialGraph=5 then 'doSpecialGraph=5 'For SA mode, do response of a 1 MHz square wave. 'For VNA modes, Calc response of an RLC circuit with optional transmission line 'ver114-7e if msaMode$="SA" then 'ver115-4c added the 1 MHz square wave for SA mode currXVal=gGetPointXVal(thisstep+1) specialWholeFreq=int(currXVal+0.5) : specialFractFreq=currXVal-specialWholeFreq 'fract may be -0.5 to +0.5 specialNoise=(1e-11)*finalbw*(1+4*Rnd(0)) if specialWholeFreq=2*int(specialWholeFreq/2) then power=10*uSafeLog10(specialNoise) else '1 MHz square wave at odd multiples of 1 MHz has power of 1/N mw, where N is the multiple. 'It tapers off per a parabola, which is wider for higher RBW. power=10*uSafeLog10(specialNoise+(1/specialWholeFreq^2)*max(0,(1-(1400*specialFractFreq/finalbw)^2))) end if phase=0 : datatable(thisstep,3) = 0 else 'VNA modes uWorkNumPoints=1 : uWorkArray(1,0)=gGetPointXVal(thisstep+1) 'ver115-1c 'set up for uRLCComboResponse uWorkArray(1,1)=0:uWorkArray(1,2)=0 'Default in case of error 'Calc response in whatever S11 or S21 setup the user has chosen if msaMode$="Reflection" then doSpecialR0=S11BridgeR0 : doSpecialJig$="S11" 'ver115-4a else doSpecialR0=S21JigR0 if S21JigAttach$="Series" then doSpecialJig$="S21Series" else doSpecialJig$="S21Shunt" end if 'Note we only have one point in uWorkArray for uRLCComboResponse to process 'Note calibration will not be applied for doSpecialGraph=5, so uRLCComboResponse 'calculates the actual final response. e.g. S21JigShuntDelay is not taken into account, because 'it would be removed by a perfect calibration. isErr=uRLCComboResponse(doSpecialRLCSpec$, doSpecialR0, doSpecialJig$) 'ver115-4a power=uWorkArray(1,1) 'get results of uRLCComboResponse phase=uWorkArray(1,2) datatable(thisstep,3) = phase end if return end if 'doSpecialGraph=6 There is currently no such thing power=0 : phase=0 : datatable(thisstep,3) = phase return sub ConvertRawDataToReflection currStep 'For the current step in reflection mode, calculate S11, referenced to S11GraphR0 ver115-5f mod by ver116-4n 'Calculate reflection in db, angle format and puts results in ReflectArray, which already contains the raw data. 'Also calculates the various items in ReflectArray() from the final reflection value. 'We need to adjust the data for calibration ' Reference calibration 'The simplest reflection calibration is to use the Open or Short as a reference. In that case, we still calculate 'OSL coefficients as though we did full OSL, using Ideal results for the missing data. ' Full OSL 'More extensive calibration would include the Open, Short and Load, from which we calculated the a, b, c OSL 'coefficients during calibration. If we have full OSL coefficients, we apply them here. 'We identify the type of jig used with S11JigType$, which the user sets during calibration. 'S11JigType$ is always set to "Reflect" when doing full OSL, since we don't even know the nature of the actual jig. 'In addition, S21JigR0 is set to S11BridgeR0. 'Note that S21 or S11 are now referenced to the S21JigR0 or S11BridgeR0, not the graph R0. We do the 'conversion here. But we also save S11 as an intermediate value before applying the R0 coversion or plane extension '(but after applying cal) to make recalculations easier. It is saved with constIntermedS11DB and constIntermedS11Ang. 'First get the raw reflection data. This is the measured data, adjusted by subtracting the reference. 'planeadj has not been applied; it is applied after applying calibration 'S21JigShuntDelay has not yet been applied. It will be applied here via the OSL coefficients. trueFreq=ReflectArray(currStep,0)*1000000 db=ReflectArray(currStep,constGraphS11DB) : ang=ReflectArray(currStep,constGraphS11Ang) if calInProgress then 'If calibrating we don't adjust anything here, or calculate anything other than S11 ReflectArray(currStep, constIntermedS11DB)=db 'ver115-2d ReflectArray(currStep, constIntermedS11Ang)=ang 'ver115-2d exit sub end if rho=uTenPower(db/20) 'mag made linear 'db, rho, and ang (degrees) now have the raw reflection data 'If necessary, we apply full OSL to the reflection data, whether it was derived 'from a reflection bridge or a transmission jig. 'If doing OSL cal, then we don't want to apply whatever coefficients we happen to have now. 'If doSpecialGraph<>0 we don't want to mess with the internally generated data if doSpecialGraph=0 and applyCalLevel<>0 then 'ver115-5f rads=ang*uRadsPerDegree() 'angle in radians mR=rho*cos(rads) : mI=rho*sin(rads) 'measured S11, real and imaginary aR=OSLa(currStep,0) : aI=OSLa(currStep,1) 'coefficient a, real and imaginary bR=OSLb(currStep,0) : bI=OSLb(currStep,1) 'coefficient b, real and imaginary cR=OSLc(currStep,0) : cI=OSLc(currStep,1) 'coefficient c, real and imaginary 'calculate adjusted db, ang via OSL. Note OSL must be referenced to S11BridgeR0 calcMethod=1 'For debugging, we have two different methods if calcMethod=1 then 'The first method uses the following formula, and corresponds to CalcOSLCoeff ' S = (M – b) / (a – c*M) 'where S is the actual reflection coefficient and M is the measured reflection coefficient. 'S and M are in rectangular form in this equation. RealCM=cR*mR-cI*mI : ImagCM=cR*mI+cI*mR 'c*M, real and imaginary call cxDivide mR-bR, mI-bI, aR-RealCM,aI-ImagCM,refR, refI 'Divide M-b by a-c*M else 'The second method uses the following formula, and corresponds to CalcOSLCoeff1 ' S = (a - cM)/(bM - 1) 'where S is the actual reflection coefficient and M is the measured reflection coefficient. 'S and M are in rectangular form in this equation. RealCM=cR*mR-cI*mI : ImagCM=cR*mI+cI*mR 'c*M, real and imaginary RealBM=bR*mR-bI*mI : ImagBM=bR*mI+bI*mR 'b*M, real and imaginary numR=aR-RealCM : numI=aI-ImagCM 'numerator, real and imaginary denR=RealBM-1 :denI=ImagBM 'denominator, real and imaginary call cxDivide numR, numI, denR, denI, refR, refI 'Divide numerator by denominator; result is reflection coeff. end if 'ver116-4k separated the following common calculations from the above if...else block magSquared=refR^2+refI^2 'mag of S, squared db=10*uSafeLog10(magSquared) 'S mag in db; multiply by 10 not 20 because mag is squared if db>0 then db=0 'Shouldn't happen ang=uATan2(refR, refI) 'angle of S in degrees 'db, ang (degrees) now have S11 data produced by applying OSL calibration. end if 'Save the angle prior to applying plane extension or Z0 transform, to make it easier to recalculate with a new values ReflectArray(currStep, constIntermedS11DB)=db 'ver115-2d ReflectArray(currStep, constIntermedS11Ang)=ang 'ver115-2d 'Note we do apply plane extension even when doSpecialGraph<>0 if planeadj<>0 or S11BridgeR0<>S11GraphR0 then call ApplyExtensionAndTransformR0 ReflectArray(currStep,0), db, ang 'ver115-2d 'Note we do not put the reflection data in datatable, which retains the original raw data ReflectArray(currStep,constGraphS11DB)=db 'Save final S11 in db, angle format (in Graph R0, after plane ext) while ang>180 : ang=ang-360 : wend while ang<=-180 : ang=ang+360 : wend ReflectArray(currStep,constGraphS11Ang)=ang 'We now compute the various items in ReflectArray() from S11, but if we are doing calibration we don't need this 'other data, and it probably doesn't make sense anyway. if calInProgress=0 then call CalcReflectDerivedData currStep 'Calc other ReflectArray() data from S11. end sub 'ver115-2d created ApplyExtensionAndR0Transform so it can be called from a couple of places sub ApplyExtensionAndTransformR0 freq, byref db, byref ang 'Apply reflection mode plane extension and transform from bridge R0 to graph R0 for reflection 'freq is in MHz 'apply plane extension. We do this after applying calibration. 'For reflection mode with S21 series jig, plane extension makes no sense, so we don't do it 'For Transmission mode, we don't get here. 'We don't do the adjustment when calibrating, 'because plane extension is used to extend the plane after calibration, and we don't need to do S11GraphR0 'ver115-2b modified this procedure if calInProgress=1 then exit sub if planeadj<>0 then 'Do the extension, but not if series fixtures is used if S11JigType$="Reflect" or S21JigAttach$="Shunt" then call uExtendCalPlane freq, ang, planeadj,1 '1 means reflection mode ver116-4j end if 'Convert into new R0 if necessary 'ver115-1e moved this here from CalcReflectDerivedData 'We don't convert if calibrating if S11BridgeR0<>S11GraphR0 then 'ver115-1e 'Transform to graph reference impedance call uS11DBToImpedance S11BridgeR0, db, ang, impR, impX 'calc impedance : R, X call uImpedanceToRefco S11GraphR0, impR, impX, rho, ang 'calc S11 db=20*uSafeLog10(rho) 'put S11 in db form ver115-1b fixed typo end if refLastGraphR0=S11GraphR0 'ver116-1b end sub [PlotDataToScreen] 'SEWgraph heavily revised PlotDataToScreen to utilize new graphing module. 'Initialization for a series of sweeps is done in the sweep loop. During the first scan we draw traces. 'At the start of each subsequent scan we call gStartNextDynamicScan which prepares for the erase-and-draw. 'At the end of each scan, if the user so selects, the screen is "refreshed", meaning that is quickly redrawn 'from strings or "flush" segments saved during the drawing process. However, if there are more than 1200 steps, 'the refresh is actually a complete redraw from scratch, because it is too time consuming to accumulate the large 'strings needed for the refresh procedure. Repeatedly adding short segments to very large strings is time consuming. 'When the scan is halted, the screen is redrawn 'from scratch using draw commands saved from the scans. However, redrawing and refreshing does not occur 'if we are graphing in one of the "stick" modes. At the end of each sweep we also figure out where the markers go, 'draw them, and display their info below the graph. The user has the option not to show the markers on the 'graph, in which case their info is still displayed. Data for the first, last and center points is displayed 'below the frequency axis (no center point for log sweeps), but those are not considered "markers". 'Data values, and their pixel coordinates, are saved in the 'graphing module. The same values are also saved in the arrays used in software versions prior to the graphing module. 'Pixel coordinates are no longer saved in those pre-existing arrays, but the slots where the pixels were saved 'still exist. 'Trace segments are discarded at the end of a scan, and also every time 1000 have accumulated. Traces are not '"flushed" until the graph is redrawn upon halting. call CalcGraphData thisstep, thispointy1, thispointy2, 0 '0 means use regular data arrays ver114-7f if referenceDoMath=2 then 'ref math is to be done on graph values ver115-5d if (referenceTrace and 1) then _ thispointy1=referenceOpA*referenceTransform(thisstep+1, 1)+referenceOpB*thispointy1 if (referenceTrace and 2) then _ thispointy2=referenceOpA*referenceTransform(thisstep+1, 2)+referenceOpB*thispointy2 end if 'We draw a point after erasing a point (if required). 'We also saves the data to gGraphVal() and the pixel values to gGraphPix() 'X values have been precalculated in gGenerateXValues if thisstep=sweepStartStep then 'ver114-6e added the refreshXXX flags refreshForceRefresh=0 'We normally want refreshGridDirty=0 because we redrew the grid when restarting. But 'for mulitscans, that step is skipped. refreshGridDirty=multiscanInProgress refreshTracesDirty=0 refreshAutoScale=0 refreshRedrawFromScratch=0 if firstScan then refreshMarkersDirty=1 'Signals to relocate any markers to correspond to their frequency. 'If required, do auto scaling of axes at end of first scan if autoScaleY2 or autoScaleY1 then refreshAutoScale=1 'ver115-3b else call gStartNextDynamicScan 'SEWgraph Initializes for erase/draw passes; done at start of scans 2... end if 'ver114-5c moved setting of isStickMode to UpdateGraphParams end if 'useExpeditedDraw is set to 1 for single trace (mag) in non-histo mode for linear y scaling 'The expedited draw procedure is slightly faster than normal drawing, and will almost always be 'used when in SA mode. if useExpeditedDraw then gosub [gDrawSingleTrace] 'Normal SA drawing occurs with this else 'Enter new Y values and draw from last point 'Comment out all but one; two choices allowed for testing 'call gDynamicDrawPoint thispointy1,thispointy2 call gDynamicComboDrawPoint thispointy1,thispointy2 'This is the full-blown drawing procedure end if if steps>=1000 then 'ver114-4k 'Discard at least every 1000 points to avoid a slowdown. oneThousandthThisStep=thisstep/1000 if int(oneThousandthThisStep)=oneThousandthThisStep then #graphBox$, "discard" end if 'ver114-4e deleted drawing of point values at start, center and end if thisstep=sweepEndStep then 'just processed final point of a sweep 'ver114-4k 'If autoscale is on for either axis then calculate the scale and redraw from raw values 'We only do this for the first scan. ver114-7a added this autoscale material if firstScan and (autoScaleY2 or autoScaleY1) then 'ver115-3b if haltAtEnd=1 then 'Halt will redraw, so we just autoscale here call PerformAutoScale 'Recalculates scaling in graph module else refreshForceRefresh=1 : refreshAutoScale=1 'ver114-7a end if end if if refreshForceRefresh or refreshEachScan then 'force full refresh unless we are in stick mode; and don't redraw if haltAtEnd=1 because 'a redraw will occur when we halt. if isStickMode=0 and haltAtEnd=0 then call RefreshGraph 1 else 'modver116-4b 'Even if we don't do a full refresh, we refresh the grid lines and traces except on first scan. 'This restores any grid lines that got erased 'If we draw markers, their movement from scan to scan can make a mess. 'If we don't draw them, the grid lines will cross them. 'So we skip this altogether if we have markers; we could do it if we had a way to erase markers. if firstScan=0 and isStickMode=0 and haltAtEnd=0 then if doGraphMarkers then call gEraseMarkers 'Erase prior markers before they move call gRefreshGridLinesOnly : call gRefreshTraces partialRefresh=1 else partialRefresh=0 end if if firstScan=1 then call gDetermineMarkerPointNumbers 'Finds new point numbers for old markers if freq changed 'Update marker info at end of every scan no matter what if hasAnyMark=1 then call mDrawMarkerInfo 'also updates marker locations 'If no refresh, draw markers on first scan only, and only if user wants them drawn if (firstScan=1 or partialRefresh) and doGraphMarkers=1 then call gDrawMarkers 'ver116-4b #graphBox$, "discard" 'Get rid of marker draw commands in memory end if if (doCycleTraceColors=1) and (isStickMode=1) then 'ver116-4s cycleTrace colors if necessary cycleNumber=cycleNumber+1 : if cycleNumber>3 then cycleNumber=1 call gSetTraceColors cycleColorsAxis1$(cycleNumber), cycleColorsAxis2$(cycleNumber) 'ver116-4s end if firstScan=0 'scan has ended; next point is not in first scan since restart doSpecialRandom=RND(1) 'Random number for doSpecialGraph ver115-1b end if if varwindow = 1 then gosub [updatevar] 'moved here from [ProcessAndPrint] ver111-34a return [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$ message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if 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$ message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if 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$ message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if 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$ message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if 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$ message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if 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$ message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if 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 'ver116-4o deleted "if" block, per Lrev1 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 if cb = 3 then Int64N.lsLong.struct = 2^23*N23+ 2^22*N22+ 2^21*N21+ 2^20*N20+ 2^19*N19+ 2^18*N18+ 2^17*N17+ 2^16*N16+ 2^15*N15+_ 2^14*N14+ 2^13*N13+ 2^12*N12+ 2^11*N11+ 2^10*N10+ 2^9*N9+ 2^8*N8+_ 2^7*N7+ 2^6*N6+ 2^5*N5+ 2^4*N4+ 2^3*N3+ 2^2*N2+ 2^1*N1+ 2^0*N0 'ver116-4o per Lrev1 if cb = 3 then Int64N.msLong.struct = 0 'ver116-4o per Lrev1 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 'ver116-4o deleted "if" block, per Lrev1 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 if cb = 3 then Int64N.lsLong.struct = 2^23*N23+ 2^22*N22+ 2^21*N21+ 2^20*N20+ 2^19*N19+ 2^18*N18+ 2^17*N17+ 2^16*N16+ 2^15*N15+_ 2^14*N14+ 2^13*N13+ 2^12*N12+ 2^11*N11+ 2^10*N10+ 2^9*N9+ 2^8*N8+_ 2^7*N7+ 2^6*N6+ 2^5*N5+ 2^4*N4+ 2^3*N3+ 2^2*N2+ 2^1*N1+ 2^0*N0 'ver116-4o per Lrev1 if cb = 3 then Int64N.msLong.struct = 0 'ver116-4o per Lrev1 '[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 'ver116-4o deleted "if" block, per Lrev1 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 if cb = 3 then Int64N.lsLong.struct = 2^23*N23+ 2^22*N22+ 2^21*N21+ 2^20*N20+ 2^19*N19+ 2^18*N18+ 2^17*N17+ 2^16*N16+ 2^15*N15+_ 2^14*N14+ 2^13*N13+ 2^12*N12+ 2^11*N11+ 2^10*N10+ 2^9*N9+ 2^8*N8+_ 2^7*N7+ 2^6*N6+ 2^5*N5+ 2^4*N4+ 2^3*N3+ 2^2*N2+ 2^1*N1+ 2^0*N0 'ver116-4o per Lrev1 if cb = 3 then Int64N.msLong.struct = 0 ''ver116-4o per Lrev1 '[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 'ver116-4o deleted "if" block, per Lrev1 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 if cb = 3 then Int64N.lsLong.struct = 2^23*N23+ 2^22*N22+ 2^21*N21+ 2^20*N20+ 2^19*N19+ 2^18*N18+ 2^17*N17+ 2^16*N16+ 2^15*N15+_ 2^14*N14+ 2^13*N13+ 2^12*N12+ 2^11*N11+ 2^10*N10+ 2^9*N9+ 2^8*N8+_ 2^7*N7+ 2^6*N6+ 2^5*N5+ 2^4*N4+ 2^3*N3+ 2^2*N2+ 2^1*N1+ 2^0*N0 'ver116-4o per Lrev1 if cb = 3 then Int64N.msLong.struct = 0 'ver116-4o per Lrev1 '[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 'ver116-4o deleted "if" block, per Lrev1 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 if cb = 3 then Int64N.lsLong.struct = 2^23*N23+ 2^22*N22+ 2^21*N21+ 2^20*N20+ 2^19*N19+ 2^18*N18+ 2^17*N17+ 2^16*N16+ 2^15*N15+_ 2^14*N14+ 2^13*N13+ 2^12*N12+ 2^11*N11+ 2^10*N10+ 2^9*N9+ 2^8*N8+_ 2^7*N7+ 2^6*N6+ 2^5*N5+ 2^4*N4+ 2^3*N3+ 2^2*N2+ 2^1*N1+ 2^0*N0 'ver116-4o per Lrev1 if cb = 3 then Int64N.msLong.struct = 0 'ver116-4o per Lrev1 return [Command4112R]'needed: rcounter,preselector,phasepolarity,control,Jcontrol,port,LEPLL,contclear ; commands AD4112 rcounter '[Create4112InitBuffer]'needed:preselector,phasepolarity 'ver116-4o deleted "if" block, per Lrev1 N23=1 'N23,22 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=0 'N20,19,18 Phase Current for Set 2 '12-3-10 N19=0 'current= min current + min current*bit value '12-3-10 N18=1 'use bit value of 1 and 4.7 Kohm for 1.25 ma '12-3-10 N17=0 'N17,16,15 Phase Current for Set 1 '12-3-10 N16=0 'current= min current + min current*bit value '12-3-10 N15=1 'use bit value of 1 and 4.7 Kohm for 1.25 ma '12-3-10 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 if cb = 3 then Int64N.lsLong.struct = 2^23*N23+ 2^22*N22+ 2^21*N21+ 2^20*N20+ 2^19*N19+ 2^18*N18+ 2^17*N17+ 2^16*N16+ 2^15*N15+_ 2^14*N14+ 2^13*N13+ 2^12*N12+ 2^11*N11+ 2^10*N10+ 2^9*N9+ 2^8*N8+_ 2^7*N7+ 2^6*N6+ 2^5*N5+ 2^4*N4+ 2^3*N3+ 2^2*N2+ 2^1*N1+ 2^0*N0 'ver116-4o per Lrev1 if cb = 3 then Int64N.msLong.struct = 0 'ver116-4o per Lrev1 '[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 'ver116-4o deleted "if" block, per Lrev1 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 if cb = 3 then Int64N.lsLong.struct = 2^23*N23+ 2^22*N22+ 2^21*N21+ 2^20*N20+ 2^19*N19+ 2^18*N18+ 2^17*N17+ 2^16*N16+ 2^15*N15+_ 2^14*N14+ 2^13*N13+ 2^12*N12+ 2^11*N11+ 2^10*N10+ 2^9*N9+ 2^8*N8+_ 2^7*N7+ 2^6*N6+ 2^5*N5+ 2^4*N4+ 2^3*N3+ 2^2*N2+ 2^1*N1+ 2^0*N0 'ver116-4o per Lrev1 if cb = 3 then Int64N.msLong.struct = 0 'ver116-4o per Lrev1 '[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:message$="Error, ddsoutput > .5 ddsclock" : call PrintMessage :goto [Halted] 'ver114-4e end if 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)) if cb = 3 then 'USB:05/12/2010 Int64SW.msLong.struct = 0 'USB:05/12/2010 Int64SW.lsLong.struct = int( base ) 'USB:05/12/2010 else 'USB:05/12/2010 '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 end if 'USB:05/12/2010 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] [ResetDDS1serUSB] 'USB:01-08-2010 pdmcmd = phaarray(thisstep,0) 'ver111-39d '(reset DDS3 to parallel)WCLK up,WCLK up and FQUD up,WCLK up and FQUD down,WCLK down USBwrbuf$ = "A10100"+ToHex$(filtbank + 1) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 4 as short, result as boolean if result <> TRUE then if USBdevice <> 0 then CALLDLL #USB, "UsbMSAInit", USBdevice as long, result as boolean if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 4 as short, result as boolean end if USBwrbuf2$ = "A30200"+ToHex$(pdmcmd*64 + 2)+ToHex$(pdmcmd*64) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf2$ as ptr, 5 as short, result as boolean USBwrbuf$ = "A10300"+ToHex$(filtbank)+ToHex$(filtbank + 1)+ToHex$(filtbank) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 6 as short, result as boolean if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf2$ as ptr, 5 as short, result as boolean '(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 USBwrbuf$ = "A12801" USBwrbuf3$ = ToHex$( filtbank ) for thisloop = 0 to 39 USBwrbuf$ = USBwrbuf$ + USBwrbuf3$ next thisloop if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 43 as short, result as boolean if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf2$ as ptr, 5 as short, result as boolean '(end flush command DDS3) return [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) [ResetDDS3serUSB] 'USB:01-08-2010 'reset serial DDS3 without disturbing Filter Bank or PDM. usb v1.0 '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 USBwrbuf$ = "A10100"+ToHex$(filtbank + 1) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 4 as short, result as boolean USBwrbuf2$ = "A30200"+ToHex$(pdmcmd*64 + 8)+ToHex$(pdmcmd*64) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf2$ as ptr, 5 as short, result as boolean USBwrbuf$ = "A10300"+ToHex$(filtbank)+ToHex$(filtbank + 1)+ToHex$(filtbank) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 6 as short, result as boolean if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf2$ as ptr, 5 as short, result as boolean '(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 USBwrbuf$ = "A12801" USBwrbuf3$ = ToHex$( filtbank ) for thisloop = 0 to 39 USBwrbuf$ = USBwrbuf$ + USBwrbuf3$ next thisloop if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 43 as short, result as boolean if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf2$ as ptr, 5 as short, result as boolean '(end flush command DDS3) return 'to '(InitializeDDS 3) [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 if cb = 3 then gosub [CommandAllSlimsUSB]'will command all 4 modules. ver113-4a 'USB:01-08-2010 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 if cb = 3 then gosub [CommandAllSlimsUSB]'will command all 4 modules. ver113-4a 'USB:01-08-2010 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 if cb = 2 then gosub [CommandAllSlims]'will command all 4 modules. ver113-4a if cb = 3 then gosub [CommandAllSlimsUSB]'will command all 4 modules. 'USB:01-08-2010 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 affected. '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 if cb = 2 then gosub [CommandAllSlims]'will command all 4 modules. ver113-4a if cb = 3 then gosub [CommandAllSlimsUSB]'will command all 4 modules. 'USB:01-08-2010 moved ver116-4f 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 'SEWgraph updated the following to deal with changes in text boxes call SetCenterSpanFreq 0,0 'SEWgraph zero width, zero center wate=3 'SEWgraph 3ms wait time ver114-4d if primaryAxisNum=1 then 'ver115-3b call SetY2Range 0,360 'Phase range 0 to 360 ver114-4d call SetY1Range -5, 5 'Mag range -5 to 5 ver114-4d else call SetY1Range 0,360 'Phase range 0 to 360 ver114-4d call SetY2Range -5, 5 'Mag range -5 to 5 ver114-4d end if call gSetXIsLinear 1 'SEWgraph Be sure sweep is linear call gCalcGraphParams 'SEWgraph Calculate scaling, etc. with new parameters setpdm = 1 : print #special.pdminv, "PDM in Normal":gosub [PdmNorm] haltsweep=0 'So Restart actually restarts 'ver114-6e 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-sweepDir,3) - phaarray(thisstep,3) 'ver114-4m 'convert deltabits to delta phase deltaphase = 360 * deltabits/maxpdmout power = deltaphase return [PresetVNAlin] 'ver112-2b print #special.prevnalin, "Test Transmission Linearity" 'change the button name if vnalintest = 1 then goto [VNAlinTest] vnalintest = 1 for i=0 to steps : lineCalArray(i,0)=0 : lineCalArray(i,1)=0 : lineCalArray(i,2)=0 : next i 'ver116-1b call SignalNoCalInstalled 'ver116-4b 'SEWgraph updated the following to deal with changes in text boxes call SetCenterSpanFreq 500,1000 'SEWgraph; 500 MHz center, 1000 MHz span wate=22 'ver114-4d; 22 ms wait time '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) if primaryAxisNum=1 then 'ver115-3b call SetY1Range -5, 5 'This is actually degrees, not power call SetY2Range -180, 180 'phase else call SetY2Range -5, 5 'This is actually degrees, not power call SetY1Range -180, 180 'phase end if call gSetXIsLinear 1 'SEWgraph be sure sweep is linear call gCalcGraphParams 'SEWgraph Calculate scaling, etc. with restored parameters haltsweep=0 'So Restart actually restarts 'ver114-6e 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 haltsweep=0 'So Restart actually restarts 'ver114-6e 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 'lpt, added by Scotty ver116-4b [LPTportTest] if suppressHardware then wait 'No hardware--can't test port enterport=port:enterstatus=status:entercontrol=control UpperLeftX = 5 UpperLeftY = 5 WindowWidth = 350 WindowHeight = 350 BackgroundColor$ = "darkblue" ForegroundColor$ = "white" TextboxColor$ = "blue" button #LPTwindow.button17down, "0", [Pin17down], UL, 5, 5, 20, 20 button #LPTwindow.button16down, "0", [Pin16down], UL, 5, 30, 20, 20 button #LPTwindow.button14down, "0", [Pin14down], UL, 5, 55, 20, 20 button #LPTwindow.button1down, "0", [Pin1down], UL, 5, 80, 20, 20 button #LPTwindow.button2down, "0", [Pin2down], UL, 5, 105, 20, 20 button #LPTwindow.button3down, "0", [Pin3down], UL, 5, 130, 20, 20 button #LPTwindow.button4down, "0", [Pin4down], UL, 5, 155, 20, 20 button #LPTwindow.button5down, "0", [Pin5down], UL, 5, 180, 20, 20 button #LPTwindow.button6down, "0", [Pin6down], UL, 5, 205, 20, 20 button #LPTwindow.button7down, "0", [Pin7down], UL, 5, 230, 20, 20 button #LPTwindow.button8down, "0", [Pin8down], UL, 5, 255, 20, 20 button #LPTwindow.button9down, "0", [Pin9down], UL, 5, 280, 20, 20 button #LPTwindow.button17up, "1", [Pin17up], UL, 30, 5, 20, 20 button #LPTwindow.button16up, "1", [Pin16up], UL, 30, 30, 20, 20 button #LPTwindow.button14up, "1", [Pin14up], UL, 30, 55, 20, 20 button #LPTwindow.button1up, "1", [Pin1up], UL, 30, 80, 20, 20 button #LPTwindow.button2up, "1", [Pin2up], UL, 30, 105, 20, 20 button #LPTwindow.button3up, "1", [Pin3up], UL, 30, 130, 20, 20 button #LPTwindow.button4up, "1", [Pin4up], UL, 30, 155, 20, 20 button #LPTwindow.button5up, "1", [Pin5up], UL, 30, 180, 20, 20 button #LPTwindow.button6up, "1", [Pin6up], UL, 30, 205, 20, 20 button #LPTwindow.button7up, "1", [Pin7up], UL, 30, 230, 20, 20 button #LPTwindow.button8up, "1", [Pin8up], UL, 30, 255, 20, 20 button #LPTwindow.button9up, "1", [Pin9up], UL, 30, 280, 20, 20 statictext #LPTwindow.button17, "Pin 17, Sel(L1) = 0", 55, 7, 110, 15 'ver116-4e added latch numbers statictext #LPTwindow.button16, "Pin 16, Init(L2) = 0", 55, 32, 110, 15 statictext #LPTwindow.button14, "Pin 14, Auto(L3) = 0", 55, 57, 110, 15 statictext #LPTwindow.button1, "Pin 1, Strobe(L4) = 0", 55, 82, 110, 15 statictext #LPTwindow.button2, "Pin 2, D0 = 0", 55, 107, 75, 15 statictext #LPTwindow.button3, "Pin 3, D1 = 0", 55, 132, 75, 15 statictext #LPTwindow.button4, "Pin 4, D2 = 0", 55, 157, 75, 15 statictext #LPTwindow.button5, "Pin 5, D3 = 0", 55, 182, 75, 15 statictext #LPTwindow.button6, "Pin 6, D4 = 0", 55, 207, 75, 15 statictext #LPTwindow.button7, "Pin 7, D5 = 0", 55, 232, 75, 15 statictext #LPTwindow.button8, "Pin 8, D6 = 0", 55, 257, 75, 15 statictext #LPTwindow.button9, "Pin 9, D7 = 0", 55, 282, 75, 15 statictext #LPTwindow.explain, "Click 0 or 1 to change state.", 5, 305, 180, 20 statictext #LPTwindow.message4, "Click to read Status Pins:", 175, 7, 150, 15 if USBdevice <> 0 then statictext #LPTwindow.noteusb, "(Invalid with USB)", 175, 27, 170, 15 'ver116-4r 'the positions of all below have been lowered by 20 pixels 'ver116-4r button #LPTwindow.status, "CAPTURE STATUS", [ReadLPTStatus], UL, 175, 50, 130, 20 textbox #LPTwindow.waitbox, 175, 75, 20, 20 textbox #LPTwindow.ackbox, 175, 100, 20, 20 textbox #LPTwindow.pebox, 175, 125, 20, 20 textbox #LPTwindow.selbox, 175, 150, 20, 20 textbox #LPTwindow.errbox, 175, 175, 20, 20 statictext #LPTwindow.message11, "WAIT, pin 11", 200, 77, 80, 15 statictext #LPTwindow.message10, "ACK, pin 10", 200, 102, 80, 15 statictext #LPTwindow.message12, "PE, pin 12", 200, 127, 80, 15 statictext #LPTwindow.message13, "SELECT, pin 13", 200, 152, 80, 15 statictext #LPTwindow.message15, "ERROR, pin 15", 200, 177, 80, 15 statictext #LPTwindow.portaddres, "LPT Port Address (Hex)", 150, 227, 120, 15 textbox #LPTwindow.addressbox, 270, 225, 35, 20 statictext #LPTwindow.changeas, "Enter value as:", 150, 250, 75, 15 button #LPTwindow.hexbutton, "Hex", [ChangeAsHex], UL, 235, 250, 30, 20 button #LPTwindow.decbutton, "Dec", [ChangeAsDec], UL, 270, 250, 30, 20 open "LPT Printer Port Test" for dialog as #LPTwindow:lptwindow=1 'put lptwindow in main sw. print #LPTwindow.status, "!setfocus" print #LPTwindow, "trapclose [closeLPTwindow]" lptpin1=1 : lptpin14=2 : lptpin16=0 : lptpin17=8 'start with control line values at zero if port = 0 then port = 888 'default address in decimal, when LPT Test is stand-alone print #LPTwindow.addressbox,""; dechex$(port) [ChangeAsHex] print #LPTwindow.addressbox, "!contents? newport$"; port = hexdec(newport$):status=port+1:control=port+2 print #LPTwindow.addressbox,""; dechex$(port) wait [ChangeAsDec] print #LPTwindow.addressbox, "!contents? newport$"; port = val(newport$):status=port+1:control=port+2 print #LPTwindow.addressbox,""; dechex$(port) wait [Pin2down] lptD0=0 print #LPTwindow.button2, "Pin 2, D0 = 0" goto [SetLPTport] [Pin3down] lptD1=0 print #LPTwindow.button3, "Pin 3, D1 = 0" goto [SetLPTport] [Pin4down] lptD2=0 print #LPTwindow.button4, "Pin 4, D2 = 0" goto [SetLPTport] [Pin5down] lptD3=0 '116-4sLPT print #LPTwindow.button5, "Pin 5, D3 = 0" goto [SetLPTport] [Pin6down] lptD4=0 '116-4sLPT print #LPTwindow.button6, "Pin 6, D4 = 0" goto [SetLPTport] [Pin7down] lptD5=0 '116-4sLPT print #LPTwindow.button7, "Pin 7, D5 = 0" goto [SetLPTport] [Pin8down] lptD6=0 '116-4sLPT print #LPTwindow.button8, "Pin 8, D6 = 0" goto [SetLPTport] [Pin9down] lptD7=0 '116-4sLPT print #LPTwindow.button9, "Pin 9, D7 = 0" goto [SetLPTport] [Pin2up] lptD0=1 print #LPTwindow.button2, "Pin 2, D0 = 1" goto [SetLPTport] [Pin3up] lptD1=2 print #LPTwindow.button3, "Pin 3, D1 = 1" goto [SetLPTport] [Pin4up] lptD2=4 print #LPTwindow.button4, "Pin 4, D2 = 1" goto [SetLPTport] [Pin5up] lptD3=8 '116-4sLPT print #LPTwindow.button5, "Pin 5, D3 = 1" goto [SetLPTport] [Pin6up] lptD4=16 '116-4sLPT print #LPTwindow.button6, "Pin 6, D4 = 1" goto [SetLPTport] [Pin7up] lptD5=32 '116-4sLPT print #LPTwindow.button7, "Pin 7, D5 = 1" goto [SetLPTport] [Pin8up] lptD6=64 '116-4sLPT print #LPTwindow.button8, "Pin 8, D6 = 1" goto [SetLPTport] [Pin9up] lptD7=128 '116-4sLPT print #LPTwindow.button9, "Pin 9, D7 = 1" goto [SetLPTport] [Pin1down] 'STROBE lptpin1 = 1 regPD3 = 0 'ver116-4r print #LPTwindow.button1, "Pin 1, Strobe(L4) = 0" goto [SetLPTControl] [Pin14down] 'AUTO lptpin14 = 2 regPD2 = 0 'ver116-4r print #LPTwindow.button14, "Pin 14, Auto(L3) = 0" goto [SetLPTControl] [Pin16down] 'INIT lptpin16 = 0 regPD1 = 0 'ver116-4r print #LPTwindow.button16, "Pin 16, Init(L2) = 0" goto [SetLPTControl] [Pin17down] 'SELT lptpin17 = 8 regPD0 = 0 'ver116-4r print #LPTwindow.button17, "Pin 17, Sel(L1) = 0" goto [SetLPTControl] [Pin1up] 'STROBE lptpin1 = 0 regPD3 = 8 'ver116-4r print #LPTwindow.button1, "Pin 1, Strobe(L4) = 1" goto [SetLPTControl] [Pin14up] 'AUTO lptpin14 = 0 regPD2 = 4 'ver116-4r print #LPTwindow.button14, "Pin 14, Auto(L3) = 1" goto [SetLPTControl] [Pin16up] 'INIT lptpin16 = 4 regPD1 = 2 'ver116-4r print #LPTwindow.button16, "Pin 16, Init(L2) = 1" goto [SetLPTControl] [Pin17up] 'SELT lptpin17 = 0 regPD0 = 1 'ver116-4r print #LPTwindow.button17, "Pin 17, Sel(L1) = 1" goto [SetLPTControl] [SetLPTport] out port, lptD0 +lptD1 +lptD2 +lptD3 +lptD4 +lptD5 +lptD6 +lptD7 'for USB, this is register PB, bits 0-7 USBwrbuf$ = "A60200"+ToHex$(lptD0+lptD1+lptD2 +lptD3 +lptD4 +lptD5 +lptD6 +lptD7)+"000000" '116-4sLPT if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 7 as short, result as boolean 'ver116-4r wait [SetLPTControl] out control, lptpin1 +lptpin14 +lptpin16 +lptpin17 'for USB, this is register PD, bits 0-3 USBwrbuf$ = "A608000000"+ToHex$(regPD0+regPD1+regPD2+regPD3)+"00" 'ver116-4r if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 7 as short, result as boolean 'ver116-4r wait [ReadLPTStatus] lptpin11=1:lptpin10=0:lptpin12=0:lptpin13=0:lptpin15=0 read7 = inp(status) if read7 > 127 then lptpin11 = 0:read7 = read7 - 128 print #LPTwindow.waitbox, lptpin11 if read7 > 63 then lptpin10 = 1:read7 = read7 - 64 print #LPTwindow.ackbox, lptpin10 if read7 >31 then lptpin12 = 1:read7 = read7 - 32 print #LPTwindow.pebox, lptpin12 if read7 > 15 then lptpin13 = 1:read7 = read7 - 16 print #LPTwindow.selbox, lptpin13 if read7 > 7 then lptpin15 = 1 print #LPTwindow.errbox, lptpin15 wait [closeLPTwindow] out port, 0 out control, contclear port=enterport:status=enterstatus:control=entercontrol 'put MSA addresses back to what they were when entering this subroutine close #LPTwindow lptwindow=0 wait 'End LPT port tester sub RequireRestart 'Disable OneStep and Continue so user can only proceed by Restart if doingInitialization then exit sub 'Buttons don't exist yet ver114-3f haltsweep=0 call DisplayButtonsForHalted #handle.OneStep, "!disable" #handle.Continue, "!disable" end sub sub DisplayButtonsForRunning 'Display buttons for sweep in progress if doingInitialization then exit sub 'Buttons don't exist yet ver114-3f #handle.OneStep, "!enable" #handle.Continue, "!enable" print #handle.Restart, "Running" 'ver114-4c deleted print to #main.restart 'OneStep becomes HaltAtEnd when scan is in progress #handle.OneStep, "Halt At End" 'SEWgraph 'Continue becomes Halt when scan is in progress #handle.Continue, "Halt" 'SEWgraph #handle.Redraw, "!hide" 'SEWgraph hide during scan end sub sub DisplayButtonsForHalted 'Display buttons for sweep halted, to enable resuming or restarting if doingInitialization then exit sub 'Buttons don't exist yet ver114-3f #handle.OneStep, "!enable" #handle.Continue, "!enable" print #handle.Restart, "Restart" 'ver114-4c deleted print to #main.restart 'OneStep becomes HaltAtEnd when scan is in progress #handle.OneStep, "One Step" 'SEWgraph 'Continue becomes Halt when scan is in progress #handle.Continue, "Continue" 'SEWgraph #handle.Redraw, "!show" 'SEWgraph hide during scan end sub sub CalcReflectDerivedData currStep 'Calc ReflectArray() data from S11. frequency and S11 must already be in place. 'if currStep<0 then we get the data from uWorkReflectData(x) and put results into uWorkReflectData(x) 'otherwise we get the data from ReflectArray() and put results into ReflectArray(currStep,x) 'S11 is assumed to be re S11GraphR0 if currStep<0 then 'Get frequency and S11; we calculate everything else trueFreq=1000000*uWorkReflectData(0) 'ver115-1f db=uWorkReflectData(constGraphS11DB) ang=uWorkReflectData(constGraphS11Ang) else trueFreq=1000000*ReflectArray(currStep,0) db=ReflectArray(currStep,constGraphS11DB) ang=ReflectArray(currStep,constGraphS11Ang) end if rho=10^(db/20) call uRefcoToImpedance S11GraphR0, rho, ang, serR, serReact call uEquivSeriesLC trueFreq, serR, serReact, serL, serC if abs(serReact)<0.001 then serReact=0 'ver115-5d if serR<0.001 then serR=0 'ver115-5d call uEquivParallelImped serR, serReact, parR, parReact 'Convert imped to equivalent parallel resistance and reactance ver114-7b if abs(parReact)<0.001 then parReact=0 'ver115-5d if parR<0.001 then parR=0 'ver115-5d if trueFreq=0 then parR=constMaxValue: parL=constMaxValue: parC=0 'Set for max impedance else twoPiF = 2.0*uPi() * trueFreq if parReact>=constMaxValue then parL=constMaxValue else parL = parReact/twoPiF if parReact=0 then parC=constMaxValue else parC = -1.0/(twoPiF * parReact) end if if rho>0.999999 then swr=9999 else swr=(1+rho)/(1-rho) 'Impose a max of 1F or 1H if serC>1 then serC=1 if serL>1 then serL=1 if parC>1 then parC=1 if serC>1 then serC=1 if serC<-1 then serC=-1 if serL<-1 then serL=-1 if parC<-1 then parC=-1 if serC<-1 then serC=-1 minC=1e-15 : minL=1e-12 'impose min of 1 fF and 1 pH ver115-2d if abs(serC)=constAux0 and Y1DataType<=constAux5 then 'ver115-4a y1=auxGraphData(currStep, Y1DataType-constAux0) end if if Y2DataType>=constAux0 and Y2DataType<=constAux5 then 'ver115-4a y2=auxGraphData(currStep, Y2DataType-constAux0) end if if msaMode$="Reflection" then call CalcReflectGraphData currStep, y1, y2, useWorkArray else if msaMode$<>"SA" then call CalcTransmitGraphData currStep, y1, y2, useWorkArray else 'Here for spectrum analyzer mode if useWorkArray then db=uWorkArray(currStep+1,1) else db=datatable(currStep,2) end if if referenceDoMath=1 then 'ref math is to be done on db values--only allowed for SA mode ver115-5d db=referenceOpA*referenceTransform(currStep+1, 1)+referenceOpB*db end if for i=1 to 2 'modver115-3b if i=1 then c=Y1DataType else c=Y2DataType select c case constMagDBM y=db case constMagWatts pow=10^(db/10) 'ver115-9f y=pow/1000 case constMagV pow=10^(db/10) 'ver115-9f y=sqr(pow/20) 'square root of 50* mw/1000 case constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 'ver115-4a if i=1 then y=y1 else y=y2 'Auxiliary data has already been calculated, so keep it case else 'constNoGraph, or invalid data type y=0 end select if i=1 then y1=y else y2=y next i end if 'end SA mode end if 'end all modes 'The point may not be integral, so we need to interpolate wholeStep=int(currStep) : fract=currStep-wholeStep if wholeStep=globalSteps or fract<0.0000001 then exit sub 'No need to interpolate; we are done 'We interpolate the required data types, not the raw S21, S11, etc. call CalcGraphData wholeStep+1, nextY1, nextY2, useWorkArray 'Get values at next step if Y1DataType<>constNoGraph then y1=LinearInterpolateDataType(Y1DataType, fract, y1, nextY1) if Y2DataType<>constNoGraph then y2=LinearInterpolateDataType(Y2DataType, fract, y2, nextY2) end sub function DataTypeIsAngle(dataType) 'Return 1 if dataType is an angle; otherwise 0 select case dataType case constGraphS11Ang,constImpedAng,constAdmitAng, constAngle,constRawAngle 'angles--must worry about wraparound DataTypeIsAngle=1 case constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 DataTypeIsAngle=auxGraphDataInfo(dataType-constAux0,0) 'This has info on auxiliary data ver116-1b case else 'non-angles DataTypeIsAngle=0 end select end function function LinearInterpolateDataType(dataType, fract, v1, v2) 'Interpolate between values v1 and v2 based on fract 'If the dataType is an angle, deal with wraparound using angle range of -180 to +180 if DataTypeIsAngle(dataType) then LinearInterpolateDataType=intLinearInterpolateDegrees(fract, v1, v2, -180, 180) 'ver116-4k else 'non-angles LinearInterpolateDataType=v1 + fract*(v2-v1) end if end function sub CalcReflectGraphData currStep, byref y1, byref y2, useWorkArray 'Calculate y1,y2 per user request 'If useWorkArray=1 then the data source is uWorkReflectData(); otherwise it is ReflectArray() 'Power is in uWorkArray(currStep+1,1), phase in uWorkArray(currStep+1,2) 'S11 db is in ReflectArray(currStep,2), phase in ReflectArray(currStep,3) for dataNum=2 to 1 step -1 if dataNum=1 then if msaMode$="SA" or msaMode$="ScalarTrans" then exit for 'don't have phase componConst=Y1DataType else componConst=Y2DataType end if select componConst case constGraphS11DB, constGraphS11Ang, constRho, constImpedMag, constImpedAng, constSerR,constSerReact,constParR,constParReact,_ constSerC,constSerL,constParC,constParL,constSWR 'All these have already been computed if useWorkArray then y=uWorkReflectData(componConst) else y=ReflectArray(currStep,componConst) 'ver115-1e case constTheta 'Same as angle if useWorkArray then y=uWorkReflectData(constGraphS11Ang) else y=ReflectArray(currStep,constGraphS11Ang) 'ver115-1e case constReturnLoss if useWorkArray then y=0-uWorkReflectData(constGraphS11DB) else y=0-ReflectArray(currStep,constGraphS11DB) 'ver115-1e case constReflectPower if useWorkArray then y=100*uWorkReflectData(constRho)^2 else y=100*ReflectArray(currStep,constRho)^2 'ver115-2d case constComponentQ 'ver115-2d 'Note that this formula works only for a single L or C. For LC combos, we would need the reactance 'of the individual components if useWorkArray then X=uWorkReflectData(constSerReact) : R=uWorkReflectData(constSerR) else X=ReflectArray(currStep,constSerReact) : R=ReflectArray(currStep,constSerR) end if if R=0 then y=99999 else y=abs(X)/R 'Q=X/R case constAdmitMag, constAdmitAng, constConductance, constSusceptance 'ver115-4a select case componConst case constAdmitMag if useWorkArray then mag=uWorkReflectData(constImpedMag) else mag=ReflectArray(currStep,constImpedMag) if mag=0 then y=constMaxValue else y=1/mag case constAdmitAng if useWorkArray then ang=uWorkReflectData(constImpedAng) else ang=ReflectArray(currStep,constImpedAng) y=0-ang case else 'constConductance, constSusceptance if useWorkArray then R=uWorkReflectData(constSerR) : X=uWorkReflectData(constSerReact) _ else R=ReflectArray(currStep,constSerR) : X=ReflectArray(currStep,constSerReact) call cxInvert R, X, G, S if componConst=constConductance then y=G else y=S end select case constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 'ver115-4a if dataNum=1 then y=y1 else y=y2 'Auxiliary data has already been calculated, so keep it case else y=0 'invalid data, or None end select if dataNum=1 then 'Put data into y1 or y2 y1=y else y2=y end if next dataNum end sub sub CalcTransmitGraphData currStep, byref y1, byref y2, useWorkArray 'Calculate y1,y2 per user request 'If useWorkArray=1 then the data source is uWorkArray(); otherwise it is S21DataArray() 'ver116-1b deleted calc of trueFreq, which was incorrect and not needed if useWorkArray then db=uWorkArray(currStep+1,1) ang=uWorkArray(currStep+1,2) else db=S21DataArray(currStep,1) 'ver115-2b ang=S21DataArray(currStep,2) 'ver115-2b end if 'ver115-1e deleted impedance transform for transmission mode for dataNum=1 to 2 'ver115-3b if dataNum=1 then componConst=Y1DataType else componConst=Y2DataType end if select componConst case constMagDB y=db case constMagDBM 'This gives raw data before cal was applied 'Used for transmission mode only if applyCalLevel=0 then y=db else y=db+lineCalArray(currStep,1) case constMagRatio y=10^(db/20) case constInsertionLoss y=0-db case constAngle 'Source data is raw y=ang case constRawAngle ' raw phase before cal. Used for transmission mode only if applyCalLevel=0 then y=ang else y=gNormalizePhase(ang+lineCalArray(currStep,2)) 'ver116-4b case constGD 'calc group delay if startfreq=endfreq then message$= "Can't calculate Group Delay with zero sweep width." : call PrintMessage y=-1 else call gGetSweepStartAndEndPointNum pStart, pEnd dir=gGetSweepDir() '1 or -1 if currStep=pStart-1 then y=-1 'Need two points; only have one at first point else if useWorkArray then y=(uWorkArray(currStep+1,2)-uWorkArray(currStep+1-dir,2))/360 _ else y=(S21DataArray(currStep,2)-S21DataArray(currStep-dir,2))/360 'delta phase in cycles ver116-1b if y>0.5 then y=y-1 else if y<-0.5 then y=y+1 'Deal with wraparound ver114-6k if useWorkArray then deltaF=1000000*(uWorkArray(currStep+1,0)-uWorkArray(currStep+1-dir,0)) _ else deltaF=1000000*(S21DataArray(currStep,0)-S21DataArray(currStep-dir,0)) 'delta freq, cycles per second ver116-1b y=0-y/deltaF 'negative of delta phase over delta freq end if end if case constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 'ver115-4a if dataNum=1 then y=y1 else y=y2 'Auxiliary data has already been calculated, so keep it case else y=0 'invalid data, or None end select if dataNum=1 then 'Put data into y1 or y2 y1=y else y2=y end if next dataNum end sub sub CreateReferenceSource 'Return reference trace ver114-7e 'Create referenceSource() data in accordance with referenceLineType and referenceLineSpec$ 'referenceSource entries are numbered from 1 'refType describes the reference type: ' referenceLineType=0 No Reference lines ' referenceLineType=1 Use existing datatable() data at time reference was created ' referenceLineType=2 Calculate trace for RLC combo specified in spec$, per uParseRLC ' referenceLineType=3 use fixed value references 'This routine is specific to the test setup. In the case of RLC combos, it can calculate impedance at a freq, and 'then determine the S21 that the impedance would generate in the S21 fixture, or it can generate S11 data 'based on the current ref impedance. if referenceLineType=0 then referenceSourceNumPoints=0 : exit sub 'No reference lines needed if referenceLineType=2 then '2=RLC call uSetMaxWorkPoints gNumDynamicSteps()+1,3 uWorkNumPoints=gNumDynamicSteps()+1 for i=0 to uWorkNumPoints : uWorkArray(i+1,0)=datatable(i,1) : next i 'set up for uRLCComboResponse 'Calc response in whatever S11 or S21 setup the user has chosen if msaMode$="Reflection" then doSpecialR0=S11BridgeR0 : doSpecialJig$="S11" 'ver115-2a else doSpecialR0=S21JigR0 if S21JigAttach$="Series" then doSpecialJig$="S21Series" else doSpecialJig$="S21Shunt" end if 'TO DO--Note uRLCComboResponse does not adjust for S21JigShuntDelay. If we need to do so, do it here. isErr= uRLCComboResponse(referenceLineSpec$, doSpecialR0, doSpecialJig$) if isErr then notice "Invalid RLC reference specification" : exit sub 'uWorkArray now contains the db, degrees response for each frequency 'Transfer to referenceSource() referenceSourceNumPoints=uWorkNumPoints for i=1 to uWorkNumPoints referenceSource(i, 0)=uWorkArray(i, 0) 'freq referenceSource(i, 1)=uWorkArray(i, 1) 'db referenceSource(i, 2)=uWorkArray(i, 2) 'ang next i else if referenceLineType=3 then '3=Fixed value s$=referenceLineSpec$ isErr=uExtractNumericItems(2, s$, ";",v1, v2, v3) referenceSourceNumPoints=gNumDynamicSteps()+1 for i=1 to referenceSourceNumPoints referenceSource(i, 0)=gGetPointXVal(i) 'Actual tuning freq, in MHz referenceSource(i, 1)=v1 'Fixed val for trace 1 referenceSource(i, 2)=v2 'Fixed val for trace 2 next i else 'referenceLineType=1; use current data 'ver115-7a modified this referenceSourceNumPoints=gNumDynamicSteps()+1 if msaMode$="SA"then source1=constMagDBM : source2=constNoGraph if msaMode$="ScalarTrans"then source1=constMagDB : source2=constNoGraph if msaMode$="VectorTrans"then source1=constMagDB : source2=constAngle if msaMode$="Reflection"then source1=constGraphS11DB : source2=constGraphS11Ang for i=1 to referenceSourceNumPoints referenceSource(i, 0)=gGetPointXVal(i) 'Actual tuning freq, in MHz 'No matter what we are doing with the reference, we save dB(m)/angle data as the "source" 'and later do any necessary "transform". call CalcGraphDataType i-1, source1, source2, y1, y2,0 'calc db/angle info referenceSource(i, 1)= y1 'dB or dBm referenceSource(i, 2)=y2 'angle or 0 next i end if end if end sub sub CreateReferenceTransform 'Transform referenceSource() data into actual graph data; put it into referenceTransform for i=0 to referenceSourceNumPoints-1 'iterate by step num, though referenceTransform starts at 1 (point num) call CalcReferencesWholeStep i, ref1, ref2 referenceTransform(i+1, 0)=referenceSource(i+1, 0) 'freq referenceTransform(i+1, 1)=ref1 'Trace 1 referenceTransform(i+1, 2)=ref2 'Trace 2 next i end sub sub CalcReferencesWholeStep stepNum, byRef ref1, byRef ref2 'Calculate reference line data at whole step stepNum pointNum=stepNum+1 if referenceLineType=3 then 'Here we have a fixed value reference, which we don't need to transform. 'We just transfer the values. ref1=referenceSource(pointNum, 1) ref2=referenceSource(pointNum, 2) exit sub end if if msaMode$="Reflection" then 'For reflection we have to calculate a bunch of derived data, such as impedance, 'which may be needed to calculate the graph data. This is done frequency by frequency 'using uWorkReflectData() as an intermediary uWorkReflectData(0)=referenceSource(pointNum,0) 'freq uWorkReflectData(1)=referenceSource(pointNum, 1) 'db uWorkReflectData(2)=referenceSource(pointNum, 2) 'ang call CalcReflectDerivedData -1 'Calculate other reflection derived data from the above 'Calc graph data from info just put into uWorkReflectData thispointy1=0 : thispointy2=0 call CalcReflectGraphData -1, ref1, ref2, 1 else 'For non-reflection modes, the only source data we need for the calculations are 'freq, db and ang (or dBm as the case may be). We transfer all the data to uWorkArray 'and then calculate from there uWorkArray(1,0)=referenceSource(pointNum, 0) 'freq uWorkArray(1, 1)=referenceSource(pointNum, 1) 'db uWorkArray(1, 2)=referenceSource(pointNum, 2) 'ang call CalcGraphData 0, ref1, ref2, 1 'calc values from uWorkArray end if end sub sub CalcReferences stepNum, ref1IsAngle, byref ref1, ref2IsAngle, byref ref2 'Return value of reference lines at step stepNum, possibly fractional 'We interpolate if necessary. ref1IsAngle=1 means reference 1 is an angle and we have to 'deal with possible wraparound when interpolating. Likewise for ref2IsAngle if stepNum<0 then stepNum=0 if stepNum>globalSteps then stepNum=globalSteps 'The point may not be integral, so we need to interpolate whole=int(stepNum) : fract=stepNum-whole if fract=0 then call CalcReferencesWholeStep stepNum, ref1, ref2 exit sub else 'If we are not at a whole step, we need to interpolate. The regular graph will interpolate the value 'being graphed, not the underlying S11, so we do the same call CalcReferencesWholeStep whole, refA1, refA2 'ref values at wholeStep call CalcReferencesWholeStep whole+1, refB1, refB2 'ref values at wholeStep+1 if (referenceTrace and 1)=0 then ref1=0 'Don't have ref line for axis Y1 else if ref1IsAngle then 'angles--must worry about wraparound 'Note angles are kept in range -180 to +180; will be adjusted in gGraphVal to fit range ref1=intLinearInterpolateDegrees(fract, refA1, refB1, -180, 180) 'ver116-4k else ref1=refA1 + fract*(refB1-refA1) end if end if if (referenceTrace and 2)=0 then ref2=0 'Don't have ref line for axis Y2 else if ref2IsAngle then 'angles--must worry about wraparound 'Note angles are kept in range -180 to +180; will be adjusted in gGraphVal to fit range ref2=intLinearInterpolateDegrees(fract, refA2, refB2, -180, 180) 'ver116-4k else ref2=refA2 + fract*(refB2-refA2) end if end if end if end sub sub PrintReferenceHeading 'Print above axis to indicate which line matches which axis if referenceLineType<>0 then if referenceDoMath=0 then refHeadingColor1$=referenceColor1$ : refHeadingColor2$=referenceColor2$ 'Use ref color if ref line is drawn else call gGetTraceColors refHeadingColor1$, refHeadingColor2$ 'Use trace colors for "REF" if math is used end if if referenceLineType=3 then 'For fixed value ref, print the value semiPos=instr(referenceLineSpec$,";") v1$= "=";Left$(referenceLineSpec$, semiPos-1) 'Up to semicolon is first value v2$= "=";Mid$(referenceLineSpec$, semiPos+1) 'After semicolon is second value else v1$="" : v2$="" end if if (referenceTrace and 2) then call gPrintAxisAnnotation 2, "Ref";v2$, "Tahoma 8 bold", refHeadingColor2$ end if if (referenceTrace and 1) then call gPrintAxisAnnotation 1, "Ref";v1$, "Tahoma 8 bold", refHeadingColor1$ end if end if end sub function CreateReferenceTraces$(tCol$, tSize,traceNum) 'Return reference trace ver114-7e 'The trace is created from the data in referenceTransform(). 'referenceTrace indicates which traces we want if (traceNum and referenceTrace)=0 then CreateReferenceTraces$="down" : exit function call uSetMaxWorkPoints referenceSourceNumPoints,3 uWorkNumPoints=referenceSourceNumPoints for i=1 to uWorkNumPoints uWorkArray(i, 0)=referenceTransform(i, 0) 'freq uWorkArray(i, 1)=referenceTransform(i, 1) 'Trace 1 data uWorkArray(i, 2)=referenceTransform(i, 2) 'Trace 2 data next i CreateReferenceTraces$="color ";tCol$;";size ";tSize;";"; _ PrivateCreateReferenceTrace$(traceNum, 1, gNumDynamicSteps()+1) end function function PrivateCreateReferenceTrace$(traceNum, startPoint, endPoint) 'Return reference line for RLC combo 'We generate values from startPoint to endPoint for a reference trace, using data in uWorkArray() 'traceNum=1 for Y1 and 2 for Y2. 'color and size prefix not included span=endPoint-startPoint if span=0 then PrivateCreateReferenceTrace$="down" : exit function 'down is a NOP in order to have a valid command if span>20 then 'If large number of points, divide in half and then put the two halves together mid=startPoint+int(span/2) PrivateCreateReferenceTrace$=PrivateCreateReferenceTrace$(traceNum, startPoint, mid)+ _ PrivateCreateReferenceTrace$(traceNum, mid+1, endPoint) exit function end if call gGetIsPhase y1IsPhase, y2IsPhase if startPoint<>1 then 'If not very first point of trace, the starting point is the point before startPoint if traceNum=1 then if y1IsPhase then lastY=gAdjustPhaseToDisplay(1, startPoint-1, 1) else lastY=uWorkArray(startPoint-1, 1) call gConvertY1ToPix lastY else if y2IsPhase then lastY=gAdjustPhaseToDisplay(2, startPoint-1, 1) else lastY=uWorkArray(startPoint-1, 2) call gConvertY2ToPix lastY end if lastX=gGetPointXPix(startPoint-1) 'Ref has same x pixel as main graph end if for currPoint=startPoint to endPoint 'create segment from prior point to this point, for both y1 and y2 as appropriate if traceNum=1 then if y1IsPhase then y=gAdjustPhaseToDisplay(1, currPoint, 1) else y=uWorkArray(currPoint, 1) call gConvertY1ToPix y else if y2IsPhase then y=gAdjustPhaseToDisplay(2, currPoint, 1) else y=uWorkArray(currPoint, 2) call gConvertY2ToPix y end if x=gGetPointXPix(currPoint) 'Ref has same x pixel as main graph if currPoint=1 then t$="set ";x;" ";y 'just set the point else t$=t$;";"; "line ";lastX; " ";lastY;" ";x;" ";y 'draw final segment (of this larger segment) in reverse to be sure the very last pixel gets drawn. if currPoint=endPoint then t$=t$;";"; "line ";x;" ";y;" ";lastX; " ";lastY end if lastX=x : lastY=y next currPoint 'Result is what we have put together so far, plus the final line drawn backward to 'be sure final point is fully drawn PrivateCreateReferenceTrace$=t$;";line ";x;" ";y;" ";lastX; " ";lastY end function sub GetDialogPlacement 'calculate top left for placement of dialog 'Dialog height,width are in WindowHeight, WindowWidth. Placement is put into UpperLeftX and UpperLeftY 'Dialog is placed relative to parent window client origin. Place so it does not cover graph area, 'aligned with right graph window edge. call gGetGridCorner "LR", cornerX, cornerY UpperLeftX = currGraphBoxWidth+clientWidthOffset-WindowWidth-30 'puts right edge of dialog near right window edge UpperLeftY=cornerY+30 'puts top of dialog under graph end sub [menuVNARef] if haltsweep=1 then gosub [FinishSweeping] WindowWidth = 150 : WindowHeight = 150 call GetDialogPlacement 'ver115-1c BackgroundColor$="gray" 'ver115-5b ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" VNAinfoLeft=15 : VNAapplyTop=10 if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then statictext #VNAref.Apply, "Reference Transmission Measurements To:",VNAinfoLeft,VNAapplyTop+10,120, 35 else statictext #VNAref.Apply, "Reference Reflection Measurements To:",VNAinfoLeft,VNAapplyTop+10,120, 35 end if checkbox #VNAref.Line, "Band Sweep Cal", [VNAapplyLineOn], [VNAapplyLineOff], VNAinfoLeft+5,VNAapplyTop+45, 150, 15 checkbox #VNAref.BaseLine, "Baseline Cal", [VNAapplyBaseLineOn], [VNAapplyBaseLineOff], VNAinfoLeft+5,VNAapplyTop+65, 150, 15 checkbox #VNAref.None, "No Reference", [VNAapplyNoneOn], [VNAapplyNoneOff], VNAinfoLeft+5,VNAapplyTop+85, 150, 15 open "Ref" for dialog_modal as #VNAref 'ver115-1b print #VNAref, "trapclose [VNARefFinished]" 'goto [finished] if xit is clicked savedesiredCalLevel=desiredCalLevel 'ver114-5L if desiredCalLevel=0 then #VNAref.None, "set" : wait if desiredCalLevel=2 then #VNAref.Line, "set" : wait #VNAref.BaseLine, "set" wait [VNARefFinished] #VNAref.None, "value? calLevel$" 'ver115-1b applied same procedure to reflection as for transmission if calLevel$="set" then desiredCalLevel=0 else #VNAref.BaseLine, "value? calLevel$" if calLevel$="set" then desiredCalLevel=1 else desiredCalLevel=2 end if 'Implement selected calibration if anything changed if savedesiredCalLevel<>desiredCalLevel then 'ver114-5L created if... call SignalNoCalInstalled 'ver116-4b call RequireRestart end if close #VNAref wait [VNAapplyLineOn] #VNAref.BaseLine, "reset" : #VNAref.None, "reset" :wait [VNAapplyLineOff] #VNAref.Line, "set" : wait [VNAapplyBaseLineOn] #VNAref.Line, "reset" : #VNAref.None, "reset" : wait [VNAapplyBaseLineOff] #VNAref.BaseLine, "set" : wait [VNAapplyNoneOn] #VNAref.BaseLine, "reset" : #VNAref.Line, "reset" : wait [VNAapplyNoneOff] #VNAref.None, "set" : wait [menuCalPDM] if haltsweep=1 then gosub [FinishSweeping] WindowWidth = 500 : WindowHeight = 325 UpperLeftX = INT((DisplayWidth-WindowWidth)/2) UpperLeftY = 75 'ver115-1a BackgroundColor$="buttonface" 'ver116-4L changed color ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" s$="The actual phase shift caused by PDM inversion will differ from the theoretical" s$=s$;" 180 degrees. A one-time calibration is required to determine the actual phase shift." s$=s$;" This value will be used internally, and you will not directly need to know or use the value." s$=s$;" To perform this calibration you first need to do the following, which will require that" s$=s$;" you close this window and return to the Graph Window:" statictext #PDMcal.t1, s$,15,15,425, 100 statictext #PDMcal.t2, "*Set Video Filter to NARROW bandwidth.",25,112,400, 16 statictext #PDMcal.t3, "*Connect Tracking Generator output to MSA input with 1-2 foot cable.",25,129,425, 16 statictext #PDMcal.t4, "*In menu Operating Cal->Transmission, set Transmission Reference to No Reference.",25,146,475, 16 'ver114-5L'ver114-5n statictext #PDMcal.t5, "*Sweeping 0-200 MHz, find a frequency with a phase shift near 90 or 270 deg.",25,163,475, 16 statictext #PDMcal.t6, "*Center the sweep at that frequency, with zero sweep width.",25,180,425, 16 statictext #PDMcal.t7, "*Return to this window and click the PDM Inversion Cal button.",25,197,425, 16 button #PDMcal.PDM, "PDM Inversion Cal",[DoPDMCal], UL, 150, 220, 120,20 statictext #PDMcal.PDMval, "Current Inversion=xxx deg.",140,240,170, 16 button #PDMcal.Done, "Save New Value and Quit",[PDMCalFinished], UL, 60, 265, 160,20 button #PDMcal.Cancel, "Cancel",[PDMCalCancel], UL, 250, 265, 95,20 open "PDM Calibration" for dialog_modal as #PDMcal 'ver114-3g print #PDMcal, "trapclose [PDMCalWait]" #PDMcal, "font ms_sans_serif 9" 'ver116-4L #PDMcal.t1, "!font ms_sans_serif 10" 'ver116-4L #PDMcal.PDMval, "Current Inversion=";invdeg;" deg." doingPDMCal=0 CalInvDeg=360 'Will change if cal is done ver114-5L wait [PDMCalWait] wait [PDMCalCancel] close #PDMcal wait [PDMCalFinished] if doingPDMCal=1 then wait 'Don't allow quit in middle of cal if CalInvDeg<>360 then invdeg=CalInvDeg 'ver114-5L use calibrated value if cal was done globalPort=port call configSaveFile close #PDMcal wait [DoPDMCal] 'Run PDM calibration and display resulting invdeg if doingPDMCal=1 then goto [PostScan] 'continue on; don't stop ver114-5L doingPDMCal=1 'ver114-5L #PDMcal.PDMval, "Current Inversion= " #PDMcal.Done, "!disable" : #PDMcal.Cancel, "!disable" #PDMcal.PDM, "Be Patient" gosub [CalPDMinvdeg] #PDMcal.Done, "!enable" : #PDMcal.Cancel, "!enable" #PDMcal.PDMval, "Current Inversion= "; CalInvDeg ;" deg." 'Calibration result ver114-5L #PDMcal.PDM, "PDM Inversion Cal" doingPDMCal=0 'ver114-5L wait [menuPrimaryAxis] if haltsweep=0 then gosub [FinishSweeping] if ChoosePrimaryAxis()=1 then 'Returns 0 if cancelled ver115-3c call gUsePresetColors gGetLastPresetColors$() 'Reselect same appearance in case primary axis change had effect. call SetCycleColors 'ver116-4s select case msaMode$ case "Reflection" goto [RestartReflectionMode] case "ScalarTrans", "VectorTrans" goto [RestartTransmissionMode] case else ' "SA" if gentrk=1 then goto [RestartSATGmode] else goto [RestartPlainSAmode] 'ver115-4f end select end if wait function ChoosePrimaryAxis() 'Lets user choose axis 1 or 2 as the primary axis. Return 0 if cancelled; otherwise 1 WindowWidth = 465 WindowHeight = 300 UpperLeftX=100 UpperLeftY=100 ForegroundColor$="black" BackgroundColor$="buttonface" statictext #primaryaxis, "Your may choose either the left axis (axis Y1) or the right axis (axis Y2)", 5, 5, 425, 20 statictext #primaryaxis, "to be the primary axis. When starting up or changing modes, magnitude", 5, 25, 430, 20 statictext #primaryaxis, "will be graphed on the primary axis. Certain analyses, such as Filter", 5, 45, 415, 20 statictext #primaryaxis, "and Crystal Analysis, require dB to be graphed on the primary axis.", 5, 65, 415, 20 statictext #primaryaxis, "You must Restart after changing the primary axis.", 5, 85, 415, 20 checkbox #primaryaxis.Y1, "Left Axis (Y1)", [primarySelY1], [primarySelY1], 145, 147, 101, 25 checkbox #primaryaxis.Y2, "Right Axis (Y2)", [primarySelY2], [primarySelY2], 145, 177, 111, 25 button #primaryaxis.Done,"Done",[primaryDone], UL, 35, 217, 105, 35 button #primaryaxis.Cancel,"Cancel",[primaryCancel], UL, 245, 217, 100, 35 statictext #primaryaxis.statictext9, "Choose Primary Axis", 130, 122, 124, 20 open "Primary Axis" for dialog_modal as #primaryaxis print #primaryaxis, "font ms_sans_serif 10" print #primaryaxis, "trapclose [primaryDone]" if primaryAxisNum=1 then goto [primarySelY1] else goto [primarySelY2] wait [primarySelY1] 'Perform action for the checkbox named 'Y1' #primaryaxis.Y1, "set" : #primaryaxis.Y2, "reset" wait [primarySelY2] 'Perform action for the checkbox named 'Y2' #primaryaxis.Y2, "set" : #primaryaxis.Y1, "reset" wait [primaryDone] 'Perform action for the button named 'Done' #primaryaxis.Y1, "value? primaryY1Val$" if primaryY1Val$="set" then primaryAxisNum=1 else primaryAxisNum=2 call gSetPrimaryAxis primaryAxisNum 'ver115-3c lastCol$=gGetLastPresetColors$ if lastCol$="DARK" or lastCol$="LIGHT" then _ call gUsePresetColors lastCol$ 'Reset colors; may be affected by primary axis change ver115-3c call gGetSupplementalTraceColors referenceColor1$, referenceColor2$, dum1$, dum2$ 'ver116-4b if primaryAxisNum=1 then referenceColorSmith$=referenceColor1$ else referenceColorSmith$=referenceColor2$ 'ver116-4b call SetCycleColors 'ver116-4s close #primaryaxis ChoosePrimaryAxis=1 exit function [primaryCancel] 'Perform action for the button named 'Cancel' close #primaryaxis ChoosePrimaryAxis=0 exit function end function sub ExplainTransCal h$ 'Put up dialog explaining band/base and transmission cal WindowWidth = 635 WindowHeight = 220 UpperLeftX=0 'Doesn't seem to matter what is specified here UpperLeftY=150 BackgroundColor$="gray" ForegroundColor$="black" statictext #Explain, "Band calibration is performed at the frequency points of immediate interest and is used only as", 10, 10, 630, 20 statictext #Explain, "long as the sweep matches those points. Base calibration is performed over a broad frequency range,", 10, 30, 630, 20 statictext #Explain, "to be interpolated to the current sweep frequencies when there is no current band calibration.", 10, 50, 630, 20 statictext #Explain, "To create a Base calibration you perform a Band calibration and save it as a Base calibration.", 10, 70, 630, 20 statictext #Explain, "It is intended as a convenient coarse reference, especially when phase precision is not required.", 10, 90, 630, 20 statictext #Explain, "In Transmission Mode, Base calibrations are saved in a file for use in future sessions.", 10, 110, 630, 20 statictext #Explain, "In Transmision Mode you also specify the time delay of the calibration Through connection,", 10, 130, 630, 20 statictext #Explain, "which is ideally zero but may be greater if you need to use an adapter.", 10, 150, 630, 20 open "Reflection Calibration Help" for dialog_modal as #Explain #Explain, "trapclose [ExplainTransCalFinished]" print #Explain, "font ms_sans_serif 10" wait [ExplainTransCalFinished] close #Explain end sub [RunVNACal] if haltsweep=1 then gosub [FinishSweeping] WindowWidth = 600 : WindowHeight = 400 call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c UpperLeftY=UpperLeftY-100 BackgroundColor$="gray" 'ver115-5b changed color ForegroundColor$="black" TextboxColor$ = "white" ComboboxColor$="white" statictext #VNAcal.Path1, "The MSA is currently in Path X.",110,15,350, 18 statictext #VNAcal.Path2, "MSA calibrations are not saved separately for different paths. If the current path is not the one",25,35,560, 18 statictext #VNAcal.Path3, "for which the calibration will be used, close this window and change the path selection.",25,52,525, 18 statictext #VNAcal.Video, "VIDEO FILTER should be set to NARROW bandwidth for maximum smoothing.",25,75,525, 18 VNAbtnLeft=25 : VNAbtnTop=80 s$="Band Sweep calibration is run at the same frequency points at which it will be used." statictext #VNAcal.BandInst, s$,VNAbtnLeft+25,VNAbtnTop+42,500, 35 s$="You may save the current Band calibration as a Base calibration, to be used as a coarse" s$=s$;" reference when the Band calibration is not current." if steps>2000 then s$="(Saving Base Line calibration is disabled because it is limited to 2,000 steps.)" 'ver115-1b statictext #VNAcal.BaseInst, s$,VNAbtnLeft+25,VNAbtnTop+85,450, 40 if msaMode$="VectorTrans" then 'ver115-4e statictext #VNAcal.connect, "TG output must have THROUGH connection to MSA input.",25,90,550, 18 statictext #VNAcal.DelayLabel, "Delay of Calibration Through Connection (ns):",VNAbtnLeft+10,VNAbtnTop+160,270, 20 textbox #VNAcal.Delay, VNAbtnLeft+282,VNAbtnTop+160,50, 20 else 'Reflection statictext #VNAcal.connect, "Connect TG output and MSA input to test fixture and attach proper cal standards.",25,90,550, 18 end if statictext #VNAcal.LastBandCal, "xx",VNAbtnLeft,VNAbtnTop+62,570, 18 'Description of last calibration statictext #VNAcal.LastBaseCal, "xx",VNAbtnLeft,VNAbtnTop+120,570, 18 'Description of last calibration button #VNAcal.Perform, "Perform Band Cal",[PerformCal], UL, VNAbtnLeft+10, VNAbtnTop+210, 120,25 'ver114-5f button #VNAcal.ClearBand, "Clear Band Cal",[ClearBandCal], UL, VNAbtnLeft+175, VNAbtnTop+210, 120,25 'ver114-5f button #VNAcal.SaveBase, "Save As Base",[SaveBaseCal], UL, VNAbtnLeft+10, VNAbtnTop+250, 120,25 'ver114-5f button #VNAcal.ClearBase, "Clear Base Cal",[ClearBaseCal], UL, VNAbtnLeft+175, VNAbtnTop+250, 120,25 'ver114-5f button #VNAcal.Done, "Done",[VNACalFinished], UL, VNAbtnLeft+375, VNAbtnTop+210, 75,25 button #VNAcal.Explain, "Help",ExplainTransCal, UL, VNAbtnLeft+375, VNAbtnTop+250, 75,25 open "Perform Calibration" for dialog_modal as #VNAcal 'ver114-3g print #VNAcal, "trapclose [VNACalFinished]" 'goto [finished] if xit is clicked print #VNAcal, "font ms_sans_serif 10" #VNAcal.Path1, "The MSA is currently in "; path$ 'ver114-5p calInProgress=0 BandSweepCalDone=0 'ver114-5L 'ver115-2d if msaMode$="VectorTrans" then 'ver115-4e #VNAcal.Delay, lineCalThroughDelay 'Delay in ns 'ver115-5a end if 'Display info about last band and base cals if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then 'ver115-1b #VNAcal.LastBandCal, "Band: ";CalInfo$(bandLinePath$, bandLineTimeStamp$, bandLineLinear, _ bandLineNumSteps, bandLineStartFreq, bandLineEndFreq) #VNAcal.LastBaseCal, "Base: ";CalInfo$(baseLinePath$, baseLineTimeStamp$, baseLineLinear, _ baseLineNumSteps, baseLineStartFreq, baseLineEndFreq) else #VNAcal.LastBandCal, "Band: ";CalInfo$(OSLBandPath$, OSLBandTimeStamp$, OSLBandLinear, _ OSLBandNumSteps, OSLBandStartFreq, OSLBandEndFreq) #VNAcal.LastBaseCal, "Base: ";CalInfo$(OSLBasePath$, OSLBaseTimeStamp$, OSLBaseLinear, _ OSLBaseNumSteps, OSLBaseStartFreq, OSLBaseEndFreq) end if wait [VNACalFinished] if calInProgress=1 then goto [PostScan] 'Don't allow quit in middle of cal if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then 'ver115-4e if msaMode$="VectorTrans" then 'ver115-4e #VNAcal.Delay, "!contents? s$" lineCalThroughDelay=val(uCompact$(s$)) 'Store in ns; used to initialize if we open dialog again ver115-5a else lineCalThroughDelay=0 end if 'If we did a cal, make it the desired one and force restart to implement if BandSweepCalDone=1 then 'ver114-5L created if... 'ver115-2d if BandSweepCalDone then desiredCalLevel=2 'desire BandSweep; overrides BaseLine ver114-5L 'ver115-2d call SignalNoCalInstalled 'ver116-4b call RequireRestart 'To activate desired cal; graph is messed up anyway ver114-5L end if else 'Reflection; handled by [PerformOSLCal] end if close #VNAcal 'ver114-5n moved this outside the if... block wait sub SetCalButtonStatus stat$ 'Enable or disable all calibration buttons 'stat$ should be "!enable" or "!disable" #VNAcal.Perform, stat$ #VNAcal.SaveBase, stat$ #VNAcal.ClearBand, stat$ #VNAcal.ClearBase, stat$ #VNAcal.Done, stat$ end sub [CalAborted] ' aborted line calibration; OSL has its own window and abort button gosub [FinishSweeping] 'Finish nicely 'ver114-7d #VNAcal.Perform, "Perform Band Cal" 'ver115-1e specialOneSweep=0 calInProgress=0 'ver114-5L sweepDir=saveSweepDir : alternateSweep=saveAlternate planeadj=savePlaneAdj : wate=saveWate call SetCalButtonStatus "!enable" 'ver114-6k return [PerformCal] if calInProgress then gosub [CalAborted] : wait 'Perform changes to Abort during calibration 'ver116-4b if msaMode$="Reflection" then 'ver115-1b gosub [PerformOSLCal] 'ver115-5b changed back to gosub so others can call [PerformOSLCal] #VNAcal.LastBandCal, "Band: ";CalInfo$(OSLBandPath$, OSLBandTimeStamp$, OSLBandLinear, _ OSLBandNumSteps, OSLBandStartFreq, OSLBandEndFreq) 'ver115-5b wait else 'ver115-1f moved some items here from [BandLineCal] to make it independent of this dialog call SetCalButtonStatus "!disable" #VNAcal.Perform, "!enable" : #VNAcal.Perform, "Abort Cal" if msaMode$="VectorTrans" then 'ver115-5a #VNAcal.Delay, "!contents? s$" lineCalThroughDelay=val(uCompact$(s$)) 'Store in ns; used by [BandLineCal] else lineCalThroughDelay=0 end if gosub [BandLineCal] #VNAcal.Perform, "Perform Band Cal" BandSweepCalDone=1 'ver114-5L #VNAcal.LastBandCal, "Band: ";CalInfo$(bandLinePath$, bandLineTimeStamp$, bandLineLinear, _ bandLineNumSteps, bandLineStartFreq, bandLineEndFreq) call SetCalButtonStatus "!enable" wait end if 'Can't get here [ClearBandCal] if msaMode$="Reflection" then OSLBandNumSteps=-1 'ver116-4n else bandLineNumSteps=-1 end if #VNAcal.LastBandCal, "Band: Calibration is cleared." wait [ClearBaseCal] if msaMode$="Reflection" then OSLBaseNumSteps=-1 else 'Clear baseline and delete the file baseLineNumSteps=-1 Kill DefaultDir$;"\MSA_Info\OperatingCal\BaseLineCal.txt" end if #VNAcal.LastBaseCal, "Base: Calibration is cleared." wait [BandLineCal] 'Run Line Calibration and return. Can be called from anywhere; lineCalThroughDelay must be set calInProgress=1 : call SignalNoCalInstalled 'ver116-4n haltsweep=0 'So Restart will actually restart. ver114-4f specialOneSweep=1 saveAlternate=alternateSweep : saveSweepDir=sweepDir : savePlaneAdj=planeadj : saveWate=wate alternateSweep=0 : sweepDir=1 call FunctSetVideoAndAutoWait 1 'set video filter to narrow and autowait to Normal or Precise; 1 means save settings ver116-4b planeadj=0 'So phase will not be affected 'ver116-4b 'Note with calInProgress=1, the cal installation routine will not install anything and sets applyCalLevel=0 gosub [Restart] 'Perform one sweep and fill datatable(,) specialOneSweep=0 sweepDir=saveSweepDir : alternateSweep=saveAlternate planeadj=savePlaneAdj call FunctRestoreVideoAndAutoWait 'Cal data is now in datatable if msaMode$="VectorTrans" then 'ver115-5a degPerMillionHz=0.36*lineCalThroughDelay 'lineCalThroughDelay is delay in ns ver116-4m else degPerMillionHz=0 end if for i=0 to steps 'retrieve data 'ver114-8a added through delay calc freq=gGetPointXVal(i+1) 'freq in MHz actual tuning freq, not equiv 1G freq ver115-5c phaseDelay=degPerMillionHz*freq bandLineCal(i,0)=freq 'frequency bandLineCal(i,1)=datatable(i,2) 'mag p=datatable(i,3)+phaseDelay 'Phase, with through delay removed 'ver115-4g p=p mod 360 if p<=-180 then p=p+360 else if p>180 then p=p-360 'put in range -180 to 180 bandLineCal(i,2)=p next i 'Save the conditions under which the cal was done bandLineStartFreq=startfreq bandLineEndFreq=endfreq bandLineNumSteps=steps bandLineLinear=gGetXIsLinear() bandLineS21JigAttach$=S21JigAttach$ 'ver115-1b bandLineS21JigR0=S21JigR0 'ver115-1b bandLinePath$=path$ bandLineTimeStamp$=date$("mm/dd/yy"); "; ";time$() calInProgress=0 desiredCalLevel=2 'desire BandSweep since we just did it call RequireRestart 'So cal gets installed before user proceeds, but we don't install it here return sub TransferBandToBaseLineCal 'Create base line cal from band line cal but don't save to file ver115-5c baseLineNumSteps=min(bandLineNumSteps,2000) 'Base cal can only have 2000 steps for i=0 to baseLineNumSteps baseLineCal(i,0)=bandLineCal(i,0) 'frequency baseLineCal(i,1)=bandLineCal(i,1) 'mag baseLineCal(i,2)=bandLineCal(i,2) 'phase next i 'Save the conditions under which the cal was done baseLineStartFreq=bandLineStartFreq baseLineEndFreq=bandLineEndFreq baseLineLinear=bandLineLinear baseLineS21JigAttach$=bandLineS21JigAttach$ baseLineS21JigR0=bandLineS21JigR0 baseLinePath$=bandLinePath$ 'ver115-1e baseLineTimeStamp$=bandLineTimeStamp$ end sub sub TransferBandToBaseOSLCal 'Create base OSL cal from band OSL cal but don't save to file ver115-5c OSLBaseNumSteps=min(OSLBandNumSteps,2000) 'Base cal can only have 2000 steps for i=0 to OSLBaseNumSteps 'ver115-2d OSLBaseRef(i,0)=OSLBandRef(i,0) 'Reference, frequency OSLBaseRef(i,1)=OSLBandRef(i,1) 'mag OSLBaseRef(i,2)=OSLBandRef(i,2) 'phase OSLBaseA(i,0)=OSLBandA(i,0) : OSLBaseA(i,1)=OSLBandA(i,1) 'Coeff A real, imag OSLBaseB(i,0)=OSLBandB(i,0) : OSLBaseB(i,1)=OSLBandB(i,1) 'Coeff B real, imag OSLBaseC(i,0)=OSLBandC(i,0) : OSLBaseC(i,1)=OSLBandC(i,1) 'Coeff C real, imag next i OSLBaseStartFreq=OSLBandStartFreq OSLBaseEndFreq=OSLBandEndFreq OSLBaseLinear=OSLBandLinear OSLBasePath$=OSLBandPath$ OSLBaseS11JigType$=OSLBandS11JigType$ OSLBaseS21JigAttach$=OSLBandS21JigAttach$ OSLBaseS11BridgeR0=OSLBandS11BridgeR0 OSLBaseS21JigR0=OSLBandS21JigR0 OSLBaseRefType$=OSLBandRefType$ 'ver116-4n OSLBaseTimeStamp$=OSLBandTimeStamp$ end sub [SaveBaseCal] 'Save current cal as base cal if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then call TransferBandToBaseLineCal 'ver115-5c call SaveBaseLineCalFile 'Save base line in a file #VNAcal.LastBaseCal, "Base: ";CalInfo$(baseLinePath$, baseLineTimeStamp$, baseLineLinear, _ baseLineNumSteps, baseLineStartFreq, baseLineEndFreq) else 'Reflection--saved in array but not to file call TransferBandToBaseOSLCal 'ver115-5c #VNAcal.LastBaseCal, "Base: ";CalInfo$(OSLBasePath$, OSLBaseTimeStamp$, OSLBaseLinear, _ OSLBaseNumSteps, OSLBaseStartFreq, OSLBaseEndFreq) end if wait function CalInfo$(cPath$, dateStamp$, cLinear, nSteps, fStart, fEnd) 'Return line or OSL cal info in a string if nSteps<0 then CalInfo$="Calibration is cleared." : exit function if cLinear then lin$="linear" else lin$="log" CalInfo$="Performed ";dateStamp$;"; ";cPath$;"; ";nSteps;" ";lin$;" steps, ";fStart;" to ";fEnd;" MHz." 'ver115-1g end function sub SignalNoCalInstalled 'Clear time stamps and num of steps for installed cal to show none is installed 'ver116-4b 'We don't have to clear the cal data itself. applyCalLevel=0 installedBandLineTimeStamp$="" installedBaseLineTimeStamp$="" installedOSLBandTimeStamp$="" installedOSLBaseTimeStamp$="" 'Probably not necessary to set num steps to -1, but this is how we originally did it. installedBaseLineNumSteps=-1 installedOSLBaseNumSteps=-1 end sub function BandLineCalIsCurrent() 'Returns 1 if full line cal data was taken at current sweep settings 'Current means the full line cal exists and matches current sweep params call gGetXAxisRange xMin, xMax if globalSteps=bandLineNumSteps and gGetXIsLinear()=bandLineLinear and _ xMin=bandLineStartFreq and xMax=bandLineEndFreq then _ BandLineCalIsCurrent=1 else BandLineCalIsCurrent=0 'ver115-1b end function function BaseLineCalIsCurrent() 'Returns 1 if OSL band cal has valid data even if different sweep params 'Current does not mean it is actually installed if baseLineNumSteps>0 and path$=baseLinePath$ and baseLineS21JigAttach$=S21JigAttach$ and _ baseLineS21JigR0=S21JigR0 then isCurr=1 else isCurr=0 if isCurr then BaseLineCalIsCurrent=1 else BaseLineCalIsCurrent=0 : installedBaseLineNumSteps=-1 'Indicate not validly installed ver115-1b end if end function function BaseLineCalIsInstalled() 'Returns 1 if base line cal is already installed at current sweep params 'Current means the full line cal exists and was last installed with sweep params matching the current params if BaseLineCalIsCurrent()=0 then BaseLineCalIsInstalled=0 : exit function 'Don't have current base cal ver114-1L 'If the installed Base line cal has different time stamp from current Base cal, then current is not installed if installedBaseLineTimeStamp$<>baseLineTimeStamp$ then BaseLineCalIsInstalled=0 : exit function 'ver115-2d call gGetXAxisRange xMin, xMax if globalSteps=installedBaseLineNumSteps and gGetXIsLinear()=installedBaseLineLinear and _ xMin=installedBaseLineStartFreq and xMax=installedBaseLineEndFreq then _ BaseLineCalIsInstalled=1 else BaseLineCalIsInstalled=0 'ver115-1b end function sub InstallSelectedLineCal 'Apply full line cal or baseLine cal per applyCalLevel 'We put the necessary data into lineCalArray, and set actualLineCalLevel to 0(None), 1 (BaseLine) 'or 2 (Full LineCal) to indicate the level of line cal actually installed. 'If desiredCalLevel=2 and LineCal is current, install it if calInProgress then 'ver115-1e 'Here we want no type of cal, so signal nothing is installed but don't clear the actual data call SignalNoCalInstalled 'ver116-4b exit sub end if if desiredCalLevel=2 then isCurr=BandLineCalIsCurrent() 'If we are already applying cal, and it is valid and the installed time stamp matches the band cal, we are done if installedBandLineTimeStamp$=bandLineTimeStamp$ and applyCalLevel=2 and isCurr then exit sub 'ver115-2d if isCurr then applyCalLevel=2 else applyCalLevel=1 else applyCalLevel=1 'base cal end if if applyCalLevel=2 then installedBaseLineNumSteps=-1 'Indicate that base line cal is not installed ver115-1b fixed typo for i=0 to globalSteps 'retrieve data lineCalArray(i,0)=bandLineCal(i,0) 'freq 'ver115-5c lineCalArray(i,1)=bandLineCal(i,1) 'mag lineCalArray(i,2)=bandLineCal(i,2) 'Phase next i installedBandLineTimeStamp$=bandLineTimeStamp$ 'ver115-2d exit sub end if 'We get here if applyCalLevel<2 or we did not have a current LineCal, so use BaseLineCal if desiredCalLevel>0 then if BaseLineCalIsCurrent() then applyCalLevel=1 else applyCalLevel=0 'ver115-1b else applyCalLevel=0 end if if applyCalLevel=1 then 'We want and have BaseLine cal, so install it if BaseLineCalIsInstalled() then exit sub 'Already installed with these sweep params 'ver114-5p changed interpolation to use the new Interpolation Module if msaMode$="SA" or msaMode$="ScalarTrans" then doPhase=0 :doParams=1 'do mag only else doPhase=1 :doParams=3 'Do both mag and phase end if call intSetMaxNumPoints 1+max(baseLineNumSteps, globalSteps) 'Be sure we have room ver115-9d call intClearSrc : call intClearDest for i=0 to baseLineNumSteps 'copy cal table to intSrc call intAddSrcEntry baseLineCal(i,0),baseLineCal(i,1),gNormalizePhase(baseLineCal(i,2)) next i for i=1 to globalSteps+1 call intAddDestFreq gGetPointXVal(i) 'Install frequencies in intDest next i call intSrcToDest doPhase, 0, doParams 'Do the actual interpolation into intDest() for i=0 to globalSteps 'put the data where we want it call intGetDest i+1,f, m, p lineCalArray(i,0)=f 'ver115-2d eliminated rounding lineCalArray(i,1)=m p=gNormalizePhase(p) lineCalArray(i,2)=p next i 'Save the sweep params under which we installed base line cal installedBaseLineStartFreq=startfreq installedBaseLineEndFreq=endfreq installedBaseLineNumSteps=globalSteps installedBaseLineLinear=gGetXIsLinear() installedBaseLineTimeStamp$=baseLineTimeStamp$ 'ver115-2d 'ver115-1b xLL deleted installedBaseLinePath$ exit sub end if 'end of applying baseLine cal 'Here we want no type of line cal call SignalNoCalInstalled 'ver116-4b end sub function CreateOperatingCalFolder() 'Creates MSA_Info\OperatingCal folder if it does not already exist 'Return 1 if error 'First see if we have the folder MSA_Info\OperatingCal CreateOperatingCalFolder=0 'assume no error files DefaultDir$;"\MSA_Info", "", fileInfo$() 'get directory list numFolders=val(fileInfo$(0,1)) for i=1 to numFolders 'search list for OperatingCal if fileInfo$(i,1)="OperatingCal" then exit function next i 'Create folder if necessary if 0<>mkDir("MSA_Info\OperatingCal") then CreateOperatingCalFolder=1 : notice "Cannot create OperatingCal." end function sub SaveBaseLineCalFile if CreateOperatingCalFolder()=1 then notice "Cannot save BaseLine Cal file." : exit sub open DefaultDir$;"\MSA_Info\OperatingCal\BaseLineCal.txt" for output as #baseLineOut call BaseLineCalContextToFile "#baseLineOut" close #baseLineOut end sub function OpenBaseLineCalFile$() 'Open baseline calibration file; return its handle 'If file does not exist, return "". fName$=DefaultDir$;"\MSA_Info\OperatingCal\BaseLineCal.txt" On Error goto [noFile] open fName$ for input as #baselineFile OpenBaseLineCalFile$="#baselineFile" exit function [noFile] OpenBaseLineCalFile$="" 'ver114-2f end function function LoadBaseLineCalFile() 'Return 1 if error (file does not exist) fHndl$=OpenBaseLineCalFile$() if fHndl$="" then LoadBaseLineCalFile=1 : baseLineNumSteps=-1 : exit function nPoints=GetBaseLineCalContextFromFile(fHndl$) if nPoints<=0 then LoadBaseLineCalFile=1 : baseLineNumSteps=-1 'error else LoadBaseLineCalFile=0 end if close #fHndl$ end function sub FunctChangeAndSaveSweepParams saveSettings, bandToBase, newSteps, newStart, newEnd, newLinear 'Change sweep params for use in a Function; save old params 'We also set sweep direction, planeadj and wate to default values 'We also save the current band cal as a base cal. If saveSettings=1 we also save the current sweep settings. 'if bandToBase=1, we transfer the existing band cal to the base cal (but not to the file) and use it. 'Caller must set steps (but not globalSteps) before calling us because we can't change steps, but 'we will handle informing the graph module of the new number of steps 'Currently, this does not work for Reflection mode, because OSL is not saved. 'Example of Use: ' steps=100 'Note globalSteps will change in FunctChangeAndSaveSweepParams ' call FunctChangeAndSaveSweepParams 1,1,1, 100, 2, 200, 1 'save settings and cal and change to Linear 2 to 200 MHz, 100 steps ' specialOneSweep=1 'So we return from [Restart] ' gosub [Restart] 'Do actual scan to acquire data ' ...Process data... ' gosub [FunctRestoreSweepParams] ' suppressHardwareInitOnRestart=1 'if there is no need to update hardware and we want to save time; this is set to 0 afer restarting ' gosub [PartialRestart] 'or call RequireRestart 'If a function calls several times, the existing settings should be saved only on the first call; otherwise 'the saved data will get overwritten by the previous changes if saveSettings then 'Save existing settings functSaveAlternate=alternateSweep : functSaveSweepDir=sweepDir : functSavePlaneAdj=planeadj functSaveSteps=globalSteps : functSaveStartFreq=startfreq : functSaveEndFreq=endfreq functSaveAutoY1=autoScaleY1 : functSaveAutoY2=autoScaleY2 functSaveY1Mode=Y1DisplayMode : functSaveY1Mode=Y1DisplayMode functSaveY1DataType=Y1DataType : functSaveY2DataType=Y2DataType call gGetIsLinear functSaveXIsLinear, functSaveY1IsLinear, functSaveY2IsLinear call gGetNumDivisions functSaveNumHorDiv, functSaveNumVertDiv 'Note log sweep changes the hor divisions functSaveDesiredCalLevel=desiredCalLevel end if 'Set up the sweep params we want call FunctSetVideoAndAutoWait saveSettings 'save old settings and set new alternateSweep=0 : sweepDir=1 : planeadj=0 globalSteps=newSteps 'Caller must change steps call gSetXIsLinear newLinear call gSetNumDynamicSteps globalSteps 'Tell graph module call SetStartStopFreq newStart, newEnd if bandToBase and (msaMode$="VectorTrans" or msaMode$="ScalarTrans") then call TransferBandToBaseLineCal 'Make current band cal into a base cal so it can be interpolated desiredCalLevel=1 'Use the base cal we just created call SignalNoCalInstalled 'ver116-4b end if end sub sub FunctSetVideoAndAutoWait saveSettings 'Set video filter to narrow and wait to autoWait modver116-4k if saveSettings then _ functSaveWate=wate : functSaveAutoWait=useAutoWait: functSaveAutoWaitPrecision$=autoWaitPrecision$ : functSaveVideoFilter$=videoFilter$ 'ver116-1b if videoFilter$="XNarrow" then desiredVideoFilter$="XNarrow" else desiredVideoFilter$="Narrow" if canUseAutoWait then if useAutoWait=0 or (autoWaitPrecision$<>"Precise") then autoWaitPrecision$="Normal" 'choose Normal unless user is already Precise useAutoWait=1 else wate=500 'It should always be possible to use auto wait, but just in case... end if if videoFilter$<>desiredVideoFilter$ and switchHasVideo=0 then Notice "Physically select "; desiredVideoFilter$; " video filter." videoFilter$=desiredVideoFilter$ call SelectVideoFilter 'also recalculates auto wait info end sub sub FunctRestoreVideoAndAutoWait 'restore auto wait settings and, if automated video switch, video filter setting wate=functSaveWate : autoWaitPrecision$=functSaveAutoWaitPrecision$ : useAutoWait=functSaveAutoWait if switchHasVideo then 'if no automated video filter switch, we leave the video filter as it was set for the function videoFilter$=functSaveVideoFilter$ call SelectVideoFilter 'Note this also calls autoWaitPrecalculate ver116-4b else call autoWaitPrecalculate end if end sub [FunctRestoreSweepParams] 'Restore params and base cal to what they were when function was entered 'Not a true subroutine so it can access steps. call FunctRestoreVideoAndAutoWait sweepDir=functSaveSweepDir : alternateSweep=functSaveAlternate : planeadj=functSavePlaneAdj steps=functSaveSteps : startfreq=functSaveStartFreq : endfreq=functSaveEndFreq globalSteps=steps autoScaleY1=functSaveAutoY1 : autoScaleY2=functSaveAutoY2 Y1DisplayMode=functSaveY1Mode : Y1DisplayMode=functSaveY1Mode Y1DataType=functSaveY1DataType : Y2DataType=functSaveY2DataType call gSetIsLinear functSaveXIsLinear, functSaveY1IsLinear, functSaveY2IsLinear call gSetNumDynamicSteps steps 'Tell graph module call SetStartStopFreq functSaveStartFreq, functSaveEndFreq call gSetNumDivisions functSaveNumHorDiv, functSaveNumVertDiv if msaMode$="VectorTrans" or msaMode$="ScalarTrans" then dum=LoadBaseLineCalFile() 'Reload base cal file to restore prior state end if desiredCalLevel=functSaveDesiredCalLevel 'ver115-5e call SignalNoCalInstalled 'ver116-4b'So new cal will get installed on Restart return '---------------Routines to Handle OSL Calibration------------ added by ver115-1b function BandOSLCalIsCurrent() 'Returns 1 if band OSL cal data was taken at current sweep settings 'Current means the band cal exists and matches current sweep params; it may not actually be installed call gGetXAxisRange xMin, xMax if globalSteps=OSLBandNumSteps and gGetXIsLinear()=OSLBandLinear and path$=OSLBandPath$ and _ xMin=OSLBandStartFreq and xMax=OSLBandEndFreq and _ OSLBandS11JigType$=S11JigType$ then isCurr=1 else isCurr=0 if isCurr then 'do further tests for matching jig characteristics if S11JigType$="Trans" then 'ver115-2c if OSLBandS21JigAttach$<>S21JigAttach$ or OSLBandS21JigR0<>S21JigR0 then isCurr=0 else if OSLBandS11BridgeR0<>S11BridgeR0 then isCurr=0 end if end if BandOSLCalIsCurrent=isCurr end function function BaseOSLCalIsCurrent() 'Returns 1 if OSL base cal has valid data even if different sweep params 'Current does not mean it is actually installed if OSLBaseNumSteps>0 and path$=OSLBasePath$ and OSLBaseS11JigType$=S11JigType$ then _ isCurr=1 else isCurr=0 if isCurr then 'do further tests for matching jig characteristics if S11JigType$="Trans" then if OSLBaseS21JigAttach$<>S21JigAttach$ or OSLBaseS21JigR0<>S21JigR0 then isCurr=0 else if OSLBaseS11BridgeR0<>S11BridgeR0 then isCurr=0 end if end if if isCurr then BaseOSLCalIsCurrent=1 else BaseOSLCalIsCurrent=0 : installedOSLBaseNumSteps=-1 : OSLBaseNumSteps=-1 'Mark everything as not valid end if end function function BaseOSLCalIsInstalled() 'Returns 1 if base OSL line cal is already installed at current sweep params 'Current means the full line cal exists and was last installed with sweep params matching the current params if BaseOSLCalIsCurrent()=0 then BaseOSLCalIsInstalled=0 : exit function 'Don't have current base cal 'If the installed Base cal has different time stamp from current Base cal, then current is not installed if installedOSLBaseTimeStamp$<>OSLBaseTimeStamp$ then BaseOSLCalIsInstalled=0 : exit function 'ver115-2d call gGetXAxisRange xMin, xMax if globalSteps=installedOSLBaseNumSteps and gGetXIsLinear()=installedOSLBaseLinear and _ xMin=installedOSLBaseStartFreq and xMax=installedOSLBaseEndFreq then _ BaseOSLCalIsInstalled=1 else BaseOSLCalIsInstalled=0 end function sub InstallSelectedOSLCal 'Apply base or band OSL cal per applyCalLevel 'We put the necessary data into lineCalArray and OSLx(), and set applyCalLevel to 0(None), 1 (BaseLine) 'or 2 (Full LineCal) to indicate the level of line cal actually installed. 'If desiredCalLevel=2 and Cal is current, install it 'If a calibration is in progress, we don't install a cal, but use a zero line cal reference. if calInProgress then 'ver115-1e 'Here we want no type of cal call SignalNoCalInstalled 'ver116-4b exit sub end if if desiredCalLevel=2 then isCurr=BandOSLCalIsCurrent() 'If we are already applying cal, and it is valid and the installed time stamp matches the band cal, we are done if installedOSLBandTimeStamp$=OSLBandTimeStamp$ and applyCalLevel=2 and isCurr then exit sub 'ver115-2d if isCurr then applyCalLevel=2 else applyCalLevel=1 else applyCalLevel=1 end if if applyCalLevel=2 then 'We have determined to install Band cal installedOSLBaseNumSteps=-1 'Indicate that base cal is not installed else 'We get here if applyCalLevel<2 or we did not have a current band cal, so use base cal if available if desiredCalLevel>0 then if BaseOSLCalIsCurrent() then applyCalLevel=1 else applyCalLevel=0 else applyCalLevel=0 end if end if if applyCalLevel=0 then 'ver115-1e 'Here we want no type of OSL cal call SignalNoCalInstalled 'ver116-4b exit sub 'ver116-4b end if 'Note that OSLBandRef and OSLBaseRef hold data from updating the cal. Freq is set and data is cleared whenever full cal is done. if applyCalLevel=1 then 'base cal--must interpolate. First due reference info if BaseOSLCalIsInstalled() then exit sub 'Already installed with these sweep params 'Save the sweep params under which we installed base OSL cal installedOSLBaseStartFreq=startfreq installedOSLBaseEndFreq=endfreq installedOSLBaseNumSteps=globalSteps installedOSLBaseLinear=gGetXIsLinear() OSLRefType$=OSLBaseRefType$ : installedOSLBaseRefType$=OSLBaseRefType$ 'ver116-4n installedOSLBaseTimeStamp$=OSLBaseTimeStamp$ 'ver115-2d 'Create source interpolation table and fill in desired dest frequencies call intSetMaxNumPoints 1+max(OSLBaseNumSteps, globalSteps) 'Be sure we have room ver115-9d call intClearSrc : call intClearDest ' ver115-2d for i=0 to OSLBaseNumSteps 'copy cal table to intSrc ver115-2d call intAddSrcEntry OSLBaseRef(i,0),OSLBaseRef(i,1),gNormalizePhase(OSLBaseRef(i,2)) 'reference data from any cal update next i for i=1 to globalSteps+1 call intAddDestFreq gGetPointXVal(i) 'Install the desired frequencies intDest next i 'Do the actual interpolation into intDest() '1 means data is polar , 0 means do linear interp, 3 means do both params call intSrcToDest 1, 0, 3 'put the data where we want it; it is now in intDest for i=0 to globalSteps call intGetDest i+1,f, m, p lineCalArray(i,0)=f 'ver115-2d eliminated rounding lineCalArray(i,1)=m p=gNormalizePhase(p) lineCalArray(i,2)=p next i else 'Band cal--no interpolation, just copy OSLRefType$=OSLBandRefType$ installedOSLBandTimeStamp$=OSLBandTimeStamp$ 'ver115-2d for i=0 to globalSteps lineCalArray(i,0)=OSLBandRef(i,0) lineCalArray(i,1)=OSLBandRef(i,1) lineCalArray(i,2)=OSLBandRef(i,2) next i end if 'Next install OSL coefficients if applyCalLevel=1 then 'base cal--interpolate coefficients a, b, c 'Note the desired frequencies are already in intDest call intClearSrc 'Clear source from which we interpolate ver115-2d 'First install the a coefficients into OSLa(). Note these are in rectangular form for i=0 to OSLBaseNumSteps 'copy cal table to intSrc call intAddSrcEntry OSLBaseRef(i,0),OSLBaseA(i,0),OSLBaseA(i,1) next i 'Do the actual interpolation into intDest() 'First 0 means not polar, second 0 means do linear interp, 3 means do both params call intSrcToDest 0, 0, 3 for i=0 to globalSteps 'put the data where we want it call intGetDest i+1,f, real, imag OSLa(i,0)=real OSLa(i,1)=imag next i 'install the b coefficients into OSLb(). Note these are in rectangular form call intClearSrc 'Clear source from which we interpolate ver115-2d for i=0 to OSLBaseNumSteps 'copy cal table to intSrc call intAddSrcEntry OSLBaseRef(i,0),OSLBaseB(i,0),OSLBaseB(i,1) next i 'Do the actual interpolation into intDest() 'First 0 means not polar, second 0 means do linear interp, 3 means do both params call intSrcToDest 0, 0, 3 for i=0 to globalSteps 'put the data where we want it call intGetDest i+1,f, real, imag OSLb(i,0)=real OSLb(i,1)=imag next i 'install the c coefficients into OSLc(). Note these are in rectangular form call intClearSrc 'Clear source from which we interpolate ver115-2d for i=0 to OSLBaseNumSteps 'copy cal table to intSrc call intAddSrcEntry OSLBaseRef(i,0),OSLBaseC(i,0),OSLBaseC(i,1) next i 'Do the actual interpolation into intDest() 'First 0 means not polar, second 0 means do linear interp, 3 means do both params call intSrcToDest 0, 0, 3 for i=0 to globalSteps 'put the data where we want it call intGetDest i+1,f, real, imag OSLc(i,0)=real OSLc(i,1)=imag next i else 'band cal--just copy the coefficients for i=0 to globalSteps OSLa(i,0)=OSLBandA(i,0) : OSLa(i,1)=OSLBandA(i,1) OSLb(i,0)=OSLBandB(i,0) : OSLb(i,1)=OSLBandB(i,1) OSLc(i,0)=OSLBandC(i,0) : OSLc(i,1)=OSLBandC(i,1) next i end if end sub [PerformOSLCal] 'Perform band OSL cal and return 'We ask the user whether to perform O, S or L. When he clicks Done, we use the available data 'to create the calibration results. Any combo of O,S and L is allowed so long as it includes 'O or S. We put the data into OSLcalOpen(),OSLcalOpen() and/or OSLcalOpen for the caller to process. 'We also set flags OSLdoneO, OSLdoneS and OSLdoneL to let the caller know which were performed. OSLdoneO=0 : OSLdoneL=0 : OSLdoneS=0 'For the caller's info. Set to 1 when specified cal is done. WindowWidth = 580 : WindowHeight = 400 UpperLeftX = 0 'Relative to main cal window, since it is a dialog UpperLeftY = -100 BackgroundColor$="buttonface" : ForegroundColor$="black" TextboxColor$ = "white" : ComboboxColor$="white" '--Instructions s$="Specify the fixture used. For Shunt fixture, you may specify a delay time." statictext #OSLcal.Inst1, s$,20,15,200,50 s$="Specify the desired calibration. For OSL, specify characteristics of the standards." statictext #OSLcal.Inst2, s$,290,15,200,50 'Option to choose full OSL or reference cal 'added by ver115-1g checkbox #OSLcal.Full, "", [OSLCheckFull], [OSLCheckFull], 300, 100, 20,20 statictext #OSLcal, "Full OSL", 321, 102, 70,20 checkbox #OSLcal.Ref, "", [OSLCheckRef], [OSLCheckRef], 300, 120, 20,20 statictext #OSLcal, "Reference Cal", 321, 122, 70,16 OSLBtnTop=155 : OSLBtnLeft=280 button #OSLcal.O, "Perform Open", [OSLdoOpen],UL,OSLBtnLeft, OSLBtnTop, 85,25 button #OSLcal.S, "Perform Short", [OSLdoShort],UL,OSLBtnLeft, OSLBtnTop+45, 85,25 button #OSLcal.L, "Perform Load", [OSLdoLoad],UL,OSLBtnLeft, OSLBtnTop+90, 85,25 statictext #OSLcal.doneO,"", OSLBtnLeft-33,OSLBtnTop+2,32,20 statictext #OSLcal.doneS,"", OSLBtnLeft-33,OSLBtnTop+47,32,20 statictext #OSLcal.doneL,"", OSLBtnLeft-33,OSLBtnTop+92,32,20 'Preset cal standard sets call OSLGetCalSets 'Loads cal set names into OSLCalSetNames$() ver115-7a OSLCalSetNames$(OSLCalSetNumber)="Custom" 'Add Custom, which has no file OSLCalSetNumber=OSLCalSetNumber+1 combobox #OSLcal.stdSet, OSLCalSetNames$(),[OSLSelectSet], OSLBtnLeft+90,OSLBtnTop+140, 180, 120 'ver115-7a statictext #OSLcal.stdLab, "Calibration Standards",OSLBtnLeft+120, OSLBtnTop+120, 140, 18 statictext #OSLcal.stdDescrip, "",OSLBtnLeft+50, OSLBtnTop+170, 220, 40 'ver116-4i 'Open, Short and Load Specs textbox #OSLcal.OpenSpecs, OSLBtnLeft+90, OSLBtnTop, 200, 20 textbox #OSLcal.ShortSpecs, OSLBtnLeft+90, OSLBtnTop+47, 200, 20 textbox #OSLcal.LoadSpecs, OSLBtnLeft+90, OSLBtnTop+94, 200, 20 'R0 statictext #OSLcal.statictext15, "Fixture R0 (ohms)", 20, OSLBtnTop-40, 90, 20 textbox #OSLcal.R0, 110, OSLBtnTop-40, 40, 20 'Fixture type groupbox #OSLcal.FixGroup, "Fixture Type", 20, OSLBtnTop, 190, 120 checkbox #OSLcal.Bridge, "", [OSLcalSetBridge], [OSLcalSetBridge], 30, OSLBtnTop+20, 15, 20 checkbox #OSLcal.Series, "", [OSLcalSetSeries], [OSLcalSetSeries], 30, OSLBtnTop+45, 15, 20 checkbox #OSLcal.Shunt, "", [OSLcalSetShunt], [OSLcalSetShunt], 30, OSLBtnTop+70, 15, 20 statictext #OSLcal.BridgeLabel, "Reflection Bridge", 50, OSLBtnTop+21, 150, 20 statictext #OSLcal.SeriesLabel, "Series", 50, OSLBtnTop+46, 50, 20 statictext #OSLcal.ShuntLabel, "Shunt", 50, OSLBtnTop+71, 40, 16 statictext #OSLcal.DelayLabel, "Connect Delay (ns)", 100, OSLBtnTop+73, 110, 16 textbox #OSLcal.ShuntDelay, 110, OSLBtnTop+90, 65, 20 'Done, Cancel and Help buttons button #OSLcal.Done, "Done", [OSLDone],UL, 30, OSLBtnTop+140, 70, 30 button #OSLcal.Cancel, "Cancel", [OSLCancel],UL, 120, OSLBtnTop+140, 70, 30 button #OSLcal.Help, "Help", ExplainJigType,UL, 90, 70, 40, 20 button #OSLcal.Help2, "Help", ExplainOSL,UL, 360, 70, 40, 20 'Open the dialog open "Reflection Calibration" for dialog_modal as #OSLcal print #OSLcal, "trapclose [OSLFinished]" #OSLcal, "font ms_sans_serif 9" #OSLcal.Inst1, "!font Arial 10" #OSLcal.Inst2, "!font Arial 10" OSLSaveLastSelectedCalSet=OSLLastSelectedCalSet 'In case we need to restore on cancel gosub [OSLEnterPresetValues] if OSLCalSetNames$(OSLLastSelectedCalSet-1)="Custom" then 'ver115-4i 'If we start with Custom, enter the most recently used values #OSLcal.OpenSpecs, OSLOpenSpec$ : #OSLcal.ShortSpecs, OSLShortSpec$ : #OSLcal.LoadSpecs, OSLLoadSpec$ end if #OSLcal.stdSet, "selectindex "; OSLLastSelectedCalSet 'Select proper cal set #OSLcal.stdSet, "setfocus " #OSLcal.ShuntDelay, S21JigShuntDelay #OSLcal.ShuntDelay, "!hide" : #OSLcal.DelayLabel, "!hide" #OSLcal.R0, S21JigR0 'We display either S21JigR0 or S11BridgeR0 if S11JigType$="Reflect" then #OSLcal.Bridge, "set" : #OSLcal.R0, S11BridgeR0 else 'ver115-2a if S21JigAttach$="Series" then #OSLcal.Series, "set" if S21JigAttach$="Shunt" then #OSLcal.Shunt, "set" : #OSLcal.ShuntDelay, "!show" : #OSLcal.DelayLabel, "!show" end if if OSLcalLastUsedFull then goto [OSLCheckFull] else goto [OSLCheckRef] 'to match last time dialog was open 'can't get here [OSLEnterPresetValues] 'Enter values for preset standard set number presetNum and set box status if OSLCalSetNumber3 then notice "You are missing one of the necessary calibrations for full OSL." : wait else if isBridge then 'Be sure reference cal was done didRef=(OSLdoneO or OSLdoneS) else if isSeries then didRef=OSLdoneS else didRef=OSLdoneO end if if didRef=0 then notice "You have not performed the necessary calibration" : wait end if 'ver115-3f moved the disables to here, after a possible wait occurs call SetOSLCalCheckboxStatus "disable" 'So nothing gets clicked before dialog closes ver115-3a call SetOSLCalButtonStatus "!disable" #OSLcal.stdSet, "selectionindex? OSLLastSelectedCalSet" #OSLcal.OpenSpecs, "!contents? OSLOpenSpec$" #OSLcal.ShortSpecs, "!contents? OSLShortSpec$" #OSLcal.LoadSpecs, "!contents? OSLLoadSpec$" if OSLError then OSLBandNumSteps=-1 'Invalid cal data if math error occurred 'ver116-4b call SignalNoCalInstalled 'ver116-4b 'So new cal will get installed on Restart desiredCalLevel=2 'desire Band Sweep since we just did it call RequireRestart 'So cal gets installed before user proceeds, but we don't install it here 'In earlier versions this line was put here. 'because we sometimes returned to a strange place. Doesn't seem to happen now. cursor hourglass 'ver116-4b gosub [ProcessOSLBandCal] 'ver115-1g cursor normal 'ver116-4b close #OSLcal 'ver115-5b moved update of band cal display to the routines for the basic cal window return 'we will be back in the basic cal window, or whoever called us [OSLSelectSet] 'User Selected preset cal standard 'This is separate from OSLEnterPresetValues because when the dialog is first opened we just 'call that routine, since doing the selectionindex? seems to mess up the box. #OSLcal.stdSet, "selectionindex? s" 'ver116-4i allowed any completed cal data to remain OSLLastSelectedCalSet=s gosub [OSLEnterPresetValues] wait [OSLdoOpen] if calInProgress then gosub [OSLCalAborted] : wait 'Button says abort when cal is running call SetOSLCalButtonStatus "!disable" #OSLcal.O, "!enable" #OSLcal.O, "Abort Cal" #OSLcal.doneO, "" 'ver115-7a gosub [OSLdoCal] 'get cal data by doing one sweep 'For S11JigType$="Reflect", the data in ReflectArray will be reflection per the bridge R0 w/o OSL adjustment. 'It is normally adjusted for planeadj, but in cal we force planeadj to 0. 'For S11JigType$="Trans", the data in ReflectArray is "S21" of the fixture (unadjusted for any reference) 'which we are treating as the tentative estimate of reflection, even though it is far from true reflection. for i=0 to steps 'retrieve data re bridge R0 OSLcalOpen(i,0)=ReflectArray(i,constIntermedS11DB) 'was put here during scan ver115-7a OSLcalOpen(i,1)=ReflectArray(i,constIntermedS11Ang) 'ver115-7a next i call SetOSLCalButtonStatus "!enable" #OSLcal.O, "Perform Open" #OSLcal.doneO, "Done" OSLdoneO=1 #OSLcal.Full, "value? OSLFullval$" if OSLFullval$="reset" then goto [OSLDone] 'If Reference cal, quit after one is done wait [OSLdoShort] if calInProgress then gosub [OSLCalAborted] : wait 'Button says abort when cal is running call SetOSLCalButtonStatus "!disable" #OSLcal.S, "!enable" #OSLcal.S, "Abort Cal" #OSLcal.doneS, "" 'ver115-7d gosub [OSLdoCal] 'get cal data by doing one sweep for i=0 to steps 'retrieve data re bridge R0 OSLcalShort(i,0)=ReflectArray(i,constIntermedS11DB) 'was put here during scan 'ver115-7a OSLcalShort(i,1)=ReflectArray(i,constIntermedS11Ang) 'ver115-7a next i call SetOSLCalButtonStatus "!enable" #OSLcal.S, "Perform Short" #OSLcal.doneS, "Done" OSLdoneS=1 #OSLcal.Full, "value? OSLFullval$" if OSLFullval$="reset" then goto [OSLDone] 'If Reference cal, quit after one is done wait [OSLdoLoad] if calInProgress then gosub [OSLCalAborted] : wait 'Button says abort when cal is running call SetOSLCalButtonStatus "!disable" #OSLcal.L, "!enable" #OSLcal.L, "Abort Cal" #OSLcal.doneL, "" 'ver115-7a gosub [OSLdoCal] 'get cal data by doing one sweep for i=0 to steps 'retrieve data re bridge R0 OSLcalLoad(i,0)=ReflectArray(i,constIntermedS11DB) 'was put here during scan 'ver115-7a OSLcalLoad(i,1)=ReflectArray(i,constIntermedS11Ang) 'ver115-7a next i call SetOSLCalButtonStatus "!enable" #OSLcal.L, "Perform Load" #OSLcal.doneL, "Done" OSLdoneL=1 'ver115-2c #OSLcal.Full, "value? OSLFullval$" if OSLFullval$="reset" then goto [OSLDone] 'If Reference cal, quit after one is done wait sub SetOSLCalButtonStatus stat$ 'Set button status. stat$ is either "!enable" or "!disable" #OSLcal.O, stat$ #OSLcal.S, stat$ #OSLcal.L, stat$ #OSLcal.Done, stat$ #OSLcal.Cancel, stat$ #OSLcal.Help, stat$ 'ver115-3a #OSLcal.Help2, stat$ 'ver115-3a end sub [OSLCalAborted] 'OSL cal was aborted. Restore status and let user proceed call SetOSLCalCheckboxStatus "enable" 'ver116-4i call SetOSLCalButtonStatus "!enable" #OSLcal.O, "Perform Open" 'Restore button names--one was set to Abort Cal #OSLcal.S, "Perform Short" #OSLcal.L, "Perform Load" calInProgress=0 specialOneSweep=0 sweepDir=saveSweepDir : alternateSweep=saveAlternate planeadj=savePlaneAdj : wate=saveWate message$="Cal Aborted" 'ver115-2d call PrintMessage wait [OSLdoCal] 'Run OSL Calibration for specified standard calInProgress=1 : call SignalNoCalInstalled 'ver116-4n call SetOSLCalCheckboxStatus "disable" 'ver115-3a haltsweep=0 'So Restart will actually restart. ver114-4f specialOneSweep=1 saveAlternate=alternateSweep : saveSweepDir=sweepDir : savePlaneAdj=planeadj alternateSweep=0 : sweepDir=1 call FunctSetVideoAndAutoWait 1 '1 means save old settings 'ver116-4b planeadj=0 'So phase will not be affected 'Note with calInProgress=1, the cal installation routine will not install anything and sets applyCalLevel=0 gosub [Restart] 'Perform one sweep and fill datatable(,) specialOneSweep=0 sweepDir=saveSweepDir : alternateSweep=saveAlternate planeadj=savePlaneAdj call FunctRestoreVideoAndAutoWait 'ver116-4b 'Cal data is now in datatable calInProgress=0 call SetOSLCalCheckboxStatus "enable" 'ver115-3a return [ProcessOSLBandCal] 'Process already gathered band cal data call ProcessOSLCal desiredCalLevel=2 'opt for using band cal since we just did it if OSLError then BandSweepCalDone=0 : OSLBandNumSteps=-1 : return 'If error, nullify the cal and return 'Save the conditions under which the cal was done OSLBandStartFreq=startfreq OSLBandEndFreq=endfreq OSLBandNumSteps=steps OSLBandLinear=gGetXIsLinear() OSLBandPath$=path$ OSLBandS11JigType$=S11JigType$ OSLBandS21JigAttach$=S21JigAttach$ OSLBandS11BridgeR0=S11BridgeR0 OSLBandS21JigR0=S21JigR0 OSLBandTimeStamp$=date$("mm/dd/yy"); "; ";time$() BandSweepCalDone=1 return sub ExplainOSL h$ 'Put up dialog explaining reflection jig type WindowWidth = 635 WindowHeight = 200 UpperLeftX=0 'Doesn't seem to matter what is specified here UpperLeftY=150 BackgroundColor$="gray" ForegroundColor$="black" statictext #Explain, "All measurements in Reflection mode require some form of calibration. The simplest calibration is", 10, 10, 630, 20 statictext #Explain, "Reference Calibration, which uses either an Open or a Short calibration standard, which essentially", 10, 30, 630, 20 statictext #Explain, "allows the MSA to adjust to set a reference signal level. This works well for precise fixtures at", 10, 50, 630, 20 statictext #Explain, "relatively low frequencies. OSL Calibration involves more steps but is more accurate. OSL involves", 10, 70, 630, 20 statictext #Explain, "sequentially measuring Open, Short and Load calibration standards, in any order. ", 10, 90, 630, 20 statictext #Explain, "For OSL Calibration, you generally specify the electrical characteristics of each of the standards.", 10, 110, 630, 20 statictext #Explain, "At low frequencies it may work well just to treat them as Ideal.", 10, 130, 630, 20 open "Reflection Calibration Help" for dialog_modal as #Explain #Explain, "trapclose [OSLExplainFinished]" print #Explain, "font ms_sans_serif 10" wait [OSLExplainFinished] close #Explain end sub sub ExplainJigType h$ 'Put up dialog explaining reflection jig type WindowWidth = 600 WindowHeight = 370 UpperLeftX=0 'Doesn't seem to matter what is specified here UpperLeftY=150 BackgroundColor$="gray" ForegroundColor$="black" s$="Reflection measurements use one of several types of test fixtures to which the device under test (DUT)" s$=s$;" is attached. Many fixtures are Reflection Bridges, which make an attempt to make their output signal" s$=s$;" correspond closely to the actual reflection from the DUT. Such fixtures can use Reference Calibration" s$=s$;" with either the Open or Short, or for better accuracy can use full OSL calibration." statictext #JigExplain, s$, 20, 20, 550, 80 s$="Other fixtures produce an output which does not directly correspond to the DUT reflection, but can be" s$=s$;" mathematically transformed into a reflection measurement. These test fixtures" s$=s$;" typically consist of an attenuator, then the component, then another attenuator. The component" s$=s$;" may be connected in Series between the attenuators, or may be Shunt to ground, which accounts for the" s$=s$;" two different fixture types. The component will see a certain resistance R0 looking at the incoming signal" s$=s$;" and the outgoing signal. You must specify that R0, usually 50 ohms. The Series fixture is calibrated" s$=s$;" with just the Short or with full OSL. The Shunt fixture is calibrated with just the Open or with full OSL." statictext #JigExplain, s$, 20, 120, 550, 140 s$="If you specify the Shunt Fixture, then you may also specify the one-way connection delay time," s$=s$;" which is used for compensation when you do not use full OSL. A delay of 0.115 ns is typical." s$=s$;" For low frequencies a delay of 0 ns may be adequate." statictext #JigExplain, s$, 20, 270, 550, 60 open "Reflection Fixture Help" for dialog_modal as #JigExplain #JigExplain, "trapclose [JigExplainFinished]" print #JigExplain, "font ms_sans_serif 10" wait [JigExplainFinished] close #JigExplain end sub function OSLOpenFile$(fName$, asInput) 'Open file with OSL standards 'fName is full file name, with path and extension 'Returns LB file handle, or blank if error 'asInput=1 means open input file; otherwise open output file On Error goto [noFile] if asInput then open fName$ for input as #calSetFile else open fName$ for output as #calSetFile OSLOpenFile$="#calSetFile" exit function [noFile] OSLOpenFile$="" end function sub OSLGetFileData$ fHndl$ 'Get description of OSL standard modver116-4i 'The file handle is in fHndl 'The data is put into global variables describing the current OSL standards 'The file consists of the following lines: 'Name=xxx the short name to enter in the combo box 'Description=... long description to display when this set is selected (optional) 'Open=... 'Short=... 'Load=... 'Each ... spec is a simplified standard RLC spec Example: RLC[S or P, R25, L10n, C200p,D35f] 'S or P indicates series or parallel. R, L and C are ohms, H, and F. D is delay in seconds. 'Only the relevant components need be specified. hadName=0: hadOpen=0 : hadShort=0 : hadLoad=0 : OSLCalSetDescription$="" while EOF(#fHndl$)=0 Line Input #fHndl$, tLine$ equalPos=instr(tLine$,"=") if equalPos>2 then 'Note that lines without valid tags are allowed; we ignore them OSLid$=Upper$(Trim$(Left$(tLine$, equalPos-1))) 'everything left of the equal sign is the ID tLine$=Mid$(tLine$, equalPos+1) 'We will use everything right of the equal sign bracketPos=inStr(tLine$,"[") '0 if no bracket on this line--we will add brackets for backward compatibility ver116-4i select case OSLid$ case "NAME" OSLFileCalSetName$=Trim$(tLine$) : hadName=1 case "DESCRIPTION" 'ver116-4i OSLFileCalSetDescription$=Trim$(tLine$) 'optional case "OPEN" hadOpen=1 : if bracketPos=0 then tLine$="RLC[";tLine$;"]" OSLFileOpenSpec$=tLine$ 'Entire remainder of line is the RLC spec case "SHORT" hadShort=1 : if bracketPos=0 then tLine$="RLC[";tLine$;"]" OSLFileShortSpec$=tLine$ 'Entire remainder of line is the RLC spec case "LOAD" hadLoad=1 : if bracketPos=0 then tLine$="RLC[";tLine$;"]" OSLFileLoadSpec$=tLine$ 'Entire remainder of line is the RLC spec case else 'Ignore other lines end select end if wend if hadName=0 or hadOpen=0 or hadShort=0 or hadLoad=0 then if hadName then n$=OSLFileCalSetName$ else n$="unnamed standard" notice "Incomplete cal standard file for ";n$;"." end if end sub sub OSLSaveCalSetFile fName$ 'Save current cal set data as a file named fName$ (includes full path) modver116-4i fHndl$=OSLOpenFile$(fName$,0) 'Open file for output if fHndl$="" then notice "Error creating cal set file.": exit sub print #fHndl$, "Name=";OSLFileCalSetName$ print #fHndl$, "Description=";OSLFileCalSetDescription$ print #fHndl$, "Open=";OSLFileOpenSpec$ print #fHndl$, "Short=";OSLFileShortSpec$ print #fHndl$, "Load=";OSLFileLoadSpec$ close #fHndl$ end sub sub OSLGetCalSets 'Load cal set names 'Loads file and set names for all files in the folder \MSA_Info\OperatingCal\CalSets folder filePath$=DefaultDir$;"\MSA_Info\OperatingCal\CalSets" files DefaultDir$;"\MSA_Info\OperatingCal", "", fileInfo$() 'get directory list nFolders=val(fileInfo$(0,1)) folderFound=0 for i=1 to nFolders if fileInfo$(i,1)="CalSets" then folderFound=1 : exit for 'We found the CalSets folder next i if folderFound=0 then 'create file for Ideal, if no folder found exists if mkDir(filePath$)<>0 then notice "Error creating CalSets folder.": exit sub 'Folder doesn't exist, so make one 'ver116-4i consolidated the data for each standard into one spec OSLFileCalSetName$="Ideal 50 ohms" OSLFileCalSetDescription$="50 ohms, good for cal plane on back of SMA connectors" OSLFileOpenSpec$="RLC[S, C0, D0]" OSLFileShortSpec$="RLC[P, R0, L0, D0]" : OSLFileLoadSpec$="RLC[P,R50, C0]" call OSLSaveCalSetFile filePath$;"\Ideal50.txt" 'Save Ideal 50 ohms file per the above values 'ver116-4i end if files filePath$, "*.txt", fileInfo$() 'get list of files in CalSets folder nFiles=val(fileInfo$(0,0)) redim OSLCalSetNames$(nFiles+1) : redim OSLCalSetFileNames$(nFiles+1) 'Clear and Make room for list plus "Custom" OSLCalSetNumber=0 for i=1 to nFiles 'Read cal set name of each file fName$=fileInfo$(i,0) 'Name of this file, without path fHndl$=OSLOpenFile$(filePath$;"\";fName$, 1) 'Open this file for input if fHndl$<>"" then 'Blank means error, so we ignore file OSLCalSetFileNames$(i-1)=fName$ 'store file name (without path) call OSLGetFileData$ fHndl$ 'name is the only data we will use here OSLCalSetNames$(i-1)=OSLFileCalSetName$ 'store name that was set in OSLGetFileData$ OSLCalSetNumber=OSLCalSetNumber+1 close #fHndl$ 'Close this file end if next i end sub sub ProcessOSLCal 'Calc coefficients and reference data from raw OSL scan data 'OSLdoneO, OSLdoneSand OSLdoneS indicate which of Open, Short, and Load were performed. 'The relevant calibration data is in OSLcalOpen(), OSLcalShort() and OSLcalLoad() 'Calibration data will be the raw S11 for reflection bridge, and raw S21 for the transmission jigs. 'In the latter case we must convert to S11 before calculating OSL coefficients. ' 'The measured cal data is in OSLcalOpen(), etc., as dB/angle. It is reflection data for the reflection bridge, 'For S11JigType$="Reflect", the data in OSLcalOpen(), etc., will be reflection per the bridge w/o OSL adjustment, 'and without being adjusted for planeadj (which we force to 0 in cal). 'For S11JigType$="Trans", the data in OSLcalOpen(), etc., is "S21" of the fixture (unadjusted for any reference) 'which we are treating as the tentative estimate of reflection, even though it is far from true reflection. 'When raw data is collected in future scans, it will be adjusted by a reference installed into the line 'cal array. The reference will be the calibration data from the Open, except for the series jig it is the 'calibration data from the Short. In the case of a Reflection Bridge if we don't have the relevant 'Open data, we compute it from the Short. We assume Ideal values for the non-reference data in order to calc coefficients. ' 'We put the OSL coefficients into OSLBandA(), OSLBandB() and OSLBandC() 'DEBUG ' for i=0 to globalSteps ' OSLcalOpen(i,0)=0 : OSLcalOpen(i,1)=0 ' OSLcalShort(i,0)=42.638 : OSLcalShort(i,1)=-93.4375 ' OSLcalLoad(i,0)=39.166 : OSLcalLoad(i,1)=-92.76 ' next i calSum=OSLdoneO+OSLdoneS+OSLdoneL 'number of cals done. Will be 1 or 3 if calSum=0 then notice "No calibration performed" : OSLError=1 : exit sub if calSum=2 then notice "Incomplete calibration performed" : OSLError=1 : exit sub 'Our OSL procedure actually never allows this to happen if calSum=1 and OSLdoneL then notice "Incomplete calibration performed" : OSLError=1 : exit sub 'Our OSL procedure actually never allows this to happen 'Calc cal standard data for computing coefficients. For reference cal, we don't need all of them, 'but there is no harm in calculating them. call CalcOSLStandards 'ver116-4k 'If we have just one standard it will be reference cal with Open (bridge or shunt) or Short(bridge or series), 'but may not be ideal standard. We make up data for the missing standards so we can do regular OSL. ver116-4n if calSum=1 then 'Either the Open or Short was used as the reference. Even though the cal standard may not be ideal, we use this 'as the (line cal) reference, because it is easy to repeat when doing Update Cal. We also need to create the two missing standards. 'They will be created as ideal, so we must also be sure that the description of the standard is ideal, so we may override 'CalcOSLStandards that was just performed. We need to find how the used standard would have performed if ideal, in order 'to create the missing standards. if OSLdoneO then OSLBandRefType$="Open" else OSLBandRefType$="Short" for i=0 to globalSteps 'modver116-4n if OSLdoneO then 'Note the measured values are the raw measurements of the data, which are the fixture transmission 'values but are not adjusted to any reference. S11R=OSLstdOpen(i,0) : S11I=OSLstdOpen(i,1) 'Actual standard S11, real/imag measDB=OSLcalOpen(i,0) : measDeg=OSLcalOpen(i,1) 'measured standard else 'short S11R=OSLstdShort(i,0) : S11I=OSLstdShort(i,1) 'Actual standard S11, real/imag measDB=OSLcalShort(i,0) : measDeg=OSLcalShort(i,1) 'measured standard end if S11Mag=sqr(S11R^2+S11I^2) : S11dB=20*uSafeLog10(S11Mag) : S11Deg=uATan2(S11R, S11I) 'The calibration standard S11 spec in dB/angle format if S11JigType$="Reflect" then 'Using bridge with reference cal. Reference may be Open or Short if S11dB<-40 then notice "Reference calibration standard is too close to "; S11BridgeR0; " ohms." : OSLError=1 : exit sub if OSLdoneO then OSLcalOpen(i,0)=0 : OSLcalOpen(i,1)=0 'Open adjusted by itself as reference OSLstdShort(i,0)=-1 : OSLstdShort(i,1)=0 'Force spec of Short to be ideal (real/imag) OSLcalShort(i,0)=0-S11dB : OSLcalShort(i,1)=uNormalizeDegrees(-180-S11Deg) 'Pretend we measured the ideal Short and subtracted Open as reference (dB/ang form) else 'short is the reference OSLcalShort(i,0)=0 : OSLcalShort(i,1)=0 'Adjust short with itself as reference, resulting in 0 (dB/ang form) OSLstdOpen(i,0)=1 : OSLstdOpen(i,1)=0 'Force spec of Open to be ideal (real/imag) OSLcalOpen(i,0)=0-S11dB : OSLcalOpen(i,1)=uNormalizeDegrees(0-S11Deg) 'Pretend we measured the ideal Open and subtracted Short as reference (dB/ang form) end if OSLstdLoad(i,0)=0 : OSLstdLoad(i,1)=0 'Force spec of load to be ideal (real/imag) OSLcalLoad(i,0)=-99-S11dB : OSLcalLoad(i,1)=0 'Pretend we measured the ideal load (dB/ang form); don't worry about angle else if S21JigAttach$="Shunt" then 'calc S21 that this refco would produce 'For shunt fixture with no delay and a perfect Open, the ideal Load response would be 3.52 dB below the Open response and 'the ideal Short response would be zero. A non-zero delay or imperfect Open require us to calculate how the response of the actual Open, 'the ideal Load and the ideal Short would be transformed by the delay. We will use the measured Open as the reference for future 'measurements (i.e. it will be subtracted from the raw data the same as line cal). Therefore, whatever S21 we calculate for the actual Open, 'ideal Short or ideal Load, would produce reference-adjusted readings equal to that S21 minus that open's calculated S21. That is, use of the 'measured open as a reference makes its net reading zero, and the ideal Load and Short need to be similarly adjusted 'The delay is assumed to be in a line of 50-ohms, not S21JigR0. modver116-4k phaseDelay=ReflectArray(i,0)*0.36*S21JigShuntDelay 'one way delay in degrees call uS11DBToImpedance S21JigR0, S11dB, S11Deg, impR, impX 'calc impedance call uPhaseShiftImpedance 50, phaseDelay, impR, impX 'Calculate effective impedance of Open with 50-ohm delay call uImpedanceToRefco S21JigR0, impR, impX, S11Mag, S11Deg 'calc actual Open S11 re S21JigR0 taking into account the delay call uRefcoToShuntS21DB S11Mag, S11Deg, S21dB, S21Deg 'calc S21 from the refco of the effective impedance if S11dB>-0.25 and (S11Deg<-165 or S11Deg>165) then _ notice "Reference calibration standard is too close to a Short." : OSLError=1 : exit sub impR=0 : impX=0 'impedance of ideal Short call uPhaseShiftImpedance 50, phaseDelay, impR, impX 'Calculate effective impedance of ideal Short call uImpedanceToRefco S21JigR0, impR, impX, idealShortS11Mag, idealShortS11Deg 'calc ideal Short response taking into account the delay call uRefcoToShuntS21DB idealShortS11Mag, idealShortS11Deg, idealShortS21dB, idealShortS21Deg 'calc S21 from the refco of the effective impedance 'Adjust by the measured Open reading idealShortS21dB=idealShortS21dB - S21dB : idealShortS21Deg=uNormalizeDegrees(idealShortS21Deg - S21Deg) impR=S21JigR0 : impX=0 'impedance of ideal Load call uPhaseShiftImpedance 50, phaseDelay, impR, impX 'Calculate effective impedance of ideal Load call uImpedanceToRefco S21JigR0, impR, impX, idealLoadS11Mag, idealLoadS11Deg 'calc ideal Load response taking into account the delay call uRefcoToShuntS21DB idealLoadS11Mag, idealLoadS11Deg, idealLoadS21dB, idealLoadS21Deg 'calc S21 from the refco of the effective impedance 'Adjust by the same amount that the measured Open was high idealLoadS21dB=idealLoadS21dB - S21dB : idealLoadS21Deg=uNormalizeDegrees(idealLoadS21Deg - S21Deg) OSLcalOpen(i,0)=0 : OSLcalOpen(i,1)=0 'Adjust open with itself as reference, resulting in 0 (dB/ang form) OSLstdShort(i,0)=-1 : OSLstdShort(i,1)=0 'Force spec of short to be ideal (real/imag) OSLcalShort(i,0)=idealShortS21dB : OSLcalShort(i,1)=idealShortS21Deg 'Pretend we measured the ideal short OSLstdLoad(i,0)=0 : OSLstdLoad(i,1)=0 'Force spec of load to be ideal (real/imag) OSLcalLoad(i,0)=idealLoadS21dB : OSLcalLoad(i,1)=idealLoadS21Deg 'Pretend we measured the ideal load else 'series fixture 'Series is similar to shunt, except cal is with Short, and we don't deal with delays so everything is simpler. call uRefcoToSeriesS21DB S11Mag, S11Deg, S21dB, S21Deg 'S21 that the actual short would produce if S11dB>-0.25 and S11Deg<5 and S11Deg>-5 then _ notice "Reference calibration standard is too close to an Open." : OSLError=1 : exit sub OSLcalShort(i,0)=0 : OSLcalShort(i,1)=0 'Adjust short with itself as reference, resulting in 0 (dB/ang form) OSLstdOpen(i,0)=1 : OSLstdOpen(i,1)=0 'Force spec of Open to be ideal (real/imag) OSLcalOpen(i,0)=-99-S21dB : OSLcalOpen(i,1)=uNormalizeDegrees(0-S21Deg) 'Pretend we measured the ideal Open (dB/ang form) OSLstdLoad(i,0)=0 : OSLstdLoad(i,1)=0 'Force spec of load to be ideal (real/imag) 'Load would be 3.52 dB below ideal short; actual short would produce S21dB@S21Deg but we set measured short to zero, 'so we also have to subtract S21dB@S21Deg from ideal load. OSLcalLoad(i,0)=-3.52-S21dB : OSLcalLoad(i,1)=uNormalizeDegrees(0-S21Deg) 'Pretend we measured the ideal load (dB/ang form) end if end if OSLBandRef(i,0)=ReflectArray(i,0) 'freq--actual tuning freq, not equiv 1G freq OSLBandRef(i,1)=measDB :OSLBandRef(i,2)=measDeg 'save reference 'Save the measured reference next i else 'All three standards used 'ver116-4n 'We need to determine what to use for the reference. It will be Open, Short or Load, whichever has the largest value. 'The goal is to avoid the Open with a series fixture or a Short with a shunt fixture. open1=OSLcalOpen(0,0) : load1=OSLcalLoad(0,0) : short1=OSLcalShort(0,0) if open1>=load1 then 'choose biggest if open1>=short1 then OSLBandRefType$="Open" else OSLBandRefType$="Short" else if load1>short1 then OSLBandRefType$="Load" else OSLBandRefType$="Short" end if for i=0 to globalSteps 'copy reference and adjust measurements per reference OSLBandRef(i,0)=ReflectArray(i,0) 'freq--actual tuning freq, not equiv 1G freq select case OSLBandRefType$ case "Open" : refdB=OSLcalOpen(i,0) : refDeg=OSLcalOpen(i,1) case "Short" : refdB=OSLcalShort(i,0) : refDeg=OSLcalShort(i,1) case else : refdB=OSLcalLoad(i,0) : refDeg=OSLcalLoad(i,1) end select OSLBandRef(i,1)=refdB :OSLBandRef(i,2)=refDeg 'save reference OSLcalOpen(i,0)=OSLcalOpen(i,0)-refdB : OSLcalOpen(i,1)=uNormalizeDegrees(OSLcalOpen(i,1)-refDeg) 'Adjust measurements per reference OSLcalLoad(i,0)=OSLcalLoad(i,0)-refdB : OSLcalLoad(i,1)=uNormalizeDegrees(OSLcalLoad(i,1)-refDeg) OSLcalShort(i,0)=OSLcalShort(i,0)-refdB : OSLcalShort(i,1)=uNormalizeDegrees(OSLcalShort(i,1)-refDeg) next i end if 'ver116-4k deleted creation of missing standard when we have two. Current procedure never allows us to end up with two. OSLError=0 'ver116-4k 'We want to convert the OSLcalxxx() data into S11 in rectangular form (real, imaginary), and calc OSL coefficients. 'We leave the reference data in db, ang (degrees) format kDegToRad=uRadsPerDegree() for i=0 to globalSteps rho=10^(OSLcalOpen(i,0)/20) : rad=OSLcalOpen(i,1)*kDegToRad 'to polar, radians OSLcalOpen(i,0)=cos(rad)*rho : OSLcalOpen(i,1)=sin(rad)*rho 'polar to rectangular rho=10^(OSLcalLoad(i,0)/20) : rad=OSLcalLoad(i,1)*kDegToRad OSLcalLoad(i,0)=cos(rad)*rho : OSLcalLoad(i,1)=sin(rad)*rho rho=10^(OSLcalShort(i,0)/20) : rad=OSLcalShort(i,1)*kDegToRad OSLcalShort(i,0)=cos(rad)*rho : OSLcalShort(i,1)=sin(rad)*rho next i call CalcOSLCoeff 'Calculate A, B, C coefficients; set OSLError to 1 if math error end sub 'Here we use the measured reflection coefficients for the open, load and short 'to determine OSL coefficients a, b and c. These in turn can be used 'to calculate actual reflection coefficients from measured reflection coefficients 'by the following formulas: ' M=(S+a)/(b*S+c) ' S = (a - cM)/(bM - 1) 'where S is the actual reflection coefficient and M is the measured reflection coefficient. 'For subscripting variables in code and in the comments, the suffixes O, L and S mean 'Open, Load and Short, respectively. For example, SL is the actual 'reflection coefficient of the load; MS is the measured reflection loss of the short. ' 'The measured return losses for the open, load and short are determined 'at each frequency step before invoking this method, and placed into the arrays 'OSXOpenR, OSXOpenI, OSXLoadR, OSXLoadI, OSXShortR and OSXShortI. Variable names 'use the suffixes R and I for the real and imaginary parts, respectively. 'We could first do a line calibration with the Open 'and then measure just the load and short, assigning a perfect "1" to the Open. 'But to keep this calculation generic, if that is done the entries for the measured 'Open should just be assigned a value of 1 before invoking CalcOSL. 'We allow for the actual return losses of the open and short 'to be something other than ideal, by using arrays to hold 'their values at each frequency step. sub CalcOSLCoeff1 'Calc coeff a, b, c for base or band OSL cal 'OSLcalOpen(), OSLcalShort() and OSLcalLoad() have the raw calibration data (real, imag form) 'OSLstdOpen and OSLstdOpen() have the S11 data for the Open and Short standards (real, imag form) 'MO,ML, MS are the measured responses with the open, load and short attached 'SO, SL, SS are the actual reflection coeff. of the open, short and load standards '(SL is assumed=0) 'All must be in real, imaginary form 'The adjustment is made by the following formula: ' S = (a - cM)/(bM - 1) This model is different from that used in CalcOSLCoeff 'where S is the actual reflection coefficient and M is the measured reflection coefficient. ' 'The coefficients a, b and c are calculated according to the following formulas: 'K1= ML-MO; approx. -1 'K2= MS-ML; appro.x -1 'K3= MO-MS; approx. 2 ' 'D=MS*SS*K1 + MO*SO*K2; approx -2 ' 'c=SO*SS*K3 / D 'a=ML*c 'b=[SO*K2 + SS*K1] / D for calStep=0 to globalSteps MOr=OSLcalOpen(calStep,0) : MOi=OSLcalOpen(calStep,1) 'Measured open, real and imag MLr=OSLcalLoad(calStep,0) : MLi=OSLcalLoad(calStep,1) 'Measured load, real and imag MSr=OSLcalShort(calStep,0) : MSi=OSLcalShort(calStep,1) 'Measured short, real and imag SOr=OSLstdOpen(calStep,0) : SOi=OSLstdOpen(calStep,1) 'Open standard, real and imag SSr=OSLstdShort(calStep,0) : SSi=OSLstdShort(calStep,1) 'Short standard, real and imag 'Compute Ks K1r=MLr-MOr : K1i=MLi-MOi 'K1, real and imag K2r=MSr-MLr : K2i=MSi-MLi 'K2, real and imag K3r=MOr-MSr : K3i=MOi-MSi 'K3, real and imag 'Compute 1/D Wr=MSr*SSr-MSi*SSi : Wi=MSr*SSi+MSi*SSr 'MS*SS Xr=Wr*K1r-Wi*K1i : Xi=Wr*K1i+Wi*K1r 'MS*SS*K1 Yr=MOr*SOr-MOi*SOi : Yi=MOr*SOi+MOi*SOr 'MO*SO Zr=Yr*K2r-Yi*K2i : Zi=Yr*K2i+Yi*K2r 'MO*SO*K2 Dr=Xr+Zr : Di=Xi+Zi 'D=MS*SS*K1 + MO*SO*K2 if Dr=0 and Di=0 then notice "Divide by zero in calculating OSL coefficients." : OSLError=1 : exit sub 'ver115-4j call cxInvert Dr, Di, DinvR, DinvI 'Invert of D is in Dinv 'Compute c Wr=SOr*SSr-SOi*SSi : Wi=SOr*SSi+SOi*SSr 'SO*SS Xr=Wr*K3r-Wi*K3i : Xi=Wr*K3i+Wi*K3r 'X=SO*SS*K3 cr=DinvR*Xr-DinvI*Xi : ci=DinvR*Xi+DinvI*Xr 'c=X/D 'Compute a ar=MLr*cr-MLi*ci : ai=MLr*ci+MLi*cr 'a=ML*c 'Compute b Wr=SOr*K2r-SOi*K2i : Wi=SOr*K2i+SOi*SSr 'SO*K2 Xr=SSr*K1r-SSi*K1i : Xi=SSr*K1i+SSi*K1r 'SS*K1 Yr=Wr+Xr : Yi=Wi+Xi 'Y=SO*K2 + SS*K1 br=DinvR*Yr-DinvI*Yi : bi=DinvR*Yi+DinvI*Yr 'b=Y/D 'Put coefficients into OSLBandx() OSLBandA(calStep,0)=ar : OSLBandA(calStep,1)=ai OSLBandB(calStep,0)=br : OSLBandB(calStep,1)=bi OSLBandC(calStep,0)=cr : OSLBandC(calStep,1)=ci next calStep end sub sub CalcOSLCoeff 'Calc coeff a, b, c for base or band OSL cal 'We calculate OSL coefficients for the most general case, where no advance assumptions are 'made about the cal standards. 'OSLcalOpen(), OSLcalShort() and OSLcalLoad() have the raw calibration data (real, imag form) 'OSLstdOpen and OSLstdOpen() have the S11 data for the Open and Short standards (real, imag form) 'MO,ML, MS are the measured responses with the open, load and short attached 'SO, SL, SS are the actual reflection coeff. of the open, short and load standards 'The error model equation is as follows, where S is the actual S11 and M is 'the measured S11: ' S = (M – b) / (a – c*M) 'Using S and M for the Open, Short and Load, we can calculate the 'coefficients a, b and c. 'The double letter variables Mx and Sx are the measured and actual values, with 'the second letter (O, S or L) indicating open, short or load. ' ' K1 = ML-MS ' K2 = MS-MO ' K3 = MO-ML ' K4= SL*SS*K1 ' K5= SO*SS*K2 ' K6= SL*SO*K3 ' K7=SO*K1 ' K8=SL*K2 ' K9=SS*K3 ' ' D = K4 + K5 + K6 ' ' a= (MO*K7 + ML*K8 + MS*K9)/D ' b= (MO*K4 + ML*K5 +MS*K6)/D ' c = (K7 + K8 + K9)/D for calStep=0 to globalSteps MOr=OSLcalOpen(calStep,0) : MOi=OSLcalOpen(calStep,1) 'Measured open, real and imag MLr=OSLcalLoad(calStep,0) : MLi=OSLcalLoad(calStep,1) 'Measured load, real and imag MSr=OSLcalShort(calStep,0) : MSi=OSLcalShort(calStep,1) 'Measured short, real and imag SOr=OSLstdOpen(calStep,0) : SOi=OSLstdOpen(calStep,1) 'Open standard, real and imag SLr=OSLstdLoad(calStep,0) : SLi=OSLstdLoad(calStep,1) 'Load standard, real and imag SSr=OSLstdShort(calStep,0) : SSi=OSLstdShort(calStep,1) 'Short standard, real and imag K1r=MLr-MSr : K1i=MLi-MSi 'K1=ML-MS, real and imag K2r=MSr-MOr : K2i=MSi-MOi 'K2=MS-MO, real and imag K3r=MOr-MLr : K3i=MOi-MLi 'K3=MO-ML, real and imag Wr=SLr*SSr-SLi*SSi : Wi=SLr*SSi+SLi*SSr 'W=SL*SS K4r=Wr*K1r-Wi*K1i : K4i=Wr*K1i+Wi*K1r 'K4=SL*SS*K1 Wr=SOr*SSr-SOi*SSi : Wi=SOr*SSi+SOi*SSr 'W=SO*SS K5r=Wr*K2r-Wi*K2i : K5i=Wr*K2i+Wi*K2r 'K5=SO*SS*K2 Wr=SLr*SOr-SLi*SOi : Wi=SLr*SOi+SLi*SOr 'W=SL*SO K6r=Wr*K3r-Wi*K3i : K6i=Wr*K3i+Wi*K3r 'K6=SL*SO*K3 K7r=SOr*K1r-SOi*K1i : K7i=SOr*K1i+SOi*K1r 'K7=SO*K1 K8r=SLr*K2r-SLi*K2i : K8i=SLr*K2i+SLi*K2r 'K8=SL*K2 K9r=SSr*K3r-SSi*K3i : K9i=SSr*K3i+SSi*K3r 'K9=SS*K3 Dr=K4r+K5r+K6r : Di=K4i+K5i+K6i 'D = K4 + K5 + K6 if Dr=0 and Di=0 then notice "Divide by zero in calculating OSL coefficients." : OSLError=1 : exit sub 'ver115-4j call cxInvert Dr, Di, invDr, invDi 'invD= 1/D 'Now calculate coefficient a Wr=MOr*K7r-MOi*K7i : Wi=MOr*K7i+MOi*K7r 'W=MO*K7 Xr=MLr*K8r-MLi*K8i : Xi=MLr*K8i+MLi*K8r 'X=ML*K8 Yr=MSr*K9r-MSi*K9i : Yi=MSr*K9i+MSi*K9r 'Y=MS*K9 Zr=Wr+Xr+Yr : Zi=Wi+Xi+Yi 'Z=MO*K7 + ML*K8 + MS*K9 ar=Zr*invDr-Zi*invDi : ai=Zr*invDi+Zi*invDr 'a=(MO*K7 + ML*K8 + MS*K9)/D 'The procedure for calculating b is identical to that for a, 'just changing the K values. Wr=MOr*K4r-MOi*K4i : Wi=MOr*K4i+MOi*K4r 'W=MO*K4 Xr=MLr*K5r-MLi*K5i : Xi=MLr*K5i+MLi*K5r 'X=ML*K5 Yr=MSr*K6r-MSi*K6i : Yi=MSr*K6i+MSi*K6r 'Y=MS*K6 Zr=Wr+Xr+Yr : Zi=Wi+Xi+Yi 'Z=MO*K4 + ML*K5 + MS*K6 br=Zr*invDr-Zi*invDi : bi=Zr*invDi+Zi*invDr 'b=(MO*K4 + ML*K5 + MS*K6)/D 'Calculate coefficient c. Wr=K7r+K8r+K9r : Wi=K7i+K8i+K9i 'W = K7 + K8 + K9 cr=Wr*invDr-Wi*invDi : ci=Wr*invDi+Wi*invDr 'c = (K7 + K8 + K9)/D 'Put coefficients into OSLBandx() OSLBandA(calStep,0)=ar : OSLBandA(calStep,1)=ai OSLBandB(calStep,0)=br : OSLBandB(calStep,1)=bi OSLBandC(calStep,0)=cr : OSLBandC(calStep,1)=ci next calStep end sub sub CalcOSLStandards 'Calculate ref. coeff. of OSL standards 'The Open, Short and Load are each characterized as either a series or parallel RLC circuit to ground at the end 'of a coax delay line. This follows the normal format of an RLC spec used by uRLCComboResponse, though it 'is usually fairly simple. 'The Open is generally characterized as a time delay plus a fringe capacitance. The Short is generally characterized 'as a time delay plus a parallel resistance/inductance shunted to ground. The Load is generally characterized 'as a delay and resistance, and either a parallel capacitance or a series inductance. 'For each frequency 'in datatable, calculate the Open and Short response. Put the open response into OSLstdOpen() and 'Short response into OSLstdShort(), both in real, imag form. 'The response is calculated relative to the jig or bridge R0, not the graph R0 if S11JigType$="Trans" then R0=S21JigR0 else R0=S11BridgeR0 for i=0 to globalSteps :uWorkArray(i+1,0)=ReflectArray(i,0) : next i 'load frequencies into uWorkArray uWorkNumPoints=globalSteps+1 'number of points is one more than number of steps isErr=uRLCComboResponse(OSLOpenSpec$, R0, "S11") 'Calculate open standard response at all frequencies if isErr then notice "Error in OSL standards specifications" : OSLError=1 : exit sub radsPerDeg=uRadsPerDegree() 'For conversion from degrees to rads for i=0 to globalSteps rho=uTenPower(uWorkArray(i+1,1)/20) : theta=uWorkArray(i+1, 2)*radsPerDeg OSLstdOpen(i, 0)=rho*cos(theta) : OSLstdOpen(i,1)=rho*sin(theta) 'real, imag format next i isErr=uRLCComboResponse(OSLShortSpec$, R0, "S11") 'Calculate short standard response at all frequencies if isErr then notice "Error in OSL standards specifications" : OSLError=1 : exit sub for i=0 to globalSteps rho=uTenPower(uWorkArray(i+1,1)/20) : theta=uWorkArray(i+1, 2)*radsPerDeg OSLstdShort(i, 0)=rho*cos(theta) : OSLstdShort(i,1)=rho*sin(theta) 'real, imag format next i isErr=uRLCComboResponse(OSLLoadSpec$, R0, "S11") 'Calculate load standard response at all frequencies if isErr then notice "Error in OSL standards specifications" : OSLError=1 : exit sub for i=0 to globalSteps rho=uTenPower(uWorkArray(i+1,1)/20) : theta=uWorkArray(i+1, 2)*radsPerDeg OSLstdLoad(i, 0)=rho*cos(theta) : OSLstdLoad(i,1)=rho*sin(theta) 'real, imag format next i end sub [RunCalUpdate] 'menu item to update calibration ver116-4b if haltsweep=1 then gosub [FinishSweeping] WindowWidth = 475 : WindowHeight = 235 call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c UpperLeftY=UpperLeftY-100 BackgroundColor$="buttonface" ForegroundColor$="black" TextboxColor$ = "white" ComboboxColor$="white" 'We can update band cal if we have current cal, even if not yet installed. 'TO DO: For base cal, change the sweep settings to match the cal data. DO a scan and update the base cal data, and 'save it to file. Change desired cal level to 1 and install cal. For band cal, be sure it matches current sweep params, 'update the band cal data, change desired cal level to 2 and install cal. 'To update both reflection and transmission base cal, they must both exist but don't need matching freq range. 'Note: Currently only band cal update is implemented. if msaMode$="Reflection" then bandUpdateIsCurrent=(desiredCalLevel=2 and BandOSLCalIsCurrent()) : baseUpdateIsCurrent=BaseOSLCalIsCurrent() _ else bandUpdateIsCurrent=(desiredCalLevel=2 and BandLineCalIsCurrent()) : baseUpdateIsCurrent=BaseOSLCalIsCurrent() if bandUpdateIsCurrent=0 then Notice "Must have current band calibration to update. Cannot update base cal." : wait 'ver116-4n 'update band cal if msaMode$="Reflection" then stdType$=OSLBandRefType$;" standard" else stdType$="Through connection" s$="To update the currently band calibration, attach the "; stdType$ s$=s$;" and click Perform Update. This will update the currently installed reference to partially adjust for drift " s$=s$;"occurring since the full calibration was performed. " statictext #OSLupdate.inst, s$,10,1,450, 70 updateCalsMatch=0 'Whether other VNA mode has matching calibration if BandOSLCalIsCurrent() and BandLineCalIsCurrent() then updateCalsMatch=1 if msaMode$="VectorTrans" then statictext #OSLupdate.DelayLabel, "Delay of Calibration Through Connection (ns):",10,90,270, 18 textbox #OSLupdate.Delay, 282,90,50, 20 checkbox #OSLupdate.applyAlso, "Apply update to Reflection Cal as well.",[updateNil], [updateNil],50,115,260, 18 else 'Reflection checkbox #OSLupdate.applyAlso, "Apply update to Transmission Cal as well.",[updateNil], [updateNil],50,115,260, 18 end if button #OSLupdate.Perform, "Perform Open",[PerformCalUpdate], UL, 75, 160, 120,25 'ver114-5f button #OSLupdate.Done, "Done",[CalUpdateFinished], UL, 220, 160, 100,25 open "Update Calibration" for dialog_modal as #OSLupdate 'ver114-3g print #OSLupdate, "trapclose [CalUpdateFinished]" 'goto [OSLCalUpdateFinished] if xit is clicked print #OSLupdate, "font ms_sans_serif 10" if msaMode$="VectorTrans" then #OSLupdate.Perform, "Perform Through" : #OSLupdate.Delay, lineCalThroughDelay 'Delay in ns calUpdatePerformed=0 if updateCalsMatch=0 then #OSLupdate.applyAlso, "disable" 'gray it out in reset mode if not applicable wait [updateNil] 'nil handler wait [PerformCalUpdate] 'update button clicked 'We will re-scan the reference data, which should in theory match the current reference data. If a current 'reading minus the original is D dB @ A degrees, this means we need to subtract that extra 'amount from all future readings. Essentially, the new data becomes our new reference, 'which we need to transfer to lineCalArray. In addition, if we have Band cal, we should 'replace lineCalBandRef() or OSLBandRef(). For Base cal, it is not feasible to adust the Base cal array reference, so 'we can only adjust the currently installed data in lineCalArray. if calInProgress then goto [CalUpdateAborted] 'Perform button is actually Abort while cal in progress calUpdatePerformed=1 'set this even if we abort ver116-4b #OSLupdate.Perform, "Abort Cal" : #OSLupdate.Done, "!disable" : #OSLupdate.applyAlso, "disable" if msaMode$<>"Reflection" then gosub [PerformLineCalUpdate] else gosub [PerformOSLCalUpdate] wait [PerformOSLCalUpdate] cursor hourglass calInProgress=1 : specialOneSweep=1 saveAlternate=alternateSweep : saveSweepDir=sweepDir : savePlaneAdj=planeadj : saveWate=wate alternateSweep=0 : sweepDir=1 call FunctSetVideoAndAutoWait 1 'set video filter to narrow and autowait to Normal or Precise; 1 means save settings planeadj=0 'So phase will not be affected 'Note with calInProgress=1, the cal installation routine will not install anything and sets applyCalLevel=0 gosub [Restart] 'Perform one sweep and fill datatable(,) specialOneSweep=0 calInProgress=0 call FunctRestoreVideoAndAutoWait sweepDir=saveSweepDir : alternateSweep=saveAlternate planeadj=savePlaneAdj : wate=saveWate 'New Cal reference data is now in datatable #OSLupdate.applyAlso, "value? applyAlso$" for i=0 to steps m=datatable(i,2) : p=datatable(i,3) 'get mag and phase; freq doesn't change deltaM=m-OSLBandRef(i,1) : deltaP=p-OSLBandRef(i,2) 'change in mag and phase OSLBandRef(i,1)=m : OSLBandRef(i,2)=p 'update OSLBandRef if applyAlso$="set" then _ 'update line cal data if required bandLineCal(i,1)=bandLineCal(i,1)+deltaM : bandLineCal(i,2)=gNormalizePhase(bandLineCal(i,2)+deltaP) next i desiredCalLevel=2 : installedOSLBandTimeStamp$="" 'so installation will occur call InstallSelectedOSLCal 'So new data gets installed and installation variables get updated OSLBandTimeStamp$=date$("mm/dd/yy"); "; ";time$() if applyAlso$="set" then bandLineTimeStamp$=OSLBandTimeStamp$ cursor normal beep #OSLupdate.Perform, "Perform Update" : #OSLupdate.Done, "!enable" if updateCalsMatch then #OSLupdate.applyAlso, "enable" return [PerformLineCalUpdate] cursor hourglass if msaMode$="VectorTrans" then 'ver115-5a #OSLupdate.Delay, "!contents? s$" lineCalThroughDelay=val(uCompact$(s$)) 'Store in ns; used by [BandLineCal] else lineCalThroughDelay=0 end if 'We use BandLineCal rather than just doing our own sweep because it adjusts for lineCalThroughDelay 'It will automatically update bandLineCal, so in order for us to have access to the old info 'we have to be sure it is saved into lineCalArray. 'lineCalArray data will not be disturbed (and will not be used) during the sweep conducted by [BandLineCal]. for i=0 to steps : lineCalArray(i,1)=bandLineCal(i,1) : lineCalArray(i,2)=bandLineCal(i,2) : next i gosub [BandLineCal] 'Peforms sweep and loads into bandLineCal; saves/restores necessary settings 'new data is in datatable and bandLineCal; old data is still in lineCalArray #OSLupdate.applyAlso, "value? applyAlso$" if applyAlso$="set" then 'update OSL data if required for i=0 to steps m=bandLineCal(i,1) : p=bandLineCal(i,2) 'get mag and phase; freq doesn't change deltaM=m-lineCalArray(i,1) : deltaP=p-lineCalArray(i,2) 'change in mag and phase OSLBandRef(i,1)=OSLBandRef(i,1)+deltaM : OSLBandRef(i,2)=gNormalizePhase(OSLBandRef(i,2)+deltaP) next i end if desiredCalLevel=2 : installedBandLineTimeStamp$="" 'so installation will occur call InstallSelectedLineCal 'So new data gets installed and installation variables get updated '[BandLineCal] updates bandLineTimeStamp$ if applyAlso$="set" then OSLBandTimeStamp$=bandLineTimeStamp$ #OSLupdate.Perform, "Perform Update" : #OSLupdate.Done, "!enable" if updateCalsMatch then #OSLupdate.applyAlso, "enable" cursor normal return [CalUpdateAborted] 'abort calibration gosub [FinishSweeping] 'Finish nicely #OSLupdate.Perform, "Perform Update" : #OSLupdate.Done, "!enable" if updateCalsMatch then #OSLupdate.applyAlso, "enable" cursor normal specialOneSweep=0 : calInProgress=0 sweepDir=saveSweepDir : alternateSweep=saveAlternate planeadj=savePlaneAdj : wate=saveWate wait [CalUpdateFinished] if calInProgress=1 then goto [PostScan] 'Don't allow quit in middle of cal 'Note we do not update the time stamp of the base, band or installed cal. That is needed only to trigger a 're-install of cal info on Restart. We just installed what is necessary. If Base cal, on Restart no new install 'will be done so what we just did won't be overridden. If Band cal, it wouldn't matter if a re-install were done. cursor normal close #OSLupdate if calUpdatePerformed then call SignalNoCalInstalled 'ver116-4b desiredCalLevel=2 'desire BandSweep since we just did it call RequireRestart 'so cal will get installed before proceeding end if wait '--end of [RunCalUpdate] '---------------End Routines to Handle OSL Calibration--------------- [menuRunConfig]'Graph Window Menu,Setup,Configuration Manager was selected if haltsweep=1 then gosub [FinishSweeping] 'Finish last point of sweep that was in progress. ver116-4j savePath$=path$ 'ver114-4c 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 path$=savePath$ 'ver114-4c call SelectFilter filtbank 'ver116-4j wait end if goto [finished] 'Must restart if config was changed [menuRunCal]'Menu item for config manager was selected 'SEW6 rewrote routine.ver113-7c if haltsweep=1 then gosub [FinishSweeping] 'Finish last point of sweep that was in progress. ver116-4j if calManWindHndl$<>"" then wait 'Do nothing if cal mangager already running ver116-1b savePath$=path$ 'ver114-4c 'calRunManager will return with filter path 1 installed. call RequireRestart 'SEW8 Let the user proceed only by Restarting gosub [calManRunManager] path$=savePath$ 'ver114-4c 'restores prior filter call SelectFilter filtbank 'ver116-4j wait [CreateGraphWindow]'changed ver113-4b 'We do this only once, at startup. After that, we work with the existing window, adjust its menus and redraw. BackgroundColor$="buttonface" : ForegroundColor$="black" WindowWidth=800 : WindowHeight=600 UpperLeftX = 1 : UpperLeftY = 1 TextboxColor$="white" : ComboboxColor$="white" menu #handle, "File", "Save Image", [SaveImage], "Load Prefs", [menuLoadPreferenceFile], _ "Save Prefs", menuSavePreferenceFile, _ "Load Data", [menuLoadDataFile], "Save Data", [menuSaveDataFile], _ "Load Front End", [menuLoadFrontEndFile], _ 'ver115-9d "Save Debug Info", [DebugSaveData], "Load Debug Info", [DebugLoadData] menu #handle, "Edit", "&Copy Image",[CopyImage] 'ver116-4b if hasVNA then 'Show PDM calibration and Smith Chart options only if we have the VNA menu #handle, "Setup", "Hardware Config Manager", [menuRunConfig], _ "Initial Cal Manager", [menuRunCal], _ "Special Tests", [SpecialTests], "PDM Calibration", [menuCalPDM], _ "Primary Axis", [menuPrimaryAxis] 'ver115-3c menu #handle, "Options", "Appearances",AppearanceDialog,"Markers", mMenuMarkerOptions, _ "Sweep", [menuFreqAxisPreference], "Show Variables", [Showvar], _ "Reference Lines", ReferenceDialog, "Smith Chart", smithOpenChart else 'no VNA 'ver 115-9e displayed initial cal manager but not PDM cal when there is no VNA menu #handle, "Setup", "Hardware Config Manager", [menuRunConfig], _ "Initial Cal Manager", [menuRunCal], _ "Special Tests", [SpecialTests], _ "Primary Axis", [menuPrimaryAxis] 'ver115-3c menu #handle, "Options", "Appearances",AppearanceDialog,"Markers", mMenuMarkerOptions, _ "Sweep", [menuFreqAxisPreference], "Show Variables", [Showvar], _ "Reference Lines", ReferenceDialog end if menuOptionsPosition=3 'Options menu is fourth, which is position 3 when indexed from zero menu #handle, "Data", "Graph Data", [DataWin_GraphData], "Input Data",[MSAinputData], _ 'Data for all modes "S21 Parameters",[MagPhaS21], "Installed Line Cal",[LineCalArray], _ 'Trans Data "S11 Parameters", [MagPhaS11], "S11 Derived Data",[ReflectDerivedData], _ 'Reflection Data "Cal Reference",[LineCalArray], "OSL Info",[DataWin_OSL] 'Reflection Data menu #handle, "Functions", "Filter Analysis",SetFilterAnalysis , _ 'SA and Trans functions "Component Meter", [menuComponentMeasure], "RLC Analysis", [menuRLCAnalysis], _'Trans and reflection functions "Crystal Analysis", [menuCrystalAnalysis], "Group Delay", [FunctionGroupDelay], _ 'Trans functions "Coax Parameters", [menuCoaxAnalyzeTLScan], "Generate S21", [menuS11ToS21] 'Reflection functions menuDataPosition=4 'Data menu is fifth, which is position 4 when indexed from zero menuFunctionsPosition=5 'Functions menu is sixth, which is position 5 when indexed from zero if TGtop>0 then 'No need for operating cal menu or mode selection if SA is the only possible mode ver114-5n menu #handle, "Operating Cal", "Perform Cal", [RunVNACal], "Reference To",[menuVNARef], "Update Cal", [RunCalUpdate] 'ver116-5b menuOperatingCalPosition=6 'Cal menu is 7th, if we have it menuOperatingCalShowing=1 menuModePosition=7 if hasVNA then 'Build level 3 menu #handle, "Mode", "Spectrum Analyzer", [RestartPlainSAmode], _ 'ver115-4f "Spectrum Analyzer with TG", [RestartSATGmode], _ 'ver115-4g "VNA Transmission", [RestartTransmissionMode], _ "VNA Reflection", [RestartReflectionMode] else 'Build level 2 menu #handle, "Mode", "Spectrum Analyzer", [RestartPlainSAmode], _ "Spectrum Analyzer with TG", [RestartSATGmode], "SNA Transmission", [RestartTransmissionMode] 'ver115-4f end if menuMultiscanPosition=8 'Multiscan menu is 9th, which is position 8 when indexed from zero else menuOperatingCalPosition=0 'No Cal menu menuModePosition=0 'No mode menu menuOperatingCalShowing=0 menuMultiscanPosition=7 'Multiscan menu is 8th, which is position 7 when indexed from zero end if 'MULTISCAN MENU. menu #handle, "Multiscan", "Run Multiscan",[multiscanMenuRun], "Show Multiscan", multiscanMenuShowAll, _ "Quit Multiscan", menuQuitMultiscan, "Multiscan Help", multiscanHelp 'ver115-8d menuMultiscanShowing=1 if TGtop>0 and hasVNA then 'Two Port menu ver116-1b menu #handle, "Two-Port", "Show Two-Port Window", [TwoPortMenuDisplay] 'ver116-4a menuTwoPortPosition=menuMultiscanPosition+1 : menuTwoPortShowing=1 else menuTwoPortPosition=0 : menuTwoPortShowing=0 end if 'GraphicBox for graphing currGraphBoxHeight=WindowHeight-clientHeightOffset-41 'ver115-1b 'ver115-1c currGraphBoxWidth=WindowWidth-clientWidthOffset 'ver115-1b 'ver115-1c graphicbox #handle.g, 0,0,currGraphBoxWidth,currGraphBoxHeight 'Marker Selection buttons markTop=currGraphBoxHeight+12 'This isn't the top of anything in particular, just a reference point ver115-1b markSelLeft=5 statictext #handle.selMarkLab "Marker", markSelLeft+3, markTop-11, 40, 14 selMarkIDs$(0)="None" : for i=0 to 9 : selMarkIDs$(i+1)=markerIDs$(i) : next i 'Stylebits #handle.selMark, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a del115_1a so box generates click event combobox #handle.selMark, selMarkIDs$(), mUserMarkSelect, markSelLeft, markTop+3, 50, 180 'Marker Editing Items ver114-4a changed marker edit buttons so none need to be hidden markEditLeft=markSelLeft+55 'button #handle.markEdit, "Edit",btnMarkEdit, LL, markEditLeft, -22, 35,18 button #handle.markDelete, "Delete",mBtnMarkDelete, LL, markEditLeft, -4, 65,18 'stylebits #handle.markClear, _BS_MULTILINE, 0, 0, 0 'Prints label over two lines button #handle.markClear, "Clear Marks",mBtnMarkClear, LL, markEditLeft, -22, 65,18 button #handle.markDec, "-",[btnDecPoint], LL, markEditLeft+71, -7, 14,15 'ver116-4j button #handle.markInc, "+",[btnIncPoint], LL, markEditLeft+129, -7, 14,15 'ver116-4j statictext #handle.FreqLab, "MHz", markEditLeft+100, markTop-6, 28,13 textbox #handle.markFreq, markEditLeft+70, markTop+7, 75,20 button #handle.markEnterFreq, "Enter",mEnterMarker, LL, markEditLeft+146, -25, 35,15 'Misc Marker buttons markMiscLeft=markEditLeft+185 button #handle.ExpandLR, "Expand L-R", [menuExpandSweep],LL, markMiscLeft, -4,65,18 'ver114-7d button #handle.mMarkToCenter, "Mark->Cent", mMarkToCenter,LL, markMiscLeft, -22,65,18 'ver114-7b deleted buttons for IncDecRef 'Test Setup Button 'ver115-1g added this and deleted go/save config configLeft=markMiscLeft+70 stylebits #handle.testsetup, _BS_MULTILINE, 0, 0, 0 button #handle.testsetup, "Test Setups", [ManageTestSetups], LL, configLeft, -5, 50, 35 'ver113-1a 'Sweep Control Buttons button #handle.Redraw, "Redraw",btnRedraw, LR, 105,13,70,19 'OneStep becomes HaltAtEnd when scan is in progress button #handle.OneStep, "HaltAtEnd",[OneStep], LR, 105,-6,70,19 'Continue becomes Halt when scan is in progress button #handle.Continue, "Halt",[Continue], LR, 35,13,60,19 'Restart toggles between Restart and Running button #handle.Restart, "Running",[RestartButton], LR, 35,-6,60,19 'ver115-8c 'There is a bug in LB causing some ephemeral images to appear when resizing a window, 'but they can be eliminated by covering and then uncovering them. The following button 'is used in [ResizeGraphHandler] for that purpose. It only appears for an instant, so the handler is irrelevant. button #handle.Cover, "", nilHandler,LL, 0,40,1000,80 'SEWgraph if graphBox$<>"" then close #handle 'if a window is already open, close it open "" for window as #handle 'Caption is set in ConformMenusToMode ver115-5d graphBox$="#handle.g" 'Used to draw in the graphics box 'ver115-1a 'When left button goes down or motion occurs with left button down, we want to display info about that point. #handle.g, "when leftButtonDown gMouseQuery" 'ver116-4j #handle.g, "when leftButtonMove gMouseQuery" 'ver116-4j #handle.g, "when leftButtonUp gMouseQueryEnd" 'ver116-4h #handle.g, "when characterInput [mAddMarkerFromKeyboard]" 'ver116-4j hGraphWindow=hwnd(#handle) 'get graph window handle calldll #user32, "GetMenu",_ hGraphWindow as ulong,_ ' graph window handle hGraphMenuBar as ulong 'returns handle of menubar 'Get handles for menus that need to conform to the mode hFileMenu=uSubMenuHandle(hGraphMenuBar, 0) 'File menu is position 0 hOptionsMenu=uSubMenuHandle(hGraphMenuBar, menuOptionsPosition) hDataMenu=uSubMenuHandle(hGraphMenuBar, menuDataPosition) hFunctionsMenu=uSubMenuHandle(hGraphMenuBar, menuFunctionsPosition) if menuOperatingCalPosition=0 then hOperatingCalMenu=0 _ else hOperatingCalMenu=uSubMenuHandle(hGraphMenuBar, menuOperatingCalPosition) hTwoPortMenu=uSubMenuHandle(hGraphMenuBar, menuTwoPortPosition) hMultiscanMenu=uSubMenuHandle(hGraphMenuBar, menuMultiscanPosition) 'Get ID of various listed menu items that may need to be hidden/shown in certain modes menuDataS21ID=uMenuItemID(hDataMenu, 2) menuDataLineCalID=uMenuItemID(hDataMenu, 3) menuDataS11ID=uMenuItemID(hDataMenu, 4) menuDataS11DerivedID=uMenuItemID(hDataMenu, 5) menuDataLineCalRefID=uMenuItemID(hDataMenu, 6) menuDataLineCalOSLID=uMenuItemID(hDataMenu, 7) if hasVNA=0 then menuOptionsSmithID=0 else menuOptionsSmithID=uMenuItemID(hOptionsMenu, 5) menuFunctionsFilterID=uMenuItemID(hFunctionsMenu, 0) menuFunctionsMeterID=uMenuItemID(hFunctionsMenu, 1) menuFunctionsRLCID=uMenuItemID(hFunctionsMenu, 2) menuFunctionsCrystalID=uMenuItemID(hFunctionsMenu, 3) menuFunctionsGroupDelayID=uMenuItemID(hFunctionsMenu, 4) 'ver115-8b menuFunctionsCoaxID=uMenuItemID(hFunctionsMenu, 5) menuFunctionsGenerateS21ID=uMenuItemID(hFunctionsMenu, 6) menuMode$="" 'because menus don't conform to any mode now. call ConformMenusToMode 'Hide whatever menu items we don't need for current msaMode$ print #handle.g, "when rightButtonDown [RightButDown]" print #handle.g, "when leftButtonDouble [LeftButDouble]" print #handle, "trapclose [finished]" 'goto [finished] if xit is clicked 'Note that full initialization of graph parameters is done at the commencement of a scan series. #handle.g, "autoresize" #handle, "resizehandler [ResizeGraphHandler]" #handle.Cover, "!hide" 'Used only during resizing #handle.OneStep, "!font Arial 9 bold" : #handle.Continue, "!font Arial 9 bold" 'SEWgraph #handle.Redraw, "!font Arial 9 bold" : #handle.Restart, "!font Arial 9 bold" 'SEWgraph #handle.Redraw, "!hide" 'We start out running so hide this 'Tell graph module what size we are, and calculate scaling ver114-6f call gUpdateGraphObject graphBox$, currGraphBoxWidth, currGraphBoxHeight, _ 'ver115-1c graphMarLeft, graphMarRight, graphMarTop, graphMarBot call gCalcGraphParams 'Calculate new scaling. May change min or max. call gGetXAxisRange xMin, xMax : if startfreq<>xMin or endfreq<>xMax then call SetStartStopFreq xMin, xMax 'ver116-4k return 'From [CreateGraphWindow] sub menuQuitMultiscan 'Quit multiscan 'This command is made in the main window, so the multiscan windows will already be hidden, but haven't actually been closed. multiscanIsOpen=0 : multiscanInProgress=0 call multiscanCloseAll end sub sub ConformMenusToMode 'Make menus and window caption match mode. 'msaMode$ is the current mode. menuMode$ is the mode to which the menus are currently conformed. if msaMode$="SA" then if gentrk=0 then modeTitle$="Spectrum Analyzer Mode" else modeTitle$="Spectrum Analyzer with TG Mode" 'ver115-4f end if if msaMode$="ScalarTrans" then modeTitle$="Tracking Generator Mode" if msaMode$="VectorTrans" then modeTitle$="VNA Transmission Mode" if msaMode$="Reflection" then modeTitle$="VNA Reflection Mode" ver$="Ver";msaVersion$;", Rev"; msaRevision$ 'ver115-5f call uSetWindowText hGraphWindow, "MSA Graph Window for ";modeTitle$; "; "; ver$ 'Note we continue even if there is no mode change, mainly to get multiscan window right 'if msaMode$=menuMode$ then exit sub 'Nothing to do wasTransMode= (menuMode$="ScalarTrans" or menuMode$="VectorTrans") 'whether prior mode was transmission isTransMode= (msaMode$="ScalarTrans" or msaMode$="VectorTrans") 'whether current mode is transmission if wasTransMode and isTransMode then menuMode$=msaMode$ : exit sub 'Nothing needs changing 'Hide every menu item that is ever to be hidden, then show what we want. menuOK=uHideCommandItem(hDataMenu, menuDataS21ID) menuOK=uHideCommandItem(hDataMenu, menuDataLineCalID) menuOK=uHideCommandItem(hDataMenu, menuDataS11ID) menuOK=uHideCommandItem(hDataMenu, menuDataS11DerivedID) menuOK=uHideCommandItem(hDataMenu, menuDataLineCalRefID) menuOK=uHideCommandItem(hDataMenu, menuDataLineCalOSLID) if menuOptionsSmithID>0 then menuOK=uHideCommandItem(hOptionsMenu, menuOptionsSmithID) menuOK=uHideCommandItem(hFunctionsMenu, menuFunctionsFilterID) menuOK=uHideCommandItem(hFunctionsMenu, menuFunctionsCrystalID) menuOK=uHideCommandItem(hFunctionsMenu, menuFunctionsGroupDelayID) 'ver115-8b menuOK=uHideCommandItem(hFunctionsMenu, menuFunctionsMeterID) menuOK=uHideCommandItem(hFunctionsMenu, menuFunctionsRLCID) menuOK=uHideCommandItem(hFunctionsMenu, menuFunctionsCoaxID) menuOK=uHideCommandItem(hFunctionsMenu, menuFunctionsGenerateS21ID) 'Full menu would look like this: 'File Edit Setup Options Data Functions OperatingCal Mode Multiscan Two-Port 'It is possible that Operating Cal, Mode and Two-Port menus were not created, due to limited hardware. In 'that case their position is zero. It is possible for Operating Cal, Multiscan or Two-Port to be hidden, 'in which case their flag menuXXXShowing equals zero. 'Hide Two-Port, Multiscan and Operating Cal, but start at right side 'so hiding one doesn't change the position of another. if menuTwoPortShowing then menuOK=uHideSubMenu(hGraphMenuBar, menuTwoPortPosition) 'ver116-1b menuTwoPortShowing=0 if menuMultiscanShowing then menuOK=uHideSubMenu(hGraphMenuBar, menuMultiscanPosition) 'ver116-1b menuMultiscanShowing=0 'If we have operating cal menu, hide it if menuOperatingCalShowing then menuOK=uHideSubMenu(hGraphMenuBar, menuOperatingCalPosition) menuOperatingCalShowing=0 end if 'Multiscan will only be shown for SA without TG, so Operating cal will not be shown. 'This will move Multiscan left one position. if menuModePosition=0 then menuMultiscanPosition=6 else menuMultiscanPosition=7 'Two-Port will only be shown for full VNA modes, so Operating cal and Mode will be shown and 'Multiscan will not. This puts Two-Port after Mode. menuTwoPortPosition=menuModePosition+1 'We now have bare minimum of menus. 'Make adjustments from here if msaMode$<>"Reflection" then menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsFilterID,0, "Filter Analysis", 0) frontEndID=uMenuItemID(hFileMenu,5) ' "Load Front End" menu is sixth in File menu, which is position 5 if msaMode$<>"SA" then menuOK=uGrayMenu(hFileMenu, frontEndID) 'Disable Load Front End 'ver115-9d menuOK=uShowMenuItem(hGraphMenuBar, -1, hOperatingCalMenu, "Operating Cal", menuOperatingCalPosition) 'Operating Cal menu menuOperatingCalShowing=1 menuOK=uShowMenuItem(hGraphMenuBar, -1, hTwoPortMenu, "Two-Port", menuTwoPortPosition) menuTwoPortShowing=1 if msaMode$="Reflection" then 'Reflection Mode menuOK=uShowMenuItem(hDataMenu, menuDataS11ID, 0,"S11 Parameters", 2) 'S11 is third in Data menu menuOK=uShowMenuItem(hDataMenu, menuDataS11DerivedID, 0,"S11 Derived Data", 3) menuOK=uShowMenuItem(hDataMenu, menuDataLineCalRefID, 0, "Cal Reference", 4) menuOK=uShowMenuItem(hDataMenu, menuDataLineCalOSLID, 0, "OSL Info",5) menuOK=uShowMenuItem(hOptionsMenu, menuOptionsSmithID, 0, "Smith Chart", 5) 'Smith chart is 6th in Options list menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsMeterID, 0,"Component Meter",0) 'Component meter is first on Functions list menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsRLCID, 0,"RLC Analysis",1) menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsCoaxID, 0, "Coax Parameters", 2) 'Coax is 3rd on Functions list menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsGenerateS21ID, 0, "Generate S21", 3) else 'Transmission Mode--Scalar or Vector menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsMeterID, 0,"Component Meter",1) 'Component meter is second on Functions list menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsRLCID, 0,"RLC Analysis",2) menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsCrystalID, 0, "Crystal Analysis", 3) 'Crystal is 4th on Functions list if msaMode$="VectorTrans" then menuOK=uShowMenuItem(hFunctionsMenu, menuFunctionsGroupDelayID, 0, "Group Delay", 4) 'ver115-8b menuOK=uShowMenuItem(hDataMenu, menuDataS21ID, 0,"S21 Parameters", 2) 'S21 is third in Data menu menuOK=uShowMenuItem(hDataMenu, menuDataLineCalID, 0, "Installed Line Cal", 3) end if end if if msaMode$="SA" then menuOK=uEnableMenu(hFileMenu, frontEndID) 'Enable Load Front End 'ver115-9d end if if msaMode$="SA" and gentrk=0 then 'Display Multiscan window only when in SA mode without TG menuOK=uShowMenuItem(hGraphMenuBar, 0, hMultiscanMenu, "Multiscan", menuMultiscanPosition) menuMultiscanShowing=1 showID=uMenuItemID(hMultiscanMenu,1) ' "Show Multiscan" menu quitID=uMenuItemID(hMultiscanMenu,2) ' "Quit Multiscan" menu 'If multiscan is open, allow user to Show or Quit if multiscanIsOpen then menuOK=uEnableMenu(hMultiscanMenu, showID) 'Enable Show menuOK=uEnableMenu(hMultiscanMenu, quitID) 'Enable Quit else menuOK=uGrayMenu(hMultiscanMenu, showID) 'Gray Show menuOK=uGrayMenu(hMultiscanMenu, quitID) 'Gray Quit end if end if call uDrawMenu hGraphWindow menuMode$=msaMode$ 'We are now conformed to the current mode. end sub sub mMarkToCenter btn$ 'Recenter around marker frequency if selMarkerID$="" then notice "No marker is selected." exit sub 'No marker selected so nothing to do end if 'Get frequency from from marker number from marker ID newCenterFreq=gMarkerCurrXVal(mMarkerNum(selMarkerID$)) newCenterFreq=int(1000000*newCenterFreq+0.5)/1000000 'Round to nearest Hz. call SetCenterSpanFreq newCenterFreq, sweepwidth 'Set new center with old span; also updates startfreq and endfreq if haltsweep=1 then continueCode=3 'Forces restart if in midsweep. else call RequireRestart end if end sub [menuExpandSweep] call Expand if haltsweep then continueCode=3 : goto [PostScan] else goto [Restart] end if sub Expand 'Expand L to R markers to be the bounds of the sweep. Called from [menuExpandSweep] if hasMarkL=0 and hasMarkR=0 then exit sub 'No L or R; nothing to do. if hasMarkL=1 then newLowerFreq=gMarkerCurrXVal(mMarkerNum("L")) 'Get L frequency else newLowerFreq=startfreq end if if hasMarkR=1 then newUpperFreq=gMarkerCurrXVal(mMarkerNum("R")) 'Get R frequency else call gGetPointVal globalSteps+1, newUpperFreq, dum1, dum2 'Use final frequency ver114-7d end if 'Note that when the first scan is completed, the marker point numbers will be 'redetermined from their current frequencies, so L and R will be moved to the 'edges of the scan. call SetStartStopFreq newLowerFreq, newUpperFreq 'Enter new frequencies in globals end sub sub btnRedraw btn$ 'Redraw button was pushed 'haltsweep=1 if scan is in progress, so we set flag to halt sweeping on return from the "scan" 'command that enabled this button to be handled. if haltsweep=1 then continueCode=1 : exit sub 'Signal to halt after "scan" command call mDeleteMarker "Halt" 'Delete Halt marker ver114-4c if smithGraphHndl$()<>"" then call smithDrawChart 'To recreate bitmap of background, just in case it is messed up ver115-2c refreshGridDirty=1 : call RefreshGraph 0 'ver114-7d end sub sub RedrawGraph restoreErase 'Redraw all layers of the graph 'Redraw entire graph from scratch, using the point values previously accumulated. refreshRedrawFromScratch=1 call RefreshGraph restoreErase end sub sub RememberState 'Record state before loading a context, to allow detection of certain changes 'We want to record enough to determine whether we have to restart, do a full redraw or just 'refresh and redraw setup info. 'Some of these changes can be made during a scan without an immediate redraw, but when loading 'a context we will force a halt. 'Change to msaMode$ may reqire a new graph window prevMSAMode$=msaMode$ 'Changes to these will require a complete Restart prevFreqMode=freqBand 'ver115-1c prevPath$=path$ 'ver116-4j call gGetXAxisRange prevStartF, prevEndF : prevBaseF=baseFrequency 'ver116-4k call gGetIsLinear prevXIsLinear, prevY1IsLinear, prevY2IsLinear prevSteps=globalSteps prevSweepDir=gGetSweepDir() : prevAlternate=alternateSweep prevGenTrk=gentrk : prevSpurCheck=spurcheck 'ver114-6k prevTGOff=offset : prevSGFreq=sgout 'ver115-1a prevPath$=path$ 'ver115-1a 'Changes to these will require calling gCalcGraphParams and then a full Redraw call gGetYAxisRange 1, prevStartY1, prevEndY1 : call gGetYAxisRange 2, prevStartY2, prevEndY2 call gGetNumDivisions prevHorDiv, prevVertDiv prevSwitchFR=switchFR 'forward/reverse switch affects axis labeling ver116-1b 'Changes to graph data type will require a replotting to get the proper transform, 'and redrawing from scratch to get axis labeling correct. prevY1DataType=Y1DataType 'ver115-1b deleted source constants prevY2DataType=Y2DataType 'If in a mode where these are relevant, changes to the following are treated 'the same as a change to the data source. 'ver114-7e added these prevS21JigAttach$=S21JigAttach$ prevS21JigR0=S21JigR0 'ver115-1e prevS21JigShuntDelay=S21JigShuntDelay 'ver115-1f prevS11BridgeR0=S11BridgeR0 : prevS11GraphR0=S11GraphR0 prevS11JigType$=S11JigType$ 'ver115-1b 'Changes to these require a full Redraw from existing Y values 'Note this refers to magtable data, not graph data prevDataChanged=0 'If changed, this has to be set elsewhere 'Changes to these may require redraw from scratch or just normal refresh prevY1Disp=Y1DisplayMode : prevY2Disp=Y2DisplayMode 'If auto scale gets turned on, we will signal to do autoscale at end of sweep, 'or do it immediately if we are halted. prevAutoScaleY1=autoScaleY1 : prevAutoScaleY2=autoScaleY2 'Changing planeadj could require immediate recalc of existing data prevPlaneAdj=planeadj 'ver114-7f 'If none of the above are changed, we will do a RefreshGraph with refreshGridDirty=1 'Items that reach here include: 'Marker Options, Graph Appearance, trace width and trace color 'RBW, video filter, SigGen freq, TG offset, spur test, wait time and plane extension end sub [DetectFullChanges] 'Take appropriate redraw/restart action in response to certain changes 'This is a gosub routine so it can access [ChangeMode]. This needs to be called only if msaMode$ may have changed; 'otherwise call DetectChanges directly. doRestart=0 if prevMSAMode$<>msaMode$ then gosub [ChangeMode]: doRestart=1 call DetectChanges doRestart return 'ver114-6e added DetectChanges; modver114-7f to move mode change detection to gosub routine sub DetectChanges doRestart 'Take appropriate redraw/restart action in response to certain changes 'We want to record enough to determine whether we have to restart, do a full redraw or just 'refresh and redraw setup info. If doRestart=1, we will specify a restart no matter what. 'Some of these changes can be made during a scan without an immediate redraw, but when loading 'a context we will force a halt. 'We set continueCode to specify the user action required: 0=continue; 2=wait; 3=restart 'TO DO--The concept has been to take the minimum action necessary, primarily for speed, but also to 'preserve existing data when possible. Now that we have [PartialRestart], it might make more sense 'to require [PartialRestart] whenever there is any doubt, and to zero out the data when it no longer 'makes sense. The caller can then do [PartialRestart] and regraph the data. In fact, we could change 'this subroutine to a gosub, and take all necessary action here. But it may be better for the user to do 'the restart, in case a series of changes are being made--the restart can be done at the end of the series. 'Some things we do here, such as recalculating graph params, would become unnecessary. continueCode=0 'Assume we can continue when we are done here doCalcAndRedraw=0 doTransform=0 dataTypeChanged=0 'ver115-1b 'For certain switch settings, we don't bother to determine whether a change was made; we just 'implement the current setting. call SelectVideoFilter 'Also makes auto wait calculations if necessary ver116-1b call SelectLatchedSwitches lastSetBand 'transmit/reflect, forward/reverse; leaves band as it is (handled by restart) 'ver116-1b ver116-4s if calCanUseAutoWait=0 and useAutoWait then 'ver116-1b 'If the path calibration had insufficient or bad data, auto wait was disabled when loading 'the file. If preferences are loaded specifying to use it, we need to override that. useAutoWait=0 : wate=100 end if 'Changes to graph data type will require recalculating grid labels with new format, 'recalculating the transform and then 'redrawing from scratch to get axis labeling correct. if prevY1DataType<>Y1DataType or prevY2DataType<>Y2DataType then 'ver115-4g call gSetDoAxis (Y1DataType<>constNoGraph), (Y2DataType<>constNoGraph) 'Tell graph module whether we have graphs ver115-2c call ImplementDisplayModes 'ver114-6e doCalcAndRedraw=1 : dataTypeChanged=1 :doTransform=1 'ver115-1b end if 'Changes to these will require a complete Restart call gGetXAxisRange currStartF, currEndF call gGetIsLinear currXIsLinear, currY1IsLinear, currY2IsLinear if freqBand<>prevFreqMode or currStartF<>prevStartF _ or currEndF<>prevEndF or prevSteps<>globalSteps or baseFrequency<>prevBaseF then doRestart=1 'ver116-4k if currXIsLinear<>prevXIsLinear or currY1IsLinear<>prevY1IsLinear _ or currY2IsLinear<>prevY2IsLinear then doRestart=1 if prevGenTrk<>gentrk or prevSpurCheck<>spurcheck then doRestart=1 'ver114-6k if prevTGOff<>offset or prevSGFreq<>sgout then doRestart=1 'ver115-1a if prevPath$<>path$ then call SelectFilter filtbank : doRestart=1 'ver116-4j if doRestart then 'If we are using fixed data as the reference source and any of the above changed, 'we can no longer use it. if referenceLineType=1 then referenceLineType=0 : referenceTrace=0 : call gClearAllReferences 'ver114-7f end if if prevSweepDir<>gGetSweepDir() or prevAlternate<>alternateSweep then doRestart=1 if prevPath$<>path$ then doRestart=1 'ver115-1a 'If in a mode where these are relevant, we need to require Restart, 'but do not do anything to the existing data. Note that the calibration 'will be invalidated elsewhere in these cases, so there is no meaningful way 'to transform the data. if msaMode$="Reflection" then 'ver115-1f if prevS21JigAttach$<>S21JigAttach$ then doRestart=1 if prevS21JigR0<>S21JigR0 then doRestart=1 if prevS21JigShuntDelay<>S21JigShuntDelay then doRestart=1 if prevS11JigType$<>S11JigType$ or prevS11BridgeR0<>S11BridgeR0 then doRestart=1 end if if doRestart then 'If the data changed, we should redraw it before we exit. We assume the frequency 'points of the data are consistent with any changes to the graph module frequency points. 'If the data did not change, we may not be able to redraw it with the new sweep parameters so 'we don't try. continueCode=3 if prevDataChanged=0 then exit sub call gGenerateXValues gPointCount() 'Make sure x values correspond to sweep parameters 'For RLC or fixed value reference, recalculate reference data if referenceLineType>1 then call CreateReferenceSource : call CreateReferenceTransform 'ver114-7f doCalcAndRedraw=1 doTransform=1 end if 'Changes to these will require calling gCalcGraphParams and then a full Redraw from existing Y values rescaleReferences=0 call gGetYAxisRange 1, currStartY1, currEndY1 call gGetYAxisRange 2, currStartY2, currEndY2 call gGetNumDivisions currHorDiv, currVertDiv if prevSwitchFR<>switchFR then doCalcAndRedraw=1 'Forward/Reverse switch affects axis labels ver116-1b if currStartY1<>prevStartY1 or currEndY1<>prevEndY1 then doCalcAndRedraw=1 : rescaleReferences=1 if currStartY2<>prevStartY2 or currEndY2<>prevEndY2 then doCalcAndRedraw=1 : rescaleReferences=1 if currHorDiv<>prevHorDiv or currVertDiv<>prevVertDiv then doCalcAndRedraw=1 if rescaleReferences then call CreateReferenceTransform if doCalcAndRedraw then 'ver115-1b if dataTypeChanged or prevSwitchFR<>switchFR then call UpdateGraphDataFormat 0 'To get new data format ver116-1b call gCalcGraphParams 'Calculate new scaling. May change min or max. call gGetXAxisRange xMin, xMax if startfreq<>xMin or endfreq<>xMax then call SetStartStopFreq xMin, xMax : continueCode=3 end if doRedraw=doCalcAndRedraw if (prevAutoScaleY1=0 and autoScaleY1=1) or (prevAutoScaleY2=0 and autoScaleY2=1) then _ autoScaleTurnedOn=1 else autoScaleTurnedOn=0 'ver114-7a if autoScaleY1=1 or autoScaleY2=1 then autoScaleIsOn=1 else autoScaleIsOn=0 'ver114-7a 'If data changes, recalc x pixel values and require a restart, though proceeding will destroy the new data if msaMode$="Reflection" and prevS11GraphR0<>S11GraphR0 then continueCode=3 : doTransform=1 'ver115-1f if prevDataChanged then continueCode=3 : doTransform=1 if doTransform then call UpdateGraphDataFormat 0 'Update data formatting; may also affect data transform call RecalcYValues if autoScaleIsOn then call PerformAutoScale 'autoscale with the new data 'ver114-7a autoScaleTurnedOn=0 'Since we just did autoscale ver114-7e end if doRedraw=1 'Signal to do complete redraw from scratch end if 'If auto scale has been turned on, we signal to do the autoscaling at the end of the sweep or on redraw if autoScaleTurnedOn then refreshAutoScale=1 'ver114-7a if doRedraw then call RedrawGraph 0: exit sub 'Changing trace style requires recreating the traces and refreshing if it has just 'been turned on (since we have no accumulated trace draw commands) or if it 'was and remains on but the style changed (between histo/normal or erase/stick). if prevY1Disp<>Y1DisplayMode and (Y1DisplayMode<>0 or prevY1Disp=0) then doRefreshTraces=1 'ver114-7d if prevY2Disp<>Y2DisplayMode and (Y2DisplayMode<>0 or prevY2Disp=0) then doRefreshTraces=1 'ver114-7d if doRefreshTraces then refreshTracesDirty=1 : refreshGridDirty=1 : call RefreshGraph 0 : exit sub 'ver114-7d 'Everything else we redraw everything except the traces from scratch; traces 'will be drawn from gTrace1$() and gTrace2$() 'Marker Options, Graph Appearance, trace width and trace color will be in this category 'Also includes primaryAxisNum, which has no immediate effects except the order of marker info refreshGridDirty=1 'We don't redraw if in stick mode, because the "stuck" traces will be erased. if haltsweep=1 then doErasure=1 else doErasure=0 'Do erasure gap if still sweeping if isStickMode=0 then call RefreshGraph doErasure end sub sub RecalcYValues 'Recalculate Y values for existing graph points, and change in the graph module call gGetMinMaxPointNum pMin, pMax for i=pMin to pMax call CalcGraphData i-1, y1, y2, 0 'i-1 to get step number from point number ver114-6h if referenceDoMath=2 then 'ref math is to be done on graph values ver115-5d if (referenceTrace and 1) then _ y1=referenceOpA*referenceTransform(thisstep+1, 1)+referenceOpB*y1 if (referenceTrace and 2) then _ y2=referenceOpA*referenceTransform(thisstep+1, 2)+referenceOpB*y2 end if call gChangePoints i, y1, y2 'Change point values in graph module next i end sub sub RefreshGraph restoreErase 'Quick redraw of graph area 'This uses saved information from the most recent gDrawGrid (called in RedrawGraph) 'to quickly redraw the graph area and about 20 pixels around it to effectively erase 'the traces and markers, and also uses such saved info to quickly redraw the traces. 'We then redraw the markers at their current locations. The marker info box is also 'updated; the first step in that update is to draw a filled box with a border, which 'erases everything underneath. We don't flush, so if the window gets covered the markers 'and traces will disappear. We discard to clear some memory. 'This may be called as a result of some user action in the middle of scanning. To avoid 'interference with the dynamic scan process, we Pause dynamic scanning and then resume it. 'In a language faster than Liberty Basic we could just use RedrawGraph to redraw from scratch. 'The following globals determine whether we redraw various components from scratch or by a faster method. 'global refreshGridDirty 'Forces grid (and labels, title) and setup info and references to redraw from scratch in RefreshGraphs 'global refreshTracesDirty 'Forces traces and references to be redrawn from raw Y1 and Y2 values in RefreshGraph 'global refreshMarkersDirty 'Forces marker relocation based on frequency 'global refreshAutoScale 'Forces autoscaling of axes; implies refreshRedrawFromScratch 'global refreshRedrawFromScratch 'Forces complete redraw from scratch in RefreshGraph call gMouseQueryClear 'Should already be clear, but right-clicking during MouseOver can confuse ver116-4k if refreshAutoScale then 'ver114-7a call PerformAutoScale 'Recalculates scaling in graph module refreshRedrawFromScratch=1 end if recreateReferences=0 if refreshRedrawFromScratch or refreshGridDirty then call gDrawGrid call DrawSetupInfo recreateReferences=1 else call gRefreshGrid end if if referenceLineType<>0 then 'ver114-7f if recreateReferences or refreshTracesDirty=1 then if referenceLineType>1 then call CreateReferenceSource call CreateReferenceTransform call gClearAllReferences if referenceDoMath=0 then 'don't draw if we are using ref for math ver114-8b if (referenceTrace and 2) then call gAddReference 1,CreateReferenceTraces$(referenceColor2$,referenceWidth2,2) 'Do Y2 reference if (referenceTrace and 1) then _ call gAddReference 2,CreateReferenceTraces$(referenceColor1$,referenceWidth1,1) end if end if call PrintReferenceHeading if referenceDoMath=0 then call gDrawReferences 'don't draw if we are using ref for math ver115-5d end if call gPauseDynamicScan 'Keeps the trace redraws from accumulating if refreshTracesDirty=1 or refreshRedrawFromScratch then call gRecreateTraces 1 'Recreate and draw trace draw commands 'ver114-6e 'ver114-7e else call gRefreshTraces 'Draw from accumulated trace draw commands 'ver114-6e end if if restoreErase then call gRestoreErasure call gResumeDynamicScan 'Discard draw commands if scan is still in progress; otherwise we flush a bit later if haltsweep=1 then #graphBox$, "discard" 'In case frequency axis has changed, we want to update the marker point numbers 'to maintain their prior frequencies, if possible. We do this on every Refresh or Redraw 'through the end of the first scan. if refreshMarkersDirty or refreshRedrawFromScratch then call gDetermineMarkerPointNumbers 'locate floating markers call gUpdateMarkerXVal 'Save frequency values for markers call mDrawMarkerInfo 'Draw marker info under the x axis; also updates marker locations if doGraphMarkers then call gDrawMarkers if multiscanIsOpen then call multiscanMarkCurrentWindow 'mark current graph 'ver115-9a 'Discard draw commands if scan is still in progress; otherwise flush if haltsweep=1 then #graphBox$, "discard" else #graphBox$, "flush" if smithGraphHndl$()<>"" then 'ver115-1b draw smith chart if we have one call smithSetGraphMarkers doGraphMarkers 'Tell smith whether to draw markers on graph ver115-2c if referenceLineType<>0 and (referenceTrace and 4=4) then _ doSmithRef=(referenceDoMath=0) else doSmithRef=0 'draw non-fixed value reference ver115-7a call smithRefresh doSmithRef 'Draw chart and graph, with possible reference line end if refreshForceRefresh=0 'Clear refresh flags, since we just redrew refreshGridDirty=0 refreshTracesDirty=0 refreshMarkersDirty=0 refreshAutoScale=0 'ver114-7b refreshRedrawFromScratch=0 end sub sub PerformAutoScale 'do autoscaling of axes as required, but no redraw 'If autoscale is on then calculate the scale and redraw from raw values if autoScaleY1 then call CalcAutoScale 1, newMin, newMax : call SetY1Range newMin, newMax 'ver115-3b if autoScaleY2 then call CalcAutoScale 2, newMin, newMax : call SetY2Range newMin, newMax call gCalcGraphParams 'Calculate new scaling. May change min or max. call gGetXAxisRange xMin, xMax : if startfreq<>xMin or endfreq<>xMax then call SetStartStopFreq xMin, xMax end sub sub DrawSetupInfo 'Draw info about MSA setup at right side of graph box call gGetGraphicsSize InfoX, dum 'Get width InfoX=InfoX-100 : InfoY=graphMarTop+2 call gGetInfoColors textColor$, backColor$ #graphBox$, "font Tahoma 8 bold;color ";textColor$;";backcolor ";backColor$ if msaMode$="SA" then 'ver115-1b rewrote this if... block 'SA mode, either with or without TG if gentrk=0 then 'ver115-4f call gPrintText "Spect. Analyzer", InfoX-10,16 else call gPrintText "Spect. Analyzer with TG", InfoX-40,16 end if else if msaMode$="ScalarTrans" then call gPrintText "SNA Transmission", InfoX-10,16 'ver115-4e if msaMode$="VectorTrans" then call gPrintText "VNA Transmission", InfoX-10,16 'ver115-1c revised the printing of the cal level if msaMode$="Reflection" then call gPrintText "VNA Reflection", InfoX-10,16 if applyCalLevel0 then call gPrintText freqBand; "G", InfoX, 30 'ver116-4s if suppressHardware then call gPrintText "No MSA", InfoX, 44 'ver115-6c 'Base frequency, if not zero if baseFrequency<>0 then call gPrintText "Base Freq(MHz)=", InfoX, InfoY : InfoY=InfoY+16 : _ 'ver116-4k call gPrintText using("####.######", baseFrequency), InfoX+5, InfoY : InfoY=InfoY+16 'ver116-4k call gPrintText "RBW=";str$(finalbw)+"kHz",InfoX, InfoY : InfoY=InfoY+16 'ver116-1b call gPrintText "Vid=";videoFilter$,InfoX, InfoY : InfoY=InfoY+16 'ver116-1b put this back in if useAutoWait then wait$=autoWaitPrecision$ else wait$=str$(wate)+" ms" call gPrintText "Wait=";wait$, InfoX, InfoY : InfoY=InfoY+16 'Print number of steps call gPrintText "Steps=";str$(globalSteps), InfoX, InfoY : InfoY=InfoY+16 if gGetXIsLinear() then 'Print stepfreq as Hz, KHz, etc. with up to 3 whole places, max 4 decimals 'and max 5 total significant digits. We don't do this for log sweeps because 'the freq/step is not constant stepfreq=(endfreq-startfreq)/globalSteps 'stepfreq is only calculated for printing ver115-1b stepSize$=uFormatted$(1000000*stepfreq,"3,4,5//UseMultiplier//suffix=Hz") call gPrintText uCompact$(stepSize$);"/Step", InfoX, InfoY : InfoY=InfoY+16 'Print Freq/div. also done only for linear sweep call gGetNumDivisions nHorDiv, nVertDiv stepSize$=uFormatted$(1000000*sweepwidth/nHorDiv,"3,4,5//UseMultiplier//suffix=Hz") call gPrintText uCompact$(stepSize$);"/Div", InfoX, InfoY : InfoY=InfoY+16 end if if msaMode$="SA" and TGtop>0 then 'ver115-4f if gentrk=0 then freq$=str$(sgout) if len(freq$)<7 then 'ver116-4d call gPrintText "SG="+freq$, InfoX, InfoY: InfoY=InfoY+16 else call gPrintText "SG=", InfoX, InfoY: InfoY=InfoY+14 'ver116-4d call gPrintText " "+freq$, InfoX, InfoY: InfoY=InfoY+16 end if else if normrev=0 then nr$="TG=Normal" else nr$="TG=Reverse" call gPrintText nr$, InfoX, InfoY: InfoY=InfoY+16 freq$=str$(offset) if len(freq$)<2 then 'ver115-4g call gPrintText "Offset="+freq$, InfoX, InfoY: InfoY=InfoY+16 else call gPrintText "Offset=", InfoX, InfoY: InfoY=InfoY+14 call gPrintText " "+freq$, InfoX, InfoY: InfoY=InfoY+16 end if end if end if if msaMode$<>"SA" and msaMode$<>"ScalarTrans" then call gPrintText "Exten=";str$(planeadj)+" ns", InfoX, InfoY : InfoY=InfoY+16 'ver114-5f end if if msaMode$="Reflection" then _ 'ver116-4k call gPrintText "Z0=";uFormatted$(S11GraphR0, "3,4,5//UseMultiplier//DoCompact//SuppressMilli"), InfoX, InfoY : InfoY=InfoY+16 if msaMode$<>"SA" then #graphBox$, "font Tahoma 8 bold;color ";textColor$;";backcolor ";backColor$ if switchFR=0 then directText$=">DUT" else directText$="DUT<" call gPrintText directText$, InfoX, InfoY : InfoY=InfoY+16 end if s$="" if referenceLineType<>0 and referenceDoMath<>0 then 'If doing math with reference line, so indicate ver116-1b if referenceOpA=1 and referenceOpB=1 then s$="Data+Ref" if referenceOpA=1 and referenceOpB=-1 then s$="Ref-Data" if referenceOpA=-1 and referenceOpB=1 then s$="Data-Ref" call gPrintText s$, InfoX, InfoY : InfoY=InfoY+16 end if end sub sub PrintMessage 'Print message above top of marker info area; Limited to 75 characters; don't print if blank 'The message is in message$ call gPrintMessage message$ 'ver116-4i end sub sub SetY1Range bot, top 'Set range of Y1 axis 'Note gCalcGraphParams must be called to fully update graph module call gSetYAxisRange 1, bot, top Y1Bot=bot Y1Top=top end sub sub SetY2Range bot, top 'Set range of Y2 axis 'Note gCalcGraphParams must be called to fully update graph module call gSetYAxisRange 2, bot, top Y2Bot=bot Y2Top=top end sub [ManageTestSetups] 'Menu item to load/save test setups WindowWidth = 575 : WindowHeight = 435 UpperLeftX=int((DisplayWidth-WindowWidth)/2) : UpperLeftY=int((DisplayHeight-WindowHeight)/2) ForegroundColor$="black" : BackgroundColor$="buttonface" : ListboxColor$ = "white" if haltsweep then gosub [FinishSweeping] setupTotalNum=10 for i=0 to setupTotalNum-1 : setupList$="" : next i listbox #testsetup.List, setupList$(), [setupListClick], 105, 92, 355, 170 statictext #testsetup, "To save a test setup consisting of the current sweep settings and calibration data,", 20, 12, 500, 20 statictext #testsetup, "select a slot, change the name if desired, and click Save.", 20, 32, 450, 20 statictext #testsetup, "To load a test setup, select it and click Load.", 20, 57, 450, 20 TextboxColor$ = "white" textbox #testsetup.Name, 140, 307, 300, 25 button #testsetup.Create,"Create Name",[setupCreateName], UL, 445, 300, 100, 30 button #testsetup.Save,"Save",[setupSave], UL, 40, 352, 100, 40 button #testsetup.Load,"Load",[setupLoad], UL, 160, 352, 100, 40 button #testsetup.Delete,"Delete Setup",[setupDelete], UL, 280, 352, 100, 40 button #testsetup.Done,"Done",[setupDone], UL, 400, 352, 100, 40 statictext #testsetup, "Name:", 90, 307, 40, 20 '-----End GUI objects code open "Test Setups" for dialog_modal as #testsetup print #testsetup, "font ms_sans_serif 10" print #testsetup, "trapclose [setupDone]" #testsetup.List, "singleclickselect" gosub [setupFillList] setupCurrentSelection=-1 'start with none selected #testsetup.Load, "!disable" : #testsetup.Delete, "!disable" : #testsetup.Save, "!disable" 'Can't act without selection setupHaveDonePartialRestart=0 'see setupSave wait [setupSave] 'Save button 'We do a restart but return before taking any data. This makes sure any changes the user has 'made before coming here, such as frequency range, are actually implemented so they can be saved properly.But this only 'needs to be done once while in this dialog. #testsetup.Load, "!disable" : #testsetup.Delete, "!disable" : #testsetup.Save, "!disable" : #testsetup.Done, "!disable" if setupHaveDonePartialRestart=0 then setupHaveDonePartialRestart=1 gosub [PartialRestart] 'ver115-3c end if fHndl$=SetupOpenFile$(setupCurrentSelection, 0) '0 means output if fHndl$="" then notice "Error in opening file" #testsetup.Save, "!enable" : #testsetup.Done, "!enable" wait end if 'We save the file description as line 1, preceded by a "!" #testsetup.Name, "!contents? setupName$" newLine$=chr$(13) print #fHndl$, "!";setupName$ 'We then save the necessary info as contexts. 'First, the sweep context. We don't start with StartContext because we know what the file starts with print #fHndl$, TraceContext$();newLine$;"EndContext";newLine$;"StartContext Sweep"; newLine$;SweepContext$();newLine$;"EndContext" 'ver115-4a 'Next any applicable Band cal file. if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then if BandLineCalIsCurrent() then call BandLineCalContextToFile fHndl$ end if if msaMode$="Reflection" then if BandOSLCalIsCurrent() then call OSLCalContextToFile fHndl$, 1 '1 means band cal end if close #fHndl$ : fHndl$="" setupList$(setupCurrentSelection-1)=setupCurrentSelection;". ";setupName$ #testsetup.List, "Reload" #testsetup.Load, "!enable" : #testsetup.Delete, "!enable" : #testsetup.Save, "!enable" : #testsetup.Done, "!enable" wait [setupLoad] 'Load button #testsetup.Load, "!disable" : #testsetup.Delete, "!disable" : #testsetup.Save, "!disable" : #testsetup.Done, "!disable" fHndl$=SetupOpenFile$(setupCurrentSelection, 1) '1 means input if fHndl$="" then notice "Error in opening file" #testsetup.Load, "!enable" : #testsetup.Delete, "!enable" : #testsetup.Save, "!enable" : #testsetup.Done, "!enable" wait end if joint$="" trace$="" : setupIsFirstLine=1 while EOF(#fHndl$)=0 'Assemble the trace context lines into a single string Line Input #fHndl$, s1$ if Upper$(Trim$(s1$))="ENDCONTEXT" then exit while if setupIsFirstLine=0 then 'Skip first line, which is the descriptive file name trace$=trace$;joint$;s1$ joint$=chr$(13) end if setupIsFirstLine=0 wend joint$="" restoreContext$="" :setupIsFirstLine=1 while EOF(#fHndl$)=0 'Assemble the sweep context lines into a single string for [RestoreSweepContext] Line Input #fHndl$, s1$ if Upper$(Trim$(s1$))="ENDCONTEXT" then exit while if setupIsFirstLine=0 then 'Skip first line, which is StartContext Sweep restoreContext$=restoreContext$;joint$;s1$ joint$=chr$(13) end if setupIsFirstLine=0 wend call RememberState 'So we can detect any change ver116-4d restoreIsValidation=0 'Indicates to actually restore data traceStart=1 restoreErr$=RestoreTraceContext$(trace$,traceStart,0) 'Actual trace restoration if restoreErr$="" then gosub [RestoreSweepContext] 'Actual sweep restoration gosub [DetectFullChanges] 'ver116-4d if restoreErr$<>"" then notice "Error in loading context: ";restoreErr$ else setupNumCalPoints=0 if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then setupNumCalPoints=GetBandLineCalContextFromFile(fHndl$) if msaMode$="Reflection" then setupNumCalPoints=OSLGetCalContextFromFile(fHndl$, 1) '1 means band cal if setupNumCalPoints>0 then desiredCalLevel=2 'So band cal gets used end if close #fHndl$ : fHndl$="" close #testsetup 'We do a restart but return before taking any data. This makes sure everything is implemented 'consistently, in case we end up resaving the data we just loaded. gosub [PartialRestart] 'ver115-3c setupHaveDonePartialRestart=1 'In case of Save, we don't need to do the partial restart again 'call RequireRestart 'delver115-2a wait [setupDelete] 'Delete button fName$=DefaultDir$;"\MSA_Info\TestSetups\TestSetup";setupCurrentSelection;".txt" call uDeleteFile fName$ 'Delete the file setupList$(setupCurrentSelection-1)=setupCurrentSelection;". Empty" #testsetup.List, "Reload" #testsetup.Load, "!disable" : #testsetup.Delete, "!disable" 'No existing file; can't load or delete wait [setupDone] 'Done button or dialog closed #testsetup.Done, "!disable" 'Prevents double click which causes trouble in debugger close #testsetup wait [setupFillList] 'fill setupList$ with names of existing files 'The files are in a folder called TestSetups in the MSA_Info folder setupPath$=DefaultDir$;"\MSA_Info\TestSetups" files DefaultDir$;"\MSA_Info", "", fileInfo$() 'get directory list nFolders=val(fileInfo$(0,1)) folderFound=0 for i=1 to nFolders if fileInfo$(i,1)="TestSetups" then folderFound=1 : exit for 'We found the TestSetups folder next i if folderFound=0 then if mkDir(setupPath$)<>0 then notice "Error creating Setup folder.": return 'Folder doesn't exist, so make one end if for i=1 to setupTotalNum 'Check for each of the setupTotalNum possible files 'File exists; we need to get the descriptive name if SetupOpenFile$(i,1)="" then setupList$(i-1)=i;". Empty" else 'File is open. Get its description and close it setupName$=SetupGetDescription$("#setupFile") 'Get description of file #setupFile setupList$(i-1)=i;". ";setupName$ close #setupFile end if next i #testsetup.List, "Reload" 'transfer array info to the visible list return [setupListClick] 'User clicked an item on the list 'Enter name of selected item into name box. #testsetup.List, "selectionIndex? setupCurrentSelection" setupFullName$=setupList$(setupCurrentSelection-1) 'setupCurrentSelection starts with one; array starts with 0 dotPos=instr(setupFullName$, ".") 'Name starts with number then period. Find the period setupShortName$=Mid$(setupFullName$,dotPos+2) 'omit the number, the dot, and the space after the dot. #testsetup.Name, setupShortName$ #testsetup.Save, "!enable" if setupShortName$="Empty" then #testsetup.Load, "!disable" : #testsetup.Delete, "!disable" 'No existing file; can't load or delete #testsetup.Name, SetupName$() 'Print useful name, not "Empty" else #testsetup.Load, "!enable" : #testsetup.Delete, "!enable" 'file exists end if wait [setupCreateName] 'Create name for current setup; put it in name box #testsetup.Name, SetupName$() wait function SetupName$() 'Return descriptive name for current setup select msaMode$ case "SA" s$="SA/" case "ScalarTrans" s$="SA/TG" case "VectorTrans" s$="VNA Trans/" case else ' "Reflection" s$="VNA Reflect/" end select if gGetXIsLinear() then s$=s$;"Linear/" else s$=s$;"Log/" SetupName$=s$;startfreq;" to ";endfreq;"/";path$ end function function SetupOpenFile$(N, isInput) 'Open setup file; return its handle as text or blank if error 'If isInput, open for input, otherwise for output fName$=DefaultDir$;"\MSA_Info\TestSetups\TestSetup";N;".txt" 'Name of file N On Error goto [noFile] if isInput then open fName$ for input as #setupFile else open fName$ for output as #setupFile SetupOpenFile$="#setupFile" exit function [noFile] SetupOpenFile$="" 'ver114-2f end function function SetupGetDescription$(fHndl$) 'Get description of open file whose handle is in fHndl$ 'File exists; we need to get the descriptive name 'The description is the first line of the file, but includes a leading "!" which we delete here SetupGetDescription$="" if EOF(#fHndl$) then notice "Error getting Setup file description" : SetupGetDescription$="" : exit function Line Input #fHndl$, tLine$ SetupGetDescription$=Mid$(tLine$, 2) 'Everything except the exclamation. end function [ToggleTransmissionReflection] 'Load and graph reflection data if now in transmission, or transmission data if now in reflection 'This is used in full VNA modes only, for switching between reflection and transmission. They should have been 'scanned with the same parameters, because we don't restore any parameters here. For example, they must have the 'same number of steps. It is actually possible for the frequency ranges to differ, but that is not how this would 'normally be used. 'This will not disrupt the current data, which can be displayed by calling here again. 'Switching between VectorTrans and Reflection modes is specially handled, to preserve the data and Y-axis 'settings that were last in effect for the new mode. This special treatment is done for menu-driven change 'or by certain internally generated changes that call [ToggleTransmissionReflection], but not for changes 'resulting from loading of preference files. ver116-1b cursor hourglass restoreSettingsAfterChange=0 if menuMode$="VectorTrans" then 'menuMode$ has prior mode ver116-1b 'If changing from vector trans mode and sweep frequencies are the same, we preserve some settings if refLastSteps<>0 and refLastSteps=steps and refLastStartFreq=startfreq and_ refLastEndFreq=endfreq and refLastIsLinear=gGetXIsLinear() then restoreSettingsAfterChange=1 else 'changing from reflection to transmission if transLastSteps<>0 and transLastSteps=steps and transLastStartFreq=startfreq and_ transLastEndFreq=endfreq and transLastIsLinear=gGetXIsLinear() then restoreSettingsAfterChange=1 end if if msaMode$="Reflection" then msaMode$="VectorTrans" else msaMode$="Reflection" 'switch mode gosub [ChangeMode] 'Conform to new mode if restoreSettingsAfterChange=0 then cursor normal : return if msaMode$="Reflection" then 'These changes will be fully implemented at PartialRestart call SetYAxes refLastY1Type, refLastY1Top, refLastY1Bot, refLastY1AutoScale, _ refLastY2Type, refLastY2Top, refLastY2Bot, refLastY1AutoScale else call SetYAxes transLastY1Type, transLastY1Top, transLastY1Bot, transLastY1Auto, _ transLastY2Type, transLastY2Top, transLastY2Bot, transLastY2Auto end if 'put data to be restored into VNAData. 'Note we don't have to worry about ResizeArrays, because any resizing would have been 'done when number of steps was set to its current value. Note also that we only restore the data 'if the old data had the same sweep settings as the current settings. 'We want to apply any graph R0 transform and plane extension, if applicable, so we indicate to copy 'the "intermediate" values. call CopyModeDataToVNAData 1 'Copy data to be restored to VNAData VNARestoreDoR0AndPlaneExt=1 : gosub [RestoreVNAData] 'load and graph the data ver116-4j redim VNAData(1,2) 'save space VNADataNumSteps=1 cursor normal beep return sub CopyModeDataToVNAData doIntermed 'Copy current data to VNAData, VNATitle$, etc. 'ver116-4a 'We save all steps, even if they have not gathered any info yet 'If doIntermed=1, we copy the intermediate (pre-R0 and plane ext) data for S21 or S11. redim VNAData(globalSteps, 2) 'Allow for freq, db and ang for i=0 to globalSteps select case msaMode$ case "SA" f=ActualSignalFrequency(datatable(i,1), datatable(i,4)) 'true freq in MHz, not what hardware thinks it tuned to ver116-4m 'ver116-4s db=datatable(i,2) 'dBm ang=0 case "ScalarTrans" f=S21DataArray(i,0) 'true freq db=S21DataArray(i,1) 'dB ang=0 case "VectorTrans" f=S21DataArray(i,0) 'true freq db=S21DataArray(i,1) 'dB if doIntermed then ang=S21DataArray(i,2) : ang=S21DataArray(i,2) 'deg, intermediate or final ver116-4j case else 'Reflection f=ReflectArray(i,0) 'true freq if doIntermed then 'ver116-4j db=ReflectArray(i,constIntermedS11DB) : ang=ReflectArray(i,constIntermedS11Ang) 'intermed db and deg else db=ReflectArray(i,constGraphS11DB) : ang=ReflectArray(i,constGraphS11Ang) 'final db and deg end if end select VNAData(i,0)=f : VNAData(i,1)=db : VNAData(i,2)=ang next i for i=1 to 4: VNADataTitle$(i)=gGetTitleLine$(i) : next i VNADataNumSteps=globalSteps : VNADataLinear=gGetXIsLinear() 'In SA mode we will end up with a bogus value for VNADataZ0, but it is meaningless anyway. if msaMode$="Reflection" then VNADataZ0=S11GraphR0 else VNADataZ0=S21JigR0 end sub [ChangeMode] 'Change mode to msaMode$ 'menuMode$ indicates the mode to which the menus are currently conformed, which is the mode we are changing from. 'The very first time, we create the window at a standard size. After that, we work with the existing 'window and redo the menus, leaving the size and location as is. if multiscanIsOpen then call multiscanCloseAll 'Quit multiscan--it is for SA only call smithFinished "" 'Close smith chart if it is open ver115-1b if hasVNA=0 and (msaMode$="VectorTrans" or msaMode$="Reflection") then msaMode$="SA" : call SetDefaultGraphData 'ver115-4f if TGtop=0 then msaMode$="SA" : call SetDefaultGraphData 'ver115-4e select msaMode$ 'ver114-7f deleted changeModeTo$ case "ScalarTrans", "VectorTrans" gosub [GoTransmissionMode] case "Reflection" gosub [GoReflectionMode] case else gosub [GoSAmode] end select call autoWaitPrecalculate 'auto wait calculations depend on mode ver116-1b haltsweep=0 'So Restart will actually restart return [RestartSATGmode] 'menu for SA plus TG mode selected added ver115-4f gentrk=1 'Tracking gen on goto [RestartSAmodes] [RestartPlainSAmode] 'menu for SA mode selected added ver115-4f gentrk=0 'Tracking gen off goto [RestartSAmodes] [RestartSAmodes] 'Restart in MSA mode with or without TG. Renamed ver115-4f 'called by the menu handlers for SA and SA/TG modes 'For a menu-initiated change, we initialize certain variables 'if the Special Tests Window is open, close it. if special=1 then returnflag=1:gosub [CloseSpecial]:returnflag=0 'ver112-2f msaMode$="SA" 'ver115-2a call SetDefaultGraphData 'clears autoscale, sets Y1 and Y2 data types and range, and sets Y2DisplayMode and Y1DisplayMode ver115-3b sgout=10 'Set to 10 MHz no matter what band we are using. Will be irrelevant if in TG mode ver116-4p offset=0 'TG offset; will be irrelevant if in TG mode. ver115-4f spurcheck = 0 'this assures Spur Test is OFF. ver114-2e referenceLineSpec$="" : referenceLineType=0 gosub [ChangeMode] goto [Restart] [GoSAmode] 'Switch to MSA mode and return; Get here only from [ChangeMode] 'We don't initialize variables here because they may have been set by loading Preferences ver115-2a if graphBox$="" then 'See if window is created yet ver115-5d gosub [CreateGraphWindow] 'Note msaMode$ is new mode; menuMode$ is old mode else call ConformMenusToMode 'ver115-9a if menuMode$<>msaMode$ then 'menuMode$ has prior mode, to which menus are now conformed ver115-5d call mClearMarkers call gClearAllReferences call gSetNumPoints 0 end if end if return [RestartTransmissionMode] 'Restart in Transmission mode. Handles menu item for mode change 'if the Special Tests Window is open, close it. if special=1 then returnflag=1:gosub [CloseSpecial]:returnflag=0 'ver112-2f 'For a menu-initiated change, we initialize certain variables ver115-2a gentrk = 1:normrev = 0:offset = 0 'turn on tracking generator, normal, zero offset 'ver111-17 referenceLineSpec$="" : referenceLineType=0 'Switching between VectorTrans and Reflection modes is specially handled, to preserve the data and Y-axis 'settings that were last in effect for the new mode. This special treatment is done for menu-driven change 'or by certain internally generated changes that call [ToggleTransmissionReflection], but not for changes 'resulting from loading of preference files. ver116-1b if graphBox$<>"" and menuMode$="Reflection" and transLastSteps<>0 then gosub [ToggleTransmissionReflection] : wait end if if hasVNA then msaMode$="VectorTrans" else msaMode$="ScalarTrans" 'ver115-3b call SetDefaultGraphData 'clears autoscale, sets Y1 and Y2 data types and range, and sets Y2DisplayMode and Y1DisplayMode ver115-3b S21JigAttach$="Series" 'Start using series jig ver115-5a gosub [ChangeMode] goto [Restart] [GoTransmissionMode] 'Switch to Transmission mode and return; Get here only from [ChangeMode] 'We don't initialize variables here because they may have been set by loading Preferences ver115-2a spurcheck = 0 'this assures Spur Test is OFF. ver116-1b switchTR=0 : call SelectLatchedSwitches freqBand 'Set transmission/reflection switch to transmission 'ver116-1b ver116-4s if graphBox$="" then 'See if window is created yet ver115-5d gosub [CreateGraphWindow] 'Note msaMode$ is new mode; menuMode$ is old mode else smoothModeChange=0 if menuMode$="Reflection" then 'menuMode$ has prior mode ver116-1b 'If changing from reflection mode and sweep frequencies are the same, we preserve some settings if transLastSteps<>0 and transLastSteps=steps and transLastStartFreq=startfreq and_ transLastEndFreq=endfreq and transLastIsLinear=gGetXIsLinear() then smoothModeChange=1 end if if smoothModeChange=0 then 'We don't clear markers when changing between VectorTrans and Reflection if sweep freq is the same call mClearMarkers end if call ConformMenusToMode call gSetNumPoints 0 call gClearAllReferences 'Old ones may not make sense call SignalNoCalInstalled 'ver116-4b end if return [RestartReflectionMode] 'Restart in Reflection mode. Handles menu item for mode change 'if the Special Tests Window is open, close it. if special=1 then returnflag=1:gosub [CloseSpecial]:returnflag=0 'ver112-2f 'For a menu-initiated change, we initialize certain variables ver115-2a gentrk = 1:normrev = 0:offset = 0 'turn on tracking generator, normal, zero offset 'ver111-17 referenceLineSpec$="" : referenceLineType=0 'Switching between VectorTrans and Reflection modes is specially handled, to preserve the data and Y-axis 'settings that were last in effect for the new mode. This special treatment is done for menu-driven change 'or by certain internally generated changes that call [ToggleTransmissionReflection], but not for changes 'resulting from loading of preference files. ver116-1b if graphBox$<>"" and menuMode$="VectorTrans" and refLastSteps<>0 then gosub [ToggleTransmissionReflection] : wait end if msaMode$="Reflection" 'ver115-2a call SetDefaultGraphData 'clears autoscale, sets Y1 and Y2 data types and range, and sets Y2DisplayMode and Y1DisplayMode ver115-3b S11JigType$="Reflect" 'Start using bridge ver115-5a gosub [ChangeMode] goto [Restart] [GoReflectionMode] 'Switch to Reflection mode and return; Get here only from [ChangeMode] 'We don't initialize variables here because they may have been set by loading Preferences ver115-2a spurcheck = 0 'this assures Spur Test is OFF. ver116-1b switchTR=1 : call SelectLatchedSwitches freqBand 'Set transmission/reflection switch to reflection 'ver116-1b ver116-4s if graphBox$="" then 'See if window is created yet ver115-5d gosub [CreateGraphWindow] 'Note msaMode$ is new mode; menuMode$ is old mode else smoothModeChange=0 if menuMode$="VectorTrans" then 'menuMode$ has prior mode ver116-1b 'If changing from vector transmission mode and sweep frequencies are the same, we preserve some settings if refLastSteps<>0 and refLastSteps=steps and refLastStartFreq=startfreq and_ refLastEndFreq=endfreq and refLastIsLinear=gGetXIsLinear() then smoothModeChange=1 end if if smoothModeChange=0 then 'We don't clear markers when changing between VectorTrans and Reflection if sweep freq is the same call mClearMarkers end if call ConformMenusToMode call gSetNumPoints 0 call gClearAllReferences 'Old ones may not make sense call SignalNoCalInstalled 'ver116-4b end if 'S21JigR0 is sometimes referenced if we explicitly use the series or shunt jig. But it causes problems 'in reflection mode if it can have a different value from S11BridgeR0. S21JigR0=S11BridgeR0 'ver116-4j suppressPhase=0 'Reflection always needs phase, even if not displayed ver116-1b call smithOpenChart 'Create smith chart return sub SetYAxes data1, top1, bot1, auto1, data2, top2, bot2, auto2 'Set datatypes, axis top and bottom, and autoscale 'ver116-1b 'Note gCalcGraphParams must be called to fully update graph module autoScaleY1=auto1 : autoScaleY2=auto2 Y1DataType=data1 Y2DataType=data2 call SetY1Range bot1, top1 call SetY2Range bot2, top2 Y1DisplayMode=1 : Y2DisplayMode=1 'ver115-4e call gSetDoAxis (Y1DataType<>constNoGraph), (Y2DataType<>constNoGraph) 'Tell graph module whether we have graphs ver115-2c call ImplementDisplayModes end sub sub SetDefaultGraphData 'Set data type and range for default data, and Y2DisplayMode and Y1DisplayMode based on msaMode$ ' mod by 116-4h autoScaleY1=0 : autoScaleY2=0 call GetDefaultGraphData 1, Y1DataType, min1, max1 : call GetDefaultGraphData 2, Y2DataType, min2, max2 call SetY1Range min1, max1 : call SetY2Range min2, max2 Y1DisplayMode=1 : Y2DisplayMode=1 'ver115-4e call ImplementDisplayModes end sub sub GetDefaultGraphData axisNum, byref axisType, byref axisMin, byref axisMax 'get axis default data type and range for this mode ver116-4h select case msaMode$ case "Reflection" if primaryAxisNum=axisNum then axisType=constGraphS11DB : axisMin=-100 : axisMax=0 else axisType=constGraphS11Ang : axisMin=-180 : axisMax=180 end if case "ScalarTrans" if primaryAxisNum=axisNum then axisType=constMagDB : axisMin=-100 : axisMax=0 else axisType=constNoGraph : axisMin=-180 : axisMax=180 end if case "VectorTrans" if primaryAxisNum=axisNum then axisType=constMagDB : axisMin=-100 : axisMax=0 else axisType=constAngle : axisMin=-180 : axisMax=180 end if case else ' "SA" if primaryAxisNum=axisNum then axisType=constMagDBM : axisMin=-100 : axisMax=0 else axisType=constNoGraph : axisMin=-1 : axisMax=0 end if end select end sub sub ResizeArrays nPoints 'Resize the arrays to hold at least nPoints points maxPoints=max(nPoints+10, 801) if gMaxNumPoints() 0 Then 'USB:01-08-2010 ret = GlobalFree(hSAllArray) 'USB:01-08-2010 AllArrayBlockSize = maxPoints * 40 'USB:01-08-2010 hSAllArray = GlobalAlloc(AllArrayBlockSize) 'USB:01-08-2010 ptrSAllArray = GlobalLock(hSAllArray) 'USB:01-08-2010 DeviceArrayBlockSize = maxPoints * 8 'USB:06-08-2010 hSDDS1Array = GlobalAlloc(DeviceArrayBlockSize) 'USB:06-08-2010 ptrSDDS1Array = GlobalLock(hSDDS1Array) 'USB:06-08-2010 hSDDS3Array = GlobalAlloc(DeviceArrayBlockSize) 'USB:06-08-2010 ptrSDDS3Array = GlobalLock(hSDDS3Array) 'USB:06-08-2010 hSPLL1Array = GlobalAlloc(DeviceArrayBlockSize) 'USB:06-08-2010 ptrSPLL1Array = GlobalLock(hSPLL1Array) 'USB:06-08-2010 hSPLL3Array = GlobalAlloc(DeviceArrayBlockSize) 'USB:06-08-2010 ptrSPLL3Array = GlobalLock(hSPLL3Array) 'USB:06-08-2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceSetAllArrayPtr", USBdevice as long, ptrSAllArray as long, maxPoints as short, 40 as short, result as boolean 'USB:01-08-2010 End If 'USB:01-08-2010 redim freqCorrection(maxPoints) 'SEWgraph1 redim frontEndCorrection(maxPoints) 'ver115-9c redim ReflectArray(maxPoints,16) 'ver115-2d redim S21DataArray(maxPoints, 3) 'ver116-1b redim bandLineCal(maxPoints, 2) 'ver114-5f redim OSLa(maxPoints, 1) 'ver115-1b redim OSLb(maxPoints, 1) 'ver115-1b redim OSLc(maxPoints, 1) 'ver115-1b redim OSLstdOpen(maxPoints,1) 'ver115-1b redim OSLstdLoad(maxPoints,1) 'ver115-1b redim OSLcalOpen(maxPoints,1) 'ver115-1b redim OSLcalLoad(maxPoints,1) 'ver115-1b redim OSLcalShort(maxPoints,1) 'ver115-1b redim OSLBandA(maxPoints,1) : redim OSLBandB(800,1) : redim OSLBandC(800,1) 'ver115-4a redim OSLBandRef(maxPoints,2) 'ver115-4a redim auxGraphData(maxPoints, 5) 'ver115-4a 'Note we do not resize arrays for base Line or base OSL cal, because resizing will invalidate the data, and 'because base line cal is saved to/retrieved from a file so its max size needs to be known before retrieval. 'Plus the nature of base cal does not require a massive number of points. call intSetMaxNumPoints maxPoints 'ver114-5q 'ver115-1d put the loading of the cal file inside the if.. block 'Load BaseLine Cal file if it exists ver114-5m if TGtop>0 then dum=CreateOperatingCalFolder() 'Create OperatingCal folder if it does not exist dum=LoadBaseLineCalFile() 'Load BaseLine file if it exists; if not we don't care bandLineNumSteps=-1 'Indicate no data; we just erased it call InstallSelectedLineCal 'To restore line cal data end if end if 'Note we don't have to resize configarray or configLineCalPoints$(); a flexible number of points 'is handled by simply having the strings in configLineCalPoints$ be different lengths. 'We don't resize VNAData or uWorkArray, because they are resized when used. end sub [LeftButDouble] 'Left button was double-clicked at MouseX, MouseY 'If the double click was on the grid line values for a Y axis, then open 'a preference window for that axis. If on the title, open a window to edit the title. 'If in the grid, place a marker. If on the X-axis window or the sweep parameters text, 'open x-axis preference window. if gPixIsInGrid(MouseX, MouseY)=1 then goto [MarkerClick] 'ver114-6d ver115-1a call gGetGridCorner "LL", axis1Right, axis1Bot 'Lower left corner of grid call gGetGridCorner "LR", axis2Left, axis2Bot 'Lower right corner of grid axis1Left=graphMarLeft-50 : axisTop=graphMarTop-5 axis2Right=axis2Left+45 if MouseX>axis1Right-5 and MouseXaxis1Bot and MouseYaxis2Right+5 and MouseY>axis2Top and MouseY=axis1Left and _ MouseX<=axis1Right and MouseY<=axis1Bot+5 and MouseY>=axisTop-5 then 'ver115-3b 'Double-click was on grid values for Y1 if haltsweep=1 then gosub [FinishSweeping] 'ver115-8d call DisplayAxisYPreference 1, 0 : yAxisChange=1 end if if MouseX>=axis2Left and MouseX<=axis2Right and MouseY<=axis2Bot+5 and MouseY>=axisTop-5 then 'Double-click was on grid values for Y2 if haltsweep=1 then gosub [FinishSweeping] 'ver115-8d call DisplayAxisYPreference 2, 0 : yAxisChange=1 end if 'ver114-6d revised the redrawing procedure when the Y axis changes if yAxisChange then 'ver114-5c Moved this here from DisplayYAxisPreference useExpeditedDraw=gCanUseExpeditedDraw() if continueCode=3 then suppressHardwareInitOnRestart=1 : gosub [PartialRestart] 'ver116-4d no need for hardware init if multiscanIsOpen then call multiscanSaveContexts 0 'zero means main graph ver115-8d end if if MouseYaxis1Right and MouseX0 then 'Click was not left or right of graphed points if selMarkerID$="" then newMarkID$="L" else newMarkID$=selMarkerID$ 'if gGetDoHist() or interpolateMarkerClicks=0 then clickedPointNum=int(clickedPointNum+0.5) 'Round to integral point ver115-1a roundedClickPointNum=int(clickedPointNum+0.5) 'ver116-4k if msaMode$="SA" then clickedPointNum=roundedClickPointNum 'Round to integral point for SA mode ver115-2d 'If we are within one-half pixel of a integral point, we round off because it is nice to have integral points, 'and there is no purpose to trying to get extreme resolution. if abs(clickedPointNum-roundedClickPointNum)*gPixelsPerStep()<=0.5 then clickedPointNum=roundedClickPointNum 'ver116-4k call mAddMarkerAndRedraw newMarkID$,clickedPointNum, clickedTraceNum if twoPortWinHndl$="" and varwindow = 1 then leftstep=roundedClickPointNum-1 : gosub [preupdatevar] 'will update variables at marker point ver116-4j end if 'If a sweep is in progress return to the instruction after the scan command. if haltsweep=1 then goto [PostScan] 'SEWgraph0 wait sub CalcAutoScale axisNum, byref axisMin, byref axisMax 'Calculate min and max for autoscaling axis axisNum if axisNum=1 then componConst=Y1DataType else componConst=Y2DataType call gGetMinMaxPointNum pMin, pMax if componConst=constGD then 'For group delay, the first point is invalid so don't include it if gGetSweepDir()=1 then pMin=pMin+1 else pMax=pMax-1 end if 'Find min and max values between points pMin and pMax call gFindPeaks axisNum, pMin, pMax, dum1, dum2, axisMin, axisMax select componConst case constGraphS11DB,constMagDBM, constMagDB, constReturnLoss, constInsertionLoss 'Round db/dbm to multiple of 5 ver114-8d axisMin=uRoundDownToMultiple(axisMin-0.5, 5) axisMax=uRoundUpToMultiple(axisMax+0.5, 5) case constGraphS11Ang,constAngle, constRawAngle, constTheta, constImpedAng, constAdmitAng 'ver115-4a 'Round angles to multiple of 15 ver115-1i added raw angle axisMin=uRoundDownToMultiple(axisMin-5, 15) : if axisMin<-180 then axisMin=-180 'ver114-8c axisMax=uRoundUpToMultiple(axisMax+5, 15) : if axisMax>180 then axisMax=180 if axisMax-axisMin>120 then axisMin=-180 : axisMax=180 'Expand to full range 'ver114-8c case constSerR, constParR, constImpedMag 'Round non-negative impedances to multiple of 25 if axisMax>1000000 then axisMax=1000 'Don't scale to screwy values, such as divide by zero might produce axisMin=uRoundDownToMultiple(axisMin-5, 25) axisMax=uRoundUpToMultiple(axisMax+5, 25) if axisMin<0 then axisMin=0 'No resistance below 0 if axisMin>0 then if axisMax/axisMin>=2 then axisMin=0 'Min is zero unless range very small ver115-4h end if case constSerReact, constParReact 'Round reactances to multiple of 25; allow negative if axisMax>1000000 then axisMax=1000 'Don't scale to screwy values, such as divide by zero might produce tentMin=uRoundDownToMultiple(axisMin-5, 25) if tentMin<0 and axisMin>0 then tentMin=0 'Don't make axis<0 if axisMin>0 axisMin=tentMin tentMax=uRoundUpToMultiple(axisMax+5, 25) if tentMax>0 and axisMax<0 then tentMax=0 'Don't make axis>0 if axisMax<0 axisMax=tentMax if axisMin*axisMax>0 then 'Pin one end to zero unless range very small ver115-4h if axisMax/axisMin>=2 or axisMin/axisMax>=2 then 'ver115-4h if axisMax<0 then axisMax=0 else axisMin=0 end if end if case constMagWatts, constMagRatio, constMagV, constRho 'Fractional values that won't exceed 1 or be negative if axisMax>1 then axisMax=1 axisMin=uRoundDownToPower(axisMin, 10) axisMax=uRoundUpToPower(axisMax,10) if axisMin>0 then if axisMax/axisMin>=2 then axisMin=0 case constSerC, constSerL, constParC, constParL 'Capacitance and Inductance if axisMin<0 then axisMin=axisMin*1.1 else axisMin=axisMin*0.9 if axisMax>0 then axisMax=axisMax*1.1 else axisMax=axisMax*0.9 axisMin=uRoundDownToPower(axisMin, 10) axisMax=uRoundUpToPower(axisMax, 10) if axisMax>1 then axisMax=1 : if axisMin<-1 then axisMin=-1 'If the range does not cross the axis and is more than a factor of 2, pin one end to zero if axisMin*axisMax>0 then if axisMax/axisMin>=2 or axisMin/axisMax>=2 then 'ver115-4h if axisMax<0 then axisMax=0 else axisMin=0 end if end if case constSWR 'VSWR >=1 and we don't care about huge values ver114-8d axisMin=1 if axisMax<2 then axisMax=2 else axisMax=int(axisMax)+2 if axisMax>50 then axisMax=50 case constComponentQ '>=0 and we don't care about huge values ver115-2d axisMin=0 if axisMax<10 then axisMax=10 else axisMax=int(axisMax)+5 if axisMax>10000 then axisMax=10000 case constReflectPower 'a percentage ver115-2d axisMin=0 axisMax=100 case constAdmitMag 'ver115-4a axisMin=0 axisMax=uRoundUpToPower(axisMax, 10) case constConductance, constSusceptance 'ver115-4a if axisMin>0 then axisMin=uRoundDownToPower(axisMin, 10) else axisMin=uRoundUpToPower(axisMin, 10) if axisMax>0 then axisMax=uRoundUpToPower(axisMax, 10) else axisMax=uRoundDownToPower(axisMax, 10) case constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 'ver115-4a auxNum=componConst-constAux0 'e.g. constAux4 produces 4 axisMin=auxGraphDataInfo(auxNum,1) : axisMax=auxGraphDataInfo(auxNum,2) case constNoGraph 'ver115-2c 'Do nothing case else 'constGD and anything we missed 'These items can have a broad range of values, positive and negative if axisMax>1000000 then axisMax=1 'Don't scale to screwy values, such as divide by zero might produce if axisMin<0 then axisMin=axisMin*1.1 else axisMin=axisMin*0.9 if axisMax>0 then axisMax=axisMax*1.1 else axisMax=axisMax*0.9 axisMin=uRoundDownToPower(axisMin, 10) axisMax=uRoundUpToPower(axisMax, 10) end select end sub sub StartingLimits componConst, oldData, byref axisMin, byref axisMax 'Determine starting min and max for axes 'If the axis limits are unreasonable, we find better limits 'componConst specifies what type of value we are dealing with. E.g. constTheta. 'oldData is the data type before the change. 'axisMin and axisMax are the original limits; we change if necessary. 'This is applied only when changing graph types. 'In general we just pick standard limits. But if the old data type is related to the new one, we may take 'into account the old limits. 'If the user specifies goofy values without changing the data type, or after doing so, we go with his specs. absMin=abs(axisMin) : absMax=abs(axisMax) limitsDone=0 select componConst case constGraphS11DB,constMagDBM, constMagDB 'db and dbm values axisMax=0 : axisMin=-100 case constReturnLoss,constInsertionLoss 'Positive dB values axisMin=0 : axisMax=60 case constGraphS11Ang, constTheta 'Two names for the same angles axisMin=-180 : axisMax=180 'Expand to full range 'ver114-8c if oldData<>constGraphS11Ang and oldData<>constTheta then axisMin=-180 : axisMax=180 'If we changed from a similar data type, keep the existing limits if they are reasonable if axisMin>=axisMax then axisMin=-180 : axisMax=180 case constAngle, constRawAngle, constImpedAng, constAdmitAng 'angles 'ver115-1i added raw angle axisMin=-180 : axisMax=180 case constAdmitMag 'ver115-4a axisMin=0 : axisMax=1 case constConductance, constSusceptance 'ver115-4a axisMin=-1 : axisMax=1 case constSerR, constParR, constImpedMag 'resistances and non-negative impedance if oldData<>constSerR and oldData<>constParR and oldData<>constImpedMag then axisMin=0 : axisMax=200 'If we changed from a similar data type, keep the existing limits if they are reasonable if axisMin<0 or axisMax<0 or axisMin>=axisMax then axisMin=0 : axisMax=200 case constSerReact, constParReact 'reactances if oldData<>constSerReact and oldData<>constParReact then axisMin=-200 : axisMax=200 'If we changed from a similar data type, keep the existing limits if they are reasonable if axisMin>=axisMax then axisMin=-200 : axisMax=200 case constMagV, constMagRatio, constMagV, constRho 'Fractional values that won't exceed 1 or be negative axisMin=0 : axisMax=1 case constMagWatts 'Fractional value that won't be negative and likely won't exceed 0.001 axisMin=0 : axisMax=0.001 case constSerC, constParC 'Capacitance if oldData<>constSerC and oldData<>constParC then axisMin=0 : axisMax=0.000001 'If we changed from a similar data type, keep the existing limits if they are reasonable if axisMin>=axisMax then axisMin=0 : axisMax=0.000001 case constSerL, constParL 'Inductance if oldData<>constSerL and oldData<>constParL then axisMin=0 : axisMax=0.000001 'If we changed from a similar data type, keep the existing limits if they are reasonable if axisMin>=axisMax then axisMin=0 : axisMax=0.000001 case constSWR 'VSWR >=1 and we don't care about huge values ver114-8d axisMin=1 : axisMax=11 case constComponentQ '>=0 and we don't care about huge values ver115-2d axisMin=0: axisMax=100 case constReflectPower 'a percentage ver115-2d axisMin=0 : axisMax=100 case constAux0, constAux1, constAux2, constAux3, constAux4, constAux5 'ver115-4a auxNum=componConst-constAux0 'e.g. constAux4 produces 4 axisMin=auxGraphDataInfo(auxNum,1) : axisMax=auxGraphDataInfo(auxNum,2) case constNoGraph 'ver115-2c 'Do nothing case else 'constGD and anything we missed 'don't mess with these end select end sub sub ReferenceDialog WindowWidth = 525 : WindowHeight = 450 call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c BackgroundColor$="gray" ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" s$="You may create reference lines from fixed values, the current data, or by simulating an RLC circuit." s$=s$;" You may select to graph the reference and the input data, or to graph the result of adding or subtracting them." staticText #refDialog.A1, s$, 10,5,475,70 'These checkboxes operate as radio buttons checkbox #refDialog.Clear, "No Reference Lines", [refClearOn], [refClearReset], 20, 80, 140, 19 checkbox #refDialog.UseData, "Use Current Data", [refUseDataOn], [refUseDataReset], 170, 80, 135, 19 checkbox #refDialog.UseFixed, "Use Fixed Value", [refUseFixedOn], [refUseFixedOff], 310, 80, 150, 19 checkbox #refDialog.UseRLC, "Use RLC Circuit", [refRLCOn], [refRLCOn], 20, 105, 120, 19 staticText #refDialog.RLCInfo, "(R=; L=; C=; TL=)", 150,105,340,19 'ver115-6b added options for Smith Chart traceLeft=20 : traceTop=140 checkbox #refDialog.t1, "Do Trace for Left Axis", [t1On], [t1Off],traceLeft,traceTop+70, 160, 18 checkbox #refDialog.t2, "Do Trace for Right Axis", [t2On], [t2Off],traceLeft,traceTop, 160, 18 checkbox #refDialog.smith, "Do Trace for Smith Chart", [refSmithOn], [refSmithOff],traceLeft,traceTop+140, 180, 18 'ver115-6b 'Trace Color staticText #refDialog.colorLabel1, "Color", traceLeft+5,traceTop+90,75,15 graphicbox #refDialog.color1, traceLeft, traceTop+105, 40, 20 'Trace Color staticText #refDialog.colorLabel2, "Color", traceLeft+5,traceTop+20,75,15 graphicbox #refDialog.color2, traceLeft, traceTop+35, 40, 20 'Trace Color staticText #refDialog.colorLabelSmith, "Color", traceLeft+5,traceTop+160,75,15 graphicbox #refDialog.colorSmith, traceLeft, traceTop+175, 40, 20 'Trace Color 'Trace width TraceWidths$(0)="1" : TraceWidths$(1)="2" : TraceWidths$(2)="3" staticText #refDialog.widthLabel1 "Width", traceLeft+75,traceTop+90,70,15 Stylebits #refDialog.width1, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #refDialog.width1, TraceWidths$(), [refDoNothing],traceLeft+70, traceTop+105, 50, 90 'Trace Width staticText #refDialog.widthLabel2 "Width", traceLeft+75,traceTop+20,70,15 Stylebits #refDialog.width2, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #refDialog.width2, TraceWidths$(), [refDoNothing],traceLeft+70, traceTop+35, 50, 90 'Trace Width staticText #refDialog.widthLabelSmith "Width", traceLeft+75,traceTop+160,70,15 Stylebits #refDialog.widthSmith, _CBS_DROPDOWNLIST, 0, 0, 0 combobox #refDialog.widthSmith, TraceWidths$(), [refDoNothing],traceLeft+70, traceTop+175, 50, 90 'Trace Width 'Trace Reference value, if fixed value staticText #refDialog.valLabel1, "Ref Val", traceLeft+160,traceTop+100,75,15 textbox #refDialog.val1, traceLeft+145, traceTop+115, 80, 20 'Trace Color staticText #refDialog.valLabel2, "Ref Val", traceLeft+160,traceTop+20,75,15 textbox #refDialog.val2, traceLeft+145, traceTop+35, 80, 20 'Trace Color 'ver114-8b added reference math items optionsTop=140 : optionsLeft=300 staticText #refDialog, "Graph Options", optionsLeft, optionsTop,125,18 checkbox #refDialog.both, "Data and Ref",[refGraphOn],[refGraphOff], optionsLeft, optionsTop+20,125,18 checkbox #refDialog.add, "Data + Ref",[refAddOn],[refAddOff], optionsLeft,optionsTop+40,125,18 checkbox #refDialog.sub, "Data - Ref",[refSubOn],[refSubOff],optionsLeft, optionsTop+60,125,18 checkbox #refDialog.reverseSub, "Ref - Data",[refReverseSubOn],[refReverseSubOff], optionsLeft, optionsTop+80,125,18 if msaMode$="SA" then 'ver115-5d checkbox #refDialog.mathOnDB, "Do math on input dBm values.",[refDBon],[refDBoff],optionsLeft, optionsTop+110,200,18 checkbox #refDialog.mathOnGraph, "Do math on graph values.",[refGraphMathOn],[refGraphMathOff], optionsLeft, optionsTop+130,200,18 end if 'OK and Cancel buttons button #refDialog.NoUpdate, "Close; Keep Data", [refNoUpdate],UL, 35, 365,130,25 button #refDialog.OK, "Close; Update Data", [refDialogFinished],UL, 180, 365,130,25 button #refDialog.Cancel, "Cancel", [refCancel],UL, 325, 365,130,25 'Smith instructions s$="Smith Chart reference lines are always drawn from S11 values without addition or subtraction," s$=s$;" and may not be drawn from fixed value references." statictext #refDialog.smithInst, s$, 200,280, 280,80 open "Reference Line Specification" for dialog_modal as #refDialog 'Open Reference dialog #refDialog, "trapclose [refDialogFinished]" #refDialog.color1, "when leftButtonDown [PickColor1]" #refDialog.color2, "when leftButtonDown [PickColor2]" #refDialog.colorSmith, "when leftButtonDown [PickColorSmith]" #refDialog, "font ms_sans_serif 10" form$="3,3,4//UseMultiplier" t1Color$=referenceColor1$ : t2Color$=referenceColor2$ : t3Color$=referenceColorSmith$ 'use intermediaries in case of Cancel #refDialog.width1, "selectindex ";referenceWidth1 #refDialog.width2, "selectindex ";referenceWidth2 #refDialog.widthSmith, "selectindex ";referenceWidthSmith #refDialog.color1, "cls; fill ";t1Color$; ";flush" #refDialog.color2, "cls; fill ";t2Color$; ";flush" #refDialog.colorSmith, "cls; fill ";t3Color$; ";flush" if referenceLineType=0 then referenceTrace=0 if msaMode$="SA" then #refDialog.UseRLC, "hide" 'Can't do RLC in SA mode if (referenceTrace and 2) then 'Do trace 2 #refDialog.t2, "set" else #refDialog.t2, "reset" #refDialog.width2, "hide" : #refDialog.color2, "hide" #refDialog.widthLabel2, "!hide" : #refDialog.colorLabel2, "!hide" end if if (referenceTrace and 1) then 'Do trace 1 #refDialog.t1, "set" else #refDialog.t1, "reset" #refDialog.width1, "hide" : #refDialog.color1, "hide" #refDialog.widthLabel1, "!hide" : #refDialog.colorLabel1, "!hide" end if if (referenceTrace and 4) then 'Do smith #refDialog.smith, "set" else #refDialog.smith, "reset" #refDialog.widthSmith, "hide" : #refDialog.colorSmith, "hide" #refDialog.widthLabelSmith, "!hide" : #refDialog.colorLabelSmith, "!hide" end if noUpdate=0 'whether to update ref data when we close hadData=0 'whether we had reference data for UseData when we opened 'ver114-8b if referenceDoMath>0 then 'ver115-5d if referenceOpA=1 and referenceOpB=1 then #refDialog.add, "set" 'Ref+data if referenceOpA=-1 and referenceOpB=1 then #refDialog.sub, "set" 'data-ref if referenceOpA=1 and referenceOpB=-1 then #refDialog.reverseSub, "set" 'ref-data else #refDialog.both, "set" 'Graph ref and data without doing math end if if msaMode$="SA" then 'Only SA has these boxes ver115-5d if referenceDoMath=2 then #refDialog.mathOnDB, "reset" : #refDialog.mathOnGraph, "set" else #refDialog.mathOnDB, "set" : #refDialog.mathOnGraph, "reset" end if if referenceDoMath=0 then #refDialog.mathOnDB, "hide" : #refDialog.mathOnGraph, "hide" #refDialog.mathOnDB, "hide" : #refDialog.mathOnGraph, "hide" 'THESE ARE TEMPORARILY DISABLED ver115-5d end if if msaMode$<>"Reflection" then #refDialog.smith, "hide" #refDialog.colorLabelSmith, "!hide" #refDialog.colorSmith, "hide" #refDialog.widthLabelSmith "!hide" #refDialog.widthSmith, "hide" #refDialog.smithInst, "!hide" end if if referenceLineType=1 then #refDialog.UseData, "set" : hadData=1 : goto [refUseDataOn] if referenceLineType=2 then #refDialog.UseRLC, "set" : spec$=referenceLineSpec$ _ : gosub [refDisplayRLCValues] : goto [refRLCOn] if referenceLineType=3 then 'Insert existing values for fixed value reference s$=referenceLineSpec$ isErr=uExtractNumericItems(2,s$,";",v1,v2,v3) 'Get two value; destroys s$ call DetermineGraphDataFormat Y1DataType, dum1$, dum2$, dum3, aFormat$ #refDialog.val1, uFormatted$(v1, aFormat$) 'Y1 call DetermineGraphDataFormat Y2DataType, dum1$, dum2$, dum3, aFormat$ #refDialog.val2, uFormatted$(v2, aFormat$) 'Y2 goto [refUseFixedOn] end if #refDialog.Clear, "set" : goto [refClearOn] 'No reference lines wait 'never gets here [refCancel] close #refDialog exit sub [refDBon] 'turn dB math on #refDialog.mathOnDB, "set" : #refDialog.mathOnGraph, "reset" wait [refDBoff] 'turn graph math off #refDialog.mathOnDB, "reset" 'Can turn off only by turning on mathOnGraph wait [refGraphMathOn] 'turn graph value math on #refDialog.mathOnGraph, "set" : #refDialog.mathOnDB, "reset" wait [refGraphMathOff] 'turn graph value math off #refDialog.mathOnGraph, "reset" 'Can turn off only by turning on mathOnDB wait [refGraphOn] #refDialog.both, "set" #refDialog.add, "reset" #refDialog.sub, "reset" #refDialog.reverseSub, "reset" 'if msaMode$="SA" then #refDialog.mathOnDB, "hide" : #refDialog.mathOnGraph, "hide" 'ver115-5d gosub [ShowEligibleTraces] wait [refGraphOff] #refDialog.both, "set" 'prevents reset wait [refAddOn] #refDialog.both, "reset" #refDialog.add, "set" #refDialog.sub, "reset" #refDialog.reverseSub, "reset" 'if msaMode$="SA" then #refDialog.mathOnDB, "show" : #refDialog.mathOnGraph, "show" 'ver115-5d gosub [ShowEligibleTraces] wait [refAddOff] #refDialog.add, "set" 'prevents reset wait [refSubOn] #refDialog.both, "reset" #refDialog.add, "reset" #refDialog.sub, "set" #refDialog.reverseSub, "reset" 'if msaMode$="SA" then #refDialog.mathOnDB, "show" : #refDialog.mathOnGraph, "show" 'ver115-5d gosub [ShowEligibleTraces] wait [refSubOff] #refDialog.sub, "set" 'prevents reset wait [refReverseSubOn] #refDialog.both, "reset" #refDialog.add, "reset" #refDialog.sub, "reset" #refDialog.reverseSub, "set" 'if msaMode$="SA" then #refDialog.mathOnDB, "show" : #refDialog.mathOnGraph, "show" 'ver115-5d gosub [ShowEligibleTraces] wait [refReverseSubOff] #refDialog.reverseSub, "set" 'prevents reset wait [t1On] gosub [ShowEligibleTraces] #refDialog.color1, "fill ";t1Color$; ";flush" wait [t1Off] gosub [ShowEligibleTraces] wait [t2On] gosub [ShowEligibleTraces] #refDialog.color2, "cls; fill ";t2Color$; ";flush" wait [t2Off] gosub [ShowEligibleTraces] wait [refSmithOn] gosub [ShowEligibleTraces] #refDialog.colorSmith, "cls; fill ";t3Color$; ";flush" wait [refSmithOff] gosub [ShowEligibleTraces] wait [refClearOn] #refDialog.Clear, "set" #refDialog.UseData, "reset" #refDialog.UseRLC, "reset" #refDialog.UseFixed, "reset" #refDialog.RLCInfo, "!hide" #refDialog.t1, "hide" #refDialog.NoUpdate, "!hide" #refDialog.OK, "OK" gosub [HideTrace1] #refDialog.t2, "hide" gosub [HideTrace2] #refDialog.smith, "hide" gosub [HideTraceSmith] wait [refClearReset] #refDialog.Clear, "set" 'Prevents reset wait [refUseDataOn] #refDialog.UseData, "set" #refDialog.Clear, "reset" #refDialog.UseRLC, "reset" #refDialog.UseFixed, "reset" #refDialog.RLCInfo, "!hide" if hadData then 'ver114-8b #refDialog.NoUpdate, "!show" #refDialog.OK, "Close; Update Data" end if gosub [ShowEligibleTraces] wait [refUseDataReset] #refDialog.UseData, "set" 'Prevents reset wait [refUseFixedOn] #refDialog.UseFixed, "set" #refDialog.Clear, "reset" #refDialog.UseRLC, "reset" #refDialog.UseData, "reset" #refDialog.RLCInfo, "!hide" #refDialog.NoUpdate, "!hide" #refDialog.OK, "OK" gosub [ShowEligibleTraces] wait [refUseFixedOff] #refDialog.UseFixed, "set" 'Prevents reset wait [refRLCOn] 'RLC turned on or re-clicked when already on #refDialog.UseData, "reset" #refDialog.Clear, "reset" #refDialog.UseFixed, "reset" #refDialog.UseRLC, "set" #refDialog.RLCInfo, "!hide" #refDialog.NoUpdate, "!hide" #refDialog.OK, "OK" gosub [ShowEligibleTraces] gosub [refDisplayRLCValues] 'Get current RLC spec; if invalid do defaults parseErr=uParseRLC(spec$, DialogRLCConnect$, DialogRValue, DialogLValue, _ DialogCValue, DialogQLValue, DialogQCValue, dumD, DialogCoaxSpecs$) 'ver116-4i added delay D, whichis not used if parseErr then spec$="RLC[S,R0,L0,C";constMaxValue;"]" DialogRLCConnect$="S" : DialogRValue=0 : DialogLValue=0 DialogCValue=constMaxValue : DialogQLValue=constMaxValue : DialogQCValue=constMaxValue 'ver115-4b DialogCoaxSpecs$="" 'ver115-4a end if call RLCDialog if DialogCancelled then wait 'Get the new values; display them gosub [refDisplayRLCValues] #refDialog.RLCInfo, "!show" 'Create the RLC spec string with RLC and Coax sections spec$="RLC[";DialogRLCConnect$;",R";uCompact$(R$);",L";uCompact$(L$); ",C";uCompact$(C$); _ ",QL";uCompact$(QL$); ",QC";uCompact$(QC$);"], Coax[";DialogCoaxSpecs$;"]" 'ver115-4b wait [refDisplayRLCValues] 'Put string of RLC values into #refDialog.RLCInfo form$="3,3,4//UseMultiplier" resForm$="3,3,4//UseMultiplier//SuppressMilli" 'ver115-4e QForm$="######.#" 'ver115-4b R$=uFormatted$(DialogRValue, resForm$) 'ver115-4e L$=uFormatted$(DialogLValue, form$) C$=uFormatted$(DialogCValue, form$) QL$=uFormatted$(DialogQLValue, QForm$) 'ver115-4b QL$=uFormatted$(DialogQCValue, QForm$) 'ver115-4b if DialogRLCConnect$="S" then con$="(Series" else con$="(Parallel" #refDialog.RLCInfo, con$;" R=";R$;", L=";L$; "H, C=";C$; "F, TL=";DialogCoaxName$;")" return [refRLCOff] #refDialog.RLCInfo, "!hide" wait [PickColor1] ColorDialog t1Color$, newColor$ if newColor$<>"" then t1Color$=newColor$ #refDialog.color1, "fill "; t1Color$;";flush" 'Fill box with new trace color end if wait [PickColor2] ColorDialog t2Color$, newColor$ if newColor$<>"" then t2Color$=newColor$ #refDialog.color2, "fill "; t2Color$;";flush" 'Fill box with new trace color end if wait [PickColorSmith] ColorDialog t3Color$, newColor$ if newColor$<>"" then t3Color$=newColor$ #refDialog.color2, "fill "; t2Color$;";flush" 'Fill box with new trace color end if wait [HideTrace1] #refDialog.width1, "hide" : #refDialog.color1, "hide" #refDialog.widthLabel1, "!hide" : #refDialog.colorLabel1, "!hide" #refDialog.val1, "!hide" : #refDialog.valLabel1, "!hide" return [ShowTrace1] #refDialog.UseFixed, "value? refFixed$" #refDialog.both, "value? s$" 'See whether ref lines will be drawn or are just used for math if s$="set" or refFixed$="set" then 'drawing both ref and data traces, or using fixed value ref if s$="set" then #refDialog.width1, "show" : #refDialog.color1, "show" #refDialog.widthLabel1, "!show" : #refDialog.colorLabel1, "!show" else #refDialog.width1, "hide" : #refDialog.color1, "hide" #refDialog.widthLabel1, "!hide" : #refDialog.colorLabel1, "!hide" end if if refFixed$="set" then valStat$="!show" else valStat$="!hide" #refDialog.val1, valStat$ : #refDialog.valLabel1, valStat$ 'Show fixed val only for fixed val ref else #refDialog.width1, "hide" : #refDialog.color1, "hide" #refDialog.widthLabel1, "!hide" : #refDialog.colorLabel1, "!hide" #refDialog.val1, "!hide" : #refDialog.valLabel1, "!hide" end if return [HideTrace2] #refDialog.width2, "hide" : #refDialog.color2, "hide" #refDialog.widthLabel2, "!hide" : #refDialog.colorLabel2, "!hide" #refDialog.val2, "!hide" : #refDialog.valLabel2, "!hide" return [HideTraceSmith] #refDialog.widthSmith, "hide" : #refDialog.colorSmith, "hide" #refDialog.widthLabelSmith, "!hide" : #refDialog.colorLabelSmith, "!hide" return [ShowTrace2] #refDialog.UseFixed, "value? refFixed$" #refDialog.both, "value? s$" 'See whether ref lines will be drawn or are just used for math if s$="set" or refFixed$="set" then 'drawing both ref and data traces, or using fixed value ref if s$="set" then 'show width and color only if no math being done #refDialog.width2, "show" : #refDialog.color2, "show" #refDialog.widthLabel2, "!show" : #refDialog.colorLabel2, "!show" else #refDialog.width2, "hide" : #refDialog.color2, "hide" #refDialog.widthLabel2, "!hide" : #refDialog.colorLabel2, "!hide" end if if refFixed$="set" then valStat$="!show" else valStat$="!hide" #refDialog.val2, valStat$ : #refDialog.valLabel2, valStat$ 'Show fixed val only for fixed val ref else #refDialog.width2, "hide" : #refDialog.color2, "hide" #refDialog.widthLabel2, "!hide" : #refDialog.colorLabel2, "!hide" #refDialog.val2, "!hide" : #refDialog.valLabel2, "!hide" end if return [ShowTraceSmith] 'Note smith reference is always drawn; never used for math. But it cannot 'be drawn for Fixed Value. #refDialog.UseFixed, "value? refFixed$" if refFixed$="reset" then 'not using fixed value ref #refDialog.widthSmith, "show" : #refDialog.colorSmith, "show" #refDialog.widthLabelSmith, "!show" : #refDialog.colorLabelSmith, "!show" else #refDialog.widthSmith, "hide" : #refDialog.colorSmith, "hide" #refDialog.widthLabelSmith, "!hide" : #refDialog.colorLabelSmith, "!hide" end if return [ShowEligibleTraces] #refDialog.Clear, "value? s$" if s$="set" then 'Don't show anything if we don't have reference lines gosub [HideTrace1] : gosub [HideTrace2] : gosub [HideTraceSmith] #refDialog.t1, "hide" : #refDialog.t2, "hide" : #refDialog.smith, "hide" return end if if Y1DataType<>constNoGraph then #refDialog.t1, "show" #refDialog.t1, "value? s$" if s$="set" then gosub [ShowTrace1] else gosub [HideTrace1] else gosub [HideTrace1] #refDialog.t1, "hide" end if if Y2DataType<>constNoGraph then #refDialog.t2, "show" #refDialog.t2, "value? s$" if s$="set" then gosub [ShowTrace2] else gosub [HideTrace2] else gosub [HideTrace2] #refDialog.t2, "hide" end if #refDialog.UseFixed, "Value? refFixedVal$" if msaMode$="Reflection" and refFixedVal$="reset" then 'Show smith only in reflection mode when reference lines are enabled 'and not using fixed value reference #refDialog.smith, "show" #refDialog.smith, "value? s$" if s$="set" then gosub [ShowTraceSmith] else gosub [HideTraceSmith] else gosub [HideTraceSmith] #refDialog.smith, "hide" end if return [refNoUpdate] noUpdate=1 goto [refDialogFinished] [refDialogFinished] 'ver114-8b added reference math items referenceDoMath=0 'assume no math #refDialog.both, "value? s$" 'graph both ref and data; no math if s$="set" then referenceDoMath=0 : referenceOpA=1 : referenceOpB=1 #refDialog.add, "value? s$" 'graph ref+data if s$="set" then referenceDoMath=1 : referenceOpA=1 : referenceOpB=1 #refDialog.sub, "value? s$" 'graph data-ref if s$="set" then referenceDoMath=1 : referenceOpA=-1 : referenceOpB=1 #refDialog.reverseSub, "value? s$" 'graph ref-data if s$="set" then referenceDoMath=1 : referenceOpA=1 : referenceOpB=-1 'If we have set referenceDoMath=1, we need to figure out whether it should really be 'set to 2, meaning to do the math on the actual graph values (=2), not on raw db (=1) 'We only allow it to be 1 for SA mode, because the same thing is effectively done in VNA modes 'by calibration. 'TEMPORARILY, we only allow referenceDoMath=2 if referenceDoMath=1 then referenceDoMath=2 ' if msaMode$="SA" then ' #refDialog.mathOnDB, "value? s$" 'set if do math on the db value ' if s$="reset" then referenceDoMath=2 ' else ' referenceDoMath=2 ' end if ' end if referenceTrace=0 #refDialog.t1, "value? s$" if s$="set" then referenceTrace=referenceTrace+1 referenceColor1$=t1Color$ #refDialog.width1, "selectionindex? i" if i<1 then i=1 referenceWidth1=i end if #refDialog.t2, "value? s$" if s$="set" then referenceTrace=referenceTrace+2 referenceColor2$=t2Color$ #refDialog.width2, "selectionindex? i" if i<1 then i=1 referenceWidth2=i end if #refDialog.smith, "value? s$" #refDialog.UseFixed, "value? refFixedVal$" if s$="set" and refFixedVal$="reset" then 'No smith trace for fixed value ref referenceTrace=referenceTrace+4 'set bit for smith referenceColorSmith$=t3Color$ #refDialog.widthSmith, "selectionindex? i" if i<1 then i=1 referenceWidthSmith=i end if #refDialog.UseData, "value? s$" 'Determine reference line type. Note that even if no reference trace is currently turned on 'reference data can still be created. if s$="set" then 'Use current data as reference referenceLineType=1 : referenceLineSpec$="" 'current data else #refDialog.UseRLC, "value? s$" if s$="set" then 'ver115-7a 'Use RLC as reference referenceLineType=2 : referenceLineSpec$=spec$ else #refDialog.UseFixed, "value? s$" if s$="set" then 'Fixed value reference #refDialog.val1, "!contents? fixedVal1$" #refDialog.val2, "!contents? fixedVal2$" referenceLineType=3 'spec contains the two values separated by a semicolon in same format as markers call DetermineGraphDataFormat Y1DataType, dum1$, dum2$, dum3, format1$ call DetermineGraphDataFormat Y2DataType, dum1$, dum2$, dum3, format2$ referenceLineSpec$=uCompact$(uFormatted$(uValWithMult(fixedVal1$), format1$));";"; _ uCompact$(uFormatted$(uValWithMult(fixedVal2$), format2$)) else 'No reference lines referenceLineType=0 : referenceLineSpec$="" : referenceTrace=0 : referenceDoMath=0 'ver116-1b call gClearAllReferences refreshGridDirty=1 call RefreshGraph 0 close #refDialog exit sub end if end if end if close #refDialog 'Close before creating reference line so things don't get clicked 'Create reference data. But if we are using "current data" and user wants 'to keep the prior data, don't update. if noUpdate=0 or referenceLineType<>1 then call CreateReferenceSource refreshGridDirty=1 call RefreshGraph 0 end sub sub RLCDialog WindowWidth = 450 : WindowHeight = 445 'ver115-4e call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c BackgroundColor$="buttonface" 'colors changed ver115-4j ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" 'ver115-4e changed instructions. staticText #RLCDialog.A1, "Specify type and length of transmission line, if any, and a combined", 10,10,400,19 staticText #RLCDialog.A2, "Resistor, Inductor and Capacitor as line termination.", 10,30,400,19 if msaMode$<>"Reflection" then 'ver115-4d staticText #RLCDialog.A3, "For the series fixture the RLC values are ignored if a transmission", 10,50,400,19 staticText #RLCDialog.A4, "line is specified.", 10,70,400,19 end if RLCTop=120 'ver115-4e 'ver115-1b separated the captions from the checkboxes so the text color comes out right groupbox #RLCDialog.group, "RLC",10, RLCTop-20, 220, 170 checkbox #RLCDialog.Parallel, "", [RLCParOn], [RLCParReset], 20, RLCTop-5, 20, 19 staticText #RLCDialog.NamePar, "Parallel", 41, RLCTop-1, 45, 19 checkbox #RLCDialog.Series, "", [RLCSerOn], [RLCSerReset], 90, RLCTop-5, 20, 19 staticText #RLCDialog.NameSer, "Series", 111, RLCTop-1, 45, 19 checkbox #RLCDialog.selR, "", [RLCROn], [RLCROff], 30, RLCTop+20, 20, 19 staticText #RLCDialog.NameR, "Resistance (ohms)", 51, RLCTop+22, 100, 19 checkbox #RLCDialog.selL, "", [RLCLOn], [RLCLOff], 30, RLCTop+45, 20, 19 staticText #RLCDialog.NameL, "Inductance (henries)", 51, RLCTop+47, 100, 19 checkbox #RLCDialog.selC, "", [RLCCOn], [RLCCOff], 30, RLCTop+95, 20, 19 staticText #RLCDialog.NameC, "Capacitance (farads)", 51, RLCTop+97, 100, 19 textbox #RLCDialog.R, 155, RLCTop+20, 60, 19 textbox #RLCDialog.L, 155, RLCTop+45, 60, 19 staticText #RLCDialog.LabelQL, "QL=", 130, RLCTop+72, 22, 19 'ver115-4b textbox #RLCDialog.QL, 155, RLCTop+70, 60, 19 'ver115-4b textbox #RLCDialog.C, 155, RLCTop+95, 60, 19 staticText #RLCDialog.LabelQC, "QC=", 130, RLCTop+122, 22, 19 'ver115-4b textbox #RLCDialog.QC, 155, RLCTop+120, 60, 19 'ver115-4b fixLeft=250 statictext #RLCDialog.FixR0Label, "R0 (ohms)", fixLeft+45, RLCTop+3, 52, 16 textbox #RLCDialog.FixR0, fixLeft+103, RLCTop, 50, 20 groupbox #RLCDialog.FixGroup, "Fixture Type", fixLeft-10, RLCTop-20, 190, 100 checkbox #RLCDialog.SeriesFix, "Series", [RLCDialogSetSeries], [RLCDialogSetSeries], fixLeft, RLCTop+25, 60, 20 checkbox #RLCDialog.ShuntFix, "Shunt", [RLCDialogSetShunt], [RLCDialogSetShunt], fixLeft, RLCTop+50, 60, 20 'ver115-4b deleted the delay items tranLineTop=RLCTop+155 staticText #RLCDialog.LabR0, "R0",45,tranLineTop+45,55,15 staticText #RLCDialog.LabVF, "VF", 105,tranLineTop+45,55,15 staticText #RLCDialog.LabK1, "K1", 165,tranLineTop+45,55,15 staticText #RLCDialog.LabK2, "K2", 225,tranLineTop+45,55,15 staticText #RLCDialog.LabLen, "Len (ft)", 268,tranLineTop+45,55,15 textbox #RLCDialog.R0, 25, tranLineTop+60, 55, 19 textbox #RLCDialog.VF, 85, tranLineTop+60, 55, 19 textbox #RLCDialog.K1, 145, tranLineTop+60, 55, 19 textbox #RLCDialog.K2, 205, tranLineTop+60, 55, 19 textbox #RLCDialog.Len, 265, tranLineTop+60, 55, 19 'List of Coax choices staticText #RLCDialog.A5, "Transmission Line Connection", 25,tranLineTop+8,150,19 'Copy standard coax names from coaxNames$, but add None at beginning and Custom at end. RLCDialogCoaxTypes$(0)="None" for i=1 to numCoaxEntries aName$=coaxNames$(i) : if aName$="" then aName$="None" 'So blank names don't mess up the sequence RLCDialogCoaxTypes$(i)=aName$ next i RLCDialogCoaxTypes$(numCoaxEntries+1)="Custom" combobox #RLCDialog.Coax, RLCDialogCoaxTypes$(),[RLCSelectCoax],175, tranLineTop+5, 150, 250 'OK and Cancel buttons button #RLCDialog.OK, "OK", [RLCDialogFinished],UL, 60, RLCTop+245,80,35 'ver115-4a button #RLCDialog.Cancel, "Cancel", [RLCCancel],UL, 160, RLCTop+245,80,35 'ver115-4a button #RLCDialog.Cancel, "Help", RLCSpecHelp,UL, 260, RLCTop+245,80,35 'ver115-4b open "RLC Specification" for dialog_modal as #RLCDialog 'Open preference dialog #RLCDialog, "trapclose [RLCDialogFinished]" #RLCDialog.A1, "!font ms_sans_serif 10" #RLCDialog.A2, "!font ms_sans_serif 10" if msaMode$<>"Reflection" then 'ver115-4e #RLCDialog.A3, "!font ms_sans_serif 10" #RLCDialog.A4, "!font ms_sans_serif 10" end if DialogCancelled=0 'Display existing values form$="3,3,4//UseMultiplier" resForm$="3,3,4//UseMultiplier//SuppressMilli" 'ver115-4e QForm$="######.###" 'ver115-4b R$=uFormatted$(DialogRValue, resForm$) 'ver115-4e L$=uFormatted$(DialogLValue, form$) C$=uFormatted$(DialogCValue, form$) QL$=uFormatted$(DialogQLValue, QForm$) 'ver115-4b QC$=uFormatted$(DialogQCValue, QForm$) 'ver115-4b isErr=CoaxParseSpecs(DialogCoaxSpecs$,cR0,cVF,cK1,cK2,cLen) 'If error, default values are returned R0$=uFormatted$(cR0, resForm$) 'ver115-7a VF$=using("#.#####", cVF) K1$=using("#.#####", cK1) K2$=using("#.#####", cK2) lenFeet$=uFormatted$(cLen, resForm$) 'ver115-7a #RLCDialog.R, R$ #RLCDialog.L, L$ #RLCDialog.C, C$ #RLCDialog.QL, QL$ 'ver115-4b #RLCDialog.QC, QC$ 'ver115-4b #RLCDialog.R0, R0$ #RLCDialog.VF, VF$ #RLCDialog.K1, K1$ #RLCDialog.K2, K2$ #RLCDialog.Len, lenFeet$ #RLCDialog.selR, "set" : #RLCDialog.selL, "set" : #RLCDialog.selC, "set" 'R, L and C only if they are meaningful if DialogRLCConnect$="S" then #RLCDialog.Series, "set" #RLCDialog.Parallel, "reset" 'For series components, zero impedance component means there is no such component, 'except missing R is set to high impedance if there is no L or C. a=DialogRValue : b=DialogLValue : c=DialogCValue if DialogRValue>=constMaxValue then #RLCDialog.selR, "reset" : #RLCDialog.R, "!hide" 'ver115-4j if DialogRValue=0 and (DialogLValue<>0 or DialogCValue=constMaxValue then #RLCDialog.selC, "reset" : #RLCDialog.C, "!hide" : _ #RLCDialog.QC, "!hide" : #RLCDialog.LabelQC, "!hide" 'ver115-4b else 'parallel #RLCDialog.Parallel, "set" #RLCDialog.Series, "reset" if DialogRValue>=constMaxValue then #RLCDialog.selR, "reset" : #RLCDialog.R, "!hide" 'ver115-4b if DialogLValue>=constMaxValue then #RLCDialog.selL, "reset" : #RLCDialog.L, "!hide": _ #RLCDialog.QL, "!hide" : #RLCDialog.LabelQL, "!hide" 'ver115-4b if DialogCValue=0 then #RLCDialog.selC, "reset" : #RLCDialog.C, "!hide" : _ #RLCDialog.QC, "!hide" : #RLCDialog.LabelQC, "!hide" 'ver115-4b end if if DialogCoaxName$="" then DialogCoaxName$="None" cName$=DialogCoaxName$ 'Select current coax in combobox 'Selection of combobox by text never works, so look up the index sel=0 for i=0 to numCoaxEntries+1 'two extra for None at beginning and Custom at end thisName$=RLCDialogCoaxTypes$(i) if cName$=thisName$ then sel=i+1 : exit for '0 in array is 1 in combobox next i #RLCDialog.Coax, "selectindex ";sel #RLCDialog.Coax, "setfocus" if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then 'We only do fixture type for Transmission mode #RLCDialog.FixR0, S21JigR0 if S21JigAttach$="Series" then #RLCDialog.SeriesFix, "set" : #RLCDialog.ShuntFix, "reset" else #RLCDialog.SeriesFix, "reset" : #RLCDialog.ShuntFix, "set" end if else #RLCDialog.FixR0, "!hide" #RLCDialog.FixR0Label, "!hide" #RLCDialog.SeriesFix, "hide" #RLCDialog.ShuntFix, "hide" #RLCDialog.FixGroup, "!hide" end if #RLCDialog.Len, "!setfocus" 'to get focus off combobox gosub [RLCAdjustItemsToCoax] 'if msaMode$<>"Reflection" and S21JigAttach$="Series" then goto [RLCDialogSetSeries] 'To hide termination items ver115-4d delver115-4e wait [RLCDialogSetSeries] #RLCDialog.SeriesFix, "set" #RLCDialog.ShuntFix, "reset" 'We can have a coax in series fixture, but we can't have a termination 'call RLCSetTermStatus "hide" 'hide termination items ver115-4d 'delver115-4e wait [RLCDialogSetShunt] #RLCDialog.SeriesFix, "reset" #RLCDialog.ShuntFix, "set" 'call RLCSetTermStatus "show" 'show termination items ver115-4d 'delver115-4e wait [RLCCancel] DialogCancelled=1 close #RLCDialog exit sub [RLCParOn] #RLCDialog.Parallel, "set" #RLCDialog.Series, "reset" wait [RLCParReset] #RLCDialog.Parallel, "set" 'Prevents reset wait [RLCSerOn] #RLCDialog.Series, "set" #RLCDialog.Parallel, "reset" wait [RLCSerReset] #RLCDialog.Series, "set" 'Prevents reset wait [RLCROn] #RLCDialog.R, "!show" wait [RLCROff] #RLCDialog.R, "!hide" wait [RLCLOn] #RLCDialog.L, "!show" #RLCDialog.QL, "!show" : #RLCDialog.LabelQL, "!show" 'ver115-4b wait [RLCLOff] #RLCDialog.L, "!hide" #RLCDialog.QL, "!hide" : #RLCDialog.LabelQL, "!hide" 'ver115-4b wait [RLCCOn] #RLCDialog.C, "!show" #RLCDialog.QC, "!show" : #RLCDialog.LabelQC, "!show" 'ver115-4b wait [RLCCOff] #RLCDialog.C, "!hide" #RLCDialog.QC, "!hide" : #RLCDialog.LabelQC, "!hide" 'ver115-4b wait [RLCAdjustItemsToCoax] 'disable/enable, hide/show and fill in what needs to be done for coax cName$ if cName$="None" or cName$="" then cName$="None" #RLCDialog.R0, "50" #RLCDialog.VF, "1" #RLCDialog.K1, "0" #RLCDialog.K2, "0" #RLCDialog.Len, "0" stat$="!hide" else if cName$<>"Custom" then 'For custom, we don't change the existing data call CoaxGetData cName$, cR0, cVF, cK1, cK2 #RLCDialog.R0, cR0 : #RLCDialog.R0, "!disable" #RLCDialog.VF, cVF : #RLCDialog.VF, "!disable" #RLCDialog.K1, cK1 : #RLCDialog.K1, "!disable" #RLCDialog.K2, cK2 : #RLCDialog.K2, "!disable" else #RLCDialog.R0, "!enable" #RLCDialog.VF, "!enable" #RLCDialog.K1, "!enable" #RLCDialog.K2, "!enable" end if stat$="!show" end if #RLCDialog.LabR0, stat$ #RLCDialog.LabVF, stat$ #RLCDialog.LabK1, stat$ #RLCDialog.LabK2, stat$ #RLCDialog.LabLen, stat$ #RLCDialog.R0, stat$ #RLCDialog.VF, stat$ #RLCDialog.K1, stat$ #RLCDialog.K2, stat$ #RLCDialog.Len, stat$ return [RLCSelectCoax] 'Coax type was selected #RLCDialog.Coax, "selectionIndex? sel" if sel=0 then cName$="None" else cName$=RLCDialogCoaxTypes$(sel-1) 'Get name from the array that filled #RLCDialog.Coax gosub [RLCAdjustItemsToCoax] wait [RLCDialogFinished] if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then 'We only do fixture info for Transmission mode #RLCDialog.FixR0, "!contents? s$" v=uValWithMult(s$) if v<=0 then notice "Invalid Fixture R0; 50 ohms used." : v=50 S21JigR0=v #RLCDialog.SeriesFix, "value? s$" if s$="set" then S21JigAttach$="Series" else S21JigAttach$="Shunt" end if DialogCoaxName$=cName$ 'cName$ was set when selection was made 'Retrieve and check coax data #RLCDialog.R0, "!contents? s$" cR0=uValWithMult(s$) 'R0 if cR0<=0 then notice "Invalid coax R0" : wait #RLCDialog.VF, "!contents? s$" cVF=val(uCompact$(s$)) 'velocity Factor if cVF<=0 or cVF>1 then notice "Invalid coax VF" : wait #RLCDialog.K1, "!contents? s$" cK1=val(uCompact$(s$)) 'K1--conductor loss factor if cK1<0 or cK1>=10 then notice "Invalid coax K1" : wait #RLCDialog.K2, "!contents? s$" cK2=val(uCompact$(s$)) 'K2--dielectric loss factor if cK2<0 or cK2>=10 then notice "Invalid coax K2" : wait #RLCDialog.Len, "!contents? s$" cLen=uValWithMult(uCompact$(s$)) 'length in feet if cLen<0 then notice "Invalid coax length" : wait if cLen>50000 then notice "Coax length may not exceed 50 k feet" : wait 'big value creates overflow ver115-4d 'Use blank coax specs if no coax is used, 'as a signal for Series Fixture in transmission mode that the RLC values are to be used. if cLen=0 or cName$="None" then 'ver115-5d DialogCoaxSpecs$="" else DialogCoaxSpecs$=CoaxSpecs$(cR0,cVF,cK1,cK2,cLen) end if #RLCDialog.Parallel, "value? s$" if s$="reset" then DialogRLCConnect$="S" else DialogRLCConnect$="P" 'Get component values. For shunt fixture, these are deemed the termination. For series 'fixture, any RLC combo is in series but is ignored if there is a transmission line. To indicate 'no transmission line for this purpose, we made the spec blank. #RLCDialog.selR, "value? s$" haveR=(s$="set") #RLCDialog.selL, "value? s$" haveL=(s$="set") #RLCDialog.selC, "value? s$" haveC=(s$="set") 'ver115-5a rearranged the following if haveR then #RLCDialog.R, "!contents? s$" DialogRValue=uValWithMult(s$) : if DialogRValue<0 then DialogRValue=0 else 'if no R for parallel, use large value if DialogRLCConnect$="P" then DialogRValue=constMaxValue 'ver115-5a else 'if no R for series, use 0 if L or C are specified; otherwise use large value if (haveL or haveC) then DialogRValue=0 else DialogRValue=constMaxValue 'ver115-5a end if end if if haveL then #RLCDialog.L, "!contents? s$" DialogLValue=uValWithMult(s$) : if DialogLValue<0 then DialogLValue=0 #RLCDialog.QL, "!contents? s$" 'ver115-4b DialogQLValue=uValWithMult(s$) : if DialogQLValue<=0 then DialogQLValue=0.001 'ver115-4b if DialogQLValue>100000 then DialogQLValue=100000 'max of 1e5 so it can display properly ver115-5f else if DialogRLCConnect$="P" then DialogLValue=constMaxValue else DialogLValue=0 DialogQLValue=1e4 'ver115-4b end if if haveC then #RLCDialog.C, "!contents? s$" DialogCValue=uValWithMult(s$) : if DialogCValue<0 then DialogCValue=0 #RLCDialog.QC, "!contents? s$" 'ver115-4b DialogQCValue=uValWithMult(s$) : if DialogQCValue<=0 then DialogQCValue=0.001 'ver115-4b if DialogQCValue>100000 then DialogQCValue=100000 'max of 1e5 so it can display properly ver115-5f else 'if no C, use large value for series and 0 for parallel if DialogRLCConnect$="P" then DialogCValue=0 else DialogCValue=constMaxValue DialogQCValue=1e4 'ver115-4b end if close #RLCDialog end sub sub RLCSetTermStatus stat$ 'Set status of termination items to show or hide ver115-4d bangStat$="!";stat$ #RLCDialog.selR, "value? s$" if s$="reset" then #RLCDialog.R, "!hide" else #RLCDialog.R, bangStat$ #RLCDialog.selL, "value? s$" if s$="reset" then #RLCDialog.L, "!hide" : #RLCDialog.QL, "!hide" : #RLCDialog.LabelQL, "!hide" else #RLCDialog.L, bangStat$ : #RLCDialog.QL, bangStat$ : #RLCDialog.LabelQL, bangStat$ end if #RLCDialog.selC, "value? s$" if s$="reset" then #RLCDialog.C, "!hide" : #RLCDialog.QC, "!hide" : #RLCDialog.LabelQC, "!hide" else #RLCDialog.C, bangStat$ : #RLCDialog.QC, bangStat$ : #RLCDialog.LabelQC, bangStat$ end if #RLCDialog.NameR, bangStat$ : #RLCDialog.NameL, bangStat$ : #RLCDialog.NameC, bangStat$ #RLCDialog.selR, stat$ : #RLCDialog.selL, stat$ : #RLCDialog.selC, stat$ #RLCDialog.group, bangStat$ #RLCDialog.NamePar, bangStat$ : #RLCDialog.NameSer, bangStat$ #RLCDialog.Parallel, stat$ : #RLCDialog.Series, stat$ end sub sub RLCSpecHelp h$ 'Display help info for RLC spec dialog WindowWidth = 600 if msaMode$="Reflection" then WindowHeight = 300 else WindowHeight = 375 call GetDialogPlacement 'determine position on screen BackgroundColor$="gray" ForegroundColor$="black" s$="The RLC spec dialog lets you specify the characteristics of a circuit consisting of a resistor, inductor" s$=s$;" and capacitor. One or two of those components can be omitted. You may specify the RLC values, and for" s$=s$;" the inductor and capacitor you may specify the Q value. Low Q values represent a loss in the component" s$=s$;" that in effect puts a resistor in series with the component, whose resistance changes with frequency." s$=s$;" You also specify whether the RLC components are in series or in parallel with each other." statictext #RLCSpecHelp, s$, 10, 10, 570, 80 s$="The RLC circuit may be simulated as though it is attached via a transmission line, so the RLC combination" s$=s$;" becomes the termination of the transmission line. You specify the length of the transmission" s$=s$;" line in feet, which may be zero. You may select a type of coaxial cable," s$=s$;" or you may select Custom and enter your own parameters, which incude characteristic impedance (R0), velocity" s$=s$;" factor, conductor loss (K1), and dielectric loss (K2). The K loss factors are specified in accordance with the" s$=s$;" equation:" statictext #RLCSpecHelp, s$, 10, 110, 570, 105 s$=" Matched Loss (dB per hundred feet)=K1*sqrt(F)+K2*F, where F is the frequency in MHz." statictext #RLCSpecHelp, s$, 10, 210, 570, 20 if msaMode$<>"Reflection" then 'Reflection doesn't care what the fixture is s$="You must specify whether the fixture is series or shunt, and its R0." s$=s$;" For the shunt fixture, you may enter the time delay of the connection between the actual fixture and" s$=s$;" the components; typically on the order of 0.125 ns per inch. For the series fixture, if the" s$=s$;" transmission line is used the RLC components are ignored." statictext #RLCSpecHelp, s$, 10, 240, 570, 65 end if open "RLC Analysis Help" for dialog_modal as #RLCSpecHelp print #RLCSpecHelp, "font ms_sans_serif 10" print #RLCSpecHelp, "trapclose [RLCSpecHelpEnd]" wait [RLCSpecHelpEnd] close #RLCSpecHelp exit sub end sub sub SetCycleColors 'Set up the trace colors for cycling 'ver116-4s call gGetSupplementalTraceColors Y1ACol$, Y2ACol$, Y1BCol$, Y2BCol$ call gGetTraceColors Y1Col$, Y2Col$ cycleColorsAxis1$(1)=Y1Col$ : cycleColorsAxis1$(2)=Y1ACol$ : cycleColorsAxis1$(3)=Y1BCol$ cycleColorsAxis2$(1)=Y2Col$ : cycleColorsAxis2$(2)=Y2ACol$ : cycleColorsAxis2$(3)=Y2BCol$ end sub sub DisplayAxisYPreference axisNum, doTwoPort 'Display dialog to select Y axis preferences 'if doTwoPort=1 we are doing the Two-Port graph; otherwise the regular scan graph 'ver116-1b added changes to enable this routine to handle two-port graphs if axisPrefHandle$<>"" then close #axisPrefHandle$ 'If pref window already open; close it cycleNumber=1 : call gSetTraceColors cycleColorsAxis1$(1),cycleColorsAxis2$(1) 'start over if cycling colors ver116-4s WindowWidth = 425 : WindowHeight = 275 'ver115-2c call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c BackgroundColor$="buttonface" 'colors changed ver116-1b ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" 'Ver114-6k rearranged and added graph data selection and autoscale. 'Top and bottom limits staticText #axis, "Top Ref", 120,10,50,15 textbox #axis.topref, 120, 25, 65,20 'Top Ref ver115-2c staticText #axis, "Bot Ref", 120,50,50,15 textbox #axis.botref, 120, 65, 65,20 'Bot Ref ver115-2c 'ver115-1b separated the captions from the checkboxes so the text color comes out right if doTwoPort=0 then checkbox #axis.auto, "",[axisAutoscaleOn], [axisYDoNothing],120, 100, 25,15 'Auto Scale staticText #axis, "Auto Scale",140, 100, 60,15 'Auto Scale end if 'Trace Color staticText #axis, "Trace Color", 10,10,70,15 graphicbox #axis.color, 10, 25, 50, 20 'Trace Color 'Trace width staticText #axis "Trace Width", 10,50,70,15 TraceWidths$(0)="0" : TraceWidths$(1)="1" : TraceWidths$(2)="2" : TraceWidths$(3)="3" Stylebits #axis.width, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #axis.width, TraceWidths$(), [axisYDoNothing],10, 65, 50, 90 'Trace Width 'Trace style (Norm Erase,...) if doTwoPort=0 then staticText #axis "Trace Style", 15,95,70,15 if (msaMode$="SA" or msaMode$="ScalarTrans") and axisNum=primaryAxisNum then 'ver115-3b 'histo modes are only in non-phase modes, and only on primary axis TraceStyles$(0)="Off" : TraceStyles$(1)="Norm Erase" : TraceStyles$(2)="Norm Stick" TraceStyles$(4)="Histo Erase" : TraceStyles$(5)="Histo Stick" else 'Phase modes and secondary axis have no histo TraceStyles$(0)="Off" : TraceStyles$(1)="Erase" : TraceStyles$(2)="Stick" TraceStyles$(4)="" : TraceStyles$(5)="" end if 'Y1DisplayMode, Y2DisplayMode 0=off 1=NormErase 2=NormStick 3=HistoErase 4=HistoStick Stylebits #axis.style, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #axis.style, TraceStyles$(), [axisYDoNothing],10, 110, 80, 120 'Trace Style end if 'Number of vertical divisions staticText #axis "Number of Divisions", 10,140,140,15 staticText #axis "(Affects both Y axes)", 10,155,140,15 NumVertDiv$(0)="4" : NumVertDiv$(1)="5" : NumVertDiv$(2)="6" 'ver115-1b changed to NumVertDiv$ NumVertDiv$(3)="8" : NumVertDiv$(4)="10" : NumVertDiv$(5)="12" combobox #axis.NDiv, NumVertDiv$(), [axisYDoNothing],25, 170, 60, 120 'Number of vert divisions checkbox #axis.cycleColors, "Cycle colors in Stick modes.",[axisYDoNothing], [axisYDoNothing], 120, 120, 175,15 'Cycling ver116-4s 'SuppressPhase box 'ver116-1b if doTwoPort=0 and msaMode$<>"SA" and msaMode$<>"ScalarTrans" then doingPhase=1 checkbox #axis.suppressPhase, "Force phase to zero.",[axisYDoNothing], [axisYDoNothing],220, 100, 140,15 'suppressPhase else doingPhase=0 end if 'OK and Cancel buttons button #axis.OK, "OK", [axisYFinished],UL, 220, 175,50,25 button #axis.Cancel, "Cancel", [axisYCancel],UL, 300, 175,50,25 axisDataLeft=220 : axisDataTop=25 dim axisGraphData$(40) : dim axisDataType(40) 'ver115-4a if doTwoPort=0 then 'ver116-1b numGraphs=FillRegularGraphData(axisNum) else numGraphs=TwoPortFillGraphData(axisNum) 'Fill axisGraphData$ and axisDataType if numGraphs<2 then Notice "There are no valid parameters to graph." call TwoPortSetPrimSecTypes constNoGraph, constNoGraph call gSetNumPoints 0 call TwoPortCalcAndGraph exit sub end if end if 'List of graphs staticText #axis.Instruct1, "Graph Data",axisDataLeft, axisDataTop, 270,15 'ver115-3a omitted the stylebits, because we have to take action when the graph changes comboBox #axis.GraphData, axisGraphData$(),[axisYChangeGraph], axisDataLeft, axisDataTop+15, 175, 350 'ver115-4a button #axis.doDefault, "Default Graph",[axisYDefaultOn], UL, axisDataLeft+20, axisDataTop+40, 120, 25 'ver116-4h open "Axis Y";axisNum for dialog_modal as #axis 'Open preference dialog axisPrefHandle$="#axis" #axis, "trapclose [axisYFinished]" #axis.color, "when leftButtonDown [PickColor]" 'Get some existing values call gGetTraceWidth w1, w2 'Trace widths call gGetTraceColors c1$, c2$ 'Trace colors if axisNum=1 then tWidth=w1 tColor$=c1$ if doTwoPort=0 then if autoScaleY1=1 then #axis.auto, "set" else #axis.auto, "reset" 'ver114-7a end if else tWidth=w2 tColor$=c2$ if doTwoPort=0 then if autoScaleY2=1 then #axis.auto, "set" else #axis.auto, "reset" 'ver114-7a end if end if 'Fill in preference choices with current values call gGetYAxisRange axisNum, yMin, yMax 'Previously specified min and max call gGetAxisFormats xForm$, y1Form$, y2Form$ if axisNum=1 then yForm$=y1Form$ else yForm$=y2Form$ topref$= uFormatted$(yMax, yForm$): botref$=uFormatted$(yMin, yForm$) print #axis.topref, topref$ : print #axis.botref, botref$ if doTwoPort=0 and doingPhase and suppressPhase=1 then #axis.suppressPhase, "set" 'ver116-1b if doCycleTraceColors=1 then #axis.cycleColors, "set" else #axis.cycleColors, "reset" 'ver116-4s #axis.color, "fill "; tColor$;";flush" 'Fill box with current trace color #axis.width, "select ";tWidth #axis.width, "setfocus" 'So selection is visually active call gGetNumDivisions nHorDiv, nVertDiv #axis.NDiv, "!";nVertDiv #axis.NDiv, "setfocus" 'So selection is visually active if doTwoPort=0 then 'select initial trace style based on Y2DisplayMode or Y1DisplayMode. Note those variables run from 0 but 'combobox selection indices run from 1; hence the +1 if axisNum=1 then #axis.style, "selectindex ";Y1DisplayMode+1 _ else #axis.style, "selectindex ";Y2DisplayMode+1 #axis.style, "setfocus" 'Visually activate end if 'Select current graph data. Set sel to the index corresponding to the entries in axisGraphData$(), 'but sel is numbered from 1 whereas the arrays are indexed from 0. if doTwoPort then if axisNum=1 then origData=TwoPortGetY1Type() else origData=TwoPortGetY2Type() else if axisNum=1 then origData=Y1DataType else origData=Y2DataType end if restoreData=origData 'used to restore on cancel. origData gets changed when graph data is changed ver115-3b selectDataType=origData : gosub [SelectGraphType] call RememberState 'Remember variables so we can detect changes wait 'Wait for user to make choices [SelectGraphType] 'select graph to match selectDataType sel=0 for i=0 to 40 if axisDataType(i)=selectDataType then sel=i+1 : exit for 'Look for match next i if sel=0 then sel=1 'Error, use first entry 'sel now has the index (1...) to use to select the current data type #axis.GraphData, "selectindex ";sel #axis.GraphData, "setfocus" #axis.topref, "!setfocus" : call uHighlightText "#axis.topref" 'Highlite axis max box 'ver115-2c return [axisYDefaultOn] 'button to use default graph types ver116-4h call GetDefaultGraphData axisNum, selectDataType, yMin, yMax gosub [SelectGraphType] : gosub [axisYChangeGraph] wait 'User gets here by double-click. If he double clicks again before we are open, we may end up 'with the double-click event. We need to provide this method so as not to crash. ver115-1b [LeftButDouble] wait [TwoPortLeftButDouble] wait [axisYDoNothing] 'embedded in DisplayYAxisPreference wait [axisYChangeGraph] 'ver115-3a 'We need to record the change and also change the format for top and bottom references. #axis.GraphData, "selectionindex? sel" if sel=0 then sel=1 'In case user typed something into the box. newData=axisDataType(sel-1) 'constant indicating the data type if doTwoPort then 'ver116-1b if axisNum=1 then call TwoPortSetY1Type newData else call TwoPortSetY2Type newData else if axisNum=1 then Y1DataType=newData else Y2DataType=newData if newData=constNoGraph then #axis.auto, "reset" 'turn off autoscale if no graph ver115-3b end if if newData<>constNoGraph then 'ver116-1b if doTwoPort then call TwoPortDetermineGraphDataFormat newData, dum1$, dum2$, dum3, yForm$ 'Get new data format else call DetermineGraphDataFormat newData, dum1$, dum2$, dum3, yForm$ 'Get new data format end if 'Get current range #axis.topref "!contents? newTop$" #axis.botref "!contents? newBot$" 'uCompact deletes blanks, which can mess up negative numbers newTop=uValWithMult(newTop$) : newBot=uValWithMult(newBot$) : newWidth=val(uCompact$(newWidth$)) if newTop"" then tColor$=newColor$ #axis.color, "fill "; tColor$;";flush" 'Fill box with new trace color end if wait [axisYCancel] 'User has cancelled; 'embedded in DisplayYAxisPreference close #axis if doTwoPort then if axisNum=1 then call TwoPortSetY1Type restoreData else call TwoPortSetY2Type restoreData 'restore data type ver116-1b else if axisNum=1 then Y1DataType=restoreData else Y2DataType=restoreData 'restore data type ver115-3b end if axisPrefHandle$="" exit sub [axisYFinished] 'Window is being closed; record choices; 'embedded in DisplayAxisYPreference 'Note that if the graph type changed, action would have been taken immediately in [axisYChangeGraph] 'So Y1DataType and Y2DataType, or TwoPortY1Type and TwoPortY2Type are current ver115-3a #axis.topref "!contents? newTop$" #axis.botref "!contents? newBot$" #axis.width, "selection? newWidth$" 'uCompact deletes blanks, which can mess up negative numbers newTop=uValWithMult(newTop$) : newBot=uValWithMult(newBot$) : newWidth=val(uCompact$(newWidth$)) if newWidth<0 then newWidth=0 else if newWidth>3 then newWidth=3 'ver116-4b if newTop12 then nVertDiv=12 call gSetNumDivisions nHorDiv, nVertDiv 'ver115-1b deleted call gCalcGraphParams; DetectChanges will handle that if doTwoPort=0 then #axis.style, "selectionIndex? axisStyle" if axisStyle<1 then axisStyle=1 if axisNum=1 then 'Set Y1DisplayMode or Y2DisplayMode from contents of axis style box; to Norm Erase if no graph if Y1DataType=constNoGraph then Y1DisplayMode=1 else Y1DisplayMode=axisStyle-1 'ver115-4e else if Y2DataType=constNoGraph then Y2DisplayMode=1 else Y2DisplayMode=axisStyle-1 'ver115-4e end if call ImplementDisplayModes 'ver114-6e 'Save some sweep settings for reflection and transmission for use when changing 'back to a previously used mode if msaMode$="Reflection" then 'ver116-1b refLastY1Type=Y1DataType : refLastY1Top=Y1Top : refLastY1Bot=Y1Bot : refLastY1AutoScale=autoScaleY1 refLastY2Type=Y2DataType : refLastY2Top=Y2Top : refLastY2Bot=Y2Bot : refLastY2AutoScale=autoScaleY2 else if msaMode$="VectorTrans" then transLastY1Type=Y1DataType : transLastY1Top=Y1Top : transLastY1Bot=Y1Bot : transLastY1AutoScale=autoScaleY1 transLastY2Type=Y2DataType : transLastY2Top=Y2Top : transLastY2Bot=Y2Bot : transLastY2AutoScale=autoScaleY2 end if end if end if if axisPrefHandle$<>"" then close #axis axisPrefHandle$="" if doTwoPort=0 then call DetectChanges 0 'Redraw as required and/or signal to restart via continueCode else call TwoPortAdjustToYChanges (origData<>restoreData) end if end sub 'end DisplayAxisYPreference function FillRegularGraphData(axisNum) 'Fill axisGraphData$ and axisDataType for regular scan graphs; return number of graphs 'Added by ver116-1b for i=0 to 40 : axisGraphData$(i)="" : next i if msaMode$="SA" then axisGraphData$(0)="Magnitude (dBm)" : axisDataType(0)=constMagDBM axisGraphData$(1)="Magnitude (Watts)" : axisDataType(1)=constMagWatts axisGraphData$(2)="Magnitude (Volts)" : axisDataType(2)=constMagV if (axisNum=1 and Y2DataType<>constNoGraph) or (axisNum=2 and Y1DataType<>constNoGraph) then _ axisGraphData$(3)="None" : axisDataType(3)=constNoGraph 'ver115-3b numGraphs=4 'ver115-4a end if if msaMode$="ScalarTrans" then axisGraphData$(0)="Transmission (dB)": axisDataType(0)=constMagDB 'ver115-4f axisGraphData$(1)="Transmission (Ratio)" : axisDataType(1)=constMagRatio 'ver115-4f axisGraphData$(2)="Insertion Loss (db)" : axisDataType(2)=constInsertionLoss numGraphs=3 'ver116-1b if (axisNum=1 and Y2DataType<>constNoGraph) or (axisNum=2 and Y1DataType<>constNoGraph) then _ axisGraphData$(3)="None" : axisDataType(3)=constNoGraph: numGraphs=numGraphs+1 'ver116-1b end if if msaMode$="VectorTrans" then axisGraphData$(0)="S21 Magnitude (dB)" :axisDataType(0)=constMagDB axisGraphData$(1)="S21 Phase Angle" : axisDataType(1)=constAngle axisGraphData$(2)="Raw Power (dBm)" : axisDataType(2)=constMagDBM axisGraphData$(3)="Raw Phase Angle" : axisDataType(3)=constRawAngle axisGraphData$(4)="Insertion Loss (db)" : axisDataType(4)=constInsertionLoss axisGraphData$(5)="S21 Group Delay" : axisDataType(5)=constGD numGraphs=6 'ver116-1ba 'Display "None" only if the other axis is not set to None. if (axisNum=1 and Y2DataType<>constNoGraph) or (axisNum=2 and Y1DataType<>constNoGraph) then _ axisGraphData$(6)="None" : axisDataType(6)=constNoGraph: numGraphs=numGraphs+1 'ver116-1b end if 'ver115-2d changed some reflection graph names if msaMode$="Reflection" then 'ver115-1f added impedance and renumbered axisGraphData$(0)="S11 Magnitude (dB)" : axisDataType(0)=constGraphS11DB axisGraphData$(1)="S11 Phase Angle (Deg)" : axisDataType(1)=constGraphS11Ang axisGraphData$(2)="Reflect Coef. Mag (Rho)" : axisDataType(2)=constRho axisGraphData$(3)="Reflect Coef. Angle (Theta)" : axisDataType(3)=constTheta axisGraphData$(4)="Impedance Mag (Z Mag)" : axisDataType(4)=constImpedMag axisGraphData$(5)="Impedance Angle (Z Ang)" : axisDataType(5)=constImpedAng axisGraphData$(6)="Series Resistance (Rs)" : axisDataType(6)=constSerR axisGraphData$(7)="Series Reactance (Xs)" : axisDataType(7)=constSerReact axisGraphData$(8)="Series Capacitance (Cs)" : axisDataType(8)=constSerC axisGraphData$(9)="Series Inductance (Ls)" : axisDataType(9)=constSerL axisGraphData$(10)="Parallel Resistance (Rp)" : axisDataType(10)=constParR axisGraphData$(11)="Parallel Reactance (Xp)" : axisDataType(11)=constParReact axisGraphData$(12)="Parallel Capacitance (Cp)" : axisDataType(12)=constParC axisGraphData$(13)="Parallel Inductance (Lp)" : axisDataType(13)=constParL axisGraphData$(14)="Return Loss (db)" : axisDataType(14)=constReturnLoss axisGraphData$(15)="Reflected Power (%)" : axisDataType(15)=constReflectPower 'ver115-2d axisGraphData$(16)="Component Q" : axisDataType(16)=constComponentQ 'ver115-2d axisGraphData$(17)="VSWR" : axisDataType(17)=constSWR numGraphs=18 'ver116-1b 'Display "None" only if the other axis is not set to None. if (axisNum=1 and Y2DataType<>constNoGraph) or (axisNum=2 and Y1DataType<>constNoGraph) then _ axisGraphData$(18)="None" : axisDataType(18)=constNoGraph : numGraphs=numGraphs+1 'ver116-1b 'ver115-2c deleted informational text about R0 end if for i=0 to 5 'ver115-4a 'Add graphs for each auxiliary item that does not have a blank name auxName$=auxGraphDataFormatInfo$(i,0) if auxName$<>"" then axisGraphData$(numGraphs)=auxName$ axisDataType(numGraphs)=constAux0+i 'aux constants are sequential starting with constAux0 numGraphs=numGraphs+1 end if next i FillRegularGraphData=numGraphs end function sub FillAppearancesArray for i=0 to 10 : Appearances$(i)="" : next i 'Clear Appearances$(0)="DARK" : Appearances$(1)="LIGHT" k=1 'max currently used appearance index ver115-2a for i=1 to 5 'add custom names ver115-2a customName$=customPresetNames$(i) if customName$<>"Empty" then k=k+1 : Appearances$(k)=customName$ next i end sub 'ver114-5o added [menuFreqAxisPreference] as wrapper to be invoked by menu; 'ends in wait instead of return [menuFreqAxisPreference] gosub [FreqAxisPreference] wait [FreqAxisPreference] 'called from menu 'Call routine to display frequency axis preference window. We do this in two stages because 'the subroutine cannot access steps directly (it is not global, for speed reasons). 'ver114-5o modified to require restart only when absolutely necessary 'ver114-6e revised if haltsweep then gosub [FinishSweeping] 'ver115-8d needRestart=DisplayAxisXPreference() steps=globalSteps 'transfer to non-global 'ver116-4j deleted call to selectFilter, leaving it to DetectChanges sweepDir=gGetSweepDir() 'transfer to non-global if (calCanUseAutoWait=0) and useAutoWait then 'ver116-4e useAutoWait=0 : wate=100 end if if needRestart=1 then gosub [PartialRestart] continueCode=0 'signal to keep going ver115-8d if multiscanIsOpen then call multiscanSaveContexts 0 'zero means main graph ver115-8d wait function DisplayAxisXPreference() 'Display dialog to select axis preferences 'Returns 1 if a restart is needed--only if frequency points or direction changed 'Also sets continueCode by calling DetectChanges if axisPrefHandle$<>"" then close #axisPrefHandle$ 'If pref window already open; close it WindowWidth = 800 : WindowHeight = 220 call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c UpperLeftX=1 'Window is very wide, so align to left side of graph window ver115-1c BackgroundColor$="buttonface" 'colors changed ver116-1b ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" 'Graph types statictext #axis.modeLab, "Data Mode", 15, 10, 90, 15 specialGraphs$(0)="0(Normal Operation)" specialGraphs$(1)="1(Graph Mag Cal)" specialGraphs$(2)="2(Graph Freq Cal)" specialGraphs$(3)="3(Graph Noisy Sine)" specialGraphs$(4)="4(Graph 1MHz Peak)" if msaMode$="SA" then specialGraphs$(5)="5(1MHz Square Wave)" else specialGraphs$(5)="5(Simulate RLC/Coax)" 'ver115-4c Stylebits #axis.OpMode, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #axis.OpMode, specialGraphs$(), [axisSetupNOP], 5, 25, 130, 130 'Operating Mode ver115-1a 'RBW Filter List statictext #axis.filter, "Select Final Filter Path:", 5, 55, 130, 12 Stylebits #axis.FiltList, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #axis.FiltList, MSAFiltStrings$(), [axisSetupNOP],5,68,140,100 'Filter list ver115-1b 'Video Filter statictext #axis.vidLab, "Video Filter BW", 15,100,80,15 Stylebits #axis.VideoFilt, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #axis.VideoFilt, videoFilterNames$(), [axisSetupNOP], 5, 115, 100, 100 'Video Filter ver116-1b 'Graph Appearance statictext #axis, "Graph Appearance",5,140,130,15 'ver115-2a moved creating Appearances to top call FillAppearancesArray combobox #axis.Appearance, Appearances$(), [axisSetupSelectAppearance], 5, 155, 110,100 'Appearance List 'ver115-4c 'Refresh; sweep time checkbox #axis.Refresh, "", [axisSetupNOP], [axisSetupNOP], 160, 10, 20, 15 'ver115-4c statictext #axis, "Refresh Screen Each Scan", 180, 10, 140, 15 'ver115-4c checkbox #axis.SweepTime, "", [axisSetupNOP], [axisSetupNOP], 160, 30, 20, 15 'ver115-4c statictext #axis, "Display Sweep Time", 180, 30, 140, 15 'ver115-4c 'ver115-4g applied spurbox to all modes checkbox #axis.spurbox, "",[axisSetupNOP], [axisSetupNOP], 160, 50, 20, 15 'ver115-4g statictext #axis, "Spur Test", 180, 50, 75, 15 'ver115-4g if msaMode$="SA" then 'SA mode, maybe with TG if gentrk=1 then 'Tracking gen mode ver115-4f groupbox #axis, "Tracking Generator",160,70,145,70 button #axis.normReverse, "Normal", [NormRevbutton], UL, 211, 90, 50, 20 'ver115-4f statictext #axis, "Offset", 167, 115, 30, 15 'ver115-4f textbox #axis.freqoffbox, 200, 113, 72, 20 'TG offset statictext #axis, "MHz", 275, 115, 24, 15 else if TGtop>0 then 'Have TG hardware but not in TG mode; use if for signal gen 'ver115-4f deleted SG/TG button statictext #axis, "Sig Gen Freq", 208, 92, 75, 15 'ver115-4f textbox #axis.freqoffbox, 200, 110, 72, 20 'Sig Gen freq statictext #axis, "MHz", 275, 112, 24, 15 end if end if end if if msaMode$<>"SA" and msaMode$<>"ScalarTrans" then 'modes with phase 'ver115-4e statictext #axis.pdminvert, "PDM Inversion (deg)", 320,15,105,15 textbox #axis.invdegbox, 335, 30, 50, 20 'ver115-2b modified to use groupbox and button groupbox #axis.planeadj, "Plane Extension", 315, 60, 100, 70 'ver115-2b textbox #axis.planeadjbox, 335, 80, 50, 20 'create "plane extension" box button #axis.PlaneRecalc,"Recalc",[RecalcPlaneExtAndR0], UL 335, 105, 50,20 'ver115-2d statictext #axis, "ns", 386, 81,20,20 end if 'Graph R0 added by ver115-2c moved ver116-1b if msaMode$="Reflection" then statictext #axis, "Graph R0", 240, 60, 65, 17 textbox #axis.R0, 245, 76, 30, 20 statictext #axis "ohms", 277, 78, 35, 20 end if 'DUT Direction if msaMode$<>"SA" then 'ver116-1b checkbox #axis.DirectionF, "DUT Forward", [setDUTForward], [setDUTReverse], 160, 105, 110, 12 checkbox #axis.DirectionR, "DUT Reverse", [setDUTReverse], [setDUTForward], 160, 123, 110, 12 end if sweepParamLeft=450 : sweepParamTop=20 'ver116-4k 'Center/Span frequencies and Start/Stop frequencies, with radio buttons to select one pair groupbox #axis.ParamGroup, "", sweepParamLeft-2, sweepParamTop-23, 310, 56 checkbox #axis.btnCentSpan, "", [setCentSpan], [setStartStop], sweepParamLeft+2,sweepParamTop, 14, 12 statictext #axis.CentLab, "Cent", sweepParamLeft+18, sweepParamTop-12, 27,15 statictext #axis.SpanLab, "Span", sweepParamLeft+18, sweepParamTop+11, 27,15 statictext #axis.MHzLabA, "MHz", sweepParamLeft+125, sweepParamTop-12, 25,15 statictext #axis.MHzLabB, "MHz", sweepParamLeft+125, sweepParamTop+12, 25,15 textbox #axis.SweepCent, sweepParamLeft+46, sweepParamTop-12, 75,20 textbox #axis.SweepSpan, sweepParamLeft+46, sweepParamTop+9, 75,20 checkbox #axis.btnStartStop, "", [setStartStop], [setCentSpan], sweepParamLeft+160,sweepParamTop, 14, 12 statictext #axis.StartLab, "Start", sweepParamLeft+175, sweepParamTop-12, 25,15 statictext #axis.StopLab, "Stop", sweepParamLeft+175, sweepParamTop+11, 25,15 statictext #axis.MHzLabC, "MHz", sweepParamLeft+278, sweepParamTop-12, 25,15 statictext #axis.MHzLabD, "MHz", sweepParamLeft+278, sweepParamTop+12, 25,15 textbox #axis.SweepStart, sweepParamLeft+201, sweepParamTop-12, 75,20 textbox #axis.SweepStop, sweepParamLeft+201, sweepParamTop+8, 75,20 'Steps per sweep statictext #axis.StepsLab, "Steps/Sweep", sweepParamLeft-10, sweepParamTop+40, 68,15 textbox #axis.SweepSteps, sweepParamLeft, sweepParamTop+55, 40,20 'Wait time statictext #axis.WaitLab, "Wait (ms)", sweepParamLeft-3, sweepParamTop+80, 45,13 textbox #axis.SweepWait, sweepParamLeft, sweepParamTop+93, 40,20 'manual text entry waitPrecisions$(1)="Fast" : waitPrecisions$(2)="Normal" : waitPrecisions$(3)="Precise" 'ver116-1b Stylebits #axis.waitPrecision, _CBS_DROPDOWNLIST, 0, 0, 0 'Prevent direct user typing 'ver116-1b combobox #axis.waitPrecision, waitPrecisions$(), [axisXDoNothing],sweepParamLeft, sweepParamTop+89, 70,90 'list of precisions 'ver116-1b checkbox #axis.cbAutoWait, "", [setAutoWait], [clearAutoWait], sweepParamLeft+85,sweepParamTop+93, 14, 12 'ver116-4q statictext #axis.cbAutoWaitLab, "Auto Wait", sweepParamLeft+100, sweepParamTop+93, 60,15 'ver116-4q 'Frequency Band added by ver115-1c statictext #axis, "Frequency Band", sweepParamLeft+15, sweepParamTop+126, 120,15 'ver114-3a IF1=int(appxLO2-10.7) 'Approx. IF1 frequency; assumes 10.7 MHz final filter FreqModes$(0)="Auto" 'ver116-4s FreqModes$(1)="1G; approx. 0-";IF1;" MHz" 'ver116-4s FreqModes$(2)="2G; approx. ";IF1-100; "-";2*IF1+100;" MHz" 'ver116-4s FreqModes$(3)="3G; approx. ";2*IF1+2; "-";3*IF1;" MHz" 'ver116-4s Stylebits #axis.FreqMode, _CBS_DROPDOWNLIST, 0, 0, 0 'Prevent direct user typing combobox #axis.FreqMode, FreqModes$(), [axisXDoNothing],sweepParamLeft-3, sweepParamTop+141, 160, 90 'Number of horizontal divisions staticText #axis.DivLab1 "Hor. Div.", sweepParamLeft+80,sweepParamTop+40,60,15 NumHorDiv$(0)="4" : NumHorDiv$(1)="6" : NumHorDiv$(2)="8" 'ver115-1b changed to NumHorDiv$ NumHorDiv$(3)="10" : NumHorDiv$(4)="12" combobox #axis.NDiv, NumHorDiv$(), [axisXDoNothing],sweepParamLeft+80, sweepParamTop+54, 50, 120 'Base Frequency (added by ver116-4k) staticText #axis, "Base Freq(MHz)",sweepParamLeft+190, sweepParamTop+40, 90, 15 textbox #axis.baseFreq, sweepParamLeft+190, sweepParamTop+54, 75,20 'Groupbox with "radio" buttons for linear/log groupbox #axis.group, "Sweep", sweepParamLeft+160, sweepParamTop+80, 165, 60 'ver115-1b separated the captions from the checkboxes so the text color comes out right checkbox #axis.linear, "", [axisXSelLinear],[axisXSelLog],sweepParamLeft+215, sweepParamTop +95, 15, 15 'ver115-1c staticText #axis, "Linear",sweepParamLeft+230, sweepParamTop +95, 40, 15 checkbox #axis.log, "", [axisXSelLog],[axisXSelLinear],sweepParamLeft+275, sweepParamTop +95, 15, 15 'ver115-1c staticText #axis, "Log", sweepParamLeft+290, sweepParamTop +95, 30, 15 'ver114-4k added reverse checkbox #axis.LR, "", [axisLRon],[axisLRoff],sweepParamLeft+165, sweepParamTop +120, 15, 15 'ver115-1c staticText #axis, "L-R",sweepParamLeft+180, sweepParamTop +120, 20, 15 checkbox #axis.RL, "", [axisRLon],[axisRLoff],sweepParamLeft+210, sweepParamTop +120, 15, 15 'ver115-1c staticText #axis, "R-L", sweepParamLeft+225, sweepParamTop +120, 20, 15 checkbox #axis.Alternate, "", [axisALTon],[axisALToff],sweepParamLeft+255, sweepParamTop +120, 15, 15 'ver115-1c staticText #axis, "Alternate", sweepParamLeft+270, sweepParamTop +120, 50, 15 'OK and Cancel buttons button #axis.OK, "OK", [axisXFinished],UL, 150, 155,90,30 button #axis.Cancel, "Cancel", [axisXCancel],UL, 300, 155,90,30 'Open preference dialog open "Sweep Parameters" for dialog_modal as #axis axisPrefHandle$="#axis" #axis, "trapclose [axisXFinished]" #axis, "font ms_sans_serif 9" 'ver116-1b #axis.OK, "!font Arial 10 bold" #axis.Cancel, "!font Arial 10 bold" #axis.waitPrecision "select ";autoWaitPrecision$ 'ver116-1b if calCanUseAutoWait=0 then useAutoWait=0 'ver116-4e if useAutoWait then 'ver116-1b #axis.WaitLab, "!hide" #axis.SweepWait, "!hide" #axis.waitPrecision, "show" #axis.cbAutoWait, "set" else #axis.WaitLab, "!show" #axis.SweepWait, "!show" #axis.waitPrecision, "hide" #axis.cbAutoWait, "reset" if calCanUseAutoWait=0 then #axis.cbAutoWait, "hide" 'Hide checkbox if auto wait disabled. end if 'Fill in preference choices with current values if alternateSweep then 'ver114-5a added alternateSweep #axis.Alternate, "set" else if gGetSweepDir()=1 then #axis.LR, "set" else #axis.RL, "set" end if linearF=gGetXIsLinear() 'Get freq linearity if linearF then 'modver115-1d #axis.linear, "set" else #axis.log, "set" #axis.DivLab1, "!hide" 'Can't choose number of divisions for log sweep #axis.NDiv, "hide" end if xForm$="#####.######" 'ver116-4k print #axis.SweepCent, uFormatted$(centfreq, xForm$) print #axis.SweepSpan, uFormatted$(sweepwidth, xForm$) print #axis.SweepStart, uFormatted$(startfreq, xForm$) print #axis.SweepStop, uFormatted$(endfreq, xForm$) print #axis.baseFreq, uFormatted$(baseFrequency, xForm$) 'ver116-4k print #axis.SweepSteps, globalSteps #axis.FreqMode, "selectindex ";freqBand+1 'freqBand is 0(auto),1, 2 or 3 ver116-4s #axis.FreqMode, "setfocus" 'ver115-1c print #axis.SweepWait, "";wate 'Wait time ver114-4d call gGetNumDivisions nHorDiv, nVertDiv #axis.NDiv, "!";nHorDiv #axis.NDiv, "setfocus" 'So selection is visually active #axis.SweepCent, "!setfocus" filtIndex=val(Word$(path$, 2))-1 'Index is one less than filter number, moved ver113-7a #axis.FiltList, "select ";MSAFiltStrings$(filtIndex) 'SEW2 Select filter for path$ #axis.FiltList, "setfocus" #axis.OpMode, "selectindex ";doSpecialGraph+1 #axis.OpMode, "setfocus" #axis.VideoFilt, "select "; videoFilter$ 'ver114-5p #axis.VideoFilt, "setfocus" 'ver114-5p 'We want to select the last preset that was used. If it is in the form CustomN, we want to 'translate it to the name the user gave it when it was defined. ver115-2a lastColorPreset$=gGetLastPresetColors$() if Upper$(Left$(lastColorPreset$, 6))="CUSTOM" then customPresetNum=val(Mid$(lastColorPreset$,7)) lastColorPreset$=customPresetNames$(customPresetNum) end if #axis.Appearance, "select ";lastColorPreset$ 'ver115-2a #axis.Appearance, "setfocus" 'Makes sure selection is visually activated if refreshEachScan then #axis.Refresh, "set" else #axis.Refresh, "reset" if displaySweepTime then #axis.SweepTime, "set" else #axis.SweepTime, "reset" 'ver114-4f changeAppearance=0 call RememberState 'Remember various variables so we can see if they change if spurcheck=1 then #axis.spurbox, "set" else #axis.spurbox, "reset" 'ver115-4g if msaMode$="SA" then 'ver115-4f if TGtop = 2 then 'ver114-4j print proper label; button only exists for SA mode with TGtop=2 if normrev = 1 then print #axis.normReverse, "Reverse" end if if TGtop>0 then 'Do if we have the TG--print either SG freq or TG offset if gentrk=0 then print #axis.freqoffbox, "";sgout else print #axis.freqoffbox, "";offset 'ver115-4f end if else if switchFR=0 then 'ver116-1b #axis.DirectionF, "set" : #axis.DirectionR, "reset" else #axis.DirectionF, "reset" : #axis.DirectionR, "set" end if if msaMode$<>"ScalarTrans" then 'modes with phase ver115-4f #axis.invdegbox, invdeg #axis.planeadjbox, planeadj end if end if 'R0 for Reflection if msaMode$="Reflection" then #axis.R0 uFormatted$(S11GraphR0,"3,4,5//UseMultiplier//DoCompact//SuppressMilli") 'ver116-4k if userFreqPref=0 then 'This is based on last user setting 'ver115-1d #axis.btnCentSpan, "set" 'Start in center/span mode gosub [enableCentSpan] else #axis.btnStartStop, "set" 'Start in start/stop mode gosub [enableStartStop] end if wait 'Wait for user to make choices 'User gets here by double-click. If he double clicks again before we are open, we may end up 'with the double-click event. We need to provide this method so as not to crash. ver115-1b [LeftButDouble] wait [axisXDoNothing] 'embedded in DisplayAxisXPreference wait [setDUTForward] 'ver116-1b #axis.DirectionF, "set" : #axis.DirectionR, "reset" wait [setDUTReverse] 'ver116-1b #axis.DirectionF, "reset" : #axis.DirectionR, "set" wait [setAutoWait] 'ver116-1b #axis.WaitLab, "!hide" #axis.SweepWait, "!hide" #axis.waitPrecision, "show" wait [clearAutoWait] 'ver116-1b #axis.WaitLab, "!show" #axis.SweepWait, "!show" #axis.waitPrecision, "hide" wait [axisLRon] #axis.RL, "reset" #axis.Alternate, "reset" wait [axisLRoff] #axis.LR, "set" wait [axisRLon] #axis.LR, "reset" #axis.Alternate, "reset" wait [axisRLoff] #axis.RL, "set" wait [axisALTon] #axis.RL, "reset" #axis.LR, "reset" wait [axisALToff] #axis.Alternate, "set" wait [axisXSelLinear] #axis.DivLab1, "!show" #axis.NDiv, "show" #axis.NDiv, "select 10" 'Start with 10 divisions when switching from log to linear ver114-2c #axis.log, "reset" #axis.linear, "set" 'ver115-1c wait [axisXSelLog] #axis.DivLab1, "!hide" 'Can't choose number of divisions for log sweep ver114-5p #axis.NDiv, "hide" #axis.linear, "reset" #axis.log, "set" 'ver115-1c #axis.btnStartStop, "value? ssVal$" if ssVal$="reset" then #axis.btnStartStop, "set" : goto [setStartStop] 'Log should be in start/stop mode wait [setCentSpan] 'Select Center/Span mode; use Start/Stop to fill in Center/Span 'embedded in DisplayAxisXPreference #axis.btnStartStop, "reset" #axis.btnCentSpan, "set" 'ver115-1d #axis.SweepStart, "!contents? currStart$" #axis.SweepStop, "!contents? currStop$" currStart=val(uCompact$(currStart$)) : currStop=val(uCompact$(currStop$)) print #axis.SweepCent, using("#####.######",(currStart+currStop)/2) 'Enter center print #axis.SweepSpan, using("#####.######",currStop-currStart) 'Enter span gosub [enableCentSpan] wait [enableCentSpan] #axis.SweepCent, "!enable" : #axis.SweepSpan, "!enable" #axis.SweepStart, "!disable" : #axis.SweepStop, "!disable" #axis.SweepCent, "!setfocus" : call uHighlightText "#axis.SweepCent" 'ver115-1d return [setStartStop] 'Select Start/Stop mode; use Center/Span to fill in Start/Stop 'embedded in DisplayAxisXPreference #axis.btnCentSpan, "reset" #axis.btnStartStop, "set" 'ver115-1d #axis.SweepCent, "!contents? currCent$" #axis.SweepSpan, "!contents? currSpan$" currCent=val(uCompact$(currCent$)) : currSpan=val(uCompact$(currSpan$)) print #axis.SweepStart, using("#####.######",currCent-currSpan/2) 'Enter start print #axis.SweepStop, using("#####.######",currCent+currSpan/2) 'Enter stop gosub [enableStartStop] wait [enableStartStop] #axis.SweepCent, "!disable" : #axis.SweepSpan, "!disable" #axis.SweepStart, "!enable" : #axis.SweepStop, "!enable" #axis.SweepStart, "!setfocus" : call uHighlightText "#axis.SweepStart" 'ver115-1d return [axisXCancel] 'User has cancelled; 'embedded in DisplayAxisXPreference close #axis axisPrefHandle$="" DisplayAxisXPreference=0 'signals no restart needed exit function [axisSetupNOP] wait 'ver115-2b added [RecalcPlaneExt] modver115-2d [RecalcPlaneExtAndR0] ' button to Recalculate and draw data with new plane extension or new S11 graph R0 'R0 transform is done only for reflection mode #axis.planeadjbox, "!contents? planeadj$" planeadj=val(uCompact$(planeadj$)) 'Get new planeadj if msaMode$="Reflection" then #axis.R0, "!contents? R0$" S11GraphR0=uValWithMult(uCompact$(R0$)) 'Get R0 ver116-4k end if gosub [VerifyPlaneExtension] 'See if we can do plane ext. ver115-4j #axis.planeadjbox, planeadj 'In case it got zeroed 'ver115-4j call RecalcPlaneExtendAndR0AndRedraw 'Do actual recalc and redraw prevPlaneAdj=planeadj 'because we are making the adjustment here; DetectChanges doesn't have to do anything prevS11GraphR0=S11GraphR0 wait [VerifyPlaneExtension] 'See if we can do plane extension ver115-4j if planeadj<>0 and msaMode$="Reflection" then if S11JigType$<>"Reflect" then 'Reflect means bridge if S21JigAttach$="Shunt" then notice "Can't do plane extension for shunt fixture." : planeadj=0 'we could but we don't else notice "Can't do plane extension for series fixture in Reflection Mode." : planeadj=0 end if end if 'Note: in transmission mode, plane extension with the shunt fixture requires fancier calculations 'than we do, but we can't be sure what fixture is being used so we can't warn. end if return [axisSetupSelectAppearance] 'Select graph appearance. Invoked by user click on combo box 'Note that unless the user changes the appearance, we do not activate the selection upon 'exit. This is because it will override previously selected trace colors. changeAppearance=1 wait 'ver115-4f deleted routines for toggling signal generator button, which is gone [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 #axis.normReverse, "Reverse":normrev = 1:wait if normrev = 1 then print #axis.normReverse, "Normal":normrev = 0:wait [axisXFinished] 'Window is being closed; record choices; 'embedded in DisplayAxisXPreference 'ver115-2b moved planeadj here so any necessary redraw can be done prior to anything else changing. 'If planeadj and other items are changed, there may be a superfluous redraw here. #axis.SweepSteps, "!contents? steps$" 'Get user specified number of steps globalSteps=val(steps$) if globalSteps<>prevSteps then 'SEWgraph2 Note we set globalSteps here; steps is set from globalSteps 'after we exit back to [FreqAxisPreference] if globalSteps<1 then globalSteps=1 else if globalSteps>maxNumSteps then globalSteps=maxNumSteps 'ver115-1b if globalSteps>2000 then 'ver116-4k confirm "Processing with more than 2,000 steps will be slow. Proceed anyway?"; stepsAns$ if stepsAns$="no" then #axis.SweepSteps, 2000 : wait end if 'Note we are called by [FreqAxisPreference], which will transfer globalSteps to steps. 'Resize arrays if necessary for all steps and a few to spare if globalSteps>=gMaxNumPoints() then call ResizeArrays globalSteps+10 'ver114-2a call gSetNumDynamicSteps globalSteps 'Tell graph module ver114-1f end if R0Changed=0 if msaMode$="Reflection" then 'ver115-2d #axis.R0, "!contents? newR0$" newR0=uValWithMult(newR0$) 'ver116-4k if newR0<0 then notice "Invalid Graph R0. 50 ohms used." : newR0=50 :#axis.R0, "50" if S11GraphR0<>newR0 then R0Changed=1 'for below S11GraphR0=newR0 end if 'ver115-4j moved retrieval of doSpecialGraph before doing plane adj. #axis.OpMode, "selectionindex? doSpecialGraph" if doSpecialGraph<1 then doSpecialGraph=0 else doSpecialGraph=doSpecialGraph-1 'e.g. selection 1 is doSpecialGraph=0 if doSpecialGraph>0 and doSpecialGraph<>5 and msaMode$="VectorTrans" then S21JigAttach$="Series" 'ver115-4k ver115-5a if msaMode$="VectorTrans" or msaMode$="Reflection" then print #axis.planeadjbox, "!contents? planeadj$" planeadj=val(uCompact$(planeadj$)) gosub [VerifyPlaneExtension] 'See if we can do plane ext. ver115-4j if planeadj<>prevPlaneAdj or R0Changed then 'prevPlaneAdj was saved by RememberState call RecalcPlaneExtendAndR0AndRedraw 'Redo planeadj adjustment from intermediate data and redraw graph prevPlaneAdj=planeadj 'because we are making the adjustment here; DetectChanges doesn't have to do anything prevS11GraphR0=S11GraphR0 end if end if 'DUT Direction if msaMode$<>"SA" then 'ver116-1b #axis.DirectionF, "value? DUTDirect$" if DUTDirect$="set" then switchFR=0 else switchFR=1 end if #axis.Alternate, "value? s$" 'ver114-5a if s$="set" then alternateSweep=1 else alternateSweep=0 'ver114-5a 'ver114-5a added this if... block if alternateSweep then dir=1 'if alternating, start with forward else #axis.LR, "value? s$" if s$="set" then dir=1 else dir=-1 'set forward or reverse end if call gSetSweepDir dir 'save in graph module; caller must transfer it to sweepDir 'ver114-4n #axis.FreqMode, "selectionindex? freqBand" 'Get user specified frequency Mode ver115-1c freqBand=freqBand-1 'first value is zero but first index is one. ver116-4s if freqBand<0 then freqBand=0 'ver115-1c ver116-4s if freqBand>3 then freqBand=3 'ver115-1c 'Get base freq. Note that graph module knows nothing about this; it has an effect only when 'commanding hardware and applying frequency calibration. #axis.baseFreq, "!contents? baseFrequency$" baseFrequency=int(val(uCompact$(baseFrequency$))+0.5) 'round to Hz; Not perfect for negative, but OK if baseFrequency<0 then notice "Base Frequency cannot be negative; zero Hz used." : baseFrequency=0 'Get frequency range #axis.btnCentSpan, "value? CentSpan$" if CentSpan$="set" then 'Use Center/Span to determine centfreq, sweepwidth, startfreq and endfreq userFreqPref=0 'Save as user preference ver115-1d #axis.SweepCent, "!contents? currCent$" #axis.SweepSpan, "!contents? currSpan$" 'uCompact deletes spaces, which can mess up negative numbers temp1= val(uCompact$(currCent$)): temp2=val(uCompact$(currSpan$)) 'ver115-1b 'Enter new freq, but only if there is a material change. Otherwise, 'tiny differences between using center/span and start/stop will trigger a restart. 'ver115-1b if abs(temp1-centfreq)>1e-12 or abs(temp2-sweepwidth)>1e-12 then _ call SetCenterSpanFreq temp1, temp2 'new center and span else 'Use Start/Stop to determine centfreq, sweepwidth, startfreq and endfreq userFreqPref=1 'Save as user preference ver115-1d #axis.SweepStart, "!contents? currStart$" #axis.SweepStop, "!contents? currStop$" 'uCompact deletes spaces, which can mess up negative numbers temp1= val(uCompact$(currStart$)): temp2=val(uCompact$(currStop$)) 'ver115-1b 'Enter new freq, but only if there is a material change. 'ver115-1b if abs(temp1-startfreq)>1e-12 or abs(temp2-endfreq)>1e-12 then _ call SetStartStopFreq temp1, temp2 'new center and span end if 'We retrieve both the manual wait time and auto wait precision, 'even though user only wants to use one at a time. 'ver116-1b #axis.SweepWait, "!contents? wate$"; wate = val(wate$) if wate<0 then wate=0 #axis.waitPrecision, "selection? autoWaitPrecision$" #axis.cbAutoWait, "value? waitType$" if waitType$="set" then useAutoWait=1 else useAutoWait=0 'Set sweep to log or linear. We do this after first setting the new range, since log sweep 'gets automatically changed to linear if the span is too small. #axis.linear, "value? lin$" if lin$="set" then linearF=1 else linearF=0 if linearF=0 then 'ver116-4k:for log sweeps, X range can be negative and can include zero, but cannot cross zero. 'If it includes zero, that value will be changed to a small value based on the "blackHoleRadius". if (startfreq<0) and (endfreq>0) then _ 'ver116-4k notice "Log sweep cannot cross zero Hz. Range changed." : _ endfreq=max(endfreq, 1) : call SetStartStopFreq endfreq/100000, endfreq includesZero=(startfreq<=0) and (endfreq>=0) : allNegative=(startfreq<0) and (endfreq<0) 'ver116-4k if includesZero then 'includes but does not cross zero if startfreq=0 then if endfreq=0 then 'both limits are zero linearF=1 : notice "Changed to linear sweep because span is small." #axis.NDiv, "select 10" 'set to 10 divisions ver116-1b else 'starts at zero; ends above zero notice "0 Hz not allowed in log sweep; range changed" : call SetStartStopFreq 0.0001, max(0.001, endfreq) end if else 'starts below 0; ends at 0 notice "0 Hz not allowed in log sweep; range changed" : call SetStartStopFreq min(-0.001, startfreq), -0.0001 end if else 'all positive or all negative if allNegative then span=uSafeLog10(startfreq/endfreq) else span=uSafeLog10(endfreq/startfreq) 'ver116-4k if span <0.7 then linearF=1 : notice "Changed to linear sweep because span is small." 'ver114-6e #axis.NDiv, "select 10" 'set to 10 divisions ver116-1b end if if span>9 then if allNegative then call SetStartStopFreq startfreq, startfreq/1000000000 else call SetStartStopFreq endfreq/1000000000, endfreq 'ver116-4k notice "Log span cannot exceed 9 decades; sweep limits changed." 'ver114-6e end if end if end if call gSetXIsLinear linearF 'Set freq linearity #axis.NDiv, "contents? nDiv$" 'Get user specified number of divisions nHorDiv=val(nDiv$) : if nHorDiv<2 then nHorDiv=2 else if nHorDiv>12 then nHorDiv=10 'ver116-1b nHorDiv=2*int(nHorDiv/2) 'Make the number even 'Set new number of hor divisions, with old number of vert div call gSetNumDivisions nHorDiv,nVertDiv #axis.Refresh, "value? doRefresh$" if doRefresh$="set" then refreshEachScan=1 else refreshEachScan=0 #axis.SweepTime, "value? doSweepTime$" 'ver114-4f if doSweepTime$="set" then displaySweepTime=1 else displaySweepTime=0 if changeAppearance then #axis.Appearance, "contents? graphAppearance$" if graphAppearance$<>"DARK" and graphAppearance$<>"LIGHT" then 'ver115-2a 'We are using a custom color set, and must create a name in the form "CustomN" customName$="" for i=1 to 5 thisPreset$=customPresetNames$(i) if thisPreset$=graphAppearance$ then customName$="Custom";i : exit for next i if customName$="" then graphAppearance$="DARK" else graphAppearance$=customName$ end if call gUsePresetColors graphAppearance$ 'Set color scheme call SetCycleColors 'ver116-4s #axis.OK, "!setfocus" 'Take focus off combo box to protect from scroll wheel end if #axis.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 #axis.FiltList, "select ";MSAFiltStrings$(0) 'Select default #axis.FiltList, "setfocus" 'SEW2 Needed to activate the highlight end if path$="Path "+str$(filtIndex) 'Name of filter path; Path 1, ver113-7c 'RBW filter will actually be selected after we return and load the RBW path cal data #axis.VideoFilt, "contents? videoFilter$" 'get selected video filter ver114-5p 'Note DetectChanges will take care of actually selecting the video filter #axis.spurbox, "value? doSpur$" 'ver115-4g if doSpur$="set" then spurcheck=1 else spurcheck=0 'ver115-4g if msaMode$="SA" then 'ver115-4g if TGtop > 0 then print #axis.freqoffbox, "!contents? freqoff$" 'Sig Gen Freq or TG offset box data ver116-4q if gentrk = 0 then sgout = val(using("####.######",val(uCompact$(freqoff$)))) 'ver115-4g 'delete 'ver116-4r if (sgout<=0) or (sgout>3*LO2) then sgout=10: Notice "Sig Gen Frequency was out-of-range. Changed to 10 MHz" 'ver116-4p if sgout<-75 then Notice "LO3 for Sig Gen Frequency may be too low" 'ver116-4r if sgout>3*LO2 then Notice "LO3 for Sig Gen Frequency may be too high" 'ver116-4r end if if gentrk = 1 then offset = val(using("####.######",val(uCompact$(freqoff$)))) 'ver115-4g end if if msaMode$="VectorTrans" or msaMode$="Reflection" then 'modes with phase ver115-4g print #axis.invdegbox, "!contents? invdeg$"; invdeg = val(uCompact$(invdeg$)) 'ver115-2b moved planeadj further above end if if doSpecialGraph=5 and msaMode$<>"SA" then 'ver116-4k moved this to be last thing done 'Simultated RLC/Transmission line data--give user chance to change parseErr=uParseRLC(doSpecialRLCSpec$, DialogRLCConnect$, DialogRValue, DialogLValue, _ DialogCValue, DialogQLValue, DialogQCValue, dumD, DialogCoaxSpecs$) if parseErr then doSpecialRLCSpec$="RLC[S,R0,L0,C";constMaxValue;",QL10000,QC10000]" 'ver115-4b DialogRLCConnect$="S" : DialogRValue=0 : DialogLValue=0 DialogQLValue=10000 : DialogQCValue=10000 DialogCValue=constMaxValue DialogCoaxSpecs$="" 'ver115-4a end if DialogCoaxName$=doSpecialCoaxName$ 'ver115-4b close #axis : #handle, "disable" 'ver116-4k call RLCDialog 'Get desired circuit values #handle, "enable" 'ver116-4k 'Assemble the values into a spec string 'Get the new values; assemble them into spec doSpecialCoaxName$=DialogCoaxName$ 'ver115-4b form$="3,3,4//UseMultiplier" resForm$="3,3,4//UseMultiplier//SuppressMilli" 'ver115-4e QForm$="######.###" 'ver115-5f R$=uFormatted$(DialogRValue, resForm$) L$=uFormatted$(DialogLValue, form$) C$=uFormatted$(DialogCValue, form$) QL$=uFormatted$(DialogQLValue, QForm$) 'ver115-4b QC$=uFormatted$(DialogQCValue, QForm$) 'ver115-4b doSpecialRLCSpec$="RLC[";DialogRLCConnect$;",R";uCompact$(R$);",L";uCompact$(L$); ",C";uCompact$(C$); _ ",QL";uCompact$(QL$);",QC";uCompact$(QC$); "], Coax[";DialogCoaxSpecs$;"]" else close #axis 'ver116-4k end if axisPrefHandle$="" call DetectChanges 0 'Do necessary redrawing and set continueCode ver114-6e if continueCode=3 then 'ver114-6e DisplayAxisXPreference=1 else continueCode=0 DisplayAxisXPreference=0 end if end function 'end of DisplayAxisXPreference sub SetCenterSpanFreq cent, span 'Use Center/Span to determine centfreq, sweepwidth, startfreq, endfreq 'A centralized routine is used so all these related variables can be kept in sync. 'Note gCalcGraphParams must be called to fully update graph module centfreq=cent sweepwidth=span if sweepwidth<0 then sweepwidth=0-sweepwidth startfreq=val(using("####.######",centfreq-sweepwidth/2)) 'ver114-5n endfreq=val(using("####.######",centfreq+sweepwidth/2)) 'ver114-5n 'ver115-1b deleted calc of stepfreq call gSetXAxisRange startfreq, endfreq 'ver114-6d end sub sub SetStartStopFreq startF, stopF 'Use Start/Stop to determine centfreq, sweepwidth, startfreq and endfreq 'A centralized routine is used so all these related variables can be kept in sync. 'Note gCalcGraphParams must be called to fully update graph module startfreq=startF endfreq=stopF if startfreq>endfreq then dum=startfreq : startfreq=endfreq : endfreq=dum 'Swap to get in right order centfreq=val(using("####.######",(startfreq+endfreq)/2)) 'ver114-5n sweepwidth=endfreq-startfreq 'ver115-1b deleted calc of stepfreq call gSetXAxisRange startfreq, endfreq 'ver114-6d end sub sub RecalcPlaneExtendAndR0AndRedraw 'Recalculate ReflectArray or S21DataArray for new planeadj, and Reflect array for new R0 and redraw graph call gGetMinMaxPointNum pStart, pEnd 'start and stop of points actually in current graph for currStep=pStart-1 to pEnd-1 'step numbers are one less than point numbers if msaMode$="Reflection" then 'For reflection, ReflectArray contains intermediate values of db and angle before plane 'extension was done, and before any R0 transform. We just start with those and recalculate. currFreq=ReflectArray(currStep,0) f=ReflectArray(currStep,0) db=ReflectArray(currStep,constIntermedS11DB) 'intermediate db--saved just for this purpose ang=ReflectArray(currStep,constIntermedS11Ang) 'intermed angle call ApplyExtensionAndTransformR0 f, db,ang ReflectArray(currStep,1)=db 'Enter new db ReflectArray(currStep,2)=ang 'Enter new phase call CalcReflectDerivedData currStep 'Calculate impedance and other derived quantities. else 'transmission currFreq=S21DataArray(currStep,0) thisPhase=S21DataArray(currStep, 3) 'original phase before plane ext ver116-1b call uExtendCalPlane currFreq, thisPhase, planeadj,0 'do adjustment S21DataArray(currStep,2)=thisPhase 'Enter new phase 'Note transform to graph R0 is for Reflection mode only end if next currStep 'Process next frequency call RecalcYValues 'Recalculate graph module Y values from new data if autoScaleY1=1 or autoScaleY2=1 then call PerformAutoScale 'autoscale with the new data call CreateReferenceTransform refreshTracesDirty=1 'Indicate to RefreshGraph that current traces are no good refreshGridDirty=1 'To redraw setup info with plane extension value ver115-4j call RefreshGraph 0 end sub sub DisplayTitleWindow doTwoPort 'Display dialog to change title of graph, or of two port params. 'If doTwoPort=1 then we are getting the title for the two port params, which we save 'but don't print. WindowWidth = 280 : WindowHeight = 220 call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c BackgroundColor$="buttonface" 'ver116-1b changed colors ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" statictext #title.Instruct, "Enter up to 3 lines of title information.", 40,20,200, 15 if doTwoPort=0 then statictext #title.Instruct, "(Line 3 gets overridden with date/time at Restart.)", 20,35,260, 15 textbox #title.t1, 10,50,250, 20 textbox #title.t2, 10,75,250, 20 textbox #title.t3, 10,100,250, 20 button #title.OK, "OK", [titleFinished],UL, 50, 150,50,25 button #title.Cancel, "Cancel", [titleCancel],UL, 160, 150,50,25 open "Title" for dialog_modal as #title 'Open title dialog #title, "trapclose [titleFinished]" 'Display existing title info and wait for user to change it print #title.t1, gGetTitleLine$(1) print #title.t2, gGetTitleLine$(2) print #title.t3, gGetTitleLine$(3) wait [titleCancel] 'embedded in DisplayTitleWindow close #title exit sub [titleFinished] 'embedded in DisplayTitleWindow #title.t1, "!contents? t1$" #title.t2, "!contents? t2$" #title.t3, "!contents? t3$" if doTwoPort then 'ver116-1b call TwoPortSetTitleLine 1, t1$ : call TwoPortSetTitleLine 2, t2$ : call TwoPortSetTitleLine 3, t3$ call gPrintTitle 1 'Clear old title and print new #TwoPortGraphBox$, "flush" else call gSetTitleLine 1, t1$ : call gSetTitleLine 2, t2$ : call gSetTitleLine 3, t3$ if msaMode$="Reflection" then 'ver116-1b refLastTitle$(1)=t1$ : refLastTitle$(2)=t2$ : refLastTitle$(3)=t3$ else if msaMode$="VectorTrans" then transLastTitle$(1)=t1$ : transLastTitle$(2)=t2$ : transLastTitle$(3)=t3$ end if 'Refresh the graph,but in stick mode this will eliminate 'the stuck traces, so just reprint the title ver114-7d revised this procedure refreshGridDirty=1 'So next refresh will reprint the title if isStickMode=0 then call RefreshGraph 0 'Refresh in case traces got covered else call gPrintTitle 1 '1 signals to clear old info first 'Don't want to flush in stick mode end if end if close #title end sub sub mUpdateMarkerLocations 'Find point numbers for peak markers and for L and R if relative to the peaks 'We are called from mDrawMarkerInfo, which also has the ability to move markers. saveSel$=selMarkerID$ 'We want to save and restore the current selected marker axisNum$=str$(primaryAxisNum) if hasMarkPeakPos or hasMarkPeakNeg then 'Locate peaks if doPeaksBounded=1 then if hasMarkL=0 then pStart=1 else pStart=gMarkerPointNum(mMarkerNum("L")) if hasMarkR=0 then pEnd=gPointCount() else pEnd=gMarkerPointNum(mMarkerNum("R")) else pStart=1 : pEnd=gPointCount() 'Signals to search all points end if call gFindPeaks primaryAxisNum,pStart, pEnd, minNum, maxNum, minY, maxY 'ver115-3b if hasMarkPeakPos then call gUpdateMarkerPointNum mMarkerNum("P+"),maxNum if hasMarkPeakNeg then call gUpdateMarkerPointNum mMarkerNum("P-"),minNum end if if doLRRelativeTo$<>"" then 'Locate LR relative to another marker markNum=mMarkerNum(doLRRelativeTo$) if markNum<1 then notice "Invalid Marker Number" 'For debugging pNum=gMarkerPointNum(markNum) if pNum=0 then 'Only proceed if the marker exists call mDeleteMarker "L" : call mDeleteMarker "R" 'ver115-1e else call gFindDBOffset primaryAxisNum,pNum, doLRRelativeAmount, doLRAbsolute,leftPoint, rightPoint 'ver115-3f if leftPoint>=1 then call mAddMarker "L", leftPoint, axisNum$ else call mDeleteMarker "L" 'ver115-3b if rightPoint>=1 then call mAddMarker "R", rightPoint, axisNum$ else call mDeleteMarker "R" 'ver115-3b end if end if if doFilterAnalysis then peakPoint=gMarkerPointNum(mMarkerNum(filterPeakMarkID$)) 'Get point number of marker that is the peak reference if peakPoint<0 then doFilterAnalysis=0 'Our peak marker has been deleted, so terminate the analysis end if 'If we are placing markers as part of filter analysis, we do it now. if doFilterAnalysis then peakPoint=gMarkerPointNum(mMarkerNum(filterPeakMarkID$)) 'Get point number of marker that is the peak reference if peakPoint<0 then doFilterAnalysis=0 'Our peak marker has been deleted, so terminate the analysis end if if doFilterAnalysis then 'Locate the points required for filter analysis. It is possible the points 'don't exist on the graph, in which case their point numbers will end up as -1. call gSetPeakAnalysis x1DBDown, x2DBDown, ripHighFreq, ripLowFreq 'For now we do auto determination of ripple search limits in gPeakAnalysis call gPeakAnalysis primaryAxisNum, peakPoint, 1, 1 'Find points down 3db, x1DBDown and x2DBDown, and ripple min and max; ver115-3b call gGetPeakAnalysisPoints db3LowPoint, db3HighPoint, x1LowPoint, x1HighPoint, x2LowPoint, x2HighPoint 'Place markers 2,3,4 and 5 as needed on the x1 and x2 points. Note that mAddMarker for 'an existing marker just relocates it. if x1DBDown<>0 then _ call mAddMarker "2", x1LowPoint, axisNum$ : call mAddMarker "3", x1HighPoint, axisNum$ 'ver115-3b if x2DBDown<>0 then _ call mAddMarker "4", x2LowPoint, axisNum$ : call mAddMarker "5", x2HighPoint, axisNum$ 'ver115-3b end if selMarkerID$=saveSel$ 'ver114-5L deleted call to mDisplaySelectedMarker end sub function mMarkerNum(markID$) 'Return ordinal marker number for this marker ID$ 'This value corresponds to the entry in the list of markers (1...) '-1 for invalid ID$. This is used to convert meaningful ID's into 'arbitrary storage locations. When marker info is printed, it is 'printed in the same order as the ordinal marker numbers. This is the only place 'that ID's are tied to specific ordinals, to make it easy to change. select case markID$ case "Halt" 'ver114-4c added Halt and renumbered mMarkerNum=1 case "L" mMarkerNum=2 case "R" mMarkerNum=3 case "P+" mMarkerNum=4 case "P-" mMarkerNum=5 case "1" mMarkerNum=6 case "2" mMarkerNum=7 case "3" mMarkerNum=8 case "4" mMarkerNum=9 case "5" mMarkerNum=10 case "6" mMarkerNum=11 case else mMarkerNum=-1 end select end function sub mDeleteMarker markID$ markNum=mMarkerNum(markID$) : if markNum<1 then notice "Invalid Marker Number" : exit sub call gUpdateMarkerPointNum markNum,-1 'Update the flags indicating whether we have the special markers select case markID$ case "L" hasMarkL=0 case "R" hasMarkR=0 case "P+" hasMarkPeakPos=0 case "P-" hasMarkPeakNeg=0 case "1", "2","3","4","5", "6", "Halt" 'ver114-4c 'valid markers but nothing special to do case else exit sub 'Not valid marker ID end select if gValidMarkerCount>0 then hasAnyMark=1 else hasAnyMark=0 if markID$=selMarkerID$ then call mMarkSelect "" 'ver114-5L end if end sub sub mAddMarker markID$, pointNum, trace$ 'Add specified marker at specified point markTrace$=trace$ markStyle$="LabeledWedge" markNum=mMarkerNum(markID$) if markNum<1 then notice "Invalid Marker Number" : exit sub end if if pointNum<0 then call mDeleteMarker markID$ : exit sub 'Adding with point num <0 is deleting select case markID$ case "L" hasMarkL=1 case "R" hasMarkR=1 case "P+" hasMarkPeakPos=1 markTrace$=str$(primaryAxisNum) 'Always do peak markers on primary trace case "P-" hasMarkPeakNeg=1 markTrace$=str$(primaryAxisNum) 'Always do peak markers on primary trace markStyle$="LabeledInvertedWedge" case "Halt" 'ver114-4c markTrace$="Xaxis" 'ver114-6d markStyle$="HaltPointer" 'ver114-5m case "1", "2","3","4","5", "6" 'valid markers but nothing special to do case else exit sub 'not valid marker end select hasAnyMark=1 'Indicate that we have at least one marker call gSetMarkerNum markNum, pointNum, markID$, markTrace$, markStyle$ 'Note we do not change the selected marker here end sub sub mAddMarkerAndRedraw markID$,ptNum, traceNum call mAddMarker markID$,ptNum, str$(traceNum) call mMarkSelect markID$ 'Select the marker we added ver114-5L if twoPortWinHndl$="" then call RefreshGraph 0 'ver114-7d 'ver116-4j made calling [preupdatevar] responsibility of caller else call TwoPortDrawGraph 0 end if end sub [mAddMarkerFromKeyboard] 'Add marker when marker key was pressed ver116-4j if haltsweep=1 then gosub [FinishSweeping] key$=Inkey$ 'This is the key that was pressed if isStickMode then wait 'Don't do marker in stick modes key$=upper$(key$) 'to upper case if len(key$)<>1 or inStr("LR123456", key$)=0 then wait 'exit if invalid marker call gGetLastMouseQuery queryPt, queryTrace 'point and trace number of last mouse position 'erase prior slider markers dum$=gDrawMarkerAtPointNum$(queryPt,"ALL","XOR","") 'Erase prior box if smithGraphHndl$()<>"" then call smithDrawSliderMarker queryPt 'erase in Smith chart too call mAddMarkerAndRedraw key$, queryPt, queryTrace 'record new marker and redraw, which clears the query info if twoPortWinHndl$="" and varwindow = 1 then leftstep=int(queryPt+0.5)-1 : gosub [preupdatevar] 'will update variables at marker point ver116-4j wait sub mClearMarkers hasMarkL=0 : hasMarkR=0 : hasMarkPeakPos=0 : hasMarkPeakNeg=0 : hasAnyMark=0 call gClearMarkers call gDrawMarkerInfo 'to clear info area ver114-7n call mMarkSelect "" 'ver114-5L end sub sub mDrawMarkerInfo 'Draw marker info at bottom of graph call gGetGraphicsSize graphwide, graphigh call mUpdateMarkerLocations 'Determines locations of peak markers and L,R if they are relative to the peaks 'We will draw marker info in a rectangular area below the labels of the x axis. 'This is the frequency and graph values call gDrawMarkerInfo 'Set InfoX and InfoY where additional info can be printed. InfoX=gGetMarkerInfoRight()+5 InfoY=gGetMarkerInfoTop() if selMarkerID$<>"" then call mDisplaySelectedMarker 'info may have changed 'We may have to print some additional info from an analysis if doFilterAnalysis then peakPoint=gMarkerPointNum(mMarkerNum(filterPeakMarkID$)) 'Get point number of marker that is the peak reference 'Note we know peakPoint is a valid point because mUpdateMarkerLocations set doFilterAnalysis=0 if it was not. peakFreq=gGetPointXVal(peakPoint) 'Frequency of peak 'gPeakAnalysis has found the points that are down the required number of db. It is possible the points 'don't exist on the graph, in which case their point numbers will end up as -1. call gGetPeakAnalysisPoints db3LowPoint, db3HighPoint, x1LowPoint, x1HighPoint, x2LowPoint, x2HighPoint call gGetPeakAnalysisRipple ripLowFreq, ripHighFreq, ripMinVal, ripMaxVal 'Get frequencies at each of the points db3HighFreq=gGetPointXVal(db3HighPoint) db3LowFreq=gGetPointXVal(db3LowPoint) x1HighFreq=gGetPointXVal(x1HighPoint) x1LowFreq=gGetPointXVal(x1LowPoint) x2HighFreq=gGetPointXVal(x2HighPoint) x2LowFreq=gGetPointXVal(x2LowPoint) db3BW=db3HighFreq-db3LowFreq 'If any of the required db values does not have both its points, we set a flag to zero. if db3LowPoint>0 and db3HighPoint>0 then hasDB3=1 else hasDB3=0 if x1LowPoint>0 and x1HighPoint>0 then hasX1=1 else hasX1=0 if x2LowPoint>0 and x2HighPoint>0 then hasX2=1 else hasX2=0 call gGetInfoColors textColor$, backColor$ if twoPortWinHndl$="" then gBox$="#handle.g" else gBox$="#twoPortGraphBox" 'main win or two port win 'ver116-4e #gBox$, "color ";textColor$ 'Set drawing color #gBox$, "font Tahoma 8 bold"; 'Set drawing font #gBox$, "backcolor ";backColor$ 'Set background color #gBox$, "size 1" 'We draw a filled box to get an outline and to clear any existing data boxHt= 5 + 7*13 'Assume 7 lines of height 13 each boxWidth=150 #gBox$, "place ";InfoX;" "; InfoY 'locate pen at upper left #gBox$, "boxfilled "; InfoX+boxWidth; " "; InfoY+boxHt 'This is lower right corner InfoX=InfoX+7 InfoY=InfoY+15 'Set to bottom of first line (matches marker heading) 'Now print the filter information on screen if x1DBDown<>3 and x2DBDown<>3 and hasDB3 then 'If neither x1 nor x2 is 3 db down, then print the 3db bandwidth if we have it bw$=uFormatted$(db3BW*1000000,"3,3,4//UseMultiplier//suffix=Hz") call gPrintText "BW(3dB)=";bw$, InfoX, InfoY :InfoY=InfoY+13 'e.g. BW(3dB)=123 KHz end if if hasX1 then x1BW=x1HighFreq-x1LowFreq bw$=uFormatted$(x1BW*1000000,"3,3,4//UseMultiplier//suffix=Hz") call gPrintText "BW(";str$(x1DBDown);"dB)=";bw$, InfoX, InfoY :InfoY=InfoY+13 'e.g. BW(3dB)=123 KHz end if if hasX2<>0 then x2BW=x2HighFreq-x2LowFreq bw$=uFormatted$(x2BW*1000000,"3,3,4//UseMultiplier//suffix=Hz") call gPrintText "BW("; str$(x2DBDown);"dB)=";bw$, InfoX, InfoY :InfoY=InfoY+13 'e.g. BW(3dB)=123 KHz end if 'Print Q if we have the necessary data if hasDB3 and db3BW>0 then Q$=Trim$(using("#####.#", peakFreq/db3BW)) call gPrintText "Q=";Q$, InfoX, InfoY :InfoY=InfoY+13 'e.g. Q=345.1 end if if hasX1 and hasX2 and x1BW>0 then 'Print shape factor if we have needed data shape$=Trim$(using("###.##", x2BW/x1BW)) call gPrintText "SF(";x2DBDown; "dB/";x1DBDown;"dB)=";shape$, InfoX, InfoY :InfoY=InfoY+13 'e.g. Shape=2.6 ver115-1a end if if msaMode$="ScalarTrans" or msaMode$="VectorTrans" then 'ver114-5n IL=0-gGetPointYVal(peakPoint,primaryAxisNum) 'ver116-4s allowed IL to be negative 'Note TO DO: we could also do this if in TG mode IL$=Trim$(using("###.###", IL)) 'Insertion loss, which we only do if in transmission 'ver115-1e call gPrintText "IL=";IL$, InfoX, InfoY : InfoY=InfoY+13 end if 'Print ripple. Ideally we would print the ripple search bounds, but we don't have room 'Maybe we should delete insertion loss, because it is apparent from the peak value if hasDB3 then rip$=Trim$(using("####.###", ripMaxVal-ripMinVal)) 'ver115-1e call gPrintText "Ripple=";rip$;" dB", InfoX, InfoY : InfoY=InfoY+13 InfoX=InfoX+boxWidth 'End by setting InfoX to the far right of what we just drew end if end if end sub sub mMenuMarkerOptions 'Button handler to set marker options WindowHeight=255 : WindowWidth=200 BackgroundColor$="buttonface" 'ver116-4g ForegroundColor$="black" 'ver116-4g call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c 'ver115-1b separated the captions from the checkboxes and radiobuttons so the text color comes out right checkbox #mark.Show, "", [markNil], [markNil],10,10,20,20 statictext #mark, "Show Markers On Graph",30,13,140,20 groupbox #mark.LR, "L,R Markers",5,40,160,140 radiobutton #mark.Indep, "", [markNil], [markNil],10,70,20,20 statictext #mark, "L,R Independent", 30,73,140,20 radiobutton #mark.Bounded, "", [markNil], [markNil],10,95,20,20 statictext #mark, "P+, P- bounded by L,R", 30,98,140,20 radiobutton #mark.Down3, "", [markNil], [markNil],10,120,20,20 statictext #mark, "L,R -3db re P+", 30,123,140,20 radiobutton #mark.Up3, "", [markNil], [markNil],10,145,20,20 statictext #mark, "L,R 3db re P-", 30,148,140,20 button #mark.OK "OK",[markFinished], UL, 20, 200, 50, 25 button #mark.Cancel "Cancel",[markBtnCancel], UL, 100, 200, 50, 25 open "Marker Options" for Dialog_modal as #mark #mark, "trapclose [markFinished]" #mark.Indep, "set" 'may change in next few lines if doGraphMarkers then #mark.Show, "set" else #mark.Show, "reset" if doPeaksBounded then #mark.Bounded, "set" if doLRRelativeTo$="P+" then #mark.Down3, "set" if doLRRelativeTo$="P-" then #mark.Up3, "set" wait [markNil] wait [markBtnCancel] close #mark exit sub [markFinished] #mark.Show, "value? box$" if box$="set" then doGraphMarkers=1 else doGraphMarkers=0 #mark.Bounded, "value? box$" if box$="set" then doPeaksBounded=1 else doPeaksBounded=0 doLRRelativeTo$="" : doLRRelativeAmount=0 : doLRAbsolute=0 'ver115-3f. User has no way to set doLRAbsolute #mark.Down3, "value? box$" if box$="set" then doLRRelativeTo$="P+" : doLRRelativeAmount=-3 #mark.Up3, "value? box$" if box$="set" then doLRRelativeTo$="P-" : doLRRelativeAmount=3 'Auto locating of markers prevents other automatic uses of the markers if doLRRelativeTo$<>"" then doFilterAnalysis=0 close #mark if haltsweep=0 then call RefreshGraph 0 'if not sweeping redraw graph ver114-7d end sub sub mUpdateMarkerEditButtons 'Enable/disable buttons based on selected marker 'Disable if marker does not exist or for peak markers, which cannot be manually located if selMarkerID$="" then 'ver114-4a added this if... block noMarker=1 else pointNum=gMarkerPointNum(mMarkerNum(selMarkerID$)) if pointNum<0 then noMarker=1 else noMarker=0 end if if selMarkerID$="P+" or selMarkerID$="P-" then notManual=1 else notManual=0 'ver114-4a if twoPortWinHndl$="" then 'main graph window if noMarker or notManual then 'ver114-4a #handle.markInc, "!disable" #handle.markDec, "!disable" #handle.markFreq, "!disable" #handle.markEnterFreq, "!disable" if noMarker then #handle.markDelete, "!disable" else #handle.markDelete, "!enable" else #handle.markInc, "!enable" #handle.markDec, "!enable" #handle.markFreq, "!enable" #handle.markEnterFreq, "!enable" #handle.markDelete, "!enable" end if else if noMarker or notManual then 'ver114-4a #twoPortWin.markInc, "!disable" #twoPortWin.markDec, "!disable" #twoPortWin.markFreq, "!disable" #twoPortWin.markEnterFreq, "!disable" if noMarker then #twoPortWin.markDelete, "!disable" else #twoPortWin.markDelete, "!enable" else #twoPortWin.markInc, "!enable" #twoPortWin.markDec, "!enable" #twoPortWin.markFreq, "!enable" #twoPortWin.markEnterFreq, "!enable" #twoPortWin.markDelete, "!enable" end if end if end sub sub mUserMarkSelect btn$ 'Marker was selected in combobox. if twoPortWinHndl$="" then #handle.selMark, "selection? selMarkerID$" _ else #twoPortWin.selMark, "selection? selMarkerID$" 'ver116-2a if selMarkerID$="None" then selMarkerID$="" 'Show marker editing info; ver114-4a revised call mUpdateMarkerEditButtons 'Enable/disable proper buttons call mDisplaySelectedMarker 'Display numeric info 'Update Smith chart. But if sweep is in progress don't, because we may have 'been called by program action. If sweeping, it will be updated at refresh time. if haltsweep=0 and smithGraphHndl$()<>"" then call smithRefreshMarkerInfo 'ver115-2c end sub sub mMarkSelect markID$ 'Program selection specified marker in combo box if markID$="" then s$="None" else s$=markID$ if twoPortWinHndl$="" then #handle.selMark, "select ";s$ if multiscanInProgress=0 then 'Don't do if window is hidden due to multiscan ver115-8d #handle.selMark, "setfocus" 'ver116-2a #handle.Restart, "!setfocus" 'take focus off combobox end if else #twoPortWin.selMark, "select ";s$ 'ver116-2a if multiscanInProgress=0 then 'Don't do if window is hidden due to multiscan ver115-8d #twoPortWin.selMark, "setfocus" 'ver116-2a #twoPortWin.markInc, "+" 'take focus off combobox end if end if call mUserMarkSelect "" 'Take same action as though user selected the marker end sub sub mBtnMarkClear btn$ 'Button to clear all markers was clicked call mClearMarkers 'call HideMarkerEdit 'delver114-4a if twoPortWinHndl$="" then 'ver116-4a if doGraphMarkers=1 then call RefreshGraph 0 'ver115-1b else call TwoPortDrawGraph 0 'ver116-4a end if end sub sub mBtnMarkEdit btn$ 'Button to edit selected marker was clicked 'call ShowMarkerEdit 'delver114-4a call mUpdateMarkerEditButtons end sub sub mBtnMarkDelete btn$ 'Button to delete selected marker was clicked call mDeleteMarker selMarkerID$ 'call HideMarkerEdit 'delver114-4a if twoPortWinHndl$="" then 'ver116-2a if doGraphMarkers=1 then call RefreshGraph 0 else call mDrawMarkerInfo 'ver114-7d else call TwoPortDrawGraph 0 'ver116-2a end if end sub [btnIncPoint] 'added by ver115-1a if haltsweep=1 then gosub [FinishSweeping] call IncDecPoint "markInc" if varwindow = 1 then gosub [preupdatevar] 'will update variables window. wait [btnDecPoint] 'added by ver115-1a if haltsweep=1 then gosub [FinishSweeping] call IncDecPoint "markDec" if varwindow = 1 then gosub [preupdatevar] 'will update variables window. wait sub IncDecPoint btn$ 'Button to increment or decrement frequency was clicked 'The button handlers call us with btn$="markInc" or "markDec" 'Change frequency, and redraw 'to update pointer on screen. But if markers are hidden, just refresh the marker info. if selMarkerID$="" then exit sub 'No marker selected, so can't modify ver114-4a 'We go back to the marker point number rather than trying to derive it from the current frequency, 'because of issues with zero-width scans or very narrow scans. markPoint=gMarkerPointNum(mMarkerNum(selMarkerID$)) 'Note: the idea of equating a frequency to a point number (possibly with fractional part) does not work perfectly 'because of rounding of frequencies to the nearest Hz. If we set a marker to an integral point number, that 'might in theory be a frequency with fractional Hz, so when the freq is rounded and converted to a point number, 'it may be point 5.997, even though we specified it as point 5. if btn$="markDec" then 'Decrease markPoint to an integral value. If its fractional part is less than 0.1, it will become 'the integer next lower than its integral part; otherwise it becomes its integral part. markPoint=int(markPoint-0.1) 'ver116-4f else 'Increment 'Increase markPoint to an integral value. If its fractional part is more than 0.9, it will become 'the integer two larger than its integral part; otherwise it becomes one greater than its integral part. markPoint=int(markPoint+1.1) 'ver116-4f end if if markPoint<1 then markPoint=1 else if markPoint>gPointCount() then markPoint=gPointCount() markFreq=gGetPointXVal(markPoint) if twoPortWinHndl$="" then print #handle.markFreq, using("####.######", markFreq) _ else #twoPortWin.markFreq, using("####.######", markFreq) ' Enter new frequency into boxver116-2a call gUpdateMarkerPointNum mMarkerNum(selMarkerID$), markPoint if twoPortWinHndl$="" then 'ver116-2a if doGraphMarkers=1 then call RefreshGraph 0 else call mDrawMarkerInfo 'ver114-7d else call TwoPortDrawGraph 0 'ver116-2a end if leftstep=markPoint-1 'Make leftstep a step number, not point number, for [preupdatevar] ver115-1a end sub sub mEnterMarker btn$ 'Marker Enter button was clicked 'Enter new marker info based on the frequency. If the point num was changed, 'the frequency was updated, but the user may have changed the frequency so 'the point number may be outdated. if twoPortWinHndl$="" then 'ver116-4a #handle.markFreq, "!contents? markFreq$" 'get frequency from proper box else #twoPortWin.markFreq, "!contents? markFreq$" end if markFreq=val(markFreq$) markPoint=gPointNumOfX(markFreq) 'Find point number matching this frequency. if msaMode$="SA" then markPoint=int(0.5+markPoint) 'Round to integral point in SA mode ver115-2d if markPoint <1 then markPoint=1 maxPoint=gPointCount() 'ver114-4a if markPoint>maxPoint then markPoint=maxPoint markFreq=gGetPointXVal(markPoint) if twoPortWinHndl$="" then 'ver116-2a print #handle.markFreq, using("####.######", markFreq) 'Enter frequency into box, in case we changed it ver116-2a call gUpdateMarkerPointNum mMarkerNum(selMarkerID$), markPoint if doGraphMarkers=1 then call RefreshGraph 0 else call mDrawMarkerInfo 'ver114-7d else print #twoPortWin.markFreq, using("####.######", markFreq) 'Enter frequency into box, in case we changed it ver116-2a call gUpdateMarkerPointNum mMarkerNum(selMarkerID$), markPoint call TwoPortDrawGraph 0 'ver116-2a end if end sub sub mDisplaySelectedMarker 'Update label, point number and freq for selected marker 'ver114-5L deleted actual selection of marker in combobox, which is usually not necessary if selMarkerID$="" then #handle.markFreq, "" : exit sub 'No marker to update ver114-4a markPoint=gMarkerPointNum(mMarkerNum(selMarkerID$)) if markPoint<0 then #handle.markFreq, "" : exit sub 'No marker to update ver114-4a markFreq=gGetPointXVal(markPoint) if twoPortWinHndl$="" then #handle.markFreq, using("####.######",markFreq) _ else #twoPortWin.markFreq, using("####.######",markFreq) 'ver116-2a 'If we have reference lines, other than fixed value, print their values as a message if twoPortWinHndl$="" and referenceLineType>0 and referenceLineType<>3 then 'ver115-6d added display of reference values message$="Marker ";selMarkerID$;": " call DetermineGraphDataFormat Y1DataType, axisLab1$, dataLab1$,isPhase1,y1Form$ call DetermineGraphDataFormat Y2DataType, axisLab2$, dataLab2$,isPhase2,y2Form$ call CalcReferences markPoint-1, isPhase1, ref1, isPhase2, ref2 if (Y1DataType<>constNoGraph) and (referenceTrace and 1) then 'Do reference for Y1 message$=message$; dataLab1$;" Ref=";uFormatted$(ref1, y1Form$);" " end if if (Y2DataType<>constNoGraph) and (referenceTrace and 2)=2 then 'Do reference for Y2 message$=message$; dataLab2$;" Ref=";uFormatted$(ref2, y2Form$);" " end if call PrintMessage end if end sub sub autoWaitPrecalculate 'Activate use of auto wait times with specified precision level ver116-1b 'Video filter should be properly set first. select case autoWaitPrecision$ case "Fast" autoWaitMaxErrorDB=1 : autoWaitMaxErrorDegrees=1.5 case "Normal" autoWaitMaxErrorDegrees=0.1 if msaMode$="SA" then autoWaitMaxErrorDB=0.25 else autoWaitMaxErrorDB=0.1 case else ' "Precise" 'Note that in precise mode we do an extra rep after determinining it is OK to quit, 'so the actual error should be much less the specified. autoWaitMaxErrorDB=0.03 : autoWaitMaxErrorDegrees=0.03 end select 'Calculate allowed errors. These are local variables maxErrorPhaseADC=int(autoWaitMaxErrorDegrees*maxpdmout/360)+1 'convert degree error to ADC error 'Max allowed mag error in ADC units is max db error times slope in ADC per dB. maxErrorLowEndADC=autoWaitMaxErrorDB*calLowEndSlope maxErrorCenterADC=autoWaitMaxErrorDB*calCenterSlope maxErrorHighEndADC=autoWaitMaxErrorDB*calHighEndSlope if msaMode$="SA" or msaMode$="ScalarTrans" then autoWaitTC=videoMagTC else autoWaitTC=max(videoMagTC, videoPhaseTC) 'ver116-4j 'We do repeated reads 'until we get stable readings. The delay between reads is nominally autoWaitTC. 'So we pre-calculate here how much the ADC should be allowed to change during that time. 'The fraction of the total change that remains unsettled after N time constants will 'be e^(-N), and the proportion that did settle is 1-e^(-N). We don't want the remaining change to 'exceed the allowed error. 'The remaining settlement is a proportion R=e^(-N)/(1-e^(-N)) of the measured settlement. 'The max allowed change is where R*measuredChange=max allowed error, so 'max allowed measured change=maxAllowedError/R ' 'In fact the time delay will generally be more than we specify, so we could allow a bigger change 'if we knew the actual time, but the approach here is conservative. 'For mag, N=1 so R=0.58 'ver116-4j changed to use autoWaitTC rather than videoMagTC as the basic wait time N=autoWaitTC/videoMagTC 'number of mag time constants that we wait unsettledFract=exp(0-N) R=max(0.3, unsettledFract/(1-unsettledFract)) 'Limit R to be conservative autoWaitMaxChangeLowEndADC=int(maxErrorLowEndADC/R)+1 autoWaitMaxChangeCenterADC=int(maxErrorCenterADC/R)+1 autoWaitMaxChangeHighEndADC=int(maxErrorHighEndADC/R)+1 N=autoWaitTC/videoPhaseTC 'number of phase time constants that we wait unsettledFract=exp(0-N) R=max(0.3, unsettledFract/(1-unsettledFract)) 'Limit R to be conservative autoWaitMaxChangePhaseADC=int(maxErrorPhaseADC/R)+1 end sub 'ver116-1b totally revised SelectVideoFilter sub SelectVideoFilter 'Select XNarrow, Narrow, Mid or Wide video filter, based on videoFilter$ ver116-1b 'We also record the capacitance values 'For speed reasons, port is not global so here we have to use globalPort to identify the parallel port 'Likewise, control is not global, so we have to recreate it here control=globalPort+2 videoFilterNum=0 for i=1 to 4 'match the name to a filter if videoFilterNames$(i)=videoFilter$ then videoFilterNum=i: exit for next i if videoFilterNum=0 then Notice "Invalid video filter selection." videoFilterNum=1 : videoMagCap=0.001 : videoPhaseCap=0.001 'default to Wide ver116-4f else videoMagCap=max(0.002, videoFilterCaps(videoFilterNum,0)) 'ver116-4f videoPhaseCap=max(0.011, videoFilterCaps(videoFilterNum,1)) 'capacitor values--but not zero 'ver116-4f end if videoFilterAddress=videoFilterNum-1 'So address runs from 0 to 3. videoPhaseTC=10*videoPhaseCap 'Time constant in ms, based on 10k resistor and cap in uF videoMagTC=2.7*videoMagCap 'Time constant in ms, based on 2.7k resistor and cap in uF switchData=switchLatchBits(freqBand) 'All bits for latch #4, with latch pulse set high ver116-4b if switchHasVideo and suppressHardware=0 then 'ver116-4b select case cb case 1 'Original 'Can't do this switch on original control board case 2 'SLIM out globalPort, switchData 'presents switch data to control buffer. Note we don't toggle latch pulse ver116-4b out control, globalSTRB 'enters data to control board latch out control, globalContClear 'freezes latch data out globalPort, 0 case 3 'USB ver116-4h USBwrbuf$ = "A20100"+ToHex$(switchData) 'write this string but don't do latch pulse if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 4 as short, result as boolean end select end if call autoWaitPrecalculate end sub sub SelectLatchedSwitches desiredFreqBand 'ver116-1b ver116-4s 'Sets the switches which (may) require a latch pulse. These are the band switch, forward/reverse and transmit/reflect 'videoFilterAddress, freqBand, switchFR and switchTR must be properly set before entering 'For speed reasons, port is not global so here we have to use globalPort to identify the parallel port 'Likewise, control is not global, so we have to recreate it here if desiredFreqBand=0 then desiredFreqBand=lastSetBand 'don't change if auto mode and actual band not yet determined ver116-4s lastSetBand=desiredFreqBand if suppressHardware then exit sub if switchHasBand=0 and switchHasTR=0 and switchHasFR=0 then exit sub 'No physical latched switches control=globalPort+2 switchData=switchLatchBits(desiredFreqBand) 'All bits, with latch pulse set high ver116-4s 'We output the required bits with the latch pulse high, then briefly bring the latch 'pulse low. Hopefully the pulse lasts somewhere between 2 and 200 us. select case cb case 1 'Original 'Can't do these switches on original control board case 2 'SLIM 'We output the required bits with the latch pulse high, then briefly bring the latch 'pulse low. Hopefully the pulse lasts somewhere between 2 and 200 us. out globalPort, switchData 'presents switch data to control buffer with latch pulse high out control, globalSTRB 'enters data to control board latch #4 out control, globalContClear 'freezes latch data out globalPort, switchData-128 'presents switch data to control buffer with latch pulse low for i=1 to 5 'repeat for time delay to lengthen pulse out control, globalSTRB 'enters data to control board latch #4; basically just activates latch pulse next i out control, globalContClear 'freezes latch data out globalPort, switchData 'presents switch data to control buffer with latch pulse high out control, globalSTRB 'enters data to control board latch #4; basically just de-activates latch pulse out control, globalContClear 'freezes latch data out globalPort, 0 'zeroes parallel port data bits case 3 'USB ver116-4h USBwrbuf$ = "A20100"+ToHex$(switchData) USBwrbuf2$ = "A20100"+ToHex$(switchData-128) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 4 as short, result as boolean if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf2$ as ptr, 4 as short, result as boolean if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 4 as short, result as boolean 'There is substantial delay in the DLL calls so the pulse will likely be at least 100 us. end select 'Wait a bit for capacitors to recover a little, to be sure we don't do a lot of latching in a short 'time and drain the switch capacitors. This should be OK if the capacitors discharge less than 10% during latching 'and the recharge time constant is one second or less. The switches can probably take several latchings 'separated by 750 ms during startup, and then one latching every sweep after that. 'Caller during startup will have to add a little extra delay. call uSleep 250 end sub function switchLatchBits(desiredFreqBand) 'Returns value for setting Latch U4 on SLIM control board 'ver116-1b 'ver116-4s 'bit 0 VS0 Video Filter Address, low order bit 'bit 1 VS1 Video Filter Address, high order bit 'bit 2 BS0 Band Selection, low order bit 'bit 3 BS1 Band Selection, high order bit 'bit 4 FR DUT Direction, Forward (0) or Reverse 'bit 5 TR VNA Selection, Transmission (0) or Reflection 'bit 6 Spare 'bit 7 PS Pulse Start (a/k/a Latch Pulse), common to all latching relays. 'Normally high; pulsed low for roughly 2-200 us to trigger relay latching. 'Note we make PS high, its normal state switchLatchBits=videoFilterAddress + 4*desiredFreqBand + 16*switchFR + 32*switchTR + 128 'ver116-4s end function sub SelectFilter byref fbank 'Select filter indicated by path$, which is in form "Path N" modver116-4j 'Note that hardware data may have to be recalculated if finalfreq changed, by doing [PartialRestart] 'filtbank is passed here as fbank so we can change the non-global filtbank filtIndex=val(Word$(path$,2)) 'ver114-4c path number is second word filtIndex will be 1-4 if filtIndex<=0 or filtIndex>MSANumFilters then filtIndex=1 : notice "Invalid filter selection." call calInstallFile filtIndex 'Loads file and sets finalfreq and finalbw if filtIndex<=2 then FiltA1=0 else FiltA1=1 'Set filter address if filtIndex=1 or filtIndex=3 then FiltA0=0 else FiltA0=1 call CommandFilter fbank 'Calculate fbank and Physically select filter ver116-4j end sub sub CommandFilter byref fbank 'ver116-4j made this a subroutine 'filtbank is passed here as fbank so we can change the non-global filtbank if cb = 0 then fbank = FiltA1*8 + FiltA0*4 : call CommandFilterOrigCB fbank if cb = 2 then fbank = FiltA1*64 + FiltA0*32 : call CommandFilterSlimCB fbank if cb = 3 then fbank = FiltA1*64 + FiltA0*32 : call CommandFilterSlimCBUSB fbank 'USB:01-08-2010 end sub sub CommandFilterOrigCB byref fbank 'command 1 of 4 and latch it ver116-4j made this a subroutine 'fbank should be the non-global filtbank if suppressHardware then exit sub 'ver115-6c control=globalPort+2 out globalPort, fbank 'presents filter address to control buffer out control, globalINIT 'presents filter address to Filter Bank out globalPort, fbank + 1 'latches filter address into Filter Bank using latch signal out globalPort, fbank 'leaves filter address on Filter Bank, removing latch signal out control, globalContClear 'removes filter address from Filter Bank out globalPort, 0 'removes filter address from control buffer end sub sub CommandFilterSlimCB byref fbank 'ver116-4j made this a subroutine 'fbank should be the non-global filtbank if suppressHardware then exit sub 'ver115-6c control=globalPort+2 out globalPort, fbank 'presents filter address to control buffer out control, globalSELT 'presents filter address to Filter Bank out globalPort, fbank + 128 'latches filter address into Filter Bank using latch signal out globalPort, fbank 'leaves filter address on Filter Bank, removing latch signal out control, globalContClear 'removes filter address from Filter Bank out globalPort, 0 'removes filter address from control buffer end sub sub CommandFilterSlimCBUSB byref fbank 'USB:01-08-2010 ver116-4j made this a subroutine 'fbank should be the non-global filtbank USBwrbuf$ = "A10300"+ToHex$(fbank)+ToHex$(fbank+128)+ToHex$(fbank) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 6 as short, result as boolean end sub 'SEWgraph added HaltAtEnd [HaltAtEnd] 'Halt At End button pushed. 'This is actually the OneStep button during a scan, so we get here from [OneStep] 'The only way to get here is for the user to click Halt At End during a sweep, which will be 'detected on the "scan" command in the sweep loop. We just set a flag and return to the point 'after the scan command. haltAtEnd=1 'Set flag to cause halt at end of this sweep. goto [PostScan] 'SEWgraph changed [OneStep] 'SEWgraph The OneStep button shows HaltAtEnd during a scan if haltsweep = 1 then goto [HaltAtEnd] 'SEWgraph 'If the graph has been redrawn without erasure, we need to erase that part, because 'the normal one-point draw only erases a single segment, several points ahead. onestep = 1 'ver111-26 goto [FocusKeyBox] [Continue] 'SEWgraph The Continue button shows Halt during a scan if haltsweep = 1 then goto [Halted] 'ver111-26 onestep = 0 'ver111-26 [FocusKeyBox] call DisplayButtonsForRunning 'SEW8 consolidated various button commands if isStickMode=0 then call gRestoreErasure 'ver116-4s No erasure in stick modes message$="" : call PrintMessage 'ver114-4f 'Indicate whether we are resuming a scan that was stopped in the middle. 'If PartialRestart was done, we stopped prior to the first step, and are not "resuming" if haltedAfterPartialRestart then scanResumed=0 else scanResumed=1 'ver119-1b goto [StartSweep] [PartialRestart] 'Restart but return before taking first data 'This is used to implement user changes without taking data. 'User should set suppressHardwareInitOnRestart=1 if desired to save time by suppressing initialization ver116-4d 'This flag is automatically turned off after Restart, so it is a one time thing. returnBeforeFirstStep=1 'So we stop before actually scanning, at which point this flag is reset gosub [Restart] return [RestartButton] 'ver115-8c if haltsweep = 1 then goto [Halted] goto [Restart] [Restart] haltsweep=0 'ver115-8c deleted check for haltsweep 'When a window is closed, all graphics drawing operations are deleted from memory 'Auxiliary graph data is computed, and does not survive the generation of new data. 'So if aux data is currently graphed, we turn it off. ver115-4a if Y1DataType>=constAux0 and Y1DataType<=constAux5 then Y1DataType=constNoGraph if Y2DataType>=constAux0 and Y2DataType<=constAux5 then Y2DataType=constNoGraph if Y1DataType=constNoGraph and Y2DataType=constNoGraph then call SetDefaultGraphData 'So we have something to graph call ClearAuxData 'Indicate aux data not valid by clearing graph names ver115-4a 'gosub [UpdateGraphParams] 'delver115-8c will be done at [SkipHardwareInitialization] onestep = 0 'ver111-26 call DisplayButtonsForRunning 'SEW8 replaced print #main.restart, "Running" 'SEWgraph1 Start new sweep series. 'Ver114-2b Reinitialize hardware every time if suppressHardwareInitOnRestart then 'ver115-8c suppressHardwareInitOnRestart=0 'Clear flag; we only skip initialization for one restart after flag is set. goto [SkipHardwareInitialization] else goto [InitializeHardware] end if sub ClearAuxData 'Clear the auxiliary graph data by blanking the graph names for i=0 to 5 auxGraphDataFormatInfo$(i,0)="" next i end sub [Showvar] 'modified by ver114-4f to avoid halting sweep and to operate from menu if varwindow=1 then close #varwin:varwindow = 0 'close existing window 'ver114-4f WindowWidth = 200 WindowHeight = 450 'ver111-26 UpperLeftX = DisplayWidth-WindowWidth-10 'ver114-4f UpperLeftY = 10 'ver114-4f 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=";using("####.###",datatable(thisstep,2)), 5, 350, 220, 15 'raw magdata bits, MSA input power(massaged) 'ver115-5b 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)+baseFrequency, 5, 380, 180, 15 'ver116-4L 'real final IF = LO2-(LO1-thisfreq) statictext #varwin.variable27, "glitchtime = ";glitchtime, 5, 395, 180, 15 'ver114-7b open "Variables Window" for dialog as #varwin:varwindow = 1 print #varwin, "trapclose Closevarwin" 'goto Closevarwin if xit is clicked ver115-1b changed to subroutine if haltsweep=1 then goto [PostScan] 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=";using("####.###",datatable(thisstep,2))' ver115-5b 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 print #varwin.variable27, "glitchtime = ";glitchtime 'ver114-7b return sub Closevarwin hndl$ 'ver115-1b changed to subroutine close #varwin:varwindow = 0 'close out variables window end sub function Equiv1GFreq(f, aBand) 'Return equivalent 1G frequency for f, based on aBand (0,1,2 or 3) 'ver116-4s if aBand=0 then 'ver116-4s aBand=1 if f>bandEnd2G then aBand=3 else if f>bandEnd1G then aBand=2 end if select case aBand 'ver116-4s case 1 Equiv1GFreq=f '1G mode; no conversion necessary case 2 '2G mode Equiv1GFreq=f-LO2 case else '3G mode IF1 = LO2 - finalfreq Equiv1GFreq=f-2*IF1 end select end function function ActualSignalFrequency(f,aBand) 'Return actual signal frequency for equiv 1G freq f, based on aBand (1,2 or 3) ver116-4s select case aBand 'ver116-4s case 1 ActualSignalFrequency=f '1G mode; no conversion necessary case 2 '2G mode ActualSignalFrequency=f+LO2 case else '3G mode IF1 = LO2 - finalfreq ActualSignalFrequency=f+2*IF1 end select end function [CalculateAllStepsForLO1Synth] haltstep = thisstep 'remember where we were in the sweep when halted for thisstep = 0 to steps 'ver116-4s moved saving of frequency in other arrays to the place where hardware frequency is calculated. 'ver116-4k added baseFrequency, which gets added when commanding but does not affect the stored frequencies. thisfreq=datatable(thisstep, 1) 'ver116-4s LO1 = baseFrequency + thisfreq + LO2 - finalfreq 'calculates the actual LO1 frequency:thisfreq,LO2,finalfreq are actuals. '[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 'ver114-4e beep:error$="DDS1output too high for filter" message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if if appxdds1-dds1output>dds1filbw/2 then 'ver114-4e beep:error$="DDS1output too low for filter" message$=error$ : call PrintMessage 'ver114-4e call RequireRestart 'ver115-1c wait end if 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 'SEWgraph Frequencies have been pre-calculated in the graphing module via gGenerateXValues thisfreq=datatable(thisstep,1) : thisBand=datatable(thisstep,4) 'ver116-4s TrueFreq=ActualSignalFrequency(thisfreq, thisBand)+baseFrequency 'ver116-4s 'ver116-4k baseFrequency gets added when commanding but does not affect the stored frequencies. 'if FreqMode=1 then thisfreq=TrueFreq else thisfreq=Equiv1GFreq(TrueFreq) 'ver115-1c get equivalent 1G frequency ver115-1d delver116-4s if TGtop = 1 then LO3 = LO2 - finalfreq - offset 'for orig, fixed freq TG ver111-15a 'or LO3 = LO1 - thisfreq - offset 'ver115-1c rearranged the following if... block and added the FreqMode=3 test if TGtop = 2 and gentrk = 1 then if normrev = 0 then if thisBand=3 then 'ver116-4s LO3 = TrueFreq + offset - LO2 'ver116-4k 'Mode 3G sets LO3 differently else LO3 = LO2 + thisfreq + offset 'ver116-4k 'for new TG, Trk Gen mode, normal end if end if if normrev = 1 then 'SEWgraph Frequencies have been pre-calculated in the graphing module via gGenerateXValues 'We can just retrieve them in reverse order. TrueFreq=gGetPointXVal(steps-thisstep+1)+baseFrequency 'Point number is 1 greater than step number ver116-4L if thisBand=1 then revfreq=TrueFreq else revfreq=Equiv1GFreq(TrueFreq, thisBand) 'ver115-1d get equiv 1G freq ver116-4s if thisBand=3 then 'ver115-1d added this if... block ver116-4s LO3 = TrueFreq + offset - LO2 'Mode 3G sets LO3 differently else LO3 = LO2 + revfreq + offset 'for new TG, Trk Gen mode, normal end if end if end if if TGtop = 2 and gentrk = 0 then 'for new TG, Sig Gen mode ver116-4p 'We will try to produce sgout, either by LO3-LO2(for 0 to LO2), LO3 (LO2 to 2*LO2) or LO3+LO2 (above 2*LO2) select case 'ver116-4p case sgout<=LO2 : LO3=sgout+LO2 'ver116-4r case sgout>2*LO2 : LO3=sgout-LO2 'ver116-4r case else : LO3=sgout 'ver116-4r end select end if '[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 'ver114-4e beep:error$="DDS3 output too high for filter" message$=error$ : call PrintMessage call RequireRestart 'ver115-1c wait end if if appxdds3-dds3output>dds3filbw/2 then 'ver114-4e beep:error$="DDS3output too low for filter" message$=error$ : call PrintMessage call RequireRestart 'ver115-1c wait end if 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 if cb = 3 then 'USB:11-08-2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADevicePopulateDDSArrayBitReverse", USBdevice as long, ptrSPLL1Array as ulong, Int64N as ptr, thisstep as short, 40 as short, result as boolean 'USB:11-08-2010 else 'USB:05/12/2010 '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 end if 'USB:05/12/2010 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 if cb = 3 then'USB:11-08-2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADevicePopulateDDSArrayBitReverse", USBdevice as long, ptrSPLL3Array as ulong, Int64N as ptr, thisstep as short, 40 as short, result as boolean 'USB:11-08-2010 else 'USB:05/12/2010 '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 end if 'USB:05/12/2010 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 if cb = 3 then'USB:11-08-2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADevicePopulateDDSArray", USBdevice as long, ptrSDDS1Array as ulong, Int64SW as ptr, thisstep as short, result as boolean 'USB:11-08-2010 else 'USB:05/12/2010 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 end if 'USB:05/12/2010 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 if cb = 3 then'USB:11-08-2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADevicePopulateDDSArray", USBdevice as long, ptrSDDS3Array as ulong, Int64SW as ptr, thisstep as short, result as boolean 'USB:11-08-2010 else 'USB:05/12/2010 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 end if 'USB:05/12/2010 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 if cb <> 3 then 'USB:05/12/2010 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 else 'USB:05/12/2010 if USBdevice <> 0 then CALLDLL #USB, "UsbMSADevicePopulateAllArray", USBdevice as long, steps as short, 40 as short, _ 0 as long, ptrSPLL1Array as long, ptrSDDS1Array as long, ptrSPLL3Array as long, _ ptrSDDS3Array as long, 0 as long, 0 as long, 0 as long, _ result as boolean 'USB:11-08-2010 end if 'USB:05/12/2010 thisstep = rememberthisstep 'ver116-4k 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 if cb = 3 then gosub [CommandPLLslimUSB] 'USB:01-08-2010 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] [CommandPLLslimUSB] 'USB:01-08-2010 if USBdevice = 0 then return 'USB:05/12/2010 CALLDLL #USB, "UsbMSADeviceWriteInt64MsbFirst", USBdevice as long, 161 as short, Int64N as ptr, 24 as short, 1 as short, filtbank as short, datavalue as short, result as boolean 'USB:11-08-2010 pdmcommand = phaarray(thisstep,0)*64 'do not disturb PDM state, this may be used during Spur Test USBwrbuf$ = "A30200"+ToHex$(pdmcommand + levalue)+ToHex$(pdmcommand) CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 5 as short, result as boolean 'USB:05/12/2010 return [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 suppressPhase or msaMode$="SA" or msaMode$="ScalarTrans" then return ' not in VNA mode, skip the PDM 'ver116-1b pdmcmd = phaarray(thisstep,0) 'ver111-39d if pdmcmd = lastpdmstate then return 'don't waste time commanding gosub [VideoGlitchPDM] 'ver114-6c 'lastpdmstate = pdmcmd 'delver114-6c we won't update "lastpdmstate" until it is actually commanded 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 msaMode$<>"SA" and msaMode$<>"ScalarTrans" then gosub [CommandPDMOrigCB] 'ver114-5n 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 lastpdmstate=phaarray(thisstep,0) 'ver114-6c 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 if cb = 3 then goto [CommandPDMSlimUSB] 'USB:01-08-2010 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 lastpdmstate=phaarray(thisstep,0) 'ver114-6c 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 lastpdmstate=phaarray(thisstep,0) 'ver114-6c return 'to [CommandPDMonly] [CommandPDMSlimUSB] 'USB:01-08-2010 i = phaarray(thisstep,0)*64 USBwrbuf$ = "A30300"+ToHex$(i)+ToHex$(i+32)+ToHex$(i) if USBdevice <> 0 then CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 6 as short, result as boolean lastpdmstate=phaarray(thisstep,0) 'ver114-6c return [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 lastpdmstate=phaarray(thisstep,0) 'ver114-6c return 'to [CommandThisStep] ' **************** 'USB:05/12/2010 ' following code changed from previous USB code ' USB: 15/08/10 ' all three of the following work. SLowest at the top, fastest at the bottom '[CommandAllSlimsUSB] 'USB:01-08-2010 ' '(send data and clocks without changing Filter Bank) ' if USBdevice = 0 then return ' CALLDLL #USB, "UsbMSADeviceAllSlims", USBdevice as long, thisstep as short, filtbank as short, result as boolean 'USB:11-08-2010 ' pdmcmd = phaarray(thisstep,0)*64 'ver111-39d ' USBwrbuf$ = "A30300"+ToHex$(le1 + fqud1 + le3 + fqud3 + pdmcmd)+ToHex$(pdmcmd + 32)+ToHex$(pdmcmd) ' CALLDLL #USB, "UsbMSADeviceWriteString", USBdevice as long, USBwrbuf$ as ptr, 6 as short, result as boolean ' lastpdmstate=phaarray(thisstep,0) 'ver114-6c ' return '[CommandAllSlimsUSB] 'USB:01-08-2010 ' '(send data and clocks without changing Filter Bank) ' if USBdevice = 0 then return ' pdmcmd = phaarray(thisstep,0)*64 ' i = le1 + fqud1 + le3 + fqud3 ' CALLDLL #USB, "UsbMSADeviceAllSlimsAndLoad", USBdevice as long, thisstep as short, filtbank as short, i as short, pdmcmd as short, 32 as short, result as boolean 'USB:14-08-2010 ' lastpdmstate=phaarray(thisstep,0) 'ver114-6c ' return [CommandAllSlimsUSB] ' USB: 15/08/10 '(send data and clocks without changing Filter Bank) if USBdevice = 0 then return 'USB:05/12/2010 if thisstep = 0 then 'USB:05/12/2010 UsbAllSlimsAndLoadData.filtbank.struct = filtbank 'USB:05/12/2010 UsbAllSlimsAndLoadData.latches.struct = le1 + fqud1 + le3 + fqud3 'USB:05/12/2010 UsbAllSlimsAndLoadData.pdmcmdmult.struct = 64 'USB:05/12/2010 UsbAllSlimsAndLoadData.pdmcmdadd.struct = 32 'USB:05/12/2010 end if 'USB:05/12/2010 UsbAllSlimsAndLoadData.pdmcommand.struct = phaarray(thisstep,0) 'USB:05/12/2010 UsbAllSlimsAndLoadData.thisstep.struct = thisstep 'USB:05/12/2010 CALLDLL #USB, "UsbMSADeviceAllSlimsAndLoadStruct", USBdevice as long, UsbAllSlimsAndLoadData as struct, result as boolean ' USB: 15/08/10 lastpdmstate=phaarray(thisstep,0) 'ver114-6c return [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 lptwindow = 1 then close #LPTwindow 'lpt ver116-4b 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 if axisPrefHandle$<>"" then close #axisPrefHandle 'SEWgraph Close axis preference window; it's a modal dialog so this should not happen if crystalListHndl$<> "" then close #crystalListHndl$ if crystalWindHndl$<> "" then close #crystalWindHndl$ 'ver115-5f if componentWindHndl$<>"" then close #componentWindHndl$ if twoPortWinHndl$<>"" then close #twoPortWinHndl$ 'ver116-1b call smithFinished "" 'ver115-1b for i=1 to multiscanMaxNum thisWindowHndl$= multiscanWindowHandlesLB$(i) if thisWindowHndl$<>"" then close #thisWindowHndl$ 'Graph windows for multiscans ver115-8c next i CallDLL #DLL.OLE, "CoUninitialize", ret as void 'To avoid tooltips crash in file dialog ver116-4q Close #DLL.OLE 'ver116-4q ' close USB interface if it was active call UsbCloseInterface 'USB:01-08-2010 close #handle 'close out graph window ret = GlobalFree(hSAllArray) 'USB:01-08-2010 end [SpecialTests]'ver111-36b if haltsweep=1 then gosub [CleanupAfterSweep] 'ver114-4f if special=1 then goto [CloseSpecial] WindowWidth = 200 WindowHeight = 300 UpperLeftX = DisplayWidth-WindowWidth-20 'ver114-4f UpperLeftY = 5 'ver114-4f BackgroundColor$ = "buttonface" 'color changed by ver116-4k ForegroundColor$ = "black" TextboxColor$ = "white" 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 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 if msaMode$<>"SA" and msaMode$<>"ScalarTrans" then button #special.pdminv, "Change PDM", [ChangePDM], UL, 5, 130, 90, 20 'ver115-4d button #special.insert, "Sync Test PDM", [SyncTestPDM], UL, 5, 155, 90, 20 'ver112-2f button #special.prevnalin, "Preset Phase Linearity", [PresetVNAlin], UL, 5, 180, 150, 20 'ver112-2f ver114-5n ver114-8c end if button #special.lpttest, "LPT Port Test", [LPTportTest], UL, 5, 220, 100, 20 'lpt ver116-4b button #special.cftest, "Cavity Filt Test", [CavityFilterTest], UL, 5, 250, 100, 20 'cav ver116-4c open "Special Tests Window" for dialog as #special:special = 1 #special, "font ms_sans_serif 9" 'ver116-4m 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 print #special, "trapclose [CloseSpecial]" 'goto [CloseSpecial] if xit is clicked 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 if cftest = 1 then gosub [CloseCavityFilterTest] 'cav ver116-4c close #special:special = 0 'close out Special Tests window call RequireRestart 'ver116-4c if returnflag = 1 then return 'ver112-2f wait 'cav :Cavity filter test routines added by ver116-4c ' Scans around zero in 0.1 MHz increments--e.g. span=10, steps=100. span=10 to 50, steps=span/0.1 ' User sets up scan, restarts, halts, opens Special Tests Window, clicks cavity filter test button ' The software will command the PLO2 to maintain an offset from PLO 1 by exactly the amount of the ' Final I.F., that is, PLO2 will always be equal to PLO1+FIF ' PLL2 Rcounter buffer is commanded one time, to assure pdf will be 100 KHz. Done during Init after "Restart" ' PLO2 N counter buffer is commanded at each step in the sweep ' The actual frequency that is passed through the Cavity Filter is the displayed frequency plus 1024 MHz. ' The Cavity Filter sweep limitations are: ' the lowest frequency possible is where PLO 1 cannot legally command (Bcounter=31, appx 964 MHz) ' (PLO1 or PLO2 bottoming out at 0V is also limit, but likely below 964 MHz) ' the highest frequency possible s where PLO 2 tops out (vco volts near 5v, somewhere between 1050 to 1073 MHz) ' Sweep can be halted at any time and Sweep Parameters can be changed, then Continue or Restart ' The Special Tests window must be closed before MSA will return to normal. Must click "Restart". [CavityFilterTest]'comes here when Cavity Filter Test button is clicked if cftest = 1 then wait cftest = 1 enterPLL2phasefreq = PLL2phasefreq PLL2phasefreq = .1 goto [Restart] [CloseCavityFilterTest]'will come here when Special Tests Window is closed cftest = 0 PLL2phasefreq = enterPLL2phasefreq return [CommandLO2forCavTest] appxVCO = finalfreq + PLL1array(thisstep,43) reference = masterclock rcounter = rcounter2 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 'ver115-1c LO2 is now global '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 return [OpenDataWindow]'ver113-5a if haltsweep = 1 then gosub [FinishSweeping] 'ver114-6f '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 = 425 'ver115-4h WindowHeight = 300 UpperLeftX = DisplayWidth-WindowWidth-20 'ver114-6f UpperLeftY = 20 'ver114-6f BackgroundColor$ = "white" ForegroundColor$ = "black" open "Data Window" for text as #datawin datawindow = 1 #datawin, "!font Courier_New 9" 'ver115-2d return sub CloseDataWindow hndl$ 'ver115-1b changed to sub. Note this is never used anyway close #datawin:datawindow = 0 end sub [MSAinputData] 'renamed ver115-5d if msaMode$<>"SA" and msaMode$<>"ScalarTrans" then goto [MagnitudePhaseMSAinput] 'Do phase if we have it gosub [OpenDataWindow] print #datawin," Step Calc Mag Mag AtoD Freq Cal" print #datawin," Num Freq(MHz) Input Bit Val Factor" validSteps=gPointCount()-1 'Number of completed steps 'ver116-1b for i = 0 to validSteps 'ver116-1b freq$=using("####.######",gGetPointXVal(i+1)) 'freq in MHz data1$=using("####.###", datatable(i,2)) 'calculated mag input data2$=using("######", magarray(i,3)) 'Raw ADC bits data3$=using("####.###", freqCorrection(i)) 'Freq correction print #datawin, uAlignDecimalInString$(str$(i),4,4); _ uAlignDecimalInString$(freq$,12,5); _ uAlignDecimalInString$(data1$,9,5); _ uAlignDecimalInString$(data2$,8,7); _ uAlignDecimalInString$(data3$,11,5) next i #datawin, "!origin 1 1" wait [MagnitudePhaseMSAinput]'ver115-4d gosub [OpenDataWindow] print #datawin," Step Calc Mag Mag A/D Freq Cal Pha A/D Processed" print #datawin," Num Freq(MHz) Input Bit Val Factor Bit Val Phase" validSteps=gPointCount()-1 'Number of completed steps 'ver116-1b for i = 0 to validSteps 'ver116-1b freq$=using("####.######",gGetPointXVal(i+1)) 'freq in MHz data1$=using("####.###", datatable(i,2)) 'calculated mag input data2$=using("######", magarray(i,3)) 'Raw ADC bits data3$=using("####.###", freqCorrection(i)) 'Freq correction data4$=using("######",phaarray(i,3)) 'Phase A/D. Bits ver115-5d data5$=using("####.##",datatable(i,3)) 'Phase Processed ver115-5d print #datawin, uAlignDecimalInString$(str$(i),4,4); _ uAlignDecimalInString$(freq$,12,5); _ uAlignDecimalInString$(data1$,9,5); _ uAlignDecimalInString$(data2$,8,7); _ uAlignDecimalInString$(data3$,11,5); _ uAlignDecimalInString$(data4$,8,7); _ uAlignDecimalInString$(data5$,10,5) next i #datawin, "!origin 1 1" wait [MagPhaS21]'ver113-5b gosub [OpenDataWindow] xclm$="!" print #datawin, gGetTitleLine$(1) 'ver115-6a put title in header print #datawin,"!select 1 1" print #datawin,"!insert xclm$" print #datawin, gGetTitleLine$(2) print #datawin,"!select 1 2" print #datawin,"!insert xclm$" print #datawin, gGetTitleLine$(3) print #datawin,"!select 1 3" print #datawin,"!insert xclm$" print #datawin, "# MHZ S DB R ";S21JigR0 print #datawin, " MHz S21_Mag S21_Ang" print #datawin,"!select 1 5" print #datawin,"!insert xclm$" validSteps=gPointCount()-1 'Number of completed steps 'ver116-1b for i = 0 to validSteps 'ver116-1b freq$=using("####.######",S21DataArray(i,0)) data1$=using("####.#####",S21DataArray(i,1)) 'ver115-4d data2$=using("####.##",S21DataArray(i,2)) print #datawin, uAlignDecimalInString$(freq$,11,4); _ uAlignDecimalInString$(data1$,9,5); _ uAlignDecimalInString$(data2$,8,5) next i #datawin, "!origin 1 1" wait [MagPhaS11] ' ver115-2d gosub [OpenDataWindow] xclm$="!" print #datawin, gGetTitleLine$(1) 'ver115-6a put title in header print #datawin,"!select 1 1" print #datawin,"!insert xclm$" print #datawin, gGetTitleLine$(2) print #datawin,"!select 1 2" print #datawin,"!insert xclm$" print #datawin, gGetTitleLine$(3) print #datawin,"!select 1 3" print #datawin,"!insert xclm$" print #datawin, "# MHZ S DB R ";S11GraphR0 print #datawin, " MHz S11_Mag S11_Ang" print #datawin,"!select 1 5" print #datawin,"!insert xclm$ +" validSteps=gPointCount()-1 'Number of completed steps 'ver116-1b for i = 0 to validSteps 'ver116-1b freq$=using("####.######",ReflectArray(i,0)) data1$=using("####.#####",ReflectArray(i,1)) 'ver115-4d data2$=using("####.##",ReflectArray(i,2)) print #datawin, uAlignDecimalInString$(freq$,11,4); _ uAlignDecimalInString$(data1$,9,5); _ uAlignDecimalInString$(data2$,8,5) next i #datawin, "!origin 1 1" wait [DataWin_GraphData] 'Display data for current graph(s) ver115-4h gosub [OpenDataWindow] xclm$="!" print #datawin, gGetTitleLine$(1) 'ver115-6a put title in header print #datawin,"!select 1 1" print #datawin,"!insert xclm$" print #datawin, gGetTitleLine$(2) print #datawin,"!select 1 2" print #datawin,"!insert xclm$" print #datawin, gGetTitleLine$(3) print #datawin,"!select 1 3" print #datawin,"!insert xclm$" #datawin,"Graph Data" print #datawin,"!select 1 4" print #datawin,"!insert xclm$" s$="Freq(MHZ)" if Y1DataType<>constNoGraph then call DetermineGraphDataFormat Y1DataType, y1AxisLabel$, dum1$,dum2,dum3$ s$=s$;" ";y1AxisLabel$ end if if Y2DataType<>constNoGraph then call DetermineGraphDataFormat Y2DataType, y2AxisLabel$, dum$,dum2,dum3$ s$=s$;" ";y2AxisLabel$ end if print #datawin, s$ 'Data heading print #datawin,"!select 1 5" print #datawin,"!insert xclm$" validSteps=gPointCount()-1 'Number of completed steps 'ver116-1b for i = 0 to validSteps 'ver116-1b freq$=using("####.######",gGetPointXVal(i+1)) call CalcGraphData i, y1Val, y2Val, 0 'Get Y1 and Y2 values if Y1DataType=constNoGraph then data1$="" else aVal=abs(y1Val) select case case aVal>=1000000 data1$=uScientificNotation$(y1Val, 6, 1) '6 decimals with zero padding case aVal>=1000 data1$=using("########.###",y1Val) case aVal>=0.000001 data1$=using("#####.######",y1Val) case else 'small values data1$=uScientificNotation$(y1Val, 6, 1) '6 decimals with zero padding end select end if if Y2DataType=constNoGraph then data2$="" else aVal=abs(y2Val) select case case aVal>=1000000 data2$=uScientificNotation$(y2Val, 6, 1) '6 decimals with zero padding case aVal>=1000 data2$=using("########.###",y2Val) case aVal>=0.000001 data2$=using("#####.######",y2Val) case else 'small values data2$=uScientificNotation$(y2Val, 6, 1) '6 decimals with zero padding end select end if if Y1DataType=constNoGraph then 'skip data1 if nonexistent ver115-9d print #datawin, uAlignDecimalInString$(freq$,11,4); _ uAlignDecimalInString$(data2$,22,8) else if Y2DataType=constNoGraph then print #datawin, uAlignDecimalInString$(freq$,11,4); _ uAlignDecimalInString$(data1$,22,8) else print #datawin, uAlignDecimalInString$(freq$,11,4); _ uAlignDecimalInString$(data1$,22,8); _ uAlignDecimalInString$(data2$,22,8) end if end if next i #datawin, "!origin 1 1" wait [LineCalArray]'ver115-2d gosub [OpenDataWindow] xclm$="!" if msaMode$="Reflection" then print #datawin,"Cal Reference" else print #datawin,"Line Calibration" 'ver115-4d print #datawin,"!select 1 1" print #datawin,"!insert xclm$ +" print #datawin, " Freq(MHz) Cal_Mag Cal_Ang" print #datawin,"!select 1 2" print #datawin,"!insert xclm$ +" for i = 0 to steps freq$=using("####.######",gGetPointXVal(i+1)) data1$=using("####.###",lineCalArray(i,1)) data2$=using("####.##",lineCalArray(i,2)) print #datawin, uAlignDecimalInString$(freq$,11,4); _ uAlignDecimalInString$(data1$,9,5); _ uAlignDecimalInString$(data2$,10,5) next i #datawin, "!origin 1 1" wait [DataWin_OSL]'ver115-4a 'OSL calibration standards and coefficients gosub [OpenDataWindow] print #datawin," Freq(MHz) Open_Real Open_Imag Short_Real Short_Imag Load_Real Load_Imag OSL_A_Real OSL_A_Imag OSL_B_Real OSL_B_Imag OSL_C_Real OSL_C_Imag" for i = 0 to steps freq$=using("####.######",gGetPointXVal(i+1)) : OSLdataMin=1e-7 if abs(OSLstdOpen(i,0))"" then 'blank means cancelled bmpName$=FullGraphBmp$() 'name of bitmap of entire graph window bmpsave bmpName$, graphFileName$ 'ver116-4h deleted open and close call uParsePath graphFileName$, imageSaveLastFolder$, dum$ 'Save folder in which file was saved ver115-2a unloadbmp bmpName$ : bmpName$="" 'ver116-1b moved this here end if wait function FullGraphBmp$() 'return name of bitmap for entire graph--grid and surrounding info 'Get Image size by finding center positions and doubling them call HideButtonsOnGraph 'ver114-4f #graphBox$, "home" #graphBox$, "posxy CenterX CenterY" clientWidth = CenterX * 2-1 clientHeight = CenterY * 2-1 print #graphBox$, "getbmp graphbmp 0 0 ";clientWidth;" ";clientHeight call ShowButtonsOnGraph 'ver114-4f FullGraphBmp$="graphbmp" end function [CopyImage] 'Copy graph image to clipboard if haltsweep=1 then notice "Sweep will halt at end. Then re-click Copy Image." haltAtEnd=1 'Set flag to cause halt at end of this sweep. goto [PostScan] end if if isStickMode=0 then refreshGridDirty=1 : call RefreshGraph 0 'Redraw without erasure mark; but not if we are in stick mode ver114-7d bmpName$=FullGraphBmp$() 'get bmp name 'ver114-5q hBitmap=hbmp(bmpName$)'get bmp handle 'ver114-5q '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 long 'ver116-4q boolean to long unloadbmp bmpName$ : bmpName$="" 'ver114-5q wait '@==================End of Save/Copy Image================ sub HideButtonsOnGraph 'Hide buttons on the graph box so image can be copied 'ver114-7b deleted the scale arrow buttons so there is nothing at the moment to hide end sub sub ShowButtonsOnGraph 'Show buttons that lie on the graph box 'ver114-7b deleted the scale arrow buttons so there is nothing at the moment to hide end sub sub SetFilterAnalysis 'Display dialog for filter analysis and set parameters 'This assumes that Trace 2 displays a peak with a marker at the peak. The user 'specifies the marker ID and two db levels: db1 and db2. For example, db1=-3 and 'db2=-40. We locate the frequencies where the response is down by those amounts, 'marking them with markers if requested. We calculate insertion loss, 'bandwidth at both db levels, Q, and shape factor. 'We can also calculate unloaded Q--i.e. the Q when not loaded 'by the VNA, if the user specifies the loads. WindowWidth = 350 : WindowHeight = 220 call GetDialogPlacement 'set UpperLeftX and UpperLeftY ver115-1c BackgroundColor$="buttonface" ForegroundColor$="black" TextboxColor$="white" ComboboxColor$="white" 'checkbox to activate or deactivate filter analysis 'ver115-1b separated the captions from the checkboxes so the text color comes out right checkbox #filt.doFilt, "Analyze filter spectrum for bandwidth, Q and shape factor.", [filtNOP], [filtNOP],10, 10, 320, 15 'ver114-7d statictext #filt.Instruct1, "Ref Marker is considered the peak. X1DB (typically 3 dB) ", 25, 35, 300, 15 statictext #filt.Instruct2, "and X2DB (perhaps 30 dB, or 0 dB to ignore) are the dB", 25, 52, 300, 15 statictext #filt.Instruct3, "levels to evaluate.", 25, 69, 300, 15 textTop=95 statictext #filt.peakLab, "Ref Marker", 30, textTop, 70, 15 'SEWgraph2 Allowed reference markers are 1, L, R and P+. 'But markers other than P+ are allowed only if they have been placed if gMarkerPointNum(mMarkerNum("1"))<0 then markIDs$(0)="" else markIDs$(i)="1" if hasMarkL then markIDs$(1)="L" else markIDs$(1)="" if hasMarkR then markIDs$(2)="R" else markIDs$(2)="" markIDs$(3)="P+" Stylebits #filt.peakMark, _CBS_DROPDOWNLIST, 0, 0, 0 'ver115-1a combobox #filt.peakMark, markIDs$(), [filtNOP],30,textTop+15,60, 90 'combo box to select reference marker statictext #filt.db1Lab, "X1DB Down", 120, textTop, 60, 15 textbox #filt.db1, 130, textTop+15, 40, 20 'textbox for x1 point statictext #filt.db2Lab, "X2DB Down", 210, textTop, 60, 15 textbox #filt.db2, 220, textTop+15, 40, 20 'textbox for x2 point button #filt.OK, "OK", [filtFinished], UL, 70, 150, 50, 25 'OK button #filt.Cancel, "Cancel", [filtCancel], UL, 175, 150, 50, 25 'Cancel 'Open dialog open "Filter Analysis" for dialog_modal as #filt #filt, "trapclose [filtCancel]" if doFilterAnalysis=0 then 'If we start out w/o analysis, set some defaults but still set #filt.doFilt filterPeakMarkID$="P+" x1DBDown=3 : x2DBDown=0 end if #filt.doFilt, "set" 'Assume we will be doing the analysis print #filt.db1, str$(x1DBDown) 'Display existing values for db points print #filt.db2, str$(x2DBDown) if filterPeakMarkID$="" then filterPeakMarkID$="P+" #filt.peakMark, "select ";filterPeakMarkID$ 'Select the current or default reference marker #filt.peakMark, "setfocus" #filt.db1, "!setfocus" wait 'If the user double clicks on the menu when invoking this routine, the second click can be 'interpreted by LB as a click on the graph, so it will call [LeftButDown]. But it doesn't do 'so until it gets into this routine, at which point the real [LeftButDown] is hidden. So 'we provide one here that just exits. [LeftButDown] goto [filtCancel] 'ver115-1e [filtNOP] wait [filtCancel] close #filt exit sub [filtFinished] 'Window is closing or OK was clicked 'Note that if #filt.doFilt is reset, indicating no filter analysis, we exit immediately and never get 'to here. Therefore, we know here that we want to do filter analysis #filt.doFilt, "value? doFilt$" 'ver114-7d if doFilt$="set" then doFilterAnalysis=1 else doFilterAnalysis=0 'ver114-7d 'Filter analysis will use many markers, so we can't have other automatic uses of the markers if doFilterAnalysis=1 then doLRRelativeTo$="" 'turn off auto locating of L and R 'ver114-7d #filt.peakMark, "selection? filterPeakMarkID$" 'selected marker ID for marker at peak if filterPeakMarkID$="" then doFilterAnalysis=0 : close #filt : exit sub 'invalid marker-user typed into combobox 'Get the db values for the x1 and x2 analysis points; force them positive #filt.db1, "!contents? c$" : x1DBDown=val(uCompact$(c$)) : if x1DBDown<0 then x1DBDown=0-x1DBDown #filt.db2, "!contents? c$" : x2DBDown=val(uCompact$(c$)) : if x2DBDown<0 then x2DBDown=0-x2DBDown 'If P+ is the reference marker, we add it if necessary. Other reference markers must already 'exist, because we wouldn't know where to add them if doFilterAnalysis=1 and filterPeakMarkID$="P+" and gMarkerPointNum(mMarkerNum("P+"))<0 then 'ver115-1b saveSel$=selMarkerID$ 'We want to save and restore the current selected marker call mAddMarker "P+", 1, "2" 'place P+ marker on trace 2 'It will be moved on Redraw ver115-1e call mMarkSelect saveSel$ 'ver114-5L end if close #filt 'If halted, redraw with markers; otherwise wait to end. ver114-7d if haltsweep=0 then call RefreshGraph 0 end sub [menuCrystalAnalysis] 'Determine Crystal Parameters 'We are in SNA or VNA mode. The user must have set up a scan that shows the series and parallel 'resonances. if haltsweep=1 then gosub [FinishSweeping] 'Halt if crystalWindHndl$<>"" then close #crystalWindHndl$ 'ver115-5f if (primaryAxis=1 and Y1DataType<>constMagDB) or (primaryAxis=2 and Y2DataType<>constMagDB) then _ notice "Primary axis must contain a graph of magnitude (dB)." : wait 'ver115-3b WindowWidth = 550 WindowHeight = 350 call GetDialogPlacement BackgroundColor$="gray" ForegroundColor$="black" TextboxColor$ = "white" statictext #crystal.title, "DETERMINATION OF CRYSTAL PARAMETERS",130, 10, 375, 20 s$="There must be an existing S21 scan of the crystal in a Series Fixture. Enter the fixture R0." s$=s$; " Select the type of scan. If desired, click Zoom to Fs to improve the scan resolution." statictext #crystal.intro, s$, 20, 30, 515, 40 crystRes=(endfreq-startfreq)/globalSteps*1000000 'Step size in Hz s$="The current step size is ";using("#####.#",crystRes);" Hz/step." statictext #crystal.step, s$, 20, 70, 515, 20 'Will have step size info crystCheckTop=95 s$="The current scan extends from below the series resonance peak to above the parallel resonance dip." checkbox #crystal.fullSweep, "", [crystFull], [crystFull], 10, crystCheckTop, 20,20 'ver115-3f statictext #crystal.inst, s$, 30, crystCheckTop+3, 500, 18 'ver115-4a s$="The scan includes the series resonance peak only; the parallel resonant frequency Fp is stated below." checkbox #crystal.seriesSweep, "", [crystSeries], [crystSeries], 10, crystCheckTop+25, 20,20 'ver115-3f statictext #crystal.inst2, s$, 30, crystCheckTop+28, 500, 20 textbox #crystal.Fp, 150, crystCheckTop+50, 75, 20 'ver115-3f statictext #crystal.FpLabel,"MHz", 230, crystCheckTop+53, 50, 20 'R0 textbox #crystal.R0, 125, crystCheckTop+95, 50, 20 statictext #crystal, "Fixture R0 (ohms)", 35, crystCheckTop+97, 88, 20 'Buttons button #crystal.zoom, "Zoom To Fs", [crystZoom], UL,225, crystCheckTop+90, 80,30 'ver115-5c crystButTop=crystCheckTop+155 button #crystal.analyze, "Analyze", [crystalAnalyze], UL,20, crystButTop, 80,30 button #crystal.rescan, "Rescan", [crystalRescan], UL,100, crystButTop, 80,30 'ver115-5g button #crystal.add, "Add To List", [crystalList], UL,200, crystButTop, 80,30 button #crystal.set, "Set ID Num", [crystalSetID], UL,280, crystButTop, 80,30 button #crystal.Help, "Help", CrystalExplain, UL,380, crystButTop, 80,30 textbox #crystal.results, 10, crystButTop+40, 510, 20 'textbox for results 'Open dialog open "Crystal Analysis" for dialog_modal as #crystal 'ver115-5g crystalWindHndl$="#crystal" 'ver115-5f #crystal, "trapclose [crystalCancel]" 'ver115-3b #crystal.intro, "!font ms_sans_serif 10" #crystal.step, "!font ms_sans_serif 10" #crystal.add, "!disable" 'disable until we have done an analysis ver115-4a call mClearMarkers 'Extra Markers just cause visual confusion ver115-3b #crystal.analyze, "!setfocus" 'to keep window in front #crystal.R0, S21JigR0 'ver115-3f lastComputedDelay=0 crystRedidScan=0 crystError=0 : crystAnalyzeDone=0 crystalScanning=0 'Set to 1 during Zoom scan or Rescan goto [crystFull] [crystFull] #crystal.fullSweep, "set" #crystal.seriesSweep, "reset" #crystal.Fp, "!hide" #crystal.FpLabel "!hide" wait [crystSeries] #crystal.fullSweep, "reset" #crystal.seriesSweep, "set" #crystal.Fp, "!show" #crystal.FpLabel "!show" wait [crystalList] 'Add current results to list if crystalListHndl$="" then 'need to create window UpperLeftX=0 : UpperLeftY=400 '0 for X centers it on #crystal window WindowWidth=450 open "Crystal List" for text as #crystalList #crystalList, "!trapclose CrystalListClosed" crystalListHndl$="#crystalList" print #crystalList,"!font Arial 10" 'ver115-1h print #crystalList," ID Fs(MHz) Fp(MHz) Rm(ohms) Lm(mH) Cm(fF) Cp(pF)" 'Print heading info for list ver115-9c end if crystalLastUsedID=crystalLastUsedID+1 'increment ID crystFreqInfo$=using("####.######",crystFs);" "; using("####.######",crystFp) crystParamInfo$= using("###.##", crystRm);" ";using("###.######", crystLm);" ";using("###.######", crystCm);" ";using("###.##", crystCp);" " crystalID$=str$(crystalLastUsedID) print #crystalList, space$(4-len(crystalID$));crystalID$;" "; crystFreqInfo$; " ";crystParamInfo$ 'Add results to list wait [crystalSetID] prompt "Enter numeric ID for this crystal"; crystalID$ if crystalID$<>"" then crystalLastUsedID=val(crystalID$)-1 'Enter new value of last used ID if prompt was not cancelled wait [crystZoom] 'button--zoom in to show Fs and the -3 dB points if crystalScanning then goto [crystalCancel] 'Zoom becomes Cancel during Zoom scan gosub [crystalFindPoints] 'Find Fs and -3 db points if crystError then goto [crystalCancel] call mDeleteMarker "P-" crystRes=(endfreq-startfreq)/globalSteps 'current MHz/step 'If coarse scan, shoot for 12 Hz/step, otherwise for 5 Hz/step if crystRes>0.000150 then crystTargetRes=0.000012 else crystTargetRes=0.000005 'ver115-9c if crystRes<=crystTargetRes then wait 'Don't zoom any further ver115-9c if crystFullSweep$="set" then 'set or reset in crystalFindPoints 'If we had a full sweep, indicate that it now has just the series peak, and enter 'the Fp value #crystal.fullSweep, "reset" #crystal.seriesSweep, "set" #crystal.Fp, "!show" #crystal.FpLabel "!show" #crystal.Fp, using("####.######", crystFp) end if doLRRelativeTo$="P+" 'To locate L and R relative to P+ db3Range=cryst3dbB-cryst3dbA crystMargin=max(2*crystRes, db3Range/20) 'Allow extra range in case 3 dB points change with the higher resolution ver115-9c crystZoomRange=db3Range+2*crystMargin crystNewStartFreq=cryst3dbA-crystMargin crystNewEndFreq=crystNewStartFreq+crystZoomRange 'Note globalSteps will change in FunctChangeAndSaveSweepParams steps=int(1+crystZoomRange/(2*crystTargetRes))*2 'To get step size near crystTargetRes, and have even number of steps if steps<50 then steps=50 if steps>500 then steps=500 'ver115-9c crystSaveExisting=(crystRedidScan=0) 'save existing settings and transfer band cal to base cal only first time we zoom crystBandToBase=(crystRedidScan=0 and applyCalLevel=2) 'Make band cal into a base cal, but only first time and only if previous scan used band cal. 'Rescan Linear between -3 dB points; 10% excess on each end call FunctChangeAndSaveSweepParams crystSaveExisting, crystBandToBase, steps, crystNewStartFreq, crystNewEndFreq, 1 'Disable buttons so they aren't clicked while we scan #crystal.analyze, "!disable" #crystal.zoom, "Cancel" 'Zoom becomes Cancel during Zoom scan #crystal.set, "!disable" : #crystal.Help, "!disable" #crystal.add, "!disable" : #crystal.rescan, "!disable" crystalScanning=1 specialOneSweep=1 'So we return from [Restart] crystRedidScan=1 gosub [Restart] 'Scan to get Fs and -3 dB points more precisely crystalScanning=0 if refreshEachScan=0 then call RefreshGraph 0 'To place the P+, L and R markers properly 'Re-enable buttons #crystal.analyze, "!enable" #crystal.zoom, "Zoom to Fs" #crystal.set, "!enable" : #crystal.Help, "!enable" : #crystal.rescan, "!enable" if crystAnalyzeDone then #crystal.add, "!enable" 'Enable only if we have done an analysis doLRRelativeTo$="" 'To cancel automatic LR placement crystRes=(endfreq-startfreq)/globalSteps*1000000 'Step size in Hz #crystal.step,"The current step size is ";using("#####.#",crystRes);" Hz/step." wait [crystalFindPoints] 'Find Fs, -3 dB points, and Fp if applicable S21JigAttach$="Series" #crystal.R0, "!contents? componR0$" 'R0 'ver115-3f S21JigR0=val(componR0$) 'ver115-3f if S21JigR0<0 then S21JigR0=50 : #crystal.R0, "50" :notice "Invalid R0. 50 ohms used." 'ver115-3f analysisAxis$=str$(primaryAxisNum) 'ver115-3b #crystal.fullSweep, "value? crystFullSweep$" 'see if we have full or partial sweep ver115-4a 'We analyze a positive peak if doing crystals call mAddMarker "P+", 1, analysisAxis$ 'place P+ marker on primary trace ver115-4a if crystFullSweep$="set" then call mAddMarker "P-", 1, analysisAxis$ 'place P- marker on primary trace ver115-4a doLRRelativeTo$="P+" 'Indicate to place L and R at -3db points around P+ doLRRelativeAmount=-3 doLRAbsolute=0 'ver115-4a call RefreshGraph 0 'To place the peak markers properly doLRRelativeTo$="" 'disable auto placement now that we have done it doLRAbsolute=0 'User never does absolute values 'ver115-3f 'We now have markers at all the critical points. We just have to get the marker info. 'The main resonance is a peak if we have a crystal or a series RLC in a series fixture, or parallel RLC in parallel fixture. crystPeakOrdinal=mMarkerNum("P+") 'Ordinal of P+ point; graph module finds info from ordinal crystFs=gMarkerCurrXVal(crystPeakOrdinal) 'We now have the exact Fs 'we need the parallel resonance frequency also ver115-4a 'For crystal we may also need to zoom in more closely around the series peak to get a good read on Fs. if crystFullSweep$="reset" then 'crystFullSweep$ was set by [crystFindPoints] #crystal.Fp, "!contents? crystFp$" crystFp=val(crystFp$) if crystFs>=crystFp then _ notice "Parallel resonant frequency must exceed series resonant frequency." : crystError=1 else 'We need to find Fp ourselves crystFp=gMarkerCurrXVal(mMarkerNum("P-")) if crystFp>endfreq-0.00005 then _ notice "Sweep does not include enough of parallel resonance." : crystError=1 'ver115-4a if crystFs>=crystFp then _ notice "Sweep does not show proper series resonance followed by parallel resonance." : crystError=1 'ver115-4a end if crystPeakPoint=gMarkerPointNum(crystPeakOrdinal) 'Point number of the main peak crystPeakdb=gGetPointYVal(crystPeakPoint, primaryAxisNum) 'Get S21 db value (primary trace) crystLNum=mMarkerNum("L") crystRNum=mMarkerNum("R") cryst3dbA=gMarkerCurrXVal(crystLNum) cryst3dbB=gMarkerCurrXVal(crystRNum) if gMarkerPointNum(crystLNum)<=0 or gMarkerPointNum(crystRNum)<=0 then _ notice "Sweep does not contain necessary -3 dB points." : crystError=1 'ver115-5c return [crystalRescan] 'Rescan per original sweep params, presumably for a new crystal. ver115-5g if crystalScanning then goto [crystalCancel] 'Rescan becomes Cancel during Rescan if crystRedidScan then call mClearMarkers 'because we are zapping the data anyway gosub [FunctRestoreSweepParams] suppressHardwareInitOnRestart=1 'no need for hardware init ver116-4d gosub [PartialRestart] end if crystRedidScan=0 #crystal.fullSweep, "disable" #crystal.seriesSweep, "disable" #crystal.zoom, "!disable" #crystal.analyze, "!disable" #crystal.rescan, "Cancel" 'Rescan becomes Cancel #crystal.add, "!disable" #crystal.set, "!disable" #crystal.Help, "!disable" #crystal.results,"" specialOneSweep=1 crystalScanning=1 gosub [Restart] 'Scan once and return crystalScanning=0 #crystal.fullSweep, "enable" #crystal.seriesSweep, "enable" #crystal.zoom, "!enable" #crystal.analyze, "!enable" #crystal.rescan, "Rescan" #crystal.add, "!enable" #crystal.set, "!enable" #crystal.Help, "!enable" 'The fullsweep box could have been reset by Zoom. We always set it when the window opens, 'so we set it here to start fresh. Rescan is unlikely to be used if the original scan did 'not include Fp, since the user then has to figure out the Fp for the new crystal being scanned. goto [crystFull] [crystalAnalyze] 'Analyze button was pushed gosub [crystalFindPoints] if crystError then goto [crystalCancel] if msaMode$="VectorTrans" or msaMode$="Reflection" then 'ver115-5c 'Refine the value of Fs by finding the point with zero phase or reactance. Reactance is best for reflection 'mode. The main advantage of this approach is that transmission phase and reflection reactance are linear near 'series resonance, so interpolation can find Fs precisely even with a coarse scan. 'Note: At the moment, we don't do crystal analysis in reflection mode. if msaMode$="VectorTrans" then crystZeroType=constSerAngle else crystZeroType=consSerReact crystZero=StepWithValue(crystZeroType, max(crystPeakOrdinal-4,0), 1, 0) 'Search forward for zero, starting just left of peak. 'Use the frequency of the point with zero value, if that point is close to the peak point. If not, 'something went wrong. if abs(crystPeakOrdinal-crystZero)<=1 then crystFs=gGetPointXVal(crystZero) call mDeleteMarker "P+" call mAddMarker "1", crystZero, str$(primaryAxisNum) call RefreshGraph 0 'Redraw to show markers. end if end if call uCrystalParameters crystFs, crystFp, crystPeakdb, cryst3dbA, cryst3dbB, crystRm, crystCm, crystLm, crystCp, crystQu, crystQL crystCm=crystCm*1000 'pF to fF ver115-9c crystLm=crystLm/1000 'uH to mH ver115-9c crystForm$="3,3,5//UseMultiplier" 'for out-of-bounds values if crystRm<100 then crystRm$=using("##.##", crystRm);" ohms" else crystRm$=uFormatted$(crystRm, crystForm$);"ohms" if crystLm<999 then crystLm$=using("###.######", crystLm);" mH" else crystLm$=uFormatted$(crystLm/1000, crystForm$);"H" if crystCm<999 then crystCm$=using("###.######", crystCm);" fF" else crystCm$=uFormatted$(crystCm*1e-15, crystForm$);"F" if crystCp<9.9 then crystCp$=using("#.###", crystCp);" pF" else crystCp$=uFormatted$(crystCp*1e-12, crystForm$);"F" #crystal.results, "Fs="; crystFs;" MHz; Fp="; crystFp;" MHz; Rm=";crystRm$;"; Cm="; crystCm$;"; Lm="; _ crystLm$; "; Cp=";crystCp$ #crystal.add, "!enable" 'enable now that we have data ver115-4a wait [crystalCancel] 'We always leave [menuCrystalAnalysis] through here ver115-3f specialOneSweep=0 if crystalScanning then crystalScanning=0 : gosub [FinishSweeping] 'ver115-5g if crystRedidScan then call mClearMarkers 'because we are zapping the data anyway gosub [FunctRestoreSweepParams] suppressHardwareInitOnRestart=1 'no need for hardware init ver116-4d gosub [PartialRestart] end if close #crystal : crystalWindHndl$="" wait 'end of [menuCrystalAnalysis] sub CrystalListClosed h$ 'Crystal list window has been closed. This is sub so it can be called from within other subs close #crystalList crystalListHndl$="" end sub sub CrystalExplain h$ WindowWidth = 550 WindowHeight = 285 UpperLeftX=int((DisplayWidth-WindowWidth)/2) UpperLeftY=int((DisplayHeight-WindowHeight)/2) BackgroundColor$="gray" ForegroundColor$="black" s$="Crystal analysis will determine the motional parameters (Rm, Cm and Lm) for a crystal." s$=s$;" It will also determine the parallel capacitance from lead to lead (Cp), and the series and" s$=s$;" parallel resonant frequencies." statictext #crystExplain, s$, 10, 10, 515, 60 s$="The crystal must be mounted in a series fixture, and you must specify the R0 of the fixture. A" s$=s$;" regular 50-ohm fixture is fine, but the standard for crystal analysis is 12.5 ohms." statictext #crystExplain, s$, 10, 65, 515, 40 s$="You must enter the Crystal Analysis function with a Transmission scan already existing, including the series resonance" s$=s$;" peak and the -3 dB points around it. You may also include the parallel resonance dip, or you may elect to" s$=s$;" explicitly specify the parallel resonant frequency, which is needed to determine Cp." 'ver115-5c statictext #crystExplain, s$, 10, 100, 515, 75 if msaMode$="VectorTrans" or msaMode$="Reflection" then s$="Fs is the parameter needing the most precision, and it will be located by interpolation to find zero" s$=s$;" phase, so a step size of 100 Hz or less likely provides sufficient accuracy." 'ver115-5c else s$="A small scan step size is important to locating Fs accurately so you likely need a step size" s$=s$;" in the range 5-50 Hz. " 'ver115-5c end if s$=s$;" You can reduce the step size by using the Zoom to Fs button, which will rescan the area around Fs." 'ver115-5c statictext #crystExplain, s$, 10, 180, 515, 85 open "Crystal Analysis Help" for dialog_modal as #crystExplain print #crystExplain, "font ms_sans_serif 10" print #crystExplain, "trapclose [CrystalExplainEnd]" wait [CrystalExplainEnd] close #crystExplain 'ver115-5c exit sub end sub 'end CrystalExplain [menuRLCAnalysis] if haltsweep=1 then gosub [FinishSweeping] 'Halt if msaMode$="Reflection" then call ReflectionRLC else call TranRLCAnalysis call RequireRestart 'Scan can continue only by Restart wait sub TranRLCAnalysis 'perform RLC analysis, transmission mode 'We determine Q from resonant frequency and -3 dB bandwidth, and directly measure Rs 'at resonance. From Q and Rs we can calculate L and C. if (primaryAxis=1 and Y1DataType<>constMagDB) or (primaryAxis=2 and Y2DataType<>constMagDB) then _ notice "Primary axis must contain a graph of magnitude (dB)." : exit sub WindowWidth = 550 WindowHeight = 400 call GetDialogPlacement BackgroundColor$="gray" ForegroundColor$="black" TextboxColor$ = "white" statictext #tranRLC.title, "DETERMINATION OF COMBINED RLC PARAMETERS",70, 10, 400, 20 s$="Determines individual components of an RLC combination from resonance and 3 dB points." s$=s$;" The scan must include the resonance and at least one of the 3 dB points." s$=s$;" High resolution improves accuracy." 'ver115-5f statictext #tranRLC.title1, s$, 20, 30, 500, 32 s$="The resistor, inductor and/or capacitor are in PARALLEL." checkbox #tranRLC.parallelRLC, "", [tranRLCParallelRLC], [tranRLCParallelRLC], 10, 65, 20,20 statictext #tranRLC.inst, s$, 30, 68, 475, 18 s$="The resistor, inductor and/or capacitor are in SERIES." checkbox #tranRLC.seriesRLC, "", [tranRLCSeriesRLC], [tranRLCSeriesRLC], 10, 90, 20,20 statictext #tranRLC.inst2, s$, 30, 93, 500, 20 tranRLCFixTop=120 groupbox #tranRLC.Fixture, "Fixture", 100,tranRLCFixTop,210,75 'Provision is made for series/shunt, R0, and shunt connector delay checkbox #tranRLC.seriesFix, "Series", [tranRLCSeriesFix], [tranRLCSeriesFix], 120, tranRLCFixTop+20, 50, 20 checkbox #tranRLC.shuntFix, "Shunt", [tranRLCShuntFix], [tranRLCShuntFix],120, tranRLCFixTop+45, 50, 20 textbox #tranRLC.R0, 240, tranRLCFixTop+20, 50, 20 statictext #tranRLC, "R0 (ohms)", 188, tranRLCFixTop+22, 50, 20 textbox #tranRLC.Delay, 240, tranRLCFixTop+45, 50, 20 statictext #tranRLC.DelayLabel, "Delay (ns)", 188, tranRLCFixTop+47, 50, 20 'ver116-4h added notch items and 3 dB explanation. tranRLCNotchTop=tranRLCFixTop+90 checkbox #tranRLC.useNotchTop, "Use points at absolute -3 dB. (Best for narrow notches.)", [tranRLCUseTop],[tranRLCUseBot], 10, tranRLCNotchTop, 400, 18 checkbox #tranRLC.useNotchBot, "Use points +3 dB from notch bottom. (Notch depth should exceed 20 dB.)", [tranRLCUseBot],[tranRLCUseTop], 10, tranRLCNotchTop+20, 400, 18 statictext #tranRLC.3dBExplain "", 40, tranRLCNotchTop+45, 400, 40 'Buttons tranRLCBtnTop=tranRLCNotchTop+90 button #tranRLC.analyze, "Analyze", [tranRLCAnalyze], UL,50, tranRLCBtnTop, 80,30 button #tranRLC.Help, "Help", tranRLCExplain, UL,250, tranRLCBtnTop, 80,30 textbox #tranRLC.results, 10, tranRLCBtnTop+40, 520, 20 'textbox for results 'Open dialog open "RLC Analysis" for dialog_modal as #tranRLC 'ver115-4a made this a modal dialog 'ver115-4a #tranRLC, "trapclose [tranRLCCancel]" 'ver115-3b #tranRLC, "font ms_sans_serif 9" 'ver116-4h #tranRLC.3dBExplain, "!font Arial 10 bold" 'ver116-4h call mClearMarkers 'Extra Markers just cause visual confusion ver115-3b #tranRLC.analyze, "!setfocus" 'to keep window in front if S21JigAttach$="Series" then #tranRLC.seriesFix, "set" else #tranRLC.shuntFix, "set" 'ver115-3f #tranRLC.R0, S21JigR0 'ver115-3f #tranRLC.Delay, S21JigShuntDelay 'ver115-4a 'ver115-4b deleted save/restore of S21 Jig items lastComputedDelay=0 if tranRLCLastNotchWasTop then #tranRLC.useNotchTop, "set" : #tranRLC.useNotchBot, "reset" _ else #tranRLC.useNotchTop, "reset" : #tranRLC.useNotchBot, "set" 'ver116-4h if tranRLCLastRLCWasSeries then #tranRLC.seriesRLC, "set" : #tranRLC.parallelRLC, "reset" _ else #tranRLC.seriesRLC, "reset" : #tranRLC.parallelRLC, "set" 'ver116-4h if S21JigAttach$="Series" then goto [tranRLCSeriesFix] else goto [tranRLCShuntFix] 'ver115-4b [tranRLCUseTop] #tranRLC.useNotchTop, "set" : #tranRLC.useNotchBot, "reset" : goto [tranRLCExplainNotchAndDB] [tranRLCUseBot] #tranRLC.useNotchTop, "reset" : #tranRLC.useNotchBot, "set" : goto [tranRLCExplainNotchAndDB] [tranRLCSeriesFix] 'mod116-4h #tranRLC.seriesFix, "set" : #tranRLC.shuntFix, "reset" #tranRLC.Delay, "!hide" : #tranRLC.DelayLabel, "!hide" #tranRLC.seriesRLC, "value? tranRLCSeriesRLC$" : if tranRLCSeriesRLC$="set" then tranRLCNotch=0 else tranRLCNotch=1 'ver116-4h goto [tranRLCExplainNotchAndDB] [tranRLCShuntFix] 'mod116-4h #tranRLC.shuntFix, "set" : #tranRLC.seriesFix, "reset" if msaMode$<>"ScalarTrans" then #tranRLC.Delay, "!show" : #tranRLC.DelayLabel, "!show" 'Only meaninful with phase ver115-4a #tranRLC.seriesRLC, "value? tranRLCSeriesRLC$" : if tranRLCSeriesRLC$="set" then tranRLCNotch=1 else tranRLCNotch=0 'ver116-4h goto [tranRLCExplainNotchAndDB] [tranRLCSeriesRLC]'mod116-4h #tranRLC.seriesRLC, "set" : #tranRLC.parallelRLC, "reset" #tranRLC.seriesFix, "value? tranRLCSeries$" : if tranRLCSeries$="set" then tranRLCNotch=0 else tranRLCNotch=1 'ver116-4h goto [tranRLCExplainNotchAndDB] [tranRLCParallelRLC] 'mod116-4h #tranRLC.seriesRLC, "reset" : #tranRLC.parallelRLC, "set" #tranRLC.seriesFix, "value? tranRLCSeries$" : if tranRLCSeries$="set" then tranRLCNotch=1 else tranRLCNotch=0 'ver116-4h goto [tranRLCExplainNotchAndDB] [tranRLCExplainNotchAndDB] 'Show notch items if using notch response (series RLC in parallel fixture or parallel RLC in series fixture) if tranRLCNotch then #tranRLC.useNotchTop, "show" : #tranRLC.useNotchBot, "show" #tranRLC.useNotchTop, "value? tranRLCUseTop$" if tranRLCUseTop$="set" then #tranRLC.3dBExplain, "Scan must show resonant notch and at least one point at absolute -3 dB level." else #tranRLC.3dBExplain, "Scan must show resonant notch and at least one point 3 dB above notch bottom." end if else #tranRLC.3dBExplain, "Scan must show resonant peak and at least one point 3 dB below peak." #tranRLC.useNotchTop, "hide" : #tranRLC.useNotchBot, "hide" end if wait [tranRLCAnalyze] 'Analyze button was pushed #tranRLC.seriesFix, "value? tranRLCSeries$" 'ver115-3f if tranRLCSeries$="set" then S21JigAttach$="Series" else S21JigAttach$="Shunt" 'ver115-3f #tranRLC.R0, "!contents? componR0$" 'R0 'ver115-3f S21JigR0=val(componR0$) 'ver115-3f if S21JigR0<0 then S21JigR0=50 : #tranRLC.R0, "50" :notice "Invalid R0. 50 ohms used." 'ver115-3f analysisAxis$=str$(primaryAxisNum) 'ver115-3b #tranRLC.seriesRLC, "value? tranRLCSeriesRLC$" '"set" if RLC circuit is series tranRLCLastRLCWasSeries=(tranRLCSeriesRLC$="set") 'For next time we open ver116-4h if S21JigAttach$="Shunt" then 'ver115-4a #tranRLC.Delay, "!contents? tranRLCDelay$" 'Delay of shunt connection S21JigShuntDelay=val(tranRLCDelay$) if S21JigShuntDelay<>lastComputedDelay then 'If using shunt fixture with delay, we must reconstruct the graphs after compensating 'for the delay. We do this by transforming S21 into impedance while accounting for the delay, 'and recalculating S21 with that new impedance but with no delay. for i=0 to gPointCount()-1 currFreq=S21DataArray(i,0)*1000000 'Has actual graph frequency 'Use datatable data but put new data only into S21DataArray, so if we do Analyze 'twice, the second time we start again with unchanged data. newDB=datatable(i, 2) : newDeg=datatable(i,3) call uAdjustS21ForConnectorDelay currFreq, newDB, newDeg 'Change the raw data; graph will be changed by RefreshGraph, called below S21DataArray(i,1)=newDB S21DataArray(i,2)=newDeg if primaryAxisNum=1 then call gChangePoints i+1, newDB, newDeg _ else call gChangePoints i+1, newDeg, newDB 'so graph module has the new data next i refreshTracesDirty=1 'So RefreshGraph recalculates Y values. lastComputedDelay=S21JigShuntDelay end if end if 'We analyze a positive peak if series RLC in series fixture or parallel RLC in shunt fixture. 'tranRLCNotch will already be set to 0 if doing a peak and 1 if doing a notch if tranRLCNotch then'ver116-4h #tranRLC.useNotchTop, "value? tranRLCUseTop$" 'set if we want top 3 dB points call mAddMarker "P-", 1, analysisAxis$ 'place P- marker on primary trace ver115-4a doLRRelativeTo$="P-" 'Indicate to place L and R at +3db points around P- if tranRLCUseTop$="set" then doLRRelativeAmount=-3 : doLRAbsolute=1 'mark absolute -3 dB 'ver116-4h tranRLCLastNotchWasTop=1 'For next time we open else doLRRelativeAmount=3 : doLRAbsolute=0 'mark 3 dB above P- 'ver116-4h tranRLCLastNotchWasTop=0 'For next time we open end if else 'Here we analyze a peak call mAddMarker "P+", 1, analysisAxis$ 'place P+ marker on primary trace ver115-4a doLRRelativeTo$="P+" 'Indicate to place L and R at -3db points around P+ doLRRelativeAmount=-3 doLRAbsolute=0 'ver115-4a end if call RefreshGraph 0 'To place the peak markers properly doLRRelativeTo$="" 'disable auto placement now that we have done it doLRAbsolute=0 'User never does absolute values 'ver115-3f 'We now have markers at all the critical points. We just have to get the marker info. 'The main resonance is a peak if we have a series RLC in a series fixture, or parallel RLC in parallel fixture. if (S21JigAttach$="Series" and tranRLCSeriesRLC$="set") or _ (S21JigAttach$="Shunt" and tranRLCSeriesRLC$="reset") then 'ver115-3f tranRLCPeakOrdinal=mMarkerNum("P+") 'Ordinal of P+ point; graph module finds info from ordinal else tranRLCPeakOrdinal=mMarkerNum("P-") 'Ordinal of P- point; graph module finds info from ordinal end if tranRLCFs=gMarkerCurrXVal(tranRLCPeakOrdinal) 'We now have the exact Fs tranRLCPeakPoint=gMarkerPointNum(tranRLCPeakOrdinal) 'Point number of the main peak or notch tranRLCPeakdb=gGetPointYVal(tranRLCPeakPoint, primaryAxisNum) 'Get S21 db value at peak (primary trace) tranRLCLNum=mMarkerNum("L") tranRLCRNum=mMarkerNum("R") tranRLC3dbA=gMarkerCurrXVal(tranRLCLNum) tranRLC3dbB=gMarkerCurrXVal(tranRLCRNum) 'ver116-4h revised checking for 3 dB points tranLPoint=gMarkerPointNum(tranRLCLNum) 'Point num of left 3 dB point, or <=0 if it does not exist tranRPoint=gMarkerPointNum(tranRLCRNum) 'Point num of right 3 dB point, or <=0 if it does not exist if tranLPoint<=0 and tranRPoint<=0 then notice "Scan does not include any 3 dB points." : wait 'We have at least one 3dB point. If we don't have the other, we calculate its frequency with formula that works for low loss if tranLPoint<=0 then tranRLC3dbA=tranRLCFs^2/tranRLC3dbB 'makes resonance the geometric mean if tranRPoint<=0 then tranRLC3dbB=tranRLCFs^2/tranRLC3dbA 'makes resonance the geometric mean if (tranRLCNotch=1) and (tranRLCUseTop$="reset") then 'ver116-4h 'analyze bottom of notch. Q determined from the 3 dB bandwidth is assumed to be Qu if S21JigAttach$="Series" then comboR=2*S21JigR0*(10^(0-tranRLCPeakdb/20)-1) 'This is the effective series or parallel resistance at resonance, not counting source and load else 'shunt fixture comboR=(S21JigR0/2)/(10^(0-tranRLCPeakdb/20)-1) end if if comboR<0.001 then comboR=0.001 BW=tranRLC3dbB-tranRLC3dbA if BW<=0 or tranRLCFs<=0 then notice "Invalid frequency data." : wait comboQu=tranRLCFs/BW : if comboQu>99999 then comboQu=99999 'Qu at resonance. Accurate if notch is deep. if tranRLCSeriesRLC$="set" then 'series RLC in shunt fixture resonReact=comboR*comboQu : comboQL=resonReact/(S21JigR0/2) : comboSerR=comboR else 'parallel RLC in series fixture resonReact=comboR/comboQu : comboQL=resonReact/(S21JigR0*2) : comboSerR=resonReact/comboQu end if twoPiF=2*uPi()*tranRLCFs*1000000 comboL=resonReact/twoPiF 'in H comboC=1/(twoPiF*resonReact) 'in F else 'Analyze top of peak or notch 'For a low-loss RLC circuit, the resonant frequency is the geometric mean of the two 3 dB points. The upper 3 dB 'point may be at a dramatically higher frequency than the lower one and in that case is subject to a lot of inaccuracies. 'So if it is too high, we will redetermine it mathematically, assuming low loss. if (transRLCNotch=0 or tranRLCUseTop$="set") and tranRLC3dbB>2*tranRLCFs and tranRLC3dbB>1e8 then 'upper point is above 100 MHz and more than twice Fs tranRLC3dbB=tranRLCFs^2/tranRLC3dbA 'makes Fs the geometric mean end if if tranRLCSeriesRLC$="set" then 'For series RLC we use the crystal routine; crystFp and crystCp are bogus crystFp=tranRLCFs*1.5 'just to be valid call uCrystalParameters tranRLCFs, crystFp, tranRLCPeakdb, tranRLC3dbA, tranRLC3dbB, comboR, comboC, comboL, crystCp, comboQu, comboQL comboL=comboL/1000000 'It was returned in uH comboC=comboC*1e-12 'It was returned in pF else 'Parallel RLC call uParallelRLCFromScalarS21 tranRLCFs, tranRLCPeakdb, tranRLC3dbA, tranRLC3dbB, comboR, comboL, comboC, comboQu, comboQL, comboSerR end if end if tranRLCForm$="3,3,4//UseMultiplier" if tranRLCSeriesRLC$="set" then f$="Fs=" else f$="Fp=" if abs(comboR)<1 then comboR$=using("#.###", comboR) else comboR$=uFormatted$(comboR, tranRLCForm$);"ohms" comboL$=uFormatted$(comboL, tranRLCForm$);"H" comboC$=uFormatted$(comboC, tranRLCForm$);"F" if comboQu<1 then comboQu$=using("#.###", comboQu) else comboQu$=uFormatted$(comboQu, tranRLCForm$) if comboQL<1 then comboQL$=using("#.###", comboQL) else comboQL$=uFormatted$(comboQL, tranRLCForm$) if tranRLCSeriesRLC$="set" then serR$="" 'For series RLC, comboR is already series R else if comboSerR<1 then serR$=using("#.###", comboSerR) else serR$=uFormatted$(comboSerR, tranRLCForm$) 'ver115-4b serR$="; (Rs="; serR$; ")" 'Enclose in parens end if #tranRLC.results, f$; tranRLCFs;" MHz; R=";comboR$;"; L="; comboL$;"; C="; comboC$; _ "; Qu="; comboQu$; "; QL="; comboQL$; serR$ wait [tranRLCCancel] 'We always leave TranRLCAnalysis through here ver115-3f close #tranRLC exit sub end sub 'end of TranRLCAnalysis sub tranRLCExplain h$ 'Help window for transmission mode RLC analysis WindowWidth = 550 WindowHeight = 325 call GetDialogPlacement 'determine position on screen ver115-4b BackgroundColor$="gray" ForegroundColor$="black" s$="RLC analysis will determine the R, L and C values for resistor, inductor and capacitor combinations." s$=s$;" The components may be in series or in parallel, and either way they may be mounted in a series or" s$=s$;" shunt fixture. The values of Q will also be determined." statictext #tranRLCExplain, s$, 10, 10, 515, 60 s$="For the shunt fixture, you may enter the time delay of the connection between the actual fixture and" s$=s$;" the components; typically on the order of 0.125 ns per inch." statictext #tranRLCExplain, s$, 10, 75, 515, 40 s$="You must enter the RLC Analysis function with a Transmission scan already existing, showing the resonance" s$=s$;" peak (for series RLC in series fixture, or parallel RLC in parallel fixture) or notch (for series RLC in" s$=s$;" parallel fixture or parallel RLC in series fixture). For resonance peaks, you should normally include the 3 dB" s$=s$;" points (3 dB below a peak, or 3 dB above a dip). It is permissible," '116-4g s$=s$;" however, to exclude one of those points. For resonant notches, you may analyze the scan be using either" s$=s$;" the absolute -3 dB points (most suitable for narrow notches) or the points 3 dB above the notch bottom" s$=s$;" (most suitable for notches over 20 dB deep)." 'ver116-4h statictext #tranRLCExplain, s$, 10, 125, 515, 130 open "RLC Analysis Help" for dialog_modal as #tranRLCExplain print #tranRLCExplain, "font ms_sans_serif 10" print #tranRLCExplain, "trapclose [tranRLCExplainEnd]" wait [tranRLCExplainEnd] close #tranRLCExplain exit sub end sub 'end tranRLCExplain [menuComponentMeasure] if componentWindHndl$<>"" then close #component if (primaryAxis=1 and Y1DataType<>constMagDB) or (primaryAxis=2 and Y2DataType<>constMagDB) then _ notice "Primary axis must contain a graph of magnitude (dB)." : wait 'ver115-3b if haltsweep=1 then gosub [FinishSweeping] WindowWidth = 550 WindowHeight = 480 call GetDialogPlacement BackgroundColor$="gray" ForegroundColor$="black" TextboxColor$ = "white" groupbox #component, "Component Type", 300, 125, 130, 90 statictext #component, "To measure resistance, capacitance or inductance you must first calibrate.", 20, 17, 500, 20 statictext #component " Then insert the component and click", 20, 37, 500, 20 statictext #component, "Measure. The video filter should be set to NARROW. Other settings will be made", 20, 57, 500, 20 statictext #component, "automatically. You can temporarily change the frequency with +Freq or -Freq.", 20, 77, 500, 20 'Fixture info 'Note for reflection mode the following fixture info items will exist but be hidden, and their 'data is irrelevant checkbox #component.Series, "Series", [ComponSeriesSet], [ComponSeriesClear], 40, 147, 64, 25 checkbox #component.Shunt, "Shunt", [ComponShuntSet], [ComponShuntClear], 40, 172, 58, 20 textbox #component.R0, 130, 170, 50, 22 if msaMode$<>"Reflection" then 'These labels not needed for reflection mode ver115-5b groupbox #component, "Test Fixture", 30, 125, 195, 90 statictext #component, "R0", 135, 152, 25, 17 statictext #component, "ohms", 180, 167, 33, 20 end if 'Component type checkbox #component.Resistor, "Resistor", ComponResistorSet, ComponResistorSet, 330, 147, 75, 20 checkbox #component.Capacitor, "Capacitor", ComponCapacitorSet, ComponCapacitorSet, 330, 167, 83, 20 checkbox #component.Inductor, "Inductor", ComponInductorSet, ComponInductorSet, 330, 187, 72, 20 statictext #component.Freq, "Frequency= 0.1 MHz", 125, 275, 130, 20 button #component.DecFreq, "-Freq", [ComponDecFreq], UL, 280, 275, 40,20 button #component.IncFreq, "+Freq", [ComponIncFreq], UL, 321, 275, 40,20 graphicbox #component.Value, 125, 300, 235, 40 staticText #component.SeriesR, "Series R=",370, 300, 200, 20 'For series resistance of inductors ver115-3d staticText #component.Q, "Q=",370, 320, 200, 20 'For Q of inductors ver115-3d button #component.Calibrate,"Calibrate",[ComponDoCalScan], UL, 30, 367, 75, 35 button #component.Measure,"Measure",[ComponentAcquireAndMeasure], UL, 150, 367, 100, 35 button #component.Stop,"Stop",ComponentStop, UL, 150, 367, 100, 35 'Stop is in same space as Measure button #component.Done,"Done",[ComponentDone], UL, 295, 367, 70, 35 button #component.Explain,"Help",[ComponentExplain], UL, 415, 367, 70, 35 statictext #component.CalInst, "", 10, 405, 125, 20 'initially blank ver115-5b open "Component Meter" for dialog_modal as #component 'ver115-4c componentWindHndl$="#component" print #component, "font ms_sans_serif 10" print #component, "trapclose ComponentCloseBox" componBoxColor$="200 200 200" print #component.Value, "font tahoma 20 bold;down; color 0 0 255;backcolor ";componBoxColor$ #component.Value, "cls; fill ";componBoxColor$ #component.Stop, "!hide" #component.Resistor, "set" #component.SeriesR, "!hide" : #component.Q, "!hide" 'ver115-3d #component.R0, "50" call mClearMarkers 'Markers just cause visual confusion ver115-3b #component.Done, "!setfocus" 'to keep window in front componFirstCal=1 'True only until first cal is done if msaMode$="Reflection" then 'No fixture info for reflection mode ver115-5b #component.Series, "hide" #component.Shunt, "hide" #component.R0, "!hide" end if componLastSeriesValue$="reset" if msaMode$="Reflection" then 'ver115-5b gosub [ComponentInvalidateCal] else goto [ComponSeriesSet] 'will also invalidate cal end if wait sub ComponentCloseBox h$ 'Close box clicked. Don't do anything, because we can't quit if Measure is in progress. 'just return and keep going end sub [ComponentInvalidateCal] 'disable buttons so all user can do is calibrate #component.Measure, "!disable" #component.DecFreq, "!disable" #component.IncFreq, "!disable" return [ComponIncFreq] 'increase freq to next point if componPointNum<=steps then componPointNum=componPointNum+1 gosub [ComponentSetItemsForMeasuring] gosub [ComponentMeasure] 'Measure at this point gosub [ComponentSetItemsForMeasuringDone] wait [ComponDecFreq] 'decrease freq to previous point if componPointNum>1 then componPointNum=componPointNum-1 gosub [ComponentSetItemsForMeasuring] gosub [ComponentMeasure] 'Measure at this point gosub [ComponentSetItemsForMeasuringDone] wait [ComponDoCalScan] 'Do calibration scan #component.Series,"disable" #component.Shunt,"disable" #component.R0,"!disable" 'Note we don't show Stop--we are only doing one sweep #component.Measure, "!disable" #component.DecFreq, "!disable" #component.IncFreq, "!disable" #component.Calibrate, "!disable" 'Save old sweep params. Note cal will also save them, so we need our own variables if componFirstCal=1 then componFirstCal=0 'No longer the first cal 'Set up the sweep params we want ver115-5c steps=8 'Note globalSteps will change in FunctChangeAndSaveSweepParams call FunctChangeAndSaveSweepParams 1, 0, steps, 0.1, 40, 0 'Log 100 kHz to 40 MHz; save old settings but don't transfer band cal to base cal 'ver115-5c : FunctChangeAndSaveSweepParams now sets wate, etc. 'Settings will be restored in ComponentDone call SetDefaultGraphData 'To get mag on primary axis ver115-3b 'Note: steps are 100K,210K,450K,950K, 2M, 4.2M, 8.9M, 18.9M, 40M end if print #component.Value, "cls; fill ";componBoxColor$ 'Clear last value if msaMode$="Reflection" then 'ver115-5b 'Use regular cal dialog for reflection mode gosub [PerformOSLCal] 'Sets OSLError=1 if math error occurs else 'ver115-5a forced lineCalThroughDelay to zero just for the current calibration componSaveThroughDelay=lineCalThroughDelay lineCalThroughDelay=0 gosub [BandLineCal] lineCalThroughDelay=componSaveThroughDelay end if desiredCalLevel=2 call RequireRestart 'Note sweep settings are not restored until we are Done #component.Freq, "Frequency= 0.1 MHz" 'Start with 100 KHz just to have something there #component.Series,"enable" #component.Shunt,"enable" #component.R0,"!enable" #component.Stop, "!hide" if msaMode$<>"Reflection" or OSLError=0 then #component.Measure, "!enable" 'Enable Measure now that we have cal ver115-5b #component.Calibrate, "!enable" wait [ComponSeriesSet] #component.Series, "set" : #component.Shunt, "reset" if componLastSeriesValue$<>"set" then gosub [ComponentInvalidateCal] 'topology changed componLastSeriesValue$="set" #component.CalInst, "Calibrate with Short" wait [ComponSeriesClear] #component.Series, "set" 'don't let it be cleared directly wait [ComponShuntSet] #component.Series, "reset" : #component.Shunt, "set" if componLastVal$<>"set" then gosub [ComponentInvalidateCal] 'topology changed componLastSeriesValue$="reset" #component.CalInst, "Calibrate with Open" wait [ComponShuntClear] #component.Shunt, "set" 'don't let it be cleared directly wait sub ComponResistorSet h$ #component.Resistor, "set" : #component.Capacitor, "reset" : #component.Inductor, "reset" #component.SeriesR, "!hide" : #component.Q, "!hide" 'ver115-3d end sub sub ComponCapacitorSet h$ #component.Resistor, "reset" : #component.Capacitor, "set" : #component.Inductor, "reset" #component.SeriesR, "!hide" : #component.Q, "!hide" 'ver115-3d end sub sub ComponInductorSet h$ #component.Resistor, "reset" : #component.Capacitor, "reset" : #component.Inductor, "set" #component.SeriesR, "Series R=" : #component.Q, "Q=" 'ver115-3d if msaMode$<>"ScalarTrans" then #component.SeriesR, "!show" : _ #component.Q, "!show" 'Show series res and Q for L if we have phase ver115-3d end sub sub ComponentStop h$ 'This button shows while Measuring componStopAtEnd=1 end sub [ComponentSetItemsForMeasuring] 'Set items they way they should be during measuring #component.Done, "!disable" #component.Series,"disable" #component.Shunt,"disable" #component.R0,"!disable" #component.Stop, "!show" #component.Measure, "!hide" #component.DecFreq, "!disable" #component.IncFreq, "!disable" #component.Calibrate, "!disable" #component.Explain, "!disable" 'ver115-3d return [ComponentSetItemsForMeasuringDone] 'Set items the way they should be when measuring has stopped #component.DecFreq, "!enable" 'Enable frequency hopping now that we have data #component.IncFreq, "!enable" #component.Stop, "!hide" #component.Measure, "!show" #component.Done, "!enable" #component.Series,"enable" #component.Shunt,"enable" #component.R0,"!enable" #component.Calibrate, "!enable" #component.Explain, "!enable" 'ver115-3d return [ComponentAcquireAndMeasure] 'button to do measurement scan gosub [ComponentSetItemsForMeasuring] componStopAtEnd=0 'can be set by user during sweep while componStopAtEnd=0 'Loop until user clicks Stop specialOneSweep=1 'So we return from [Restart] gosub [Restart] 'Do actual scan to acquire data 'Get values of all the boxes componPointNum=0 'Indicates to find best freq gosub [ComponentMeasure] 'Do actual calculations and display result wend gosub [ComponentSetItemsForMeasuringDone] wait [ComponentMeasure] 'Do actual calculations and display result #component.Resistor, "value? componRes$" #component.Capacitor, "value? componCap$" #component.Inductor, "value? componInd$" #component.Series, "value? componSeries$" if componSeries$="set" then componIsSeries=1 else componIsSeries=0 #component.R0, "!contents? componR0$" 'R0 componR0=val(componR0$) if componR0<0 then notice "Invalid R0. 50 ohms used." 'ver115-3f componType$="" if componRes$="set" then componType$="R" if componCap$="set" then componType$="C" if componInd$="set" then componType$="L" if componType$="R" then componUnits$="Ohms" else if componType$="C" then componUnits$="F" else 'Inductor componUnits$="H" end if end if call ComponentAnalyzeData componR0, componType$, componIsSeries, componValue, componSerRes, componPointNum 'ver115-3d componFreq=gGetPointXVal(componPointNum) 'Normally print value in blue, but in red if outside range of best accuracy componTextColor$="blue" 'ver115-4e if componValue<0 then 'ver115-3e rewrote this block componValue$="------" 'Invalid measurement due to self-resonance componTextColor$="red" componNegativeValue=1 else componNegativeValue=0 if componType$="R" and componValue<0.001 then componValue=0 '0.001 ohms lower limit if componType$="L" and componValue<1e-10 then componValue=0 '0.1 nH lower limit if componType$="C" and componValue<5e-14 then componValue=0 '0.05 pF lower limit componValue$=uFormatted$(componValue, "3,3,4//UseMultiplier//SuppressMilli"); componUnits$ 'ver115-4e end if 'ver115-4e added color change for out-of-range componR0ratio=S21JigR0/50 'To adjust limits based on jig R0 if componType$="R" then if S21JigAttach$="Series" then if componValue<2*componR0ratio or componValue>100000*componR0ratio then componTextColor$="red" else if componValue<0.1*componR0ratio or componValue>1000*componR0ratio then componTextColor$="red" end if end if if componType$="L" then if S21JigAttach$="Series" then if componValue<1e-8*componR0ratio or componValue>0.001*componR0ratio then componTextColor$="red" else if componValue<1e-7*componR0ratio or componValue>0.0001*componR0ratio then componTextColor$="red" end if end if if componType$="C" then if S21JigAttach$="Series" then if componValue<1e-12*componR0ratio or componValue>0.0000002*componR0ratio then componTextColor$="red" else if componValue<2e-11*componR0ratio or componValue>0.000002*componR0ratio then componTextColor$="red" end if end if #component.Freq, "Frequency=";using("###.#",componFreq); " MHz" 'display frequency at which we measured print #component.Value, "cls; fill ";componBoxColor$; ";color ";componTextColor$ 'ver115-4d print #component.Value, "place 15 30;\";componValue$ print #component.Value, "flush" if componType$="L" then 'display series resistance and Q for inductors ver115-3d if componNegativeValue then 'Negative L due to self-resonance ver115-3e #component.SeriesR, "" #component.Q, "" else componSerR$=uFormatted$(componSerRes, "3,3,4//UseMultiplier//SuppressMilli");"ohms" 'ver115-4e componSerX=2*uPi()*componValue*componFreq*1000000 'Inductor reactance if componSerRes=0 then 'ver115-5e componQ$="300+" else componQ=componSerX/componSerRes if componQ>300 then componQ$="300+" else componQ$=using("####.#",componQ) end if #component.SeriesR, "Series R=";componSerR$ #component.Q, "Q=";componQ$ end if end if return [ComponentDone] 'Note this cannot happen while Measure or Calibrate is in progress. close #component componentWindHndl$="" 'We need to restore sweep settings if we did anything if componFirstCal=0 then 'if we did a calibration, then restore prior settings ver115-5c gosub [FunctRestoreSweepParams] suppressHardwareInitOnRestart=1 'no need for hardware init ver116-4d gosub [PartialRestart] 'implement changes end if wait [ComponentExplain] WindowWidth = 540 WindowHeight = 475 UpperLeftX=int((DisplayWidth-WindowWidth)/2)+100 UpperLeftY=int((DisplayHeight-WindowHeight)/2)+100 BackgroundColor$="gray" ForegroundColor$="black" TextboxColor$ = "white" s$="Component Meter is a simple way to measure the value of components which are known" s$=s$;" to be relatively pure resistors, capacitors or inductors. It determines the component value" s$=s$;" from the attenuation caused by the component in the test fixture. You select the fixture and component" s$=s$;" type, run a single calibration, then insert and measure components." statictext #componHelp, s$, 20, 10, 500, 80 s$="When you click Measure, the MSA will determine the component value at one of several possible frequencies" s$=s$;" and display the frequency of the measurement. The possible frequencies are those that the MSA automatically" s$=s$;" included in the calibration. You may increase/decrease the frequency of the measurement with the +Freq and -Freq" s$=s$;" buttons, after pushing Stop." statictext #componHelp, s$, 20, 100, 500, 80 s$="The test fixture is typically an attenuator, then the component, then another attenuator. The component" s$=s$;" may be connected in Series between the attenuators, or may be Shunt to ground, which accounts for the" s$=s$;" two different fixture types. The component will see a certain resistance R0 looking at the incoming signal" s$=s$;" and the outgoing signal. You must specify that R0, usually 50 ohms." statictext #componHelp, s$, 20, 190, 500, 80 s$="The Series fixture is calibrated with a Short (the terminals directly shorted) and can typically measure R from" s$=s$;" 5 ohms to 100K ohms; L from 10 nH to 1 mH, and C from 1 pF to 0.2 uF." statictext #componHelp, s$, 20, 280, 500, 60 s$="The Shunt fixture is calibrated with an Open (no component attached) and can typically measure R from" s$=s$;" 0.25 ohms to 1 kohm; L from 100 nH to 100 uH, and C from 20 pF to 2 uF." statictext #componHelp, s$, 20, 340, 500, 70 s$="For inductors, the series resistance and Q will be displayed, but if Q>30, both Q and series resistance may be unreliable." statictext #componHelp, s$, 20, 400, 500, 70 open "Component Measurement Help" for dialog_modal as #componHelp print #componHelp, "font ms_sans_serif 10" print #componHelp, "trapclose [ComponentHelpDone]" wait [ComponentHelpDone] close #componHelp wait sub ComponentAnalyzeData componR0, componType$, componIsSeries, byref componValue, byref serRes, byref pointNum 'Return component value and frequency ver115-3d 'Calculate component value at point specified by pointNum, but if it is zero find best frequency 'Return the component value (ohms, F or H) and the point number at which we measured. For L and C, 'we also return the series resistance, which is valid if we have phase. 'It is possible to return a negative L or C value, which means the self-resonance has interfered and the measurement 'is not valid. 'Do an initial measurement doBestFreq=(pointNum<1 or pointNum>globalSteps+1) 'invalid point means find the best one 'Note: steps are 100K,210K,450K,950K, 2M, 4.2M, 8.9M, 18.9M, 40M if doBestFreq then 'ver115-3e rewrote this block nTries=3 'Assume need to iterate to find best frequency if componType$="R" then pointNum=4 : nTries=0 '950K Choose a frequency high enough where LO leakages are not an issue else lowFreqDB=gGetPointYVal(1,primaryAxisNum) 'Get mag data for a low frequency highFreqDB=gGetPointYVal(9,primaryAxisNum) 'Get mag data for a high frequency if componType$="C" then 'Low impedance at 100 kHz indicates a large capacitor. High impedance 'at 40 MHz indicates a small capacitor. Large cap may be past its self-resonance at low freq, but 'will still have low impedance. Small cap will not be significantly affected by self-resonance at 40 MHz. 'We have to assume here small lead lengths on capacitors. pointNum=3 'For non-extreme capacitors, we will start at 450 kHz if componIsSeries then 'We can tell whether we have extreme values by looking at 100 kHz and 40 MHz isLowZ=lowFreqDB>-0.1 : isHighZ=(isLowZ=0 and highFreqDB<-7) 'thresholds approx. 0.1 uF and 20 pF else 'shunt isLowZ=lowFreqDB<-5.5 : isHighZ=(isLowZ=0 and highFreqDB>-1.4) 'thresholds approx. .1 uF and 100 pF end if if isLowZ then pointNum=1: nTries=0 'Stick with lowest frequency if isHighZ then pointNum=9 'start with highest frequency; may turn out hiZ is due to inductance else 'Inductors are trickier, because losses can confuse the situation when just looking at S21 dB 'So we make a guess at a starting point, but always do iteration, which separates L and R. 'Low impedance at 40 MHz indicates a very small inductor, though a lossy small inductor 'may be missed. It could also be large inductor that turned to a capacitor, but the iteration 'will take care of that case. 'A non-low impedance at 100 kHz indicates a large or lossy inductor. We will start with 100 kHz 'and iterate from there. pointNum=6 'For non-extreme inductors, we will start at 4.2 MHz and iterate if componIsSeries then isHighZ=(lowFreqDB<-1.8) :isLowZ=(isHighZ=0 and highFreqDB>-0.45) 'thresholds 100 uH and 100 nH else 'shunt isHighZ=(lowFreqDB>-.9) : isLowZ=(isHighZ=0 and highFreqDB<-3.4) 'thresholds 100 uH and 100 nH end if if isHighZ then pointNum=1 'Start with lowest frequency if isLowZ then pointNum=9 'Start with highest frequency for small inductors end if end if for i=1 to nTries 'run through 0 or 2 times to get best freq. 'get value and series resistance call ComponentGetValue componR0,componIsSeries,pointNum-1, componType$, componValue, serRes 'ver115-3d 'See if we are at a reasonable frequency for this component value select componType$ case "C" 'ver115-3e rewrote the if... blocks as select statements if componIsSeries then 'Series wants high Z, meaning lower frequencies select case case componValue<0 'ver115-3e 'The capacitor measured negative, which may be a sign it is past self-resonance, so we need to go 'with a low frequency; but go high if we are already low if pointNum=1 then pointNum=9 else pointNum=max(1, int(pointNum/2)) 'ver115-3e case componValue>=2e-9 '5 nF and higher use low freq pointNum=1 '100 KHz case 5e-11<=componValue and componValue<5e-9 '50 pF to 5 nF pointNum=4 '950 KHz case else 'under 50 pF pointNum=9 '40 MHz end select 'end Series C else 'Shunt C wants low Z, meaning higher frequencies select case 'Ranges modified by ver115-3e case componValue<0 'ver115-3e 'The capacitor measured negative, which may be a sign it is past self-resonance, so we need to go 'with a low frequency; but go high if we are already low if pointNum=1 then pointNum=9 else pointNum=max(1, int(pointNum/2)) 'ver115-3e case componValue>=5e-7 '500 nF and higher use low freq pointNum=1 '100 KHz case 5e-8<=componValue and componValue<5e-7 '50 nF to 500 nF pointNum=2 '210 KHz case 1e-9<=componValue and componValue<5e-8 '1 nF to 50 nF pointNum=4 '950 KHz case 1e-10<=componValue and componValue<1e-9 '100 pF to 1 nF ver115-4e pointNum=6 '8.9 MHz case else 'under 100 pF pointNum=9 '40 MHz end select end if 'end Shunt C case else 'Inductor 'Note: Inductor measurement is much less accurate without phase info, due to inductor 'losses. These ranges are set assuming phase is available. A prime goal is then to avoid 'the lowest frequencies, where LO leakage has significant effect. if componIsSeries then 'Series wants high Z, meaning higher freq select case case componValue<0 'ver115-3e 'The inductor measured negative, which may be a sign it is past self-resonance, so we need to go 'with a low frequency; but go high if we are already low if pointNum=1 then pointNum=9 else pointNum=max(1, int(pointNum/2)) 'ver115-3e case componValue>=0.001 '1 mH and higher these need low freq for low loss pointNum=1 '100 KHz case 1e-4<=componValue and componValue<0.001 '100 uH to 1 mH pointNum=2 '210 KHz case 1e-5<=componValue and componValue<1e-4 '10 uH to 100 uH pointNum=5 '950KHz case 3e-7<=componValue and componValue<1e-5 '300 nH to 10 uH pointNum=7 '8.9 MHz case else 'under 300 nH pointNum=9 '40 MHz end select 'end Series L else 'Shunt L wants low Z, meaning lower freq 'These are currently just copied from the series values, which are based on some tests select case case componValue<0 'ver115-3e 'The inductor measured negative, which may be a sign it is past self-resonance, so we need to go 'with a low frequency; but go high if we are already low if pointNum=1 then pointNum=9 else pointNum=max(1, int(pointNum/2)) 'ver115-3e case componValue>=0.001 '1 mH and higher these need low freq for low loss pointNum=1 '100 KHz case 1e-4<=componValue and componValue<0.001 '100 uH to 1 mH pointNum=2 '210 KHz case 1e-5<=componValue and componValue<1e-4 '10 uH to 100 uH pointNum=5 '950KHz case 3e-7<=componValue and componValue<1e-5 '300 nH to 10 uH pointNum=7 '8.9 MHz case else 'under 300 nH pointNum=9 '40 MHz end select end if 'end Shunt L end select next i end if 'get value and series resistance call ComponentGetValue componR0,componIsSeries,pointNum-1, componType$, componValue, serRes 'ver115-3d end sub 'ver115-3d added ComponentGetValue sub ComponentGetValue componR0, isSeries, scanStep, componType$, byref value, byref serRes 'Calculate value (ohms, F or H) of specified component 'Returns value (Ohms, F or H) in value and, for L and C, series resistance in serRes 'componR0 is R0 of the test fixture; ignored for reflection mode, where ReflectArray data already accounts for it 'isSeries is 1 if fixture is Series; 0 if fixture is Shunt; ignored for reflection mode, where ReflectArray data already accounts for it 'db is S21 or S11 db of the component in the fixture 'phase is S21 or S11 phase, unless we are in ScalarTrans mode 'trueFreq is frequency in Hz 'componType$ is "R", "L" or "C" 'scan step is the step (0...) at which we are measuring. It is an integer. if msaMode$="Reflection" then 'ver115-5b 'For reflection mode, the values we need are already in ReflectArray() if ReflectArray(scanStep, constSerR)>0 then serRes=ReflectArray(scanStep, constSerR) else serRes=0 if serRes<0.001 then serRes=0 else if serRes>1e9 then serRes=1e9 '0.001 to 1G ohms if componType$="C" then value=ReflectArray(scanStep, constSerC) if componType$="L" then value=ReflectArray(scanStep, constSerL) 'For resistor, if reactance is inductive, assume small resistor with parasitic inductance and return series resistance 'if reactance is capacitive return parallel resistance, because we are a large resistor in parallel with parasitic capacitance if componType$="R" then serX=ReflectArray(scanStep, constSerReact) if serX>0 then value=serRes else value=ReflectArray(scanStep, constParR) end if exit sub 'No more to do for reflection mode end if 'Here for ScalarTrans or VectorTrans trueFreq=1000000*S21DataArray(scanStep, 0) : db=S21DataArray(scanStep, 1) : phase=S21DataArray(scanStep, 2) 'ver115-5e if db>0 then db=0 if msaMode$="ScalarTrans" then 'Calculate impedance from magnitude alone, assuming ideal phase componMag=10^(db/20) 'Magnitude of measured S21 if componType$="R" then serX=0 if isSeries then 'series R=(2*Ro) * (1-S21)/S21 if componMag>0.9999 then serRes=0 else serRes=2*componR0*(1-componMag)/componMag else 'shunt R=(Ro/2) * S21 / (1-S21) if componMag>0.9999 then serRes=1e9 else serRes=componR0*componMag/(2*(1-componMag)) end if else 'L and C--calculate reactance and then component value if isSeries then 'For series fixture, abs(X)=+/- 2*R0*sqr(1-M21^2)/M21, where M21 is magnitude of S21 if componMag<0.000001 then serX=0 else serX=2*componR0*sqr(1-componMag^2)/componMag else 'shunt 'For shunt fixture, abs(X)=+/- R0*M21/(2*sqr(1-M21^2)), where M21 is magnitude of S21 if componMag>0.9999 then serX=1e9 else serX=componR0*componMag/(2*sqr(1-componMag^2)) end if if componType$="C" then serX=0-serX 'capacitors have negative reactance end if else 'VectorTrans 'Calculate impedance from jig if isSeries then call uSeriesJigImpedance componR0, db, phase, serRes, serX else 'We use no delay here, so we just provide a frequency of 1 call uShuntJigImpedance componR0, db, phase, 0,1,serRes, serX 'assumes zero connector delay ver115-4a end if end if 'Get here for ScalarTrans or VectorTrans 'serRes and serX now have the series resistance and reactance if serRes<0.001 then serRes=0 else if serRes>1e9 then serRes=1e9 '0.001 to 1G ohms; avoid tiny non-zero values if componType$="R" then if serX>0 then value=serRes : exit sub 'If reactance is inductive, assume small resistor with parasitic inductance and return series resistance 'Here we want to return parallel resistance, because we are a large resistor in parallel with parasitic capacitance call uEquivParallelImped serRes, serX, parRes, parX value=parRes exit sub end if 'Here for L or C. Convert reactance to component value if componType$="C" then if serX=0 then value=1 else value=-1/(2*uPi()*serX*trueFreq) 'capacitance in farads else 'Inductor value=serX/(2*uPi()*trueFreq) 'inductance in henries end if if value>1 then value=1 'max of 1F or 1H 'ver115-3e deleted the lower limit on L and C, because it is possible they end up 'with negative values, which is a useful sign that they are past their self-resonance 'and we need to lower the frequency. end sub sub AppearanceDialog WindowWidth = 525 WindowHeight = 425 UpperLeftX=100 UpperLeftY=100 ForegroundColor$="black" BackgroundColor$="buttonface" graphicbox #gridappearance.Sample, 115, 52, 265, 155 RefTop=257 graphicbox #gridappearance.BoxText, 350, RefTop, 65, 20 graphicbox #gridappearance.BoxGrid, 265, RefTop, 65, 20 graphicbox #gridappearance.BoxBounds, 175, RefTop, 70, 20 graphicbox #gridappearance.BoxBack, 85, RefTop, 70, 20 graphicbox #gridappearance.BoxY1, 35, 65, 70, 20 graphicbox #gridappearance.BoxY2, 385, 65, 70, 20 graphicbox #gridappearance.BoxY1A, 35, 115, 70, 20 'ver116-4b graphicbox #gridappearance.BoxY2A, 385, 115, 70, 20 graphicbox #gridappearance.BoxY1B, 35, 165, 70, 20 graphicbox #gridappearance.BoxY2B, 385, 165, 70, 20 graphicbox #gridappearance.BoxX, 205, 210, 70, 20 statictext #gridappearance, "Grid", 285, RefTop+20, 30, 20 statictext #gridappearance, "Text", 365, RefTop+20, 26, 20 statictext #gridappearance, "Background", 80, RefTop+20, 73, 20 statictext #gridappearance, "Boundary", 180, RefTop+20, 58, 20 statictext #gridappearance, "Y1", 60, 85, 30, 20 statictext #gridappearance, "Y2", 405, 85, 30, 20 statictext #gridappearance, "Y1A", 60, 135, 30, 20 'ver116-4b statictext #gridappearance, "Y2A", 405, 135, 30, 20 statictext #gridappearance, "Y1B", 60, 185, 30, 20 statictext #gridappearance, "Y2B", 405, 185, 30, 20 statictext #gridappearance, "Freq", 220, 230, 40, 20 TextboxColor$ = "white" statictext #gridappearance, "Click on a color box to change it.", 135, 5,250, 20 statictext #gridappearance, "You may save this as a Custom Appearance.", 95, 20,350, 20 button #gridappearance.Use,"Use*",[AppearanceUse], UL, 70, 330, 90, 30 button #gridappearance.Save,"Save as Preset*",[AppearanceSave], UL, 180, 330, 150, 30 button #gridappearance.Cancel,"Cancel",[AppearanceCancel], UL, 350, 330, 90, 30 statictext #gridappearance, "*Must save preferences file to make changes permanent.",70,365,400,20 'ver115-2c open "Graph Appearance" for dialog_modal as #gridappearance print #gridappearance.BoxText, "down; fill white; flush" print #gridappearance.Sample, "down; fill white; flush" print #gridappearance, "font ms_sans_serif 10" print #gridappearance, "trapclose [AppearanceClosebox]" call gGetGridColors BackCol$, LineCol$, BoundsCol$ print #gridappearance.BoxBack, "cls; down;fill ";BackCol$; ";flush" print #gridappearance.BoxBounds, "cls; down; fill ";BoundsCol$; ";flush" 'ver115-2c print #gridappearance.BoxGrid, "cls; down; fill ";LineCol$; ";flush" 'ver115-2c call gGetTextColors XCol$, Y1Col$, Y2Col$, TextCol$ 'Note traces 1 and 2 are same color as text for axis 1 and 2 call gGetSupplementalTraceColors Y1ACol$, Y2ACol$, Y1BCol$, Y2BCol$ 'supplemental traces have their own color ver116-4b call gGetFonts saveXfont$, saveY1font$, saveY2font$, TextFont$ print #gridappearance.BoxText, "cls; down; fill ";TextCol$; ";flush" print #gridappearance.BoxY1, "cls; down; fill ";Y1Col$; ";flush" print #gridappearance.BoxY2, "cls; down; fill ";Y2Col$; ";flush" print #gridappearance.BoxY1A, "cls; down; fill ";Y1ACol$; ";flush" 'ver116-4b print #gridappearance.BoxY2A, "cls; down; fill ";Y2ACol$; ";flush" print #gridappearance.BoxY1B, "cls; down; fill ";Y1BCol$; ";flush" print #gridappearance.BoxY2B, "cls; down; fill ";Y2BCol$; ";flush" print #gridappearance.BoxX, "cls; down; fill ";XCol$; ";flush" print #gridappearance.BoxBack, "when leftButtonDown [AppearanceClickBack]" print #gridappearance.BoxBounds, "when leftButtonDown [AppearanceClickBounds]" print #gridappearance.BoxGrid, "when leftButtonDown [AppearanceClickGrid]" print #gridappearance.BoxText, "when leftButtonDown [AppearanceClickText]" print #gridappearance.BoxY1, "when leftButtonDown [AppearanceClickY1]" print #gridappearance.BoxY2, "when leftButtonDown [AppearanceClickY2]" print #gridappearance.BoxY1A, "when leftButtonDown [AppearanceClickY1A]" print #gridappearance.BoxY2A, "when leftButtonDown [AppearanceClickY2A]" print #gridappearance.BoxY1B, "when leftButtonDown [AppearanceClickY1B]" print #gridappearance.BoxY2B, "when leftButtonDown [AppearanceClickY2B]" print #gridappearance.BoxX, "when leftButtonDown [AppearanceClickFreq]" gosub [AppearanceDrawSample] wait [AppearanceDrawSample] 'Draw sample chart #gridappearance.Sample, "down; cls; size 1; fill ";BackCol$ #gridappearance.Sample, "color ";LineCol$;";backcolor ";BackCol$ originX=25 : originY=125 : ht=100 :width=200 for i=1 to 3 'vertical lines #gridappearance.Sample,"Line ";originX+50*i;" ";originY;" ";originX+50*i;" ";originY-ht next i for i=1 to 3 'horizontal lines #gridappearance.Sample,"Line ";originX;" ";originY-25*i;" ";originX+width;" ";originY-25*i next i #gridappearance.Sample, "color ";BoundsCol$;"; size 3" 'Draw boundary #gridappearance.Sample, "Line ";originX;" ";originY;" ";originX;" ";originY-ht #gridappearance.Sample, "Line ";originX;" ";originY-ht;" ";originX+width;" ";originY-ht #gridappearance.Sample, "Line ";originX+width;" ";originY-ht;" ";originX+width;" ";originY #gridappearance.Sample, "Line ";originX+width;" ";originY;" ";originX;" ";originY 'Draw Sample Text #gridappearance.Sample, "color ";TextCol$;"; size 1" #gridappearance.Sample, "font "; TextFont$ 'Draw text #gridappearance.Sample, "place ";originX+90;" ";originY-ht-5 #gridappearance.Sample,"\Title" 'Draw graph lines #gridappearance.Sample, "color ";Y1Col$;"; size 1" #gridappearance.Sample, "place ";originX-10;" ";originY #gridappearance.Sample,"\1" #gridappearance.Sample, "place ";originX-20;" ";originY-ht+5 #gridappearance.Sample,"\10" #gridappearance.Sample, "Line ";originX;" ";originY-30;" ";originX+width;" ";originY-40 #gridappearance.Sample, "color ";Y1ACol$;"; size 1; Line ";originX;" ";originY-20;" ";originX+width;" ";originY-30 'ver116-4b #gridappearance.Sample, "color ";Y1BCol$;"; size 1; Line ";originX;" ";originY-10;" ";originX+width;" ";originY-20 'ver116-4b #gridappearance.Sample, "color ";Y2Col$;"; size 1" #gridappearance.Sample, "place ";originX+width+5;" ";originY #gridappearance.Sample,"\1" #gridappearance.Sample, "place ";originX+width+5;" ";originY-ht+5 #gridappearance.Sample,"\10" #gridappearance.Sample, "Line ";originX;" ";originY-80;" ";originX+width;" ";originY-90 #gridappearance.Sample, "color ";Y2ACol$;"; size 1; Line ";originX;" ";originY-70;" ";originX+width;" ";originY-80 'ver116-4b #gridappearance.Sample, "color ";Y2BCol$;"; size 1; Line ";originX;" ";originY-60;" ";originX+width;" ";originY-70 'ver116-4b #gridappearance.Sample, "color ";XCol$;"; size 1" #gridappearance.Sample, "place ";originX;" ";originY+15 #gridappearance.Sample,"\1" #gridappearance.Sample, "place ";originX+width-5;" ";originY+15 #gridappearance.Sample,"\10" #gridappearance.Sample, "flush" return [AppearanceUse] 'Use but don't save the selected colors call gSetGridColors BackCol$, LineCol$, BoundsCol$ call gSetTextColors XCol$, Y1Col$, Y2Col$, TextCol$ call gSetTraceColors Y1Col$, Y2Col$ 'ver116-4b call gSetSupplementalTraceColors Y1ACol$, Y2ACol$, Y1BCol$, Y2BCol$ 'ver116-4b call SetCycleColors 'ver116-4s close #gridappearance call RedrawGraph 0 exit sub [AppearanceSave] 'Use colors and save them as a custom preset saveCancelled=0 gosub [AppearanceSubToSave] if saveCancelled then wait 'ver116-4b deleted setting graph module colors; gUsePresetColors will do that call gUsePresetColors "Custom";savedAsPresetNum 'To register that we are using this preset and implement it call SetCycleColors 'ver116-4s close #gridappearance call RedrawGraph 0 exit sub '---------------------------Start of AppearanceSubToSave------- [AppearanceSubToSave] WindowWidth = 465 WindowHeight = 335 UpperLeftX=100 UpperLeftY=100 statictext #colorpreset.statictext1, "Select the Custom Appearance to be replaced by the new colors.", 25, 17, 384, 20 statictext #colorpreset.statictext2, "You may also rename the Custom Appearance.", 60, 37, 350, 20 ListboxColor$ = "white" listbox #colorpreset.List, customPresetNames$(), [AppearanceList], 145, 82, 160, 90 textbox #colorpreset.Name, 145, 200,120, 20 statictext #colorpreset, "Name", 105, 200, 40, 20 button #colorpreset.Delete,"Delete",[AppearanceDeletePreset], UL, 70, 240, 90, 40 button #colorpreset.Save,"Save",[AppearanceSavePreset], UL, 180, 240, 90, 40 button #colorpreset.Cancel,"Cancel",[AppearanceCancelPreset], UL, 290, 240, 90, 40 open "Save Custom Appearance" for dialog_modal as #colorpreset print #colorpreset, "font ms_sans_serif 10" print #colorpreset, "trapclose [PresetClosebox]" print #colorpreset.List, "singleClickSelect" wait [PresetClosebox] wait [AppearanceList] 'Perform action for the listbox named 'List' #colorpreset.List, "selection? name$" #colorpreset.Name, name$ #colorpreset.Name, "!setfocus" call uHighlightText "#colorpreset.Name" 'to allow changing it immediately wait [AppearanceDeletePreset] #colorpreset.List, "selectionindex? sel" 'sel (1...) is index of selected item if sel=0 then notice "No Appearance is selected." : wait customPresetNames$(sel)="Empty" #colorpreset.List, "Reload" #colorpreset.Name, "Empty" wait [AppearanceSavePreset] #colorpreset.List, "selectionindex? savedAsPresetNum" 'savedAsPresetNum (1...) is index of selected item if savedAsPresetNum=0 then notice "No Appearance is selected." : wait #colorpreset.Name, "!contents? newName$" if newName$="" or newName$="Empty" then notice "You must provide a Name." : wait call gSetCustomPresetColors savedAsPresetNum,LineCol$, BoundsCol$, BackCol$,TextCol$, XCol$, Y1Col$, Y2Col$, _ Y1Col$, Y2Col$, Y1ACol$, Y2ACol$, Y1BCol$, Y2BCol$ 'ver116-4b added extra trace colors customPresetNames$(savedAsPresetNum)=newName$ call FillAppearancesArray close #colorpreset return [AppearanceCancelPreset] 'Perform action for the button named 'Cancel' close #colorpreset saveCancelled=1 return '---------------------------End of AppearanceSubToSave------- [AppearanceCancel] 'Perform action for the button named 'Cancel' close #gridappearance exit sub [AppearanceClosebox] wait 'disables close box [AppearanceClickBack] colordialog BackCol$, newCol$ if newCol$="" then wait 'cancelled BackCol$=newCol$ print #gridappearance.BoxBack, "cls; fill ";BackCol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickBounds] colordialog BackCol$, newCol$ if newCol$="" then wait 'cancelled BoundsCol$=newCol$ print #gridappearance.BoxBounds, "cls; fill ";BoundsCol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickGrid] colordialog BackCol$, newCol$ if newCol$="" then wait 'cancelled LineCol$=newCol$ print #gridappearance.BoxGrid, "cls; fill ";LineCol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickText] colordialog BackCol$, newCol$ if newCol$="" then wait 'cancelled TextCol$=newCol$ print #gridappearance.BoxText, "cls; fill ";TextCol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickY1] colordialog Y1Col$, newCol$ : if newCol$="" then wait 'cancelled Y1Col$=newCol$ : print #gridappearance.BoxY1, "cls; fill ";Y1Col$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickY2] colordialog Y2Col$, newCol$ : if newCol$="" then wait 'cancelled Y2Col$=newCol$ : print #gridappearance.BoxY2, "cls; fill ";Y2Col$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickY1A] 'ver116-4b colordialog Y1ACol$, newCol$ : if newCol$="" then wait 'cancelled Y1ACol$=newCol$ : print #gridappearance.BoxY1A, "cls; fill ";Y1ACol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickY2A] 'ver116-4b colordialog Y2ACol$, newCol$ : if newCol$="" then wait 'cancelled Y2ACol$=newCol$ : print #gridappearance.BoxY2A, "cls; fill ";Y2ACol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickY1B] 'ver116-4b colordialog Y1BCol$, newCol$ : if newCol$="" then wait 'cancelled Y1BCol$=newCol$ : print #gridappearance.BoxY1B, "cls; fill ";Y1BCol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickY2B] 'ver116-4b colordialog Y2Col$, newCol$ : if newCol$="" then wait 'cancelled Y2BCol$=newCol$ : print #gridappearance.BoxY2B, "cls; fill ";Y2BCol$; ";flush" gosub [AppearanceDrawSample] wait [AppearanceClickFreq] colordialog XCol$, newCol$ if newCol$="" then wait 'cancelled XCol$=newCol$ print #gridappearance.BoxX, "cls; fill ";XCol$; ";flush" gosub [AppearanceDrawSample] wait end sub 'end of AppearanceDialog 'ver115-5d added [menuS11ToS21] [menuS11ToS21] if haltsweep then gosub [FinishSweeping] 'stop sweeping cleanly call S11ToS21 'Do conversion call RequireRestart 'Scan can continue only by Restart wait 'ver115-5d added S11ToS21 sub S11ToS21 'Convert current S11 data to S21 in either Series or Shunt Fixture 'Results are put into auxGraphData(x,0) and auxGraphData(x,1) for each step x, representing 'S21 mag and phase. They are set as the current graph data and are listed as an additional graph type 'until the next Restart. WindowWidth = 570 WindowHeight = 275 call GetDialogPlacement BackgroundColor$="gray" ForegroundColor$="black" TextboxColor$ = "white" statictext #S11S21.title, "CONVERT S11 TO S21 IN SHUNT OR SERIES FIXTURE",70, 10, 375, 20 s$="This function determines the S21 values that would generated by a device with the impedances" s$=s$;" indicated by the current S11 values. That S21 can be generated for either the shunt or" s$=s$;" series fixture. Plane extension is not included in the calculated S21 values." statictext #S11S21.title1, s$,20, 30, 540, 60 controlTop=95 checkbox #S11S21.series, "Series Fixture", [S11S21Series], [S11S21Series], 10, controlTop, 400,20 checkbox #S11S21.shunt, "Shunt Fixture", [S11S21Shunt], [S11S21Shunt], 10, controlTop+25, 400,20 statictext #S11S21, "Fixture R0", 10, controlTop+52, 60, 16 textbox #S11S21.R0, 72, controlTop+50, 50, 20 button #S11S21.convert, "Generate S21", [S11S21Generate], UL,100,controlTop+100, 100, 25 button #S11S21.help, "Help", S11ToS21Help, UL,300,controlTop+100, 100, 25 'Open dialog open "Convert S11 to S21" for dialog_modal as #S11S21 #S11S21, "trapclose [S11S21Cancel]" #S11S21, "font ms_sans_serif 10" #S11S21.R0, S11GraphR0 'Assume we will keep same R0 goto [S11S21Series] [S11S21Cancel] close #S11S21 exit sub [S11S21Series] #S11S21.series, "set" : #S11S21.shunt, "reset" wait [S11S21Shunt] #S11S21.series, "reset" : #S11S21.shunt, "set" wait [S11S21Generate] #S11S21.series, "hide" : #S11S21.shunt, "hide" #S11S21.convert, "!hide" : #S11S21.help, "!hide" #S11S21.R0, "!contents? R0$" conversionR0=uValWithMult(R0$) 'reference R0 for S21 if conversionR0<=0 then notice "Invalid Fixture R0" : wait 'error call ClearAuxData 'Clear auxiliary graph data by blanking graph names call gGetMinMaxPointNum pMin, pMax if pMin<1 or pMaxS11GraphR0 then call CalcGraphDataType currStep, constSerR, constSerReact, serR, serX, 0 'Get current impedance for this step from scan data else call CalcGraphDataType currStep, constRho, constTheta, rho, theta, 0 'Get current S11 for this step from scan data end if if S11S21SeriesVal$="set" then if conversionR0=S11GraphR0 then call uRefcoToSeriesS21DB rho, theta, S21DB, S21Ang 'S21 for refco in series fixture else call uSeriesImpedanceToS21DB conversionR0, serR, serX, S21DB, S21Ang 'S21 for impedance in series fixture end if else 'Note we assume no delay; we could use the current shunt fixture delay if conversionR0=S11GraphR0 then call uRefcoToShuntS21DB rho, theta, S21DB, S21Ang 'S21 for refco in shunt fixture 'ver116-4k else call uShuntImpedanceToS21DB conversionR0, serR, serX, 0, 0, S21DB, S21Ang 'S21 for impedance in shunt fixture, w/o delay end if end if auxGraphData(currStep,0)=S21DB 'S21DB auxGraphData(currStep,1)=S21Ang 'S21Ang next currStep 'We must now describe the data in auxGraphData for the graphing routines 'S21 Mag R0$=uFormatted$(conversionR0, "3,2,3//UseMultiplier//DoCompact") 'Print conversion R0 as part of graph name and axis heading S21Lab$="S21(";R0$;") " auxGraphDataFormatInfo$(0,0)=S21Lab$;"dB" : auxGraphDataFormatInfo$(0,1)="####.###//DoCompact" 'Graph name; format string auxGraphDataFormatInfo$(0,2)=S21Lab$;"dB": auxGraphDataFormatInfo$(0,3)="S21 dB" 'Axis heading; marker label auxGraphDataInfo(0,0)=0 'not an angle auxGraphDataInfo(0,1)=-100 'axis min auxGraphDataInfo(0,2)=0 'axis max 'S21 Angle auxGraphDataFormatInfo$(1,0)=S21Lab$;"Deg" : auxGraphDataFormatInfo$(1,1)="####.##//DoCompact" auxGraphDataFormatInfo$(1,2)=S21Lab$;"Deg": auxGraphDataFormatInfo$(1,3)="S21 Deg" auxGraphDataInfo(1,0)=1 'is an angle auxGraphDataInfo(1,1)=-180 'axis min auxGraphDataInfo(1,2)=180 'axis max 'Db will go on primary axis if primaryAxisNum=1 then 'ver115-5f call ChangeGraphsToAuxData constAux0, constAux1 'S21 Mag on left, angle on right else call ChangeGraphsToAuxData constAux1, constAux0 'S21 angle on left, db on right end if goto [S11S21Cancel] 'quit once we convert end sub sub S11ToS21Help h$ WindowWidth = 550 WindowHeight = 370 call GetDialogPlacement BackgroundColor$="gray" ForegroundColor$="black" s$="The scanned S11 values (whether or not they are currently graphed) represent impedances that can be" s$=s$;" hypothetically placed in a Series Fixture (with the TG signal run through the DUT to the MSA input)" s$=s$;" or in a Shunt Fixture (with the TG signal run directly to the MSA input via a line to which the" s$=s$;" DUT is attached, with the other DUT terminal grounded). The fixture can have whatever R0 value the" s$=s$;" user specifies, typically 50 ohms." statictext #S11S21Explain, s$, 10, 10, 520, 85 s$="This concept only makes sense for devices that have exactly two terminals, such as resistors, capacitors," s$=s$;" inductors, crystals, or simple parallel or series RLC combinations, or for devices with one terminal" s$=s$;" plus an explicit or implicit ground, such as an antenna. It does not make sense for amplifiers, which" s$=s$;" have three terminals--input, output and ground. In addition, devices with a permanent or implicit" s$=s$;" ground cannot be made floating, and therefore it makes no sense to generate their S21 in a series fixture." statictext #S11S21Explain, s$, 10, 105, 515, 100 s$="If you have specified a plane extension value, it was taken into account in calculating S11, but it is not" s$=s$;" taken into account for the conversion to S21. That is, there is no plane extension (or other connector" s$=s$;" delay) in the hypothetical S21 fixture." statictext #S11S21Explain, s$, 10, 215, 515, 50 s$="When you click Generate S21, two new graph types will be created and displayed, for the generated S21 dB and angle" s$=s$;" values. They will also be available in the list of graph types in the Y-axis windows until Restart." statictext #S11S21Explain, s$, 10, 275, 515, 50 open "Generate S21 Help" for dialog_modal as #S11S21Explain print #S11S21Explain, "font ms_sans_serif 10" print #S11S21Explain, "trapclose [S11S21ExplainEnd]" wait [S11S21ExplainEnd] close #S11S21Explain exit sub end sub 'end S11ToS21Help sub ReflectionRLC 'Reflection mode RLC Analysis renamed ver115-5d WindowWidth = 625 : WindowHeight = 375 call GetDialogPlacement BackgroundColor$="gray" : ForegroundColor$="black" : TextboxColor$ = "white" statictext #RLC.title, "DETERMINATION OF COMBINED RLC PARAMETERS",70, 10, 375, 20 s$="This function determines the combined resistor, capacitor and inductor that best model the current scan data." s$=s$;" Analysis may be done (1) at all frequencies using the value and slope of reactance or susceptance" s$=s$;" or (2) at two specific frequencies identified by markers before this dialog was opened. If the slope" s$=s$;" method is used, the slope is determined by the specified number of points around the target point, and" s$=s$;" graphs will also be created with the results at all frequencies, with one frequency displayed in this dialog." statictext #RLC.title1, s$,20, 30, 570, 110 controlTop=145 checkbox #RLC.parallelRLC, "Parallel RLC", [RefRLCParallelRLC], [RefRLCParallelRLC], 10, controlTop, 150,20 checkbox #RLC.seriesRLC, "Series RLC", [RefRLCSeriesRLC], [RefRLCSeriesRLC], 10, controlTop+20, 150,20 'ver116-4h deleted the lossy inductor option and added Two-Frequency option checkbox #RLC.slope, "Use Slope Method", [RefRLCSlope], [RefRLCSlope], 200, controlTop, 250,20 checkbox #RLC.twoFreq, "Use Two-Frequency Method", [RefRLCTwoFreq], [RefRLCTwoFreq], 200, controlTop+20, 250,20 textbox #RLC.nPoints, 355, controlTop+50, 50, 20 statictext #RLC.nPointsLabel, "Number of points to include:", 10, controlTop+52, 340, 20 textbox #RLC.results, 10, controlTop+95, 575, 25 'textbox for results button #RLC.decFreq, "-Freq", [decFreq], UL,15,controlTop+125, 50, 20 button #RLC.incFreq, "+Freq", [incFreq], UL,67,controlTop+125, 50, 20 button #RLC.Analyze, "Analyze", [RefRLCAnalyze], UL,100,controlTop+170, 100, 25 button #RLC.Analyze, "Help", RefRLCHelp, UL,300,controlTop+170, 100, 25 'Open dialog open "RLC Analysis" for dialog_modal as #RLC #RLC, "trapclose [RefRLCCancel]" #RLC, "font ms_sans_serif 10" #RLC.results, "!font Arial 11 bold" pCount=gPointCount() if pCount<2 then notice "Not enough points for analysis." : goto [RefRLCCancel] #RLC.nPointsLabel, "Number of points to include in slope calculations (2-"; int(pCount/4);"):" if RefRLCLastNumPoints>=2 and RefRLCLastNumPoints<=pCount then defPoints=RefRLCLastNumPoints else defPoints=max(2,int(pCount/60)*2+1) 'approx pCount/30, but an odd number end if #RLC.incFreq, "!hide" : #RLC.decFreq, "!hide" #RLC.nPoints, defPoints 'If we have markers, identify two of them and default to the two-frequency method mCount=0 'start with 0 markers found. Then look for markers with positive point numbers mPt1=0 : mPt2=0 : m1$="" : m2$="" 'marker point numbers and IDs m$="P+" : mOrd=mMarkerNum(m$) : mPt=gMarkerPointNum(mOrd) 'start with P+ if mPt>0 then mCount=1 : m1$=m$ : mPt1=mPt 'save point num of P+ else 'No P+; look for P- m$="P-" : mOrd=mMarkerNum(m$) : mPt=gMarkerPointNum(mOrd) if mPt>0 then mCount=1 : m1$=m$ : mPt1=mPt 'save point num of P- if it exists and P+ did not end if mList$="LR123456" 'search in this order for i=1 to 8 'check for other markers until we have two m$=Mid$(mList$,i,1) : mOrd=mMarkerNum(m$) : mPt=gMarkerPointNum(mOrd) if mPt>0 then if mCount=0 then m1$=m$ : mPt1=mPt else m2$=m$ : mPt2=mPt mCount=mCount+1 : if mCount>=2 then exit for 'Done once we find two. end if next i if mCount=2 then 'Make marker 1 the one with with S11 angle nearest 0 or 180 a1=abs(ReflectArray(int(mPt1-0.5), constGraphS11Ang)) 'abs val of S11 angle at point 1 (point is rounded off for simplicity) a2=abs(ReflectArray(int(mPt2-0.5), constGraphS11Ang)) 'abs val of S11 angle at point 2 (point is rounded off for simplicity) d1=min(a1, abs(a1-180)) : d2=min(a2, abs(a2-180)) 'minimum angle distance to horizontal if d1>d2 then sPt=mPt2 : sID$=m2$ : mPt2=mPt1 : m2$=m1$ : mPt1=sPt : m1$=sID$ 'swap points 1 and two smallestAngToResonance=min(d1, d2) gosub [RefRLCChooseTwoFreq] 'start with Two Freq method if we have 2 markers else #RLC.twoFreq, "disable" 'disable two freq method if not two markers gosub [RefRLCChooseSlope] end if if RefRLCLastConnect$="Series" or RefRLCLastConnect$=""then goto [RefRLCSeriesRLC] goto [RefRLCParallelRLC] 'If the user double clicks on the menu when invoking this routine, the second click can be 'interpreted by LB as a click on the graph, so it will call [LeftButDown]. But it doesn't do 'so until it gets into this routine, at which point the real [LeftButDown] is hidden. So 'we provide one here that just exits. [LeftButDown] goto [RefRLCCancel] [RefRLCCancel] close #RLC exit sub [RefRLCSeriesRLC] #RLC.seriesRLC, "set" : #RLC.parallelRLC, "reset" #RLC.nPoints, defPoints : #RLC.nPoints, "!enable" gosub [RefRLCFindResonance] wait [RefRLCParallelRLC] #RLC.seriesRLC, "reset" : #RLC.parallelRLC, "set" #RLC.nPoints, defPoints : #RLC.nPoints, "!enable" gosub [RefRLCFindResonance] wait [RefRLCSlope] gosub [RefRLCChooseSlope]:wait [RefRLCTwoFreq] gosub [RefRLCChooseTwoFreq]:wait [RefRLCChooseSlope] #RLC.slope, "set" : #RLC.twoFreq, "reset" #RLC.nPointsLabel, "!show" : #RLC.nPoints, "!show" return [RefRLCChooseTwoFreq] #RLC.slope, "reset" : #RLC.twoFreq, "set" #RLC.nPointsLabel, "!hide" : #RLC.nPoints, "!hide" return [RefRLCFindResonance] #RLC.seriesRLC, "value? seriesVal$" #RLC.parallelRLC, "value? parallelVal$" if seriesVal$="set" then RefRLCLastConnect$="Series" else RefRLCLastConnect$="Parallel" 'Find where reactance or susceptance crosses zero in positive direction lowStep=-1 : highStep=-1 lastVal=0 'ver115-4b for i=0 to pCount-1 v=ReflectArray(i, constSerReact) if seriesVal$="reset" then 'Parallel; get susceptance R=ReflectArray(i, constSerR) call cxInvert R, v, G, S 'convert to admittance v=S end if if i=0 then lastVal=v else if lastVal<0 and v>=0 then lowStep=i-1 : highStep=i : exit for 'found crossing ver115-4b end if next i if highStep<1 then resonStep=-1 'We don't have the resonant frequency analysisPoint=int(gPointCount()/2) else lowVal=ReflectArray(lowStep, constSerReact) highVal=ReflectArray(highStep, constSerReact) if highVal=lowVal then fract=0 else fract=abs(lowVal)/(highVal-lowVal) 'interpolation fraction to get to zero. Numerator is 0-lowVal ver115-4b resonStep=lowStep+fract analysisPoint=int(resonStep+0.5)+1 'Display analysis at point closest to resonant frequency end if return [incFreq] if analysisPointint(nPoints/2) then analysisPoint=analysisPoint-1 goto [RefRLCCalcAndDisplayPointValues] [RefRLCCalcAndDisplayPointValues] 'Get values for slope method; subtract 1 to get analysis step from analysis point if RefRLCLastConnect$="Series" then R=ReflectArray(analysisPoint-1,constSerR) _ else R=ReflectArray(analysisPoint-1,constParR) L=auxGraphData(analysisPoint-1, 0) : C=auxGraphData(analysisPoint-1, 1) Qu=auxGraphData(analysisPoint-1, 2) f$="F=";str$(ReflectArray(analysisPoint-1,0));" MHz; " 'freq if Qu<10 then Qu$="; Qu=";using("#.###", Qu) else Qu$="; Qu=";uFormatted$(Qu, "3,3,4//UseMultiplier") [RefRLCDisplayPointValues] 'Common to both methods RLab$="Rs=" : LLab$="Ls=" : CLab$="Cs=" 'Assume series 'ver115-5d if RefRLCLastConnect$="Parallel" then RLab$="Rp=" : LLab$="Lp=" : CLab$="Cp=" form$="3,3,4//UseMultiplier//DoCompact" 'Max 3 whole dig, max 3 dec dig, max 4 total sig dig. resForm$="3,3,4//UseMultiplier//SuppressMilli//DoCompact" 'ver115-4e if R<1 then R$=using("#.####", R);" " else R$=uFormatted$(R, resForm$) 'ver115-4e L$=uFormatted$(L,form$) C$=uFormatted$(C,form$) print #RLC.results, f$;RLab$;R$;"; ";LLab$;L$;"H; ";CLab$;C$;"F";Qu$;serR$ 'ver116-4h wait [RefRLCAnalyze] #RLC.slope, "value? slope$" serR$="" if slope$="set" then 'ver116-4h added the two-frequency method #RLC.nPoints, "!contents? nPoints$" nPoints=val(nPoints$) if nPoints<2 or nPoints>pCount/4 then nPoints=defPoints : #RLC.nPoints, nPoints notice "Invalid number of points. ";defPoints;" used." end if RefRLCLastNumPoints=nPoints 'save for next time we enter this dialog if nPoints=2 then nLeft=0 : nRight=1 else nLeft=int(nPoints/3) : nRight=nPoints-nLeft-1 'skew points to right of "center" end if call ClearAuxData 'Clear auxiliary graph data by blanking graph names call gGetMinMaxPointNum pMin, pMax if RefRLCLastConnect$="Series" then dataType1=constSerReact : dataType2=constSerR else dataType1=constSusceptance : dataType2=constConductance end if call uBestFitLines dataType1, dataType2, nPoints,pMin-1, pMax-1 'Assemble data and slopes call DetermineLCEquiv RefRLCLastConnect$,pMin-1, pMax-1,resonStep call ChangeGraphsToAuxData constAux0, constAux1 'Graph L and C 'Display values #RLC.incFreq, "!show" : #RLC.decFreq, "!show" 'Enable frequency change goto [RefRLCCalcAndDisplayPointValues] else 'use two-frequency method freq1=gGetPointXVal(mPt1) 'get frequencies at the two marker points freq2=gGetPointXVal(mPt2) call CalcGraphDataType mPt1-1, constSerR, constSerReact, R1, X1, 0 'get marker R and X call CalcGraphDataType mPt2-1, constSerR, constSerReact, R2, X2, 0 if RefRLCLastConnect$="Series" then call uSeriesRLCFromPoints R1, X1, freq1, R2, X2, freq2, R, L, C else call uParallelRLCFromPoints R1, X1, freq1, R2, X2, freq2, R, L, C end if f$="Markers ";m1$;" and ";m2$;": " 'display marker IDs rather than frequencies for two-point method #RLC.incFreq, "!hide" : #RLC.decFreq, "!hide" 'disable frequency change Qu$="" if smallestAngToResonance<=30 then 'We calculate Qu at freq1, which is the closest to resonance, but only if its angle from resonance is not large LReact=2*uPi()*L*1000000*freq1 if RefRLCLastConnect$="Series" then if R=0 then Qu=99999 else Qu=LReact/R 'Qu for series else if LReact=0 then Qu=99999 else Qu=R/LReact if Qu=0 then serR=1e9 else serR=LReact/Qu 'Equivalent series R. Works near resonance if comboSerR<1 then serR$=using("#.###", serR) else serR$=uFormatted$(serR, "3,3,4//UseMultiplier") serR$="; (Rs=";serR$;")" end if if Qu<10 then Qu$="; Qu=";using("#.###", Qu) else Qu$="; Qu=";uFormatted$(Qu, "3,3,4//UseMultiplier") end if goto [RefRLCDisplayPointValues] end if wait 'Analyze is done end sub sub RefRLCHelp h$ WindowWidth = 550 WindowHeight = 400 call GetDialogPlacement BackgroundColor$="gray" ForegroundColor$="black" s$="RLC analysis done in Reflection mode will use impedance information to model the response as a combination of" s$=s$;" a resistor, inductor and capacitor. The simplest equivalent circuits use either an L or value to model the" s$=s$;" reactance at each frequency, but here we use both an L and a C value to model not only the reactance, but its change over" s$=s$;" frequency. An RLC circuit has varying reactance over frequency, but has constant L and C values. This analysis" s$=s$;" will determine those values. The components may be specified in series or in parallel." statictext #RLCExplain, s$, 10, 10, 515, 115 s$="The analysis will be most accurate in the general area of resonance. If you choose the two-frequency" s$=s$;" method, you must already have placed markers at two frequencies. Typically, you would place the P+ marker" s$=s$;" at a peak or the P- marker at a notch, and a second marker near a point where phase transistions from rapid" s$=s$;" to slow change." statictext #RLCExplain, s$, 10, 135, 515, 70 s$=" If you use the slope method, the calculation will be done at all frequencies using your specified number of" s$=s$;" points to calculate the slope of reactance or susceptance at each frequency, graphs will be created with the" s$=s$;" results, and the results for one frequency will" s$=s$;" be displayed in the dialog. You can change the display frequency with the +Freq and -Freq buttons. Note that slope" s$=s$;" calculations will be much less accurate at the edges of the scan, or in areas where slope changes rapidly." s$=s$;" Using a large number of points to calculate slope makes the results less susceptible to noise, but is not" s$=s$;" advisable where the slope changes rapidly. Typically the slope is fairly constant near resonance." statictext #RLCExplain, s$, 10, 215, 515, 130 open "RLC Analysis Help" for dialog_modal as #RLCExplain print #RLCExplain, "font ms_sans_serif 10" print #RLCExplain, "trapclose [RefRLCExplainEnd]" wait [RefRLCExplainEnd] close #RLCExplain exit sub end sub 'end RefRLCHelp 'ver116-4h deleted LossyImpedToParallelLC sub ImpedToRLC connect$,centerStep, nLeft,nRight, resonStep, byref R, byref L, byref C 'Determine RLC values from ReflectArray data 'If connect$="Series" then we have series RLC; otherwise parallel. 'We analyse the slope of reactance or susceptance to determine L and C. 'Slope is determined by best fit line of nPoints points centered at centerStep (0...) 'and including nLeft points to the left and nRight points to the right. 'if resonStep>0 then it is the step (perhaps not integral) of the resonant frequency 'SERIES: 'If the impedance is R+jX, then series R=R, and the 'L and C combine to produce a reactance of X. We determine L and C by looking at the change in X 'with respect to frequency : dX/dw, where w=2*pi*freq. 'X=wL-1/wC 'D=dX/dw=L+1/(C*w^2) 'Once we know X and D, we determine L and C as follows: 'If we know the resonant frequency (W), ' C=1/(DW^2) + 1/(Dw^2) If w (freq where we know slope) equals W, then C=2/(DW^2) ' L=1/(CW^2) 'If we don't know the resonant frequency, ' C=2/(w(wD-X)) ' L=(X+1/(wC))/w 'PARALLEL: We look at susceptance S=-X/(R^2+X^2) instead of reactance. D is then the slope of 'susceptance, and the formulas for C and L are: 'L=2/(w(wD-S)) 'C=(Y+1/(wL))/w 'If we know the resonant frequency (W), ' L=1/(DW^2) + 1/(Dw^2) If w (freq where we know slope) equals W, then C=2/(DW^2) ' C=1/(LW^2) 'If we don't know the resonant frequency, ' L=2/(w(wD-S)) ' C=(S+1/(wL))/w twoPiMillion=2*uPi()*1000000 sumX=0 : sumY=0 : sumXY=0 : sumXSquared=0 : sumR=0 if nLeft<0 then nLeft=0 if nRight<0 then nRight=0 if nLeft=0 and nRight=0 then nRight=1 startStep=centerStep-nLeft : endStep=centerStep+nRight if startStep<0 or endStep>gPointCount()+1 then _ notice "Invalid point specifications for RLC analysis" : R=0 : L=0 : C=0 : exit sub nPoints=nLeft+nRight+1 for i=startStep to endStep x=ReflectArray(i, 0) y=ReflectArray(i,constSerReact) 'Reactance if connect$<>"Series" then R=ReflectArray(i,constSerR) 'Series resistance call cxInvert R, y, G, S 'invert impedance to get admittance y=S end if sumX=sumX+x : sumY=sumY+y sumXY=sumXY+x*y : sumXSquared=sumXSquared+x*x if i=centerStep then centerXorS=y 'save middle impedance or susceptance next i if connect$<>"Series" then R=ReflectArray(centerStep,constSerR) else R=ReflectArray(centerStep,constParR) m=(nPoints*sumXY-sumX*sumY)/(nPoints*sumXSquared-sumX*sumX) 'Slope of reactance or susceptance, ohms or siemens per million Hz w=twoPiMillion*ReflectArray(centerStep,0) 'frequency, radians/sec if w<=0 then notice "Frequency error in ImpedToRLC" : R=constMaxValue :L=constMaxValue : C=constMaxValue : exit sub D=m/twoPiMillion 'To get slope in ohms/(rad/sec) if resonStep>0 then 'we know the resonant frequency Wres=twoPiMillion*gGetPointXVal(resonStep+1) if connect$="Series" then C=1/(D*Wres^2) + 1/(D*w^2) L=1/(C*Wres^2) else L=1/(D*Wres^2) + 1/(D*w^2) C=1/(L*Wres^2) end if else 'Don't know resonance. Use info about centerXorS instead. denom=w*(w*D-centerXorS) if connect$="Series" then if denom=0 then C=1 else C=2/denom L=(centerXorS+1/(w*C))/w else if denom=0 then L=1 else L=2/denom C=(centerXorS+1/(w*L))/w end if end if if C<0 then C=0 'min of zero, max of 1 if L<0 then L=0 if C>1 then C=1 if L>1 then L=1 end sub sub DetermineLCEquiv connect$,startStep, endStep, resonStep 'Determine equivalent LC values from uWorkArray(,) data 'If connect$="Series" then we have series RLC; otherwise parallel. 'uBestFitLines must already have been called to set up uWorkArray with the necessary values 'and slope for reactance (if series) or susceptance (if parallel). 'We analyse the slope of reactance or susceptance to determine L and C. 'We put L into auxGraphData(,0) and C into auxGraphData(,1), and unloaded Q into auxGraphData(,2) 'if resonStep>0 then it is the step (perhaps not integral) of the resonant frequency 'SERIES: 'If the impedance is R+jX, then series R=R, and the 'L and C combine to produce a reactance of X. We determine L and C by looking at the change in X 'with respect to frequency : dX/dw, where w=2*pi*freq. 'X=wL-1/wC 'D=dX/dw=L+1/(C*w^2) 'Once we know X and D, we determine L and C as follows: 'If we know the resonant frequency (W), ' C=1/(DW^2) + 1/(Dw^2) If w (freq where we know slope) equals W, then C=2/(DW^2) ' L=1/(CW^2) 'If we don't know the resonant frequency, ' C=2/(w(wD-X)) ' L=(X+1/(wC))/w 'PARALLEL: We look at susceptance S=-X/(R^2+X^2) instead of reactance. D is then the slope of 'susceptance, and the formulas for C and L are: 'S=wC-1/(wL) 'D=dS/dw=C+1/(L*w^2) 'If we know the resonant frequency (W), ' L=1/(DW^2) + 1/(Dw^2) If w (freq where we know slope) equals W, then L=2/(DW^2) ' C=1/(LW^2) 'If we don't know the resonant frequency, ' L=2/(w(wD-S)) ' C=(S+1/(wL))/w 'Make sure all frequencies are positive if ReflectArray(startStep,0)<=0 then notice "Frequencies must be positive for RLC analysis" 'Set R,L and C to large values for currStep=startStep to endStep auxGraphData(currStep,0)=constMaxValue : auxGraphData(currStep,1)=constMaxValue : auxGraphData(currStep,2)=constMaxValue next currStep exit sub end if twoPiMillion=2*uPi()*1000000 maxL=1e-9 : maxC=1e-12 : maxQ=1 'For determining graph axis range. These may change call gGetMinMaxPointNum pMin, pMax minStep=pMin-1 : maxStep=pMax-1 if resonStepmaxStep then resonStep=-1 'invalid so we don't know resonance if resonStep<0 then Wres=-1 else Wres=twoPiMillion*gGetPointXVal(resonStep+1) 'resonant freq in radians/sec ver115-4e if startStepmaxStep then endStep=maxStep for currStep=startStep to endStep m=uWorkArray(currStep,3) 'Slope of reactance or susceptance, ohms or siemens per million Hz w=twoPiMillion*ReflectArray(currStep,0) 'frequency, radians/sec D=m/twoPiMillion 'To get slope in ohms/(rad/sec) XorS=uWorkArray(currStep, 1) 'Reactance or susceptance if resonStep>0 then 'we know the resonant frequency. This implicitly assumes the L and C values are the same 'at this point and at resonance, which may not be a good idea. User can avoid this by 'not including resonant frequency in the scan. if connect$="Series" then C=1/(D*Wres^2) + 1/(D*w^2) L=1/(C*Wres^2) else L=1/(D*Wres^2) + 1/(D*w^2) C=1/(L*Wres^2) end if else 'Don't know resonance. Use info about reactance or susceptance instead. denom=w*(w*D-XorS) if connect$="Series" then if denom=0 then C=1 else C=2/denom L=(XorS+1/(w*C))/w else if denom=0 then L=1 else L=2/denom C=(XorS+1/(w*L))/w end if end if num=abs(XorS)+w*D 'ver115-4b if connect$="Series" then R=uWorkArray(currStep,2) 'resistance if R<0.00001 then Q=9999 else Q=num/(2*R) 'ver115-4b else G=uWorkArray(currStep,2) 'conductance if G<0.00001 then Q=9999 else Q=num/(2*G) 'ver115-4b end if if C<0 then C=0 'min of zero, max of 1 if L<0 then L=0 if C>1 then C=1 if L>1 then L=1 if Q<0 then Q=-1 if Q>1e6 then Q=1e6 if L>maxL and L<1 then maxL=L if C>maxC and C<1 then maxC=C if Q>maxQ and Q<1000 then maxQ=Q auxGraphData(currStep,0)=L 'inductance auxGraphData(currStep,1)=C 'capacitance auxGraphData(currStep,2)=Q 'Qu next currStep 'We must now describe the data in auxGraphData for the graphing routines LCForm$="3,3,4//UseMultiplier" if connect$="Series" then s1$="Series" : s2$="Ser" else s1$="Parallel" : s2$="Par" end if auxGraphDataFormatInfo$(0,0)="LC-";s1$;" L" : auxGraphDataFormatInfo$(0,1)=LCForm$ 'Inductance graph auxGraphDataFormatInfo$(0,2)="LC-";s1$;" L": auxGraphDataFormatInfo$(0,3)="LC-";s2$;" L" auxGraphDataInfo(0,0)=0 'not an angle auxGraphDataInfo(0,1)=0 'axis min auxGraphDataInfo(0,2)=uRoundUpToPower(maxL,10) 'axis max is power of 10 auxGraphDataFormatInfo$(1,0)="LC-";s1$;" C" : auxGraphDataFormatInfo$(1,1)=LCForm$ 'Capacitance graph auxGraphDataFormatInfo$(1,2)="LC-";s1$;" C": auxGraphDataFormatInfo$(1,3)="LC-";s2$;" C" auxGraphDataInfo(1,0)=0 'not an angle auxGraphDataInfo(1,1)=0 'axis min auxGraphDataInfo(1,2)=uRoundUpToPower(maxC,10) 'axis max is power of 10 QForm$="3,2,3//UseMultiplier//SuppressMilli" 'ver115-4e auxGraphDataFormatInfo$(2,0)=s1$;" Q" : auxGraphDataFormatInfo$(2,1)=QForm$ 'Q graph auxGraphDataFormatInfo$(2,2)=s1$;" Q" : auxGraphDataFormatInfo$(2,3)=s2$;" Q" auxGraphDataInfo(2,0)=0 'not an angle auxGraphDataInfo(2,1)=0 'axis min if maxQ<=9 then maxQ=10 else if maxQ<=25 then maxQ=30 else maxQ=100 auxGraphDataInfo(2,2)=maxQ end sub [menuQ] 'Menu for Q factors was selected if haltsweep=1 then gosub [FinishSweeping] call AnalyzeQ call ChangeGraphsToAuxData constAux0, constAux1 'graph series Q and parallel Q wait sub ChangeGraphsToAuxData aux1, aux2 'Change to specified graph types, which may be constNoGraph 'This is used primarily to graph one or two auxiliary graphs created by a Function. The parameters for 'auxiliary graphs are in auxGraphDataInfo 'aux1 and aux2 are constants for aux data (constAux0...) or constNoGraph or other graph data constant 'ver115-8b changed this to allow non-auxiliary data if aux1>=constAux0 and aux1<=constAux5 then auxIndex1=aux1-constAux0 'produces 0 for constAux0, 1 for constAux1, etc. axis1Min=auxGraphDataInfo(auxIndex1,1) : axis1Max=auxGraphDataInfo(auxIndex1,2) 'function determined these else 'Get default axis limits for non-auxiliary data call StartingLimits aux1, constNoGraph, axis1Min, axis1Max end if if aux2>=constAux0 and aux2<=constAux5 then auxIndex2=aux2-constAux0 axis2Min=auxGraphDataInfo(auxIndex2,1) : axis2Max=auxGraphDataInfo(auxIndex2,2) else 'Get default axis limits for non-auxiliary data call StartingLimits aux2, constNoGraph, axis2Min, axis2Max end if if aux1=constNoGraph and aux2=constNoGraph then exit sub 'Don't do anything if both are none--error condition Y1DataType=aux1 'set Y1 graph data Y2DataType=aux2 'set Y2 graph data if aux1<>constNoGraph then call SetY1Range axis1Min, axis1Max 'Y1 min and max if aux2<>constNoGraph then call SetY2Range axis2Min, axis2Max 'Y2 min and max call UpdateGraphDataFormat 0 'To get new data format call gCalcGraphParams 'Calculate new scaling. call RecalcYValues call RedrawGraph 0 'Draw the new graphs end sub sub AnalyzeQ 'Open dialog to handle Q factor analysis WindowWidth = 600 WindowHeight = 350 call GetDialogPlacement BackgroundColor$="gray" ForegroundColor$="black" TextboxColor$ = "white" statictext #analyzeQ.title, "DETERMINATION OF Q FACTORS",70, 10, 375, 20 s$="This module determines the apparent Q, series Q and parallel Q for each step of the" s$=s$;" existing scan." s$=s$;" This involves analysis of the specified number of points around the target point." statictext #analyzeQ.title1, s$,20, 30, 550, 60 controlTop=75 s$="Apparent Q is the traditional abs(X)/R, and is meaningful only if the tested device" s$=s$;" has a single L or C component (including parasitics), but not both." statictext #analyzeQ, s$,20, controlTop, 550,35 s$="Series Q and Parallel Q are Q values that will exist if the device is brought" s$=s$;" to resonance at a given frequency by combining it with an appropriate capacitor" s$=s$;" or inductor, in series for Series Q and in parallel for Parallel Q." statictext #analyzeQ, s$, 20, controlTop+40, 550,60 s$="These Q factors will be calculated and may then be graphed. They will survive until the next Restart." statictext #analyzeQ, s$, 20, controlTop+100, 550,35 textbox #analyzeQ.nPoints, 310, controlTop+150, 50, 20 statictext #analyzeQ.nPointsLabel, "Number of points to include:", 60, controlTop+152, 225, 20 button #analyzeQ.Analyze, "Analyze", [analyzeQAnalyze], UL,250,controlTop+200, 100, 25 'Open dialog open "Q Analysis" for dialog_modal as #analyzeQ #analyzeQ, "trapclose [analyzeQDone]" #analyzeQ, "font ms_sans_serif 10" pCount=gPointCount() if pCount<2 then notice "Not enough points for analysis." : goto [analyzeQDone] #analyzeQ.nPointsLabel, "Number of points to include (2-"; int(pCount/4);"):" if analyzeQLastNumPoints>=2 and analyzeQLastNumPoints<=pCount then defPoints=analyzeQLastNumPoints else defPoints=max(2,int(pCount/80)*2+1) 'approx pCount/40, but an odd number end if #analyzeQ.nPoints, defPoints wait [analyzeQDone] close #analyzeQ exit sub [analyzeQAnalyze] #analyzeQ.Analyze, "!disable" 'prevent it being pushed while we are processing. #analyzeQ.nPoints, "!contents? nPoints$" nPoints=val(nPoints$) if nPoints<2 or nPoints>pCount/4 then nPoints=defPoints : #analyzeQ.nPoints, nPoints notice "Invalid number of points. ";defPoints;" used." end if analyzeQLastNumPoints=nPoints 'save for next time we enter this dialog call ClearAuxData 'Clear auxiliary graph data by blanking graph names call QFactors nPoints 'Put Q data into auxGraphData(0...,) goto [analyzeQDone] end sub sub QFactors nPoints 'Calculate Q factors for each frequency. Put results in auxGraphData(,) 'Slopes will be calculated with best fit to nPoints 'We put results into auxGraphData(0...,): seriesQ(,0) and parallelQ(,1) call gGetMinMaxPointNum pMin, pMax startStep=pMin-1 : endStep=pMax-1 'Calculate reactance slopes call uBestFitLines constSerReact, constSerR,nPoints, startStep, endStep for i=startStep to endStep : print i;" ";uWorkArray(i,3);" ";uWorkArray(i,4) : next i 'DEBUG 'Calculate series Q and parallel Q put results into auxGraphData(,0) and auxGraphData(,1) 'uWorkArray(,) contains frequency (,0), reactance (,1), resistance (,2), 'reactance slope (,3) and reactance intercept (,4) twoPiMillion=2000000*uPi() maxSerQ=1 : maxParQ=1 for i=startStep to endStep 'For each step calculate apparentQ and seriesQ. w=twoPiMillion*uWorkArray(i,0) absX=abs(uWorkArray(i,1)) Rs=uWorkArray(i,2) dX=uWorkArray(i,3)/twoPiMillion 'current slope is based on million Hz; we want rads/sec if Rs=0 then Q=99999 else Q=(absX+w*dX)/(2*Rs) auxGraphData(i,0)=Q 'series Q if Q>maxSerQ then maxSerQ=Q next i 'Calculate susceptance slopes call uBestFitLines constSusceptance, constConductance, nPoints, startStep, endStep 'Calculate parallel Q 'uWorkArray(,) contains frequency (,0), susceptance (,1), conductance (,2), 'susceptance slope (,3) and susceptance intercept (,4) for i=startStep to endStep 'For each step calculate parallel Q w=twoPiMillion*uWorkArray(i,0) absS=abs(uWorkArray(i,1)) G=uWorkArray(i,2) dS=uWorkArray(i,3)/twoPiMillion 'current slope is based on million Hz; we want rads/sec if G=0 then Q=99999 else Q=(absS+w*dS)/(2*G) auxGraphData(i,1)=Q 'parallel Q if Q>maxParQ then maxParQ=Q next i 'We must now describe the data in auxGraphData for the graphing routines QForm$="3,2,3//UseMultiplier//SuppressMilli" 'ver115-4e auxGraphDataFormatInfo$(0,0)="Series Q" : auxGraphDataFormatInfo$(0,1)=QForm$ auxGraphDataFormatInfo$(0,2)="Series Q" : auxGraphDataFormatInfo$(0,3)="Ser Q" auxGraphDataInfo(0,0)=0 'not an angle auxGraphDataInfo(0,1)=0 'axis min if maxSerQ<=9 then maxSerQ=10 else if maxSerQ<=25 then maxSerQ=30 else maxSerQ=100 auxGraphDataInfo(0,2)=maxSerQ auxGraphDataFormatInfo$(1,0)="Parallel Q" : auxGraphDataFormatInfo$(1,1)=QForm$ auxGraphDataFormatInfo$(1,2)="Parallel Q" : auxGraphDataFormatInfo$(1,3)="Par Q" auxGraphDataInfo(1,0)=0 auxGraphDataInfo(1,1)=0 if maxParQ<=9 then maxParQ=10 else if maxParQ<=25 then maxParQ=30 else maxParQ=100 auxGraphDataInfo(1,2)=maxParQ end sub [menuSaveDataFile] 'ver115-5f if haltsweep=1 then gosub [FinishSweeping] filter$="All files" + chr$(0) + "*.*" + chr$(0) + _ "Parameter files" + chr$(0) + "*.s1p" + chr$(0) + _ "Text files" + chr$(0) + "*.txt" 'ver115-6b defaultExt$="s1p" initialDir$=touchLastFolder$+"\" initialFile$="" dataFileName$=uSaveFileDialog$(filter$, defaultExt$, initialDir$, initialFile$, "Save Data To File") if dataFileName$="" then wait 'blank means cancelled call SaveDataFile dataFileName$, 0 'Save data without preferences wait sub SaveDataFile dataFileName$, doContexts 'Save current data in file dataFileName$ 'if doContexts=1, also save the contexts flagged in contextTypes 'RestoreVNAData will be used to re-load data. It assumes VNA data is ready to go directly to 'ReflectArray or S21DataArray, without certain adjustments such as plane extension and OSL calibration. '(of course, the calibration data may not even be available when the file is loaded.) Therefore, 'in VNA modes we save the data from ReflectArray or S21DataArray, not from datatable. call uParsePath dataFileName$, touchLastFolder$, dum$ 'Save folder we are using if doContexts=0 then 'flags indicate what to save for i=0 to 30 : contextTypes(i)=0 : next i end if ' contextTypes(constGrid)=1 'DEBUG--caller should set context flags if desired ' contextTypes(constTrace)=1 ' contextTypes(constSweep)=1 contextTypes(constModeData)=1 'Indicate to save data along with whatever else is to be saved errMsg$=SaveContextFile$(dataFileName$) if errMsg$<>"" then notice errMsg$ end sub [RestoreVNAData] 'Load data for current msaMode$ from VNAData(), which holds steps+1 points 'added by ver116-1b 'Note that VNAData may actually hold data from SA mode 'We generate only those context changes necessary to accomodate the data 'Note caller must restore title, preferably before calling us 'Note caller must change msaMode$ via [ChangeMode] if necessary to suit the data 'Caller should redim VNAData to a small size when done with it. 'Caller must deal with whether plane extension must be forced to zero, and how to set the various 'jig and graph R0 values, based on whether we know how the data was gathered. If we don't, plane 'extension should be zeroed and S21JigR0 and S11BridgeR0 should be set to the VNADataZ0. ver116-4j 'If user saved the pre-R0-conversion-and-plane-extension, then VNARestoreDoR0AndPlaneExt should be set to 1 'so we apply R0 conversion and plane extension here. ver116-4j 'See if sweep settings need to be changed. We use the same touchxxx variables used when reading touchstone files. touchStartFreq=VNAData(0, 0) : touchEndFreq=VNAData(VNADataNumSteps, 0) 'Start and Stop freq of data touchIsLinear=VNADataLinear 'ver116-4a 'If settings need to be changed, then do so 'touchIsLinear, touchStartFreq and touchEndFreq are local if startfreq <>touchStartFreq or endfreq<>touchEndFreq or _ gGetXIsLinear()<>touchIsLinear or globalSteps<> uWorkNumPoints-1 then 'If freq range or sweep type changed, we need to adjust to it. steps=VNADataNumSteps : globalSteps=steps call gSetNumDynamicSteps globalSteps call SetStartStopFreq touchStartFreq, touchEndFreq call gSetXIsLinear touchIsLinear 'We will do PartialRestart below which will further implement these changes end if 'The data is now in VNAData(0,x) to VNAData(steps, x) 'We need to put it where it belongs, based on the mode we are in 'Note we do not verify that the file data matches our mode. for stepNum=0 to steps thisfreq=VNAData(stepNum, 0) 'freq datatable(stepNum,1)=thisfreq datatable(stepNum,2)=VNAData(stepNum, 1) 'dB or dBm if msaMode$="SA" or msaMode$="ScalarTrans" then datatable(stepNum,3)=0 else ang=VNAData(stepNum, 2) 'angle while ang>180 : ang=ang-360 : wend 'In case data range of angle was unusual while ang<=-180 : ang=ang+360 : wend datatable(stepNum,3)=ang 'angle end if next stepNum 'Data is now in datatable, but we have to generate the graph, which also puts the data 'into the graph module and into S21DataArray or ReflectArray if necessary. for i=1 to 4 'Set title; only 3 lines print call gSetTitleLine i, VNADataTitle$(i) next i call SignalNoCalInstalled 'To get valid cal installed, if applicable ver116-4b 'Do Restart with a flag to return before taking any data suppressHardwareInitOnRestart=1 'no need for hardware init ver116-4d gosub [PartialRestart] 'We must now recreate the graph. We proceed as though we just gathered the data 'point by point for thisstep=sweepStartStep to sweepEndStep step sweepDir 'Plot this point the same as though we just gathered it. if msaMode$<>"SA" then gosub [TransferToDataArrays] 'Enter data into S21DataArray or ReflectArray if VNARestoreDoR0AndPlaneExt then 'If user so specified, perform R0 conversion and plane extension if msaMode$="VectorTrans" or msaMode$="ScalarTrans" then if planeadj<>0 then phaseToExtend=S21DataArray(thisstep,2) 'ver116-4s call uExtendCalPlane thisfreq, phaseToAdj, planeadj,0 'Do plane adjustment ver116-1b 'ver116-4s S21DataArray(thisstep,2)=phaseToExtend 'ver116-4s end if else 'ISSUE--If OSL was not used, we don't have the raw data from the series or shunt fixture, 'so we need to force the fixture to Bridge. Or do we. Does any routine other than ConvertRawData... access raw data? if msaMode$="Reflection" then if planeadj<>0 or S11BridgeR0<>S11GraphR0 then f=VNAData(thisstep,0) : db=VNAData(thisstep,1) : ang=VNAData(thisstep,2) call ApplyExtensionAndTransformR0 f, db, ang ReflectArray(thisstep,constGraphS11DB)=db 'Save final S11 in db, angle format (in Graph R0, after plane ext) while ang>180 : ang=ang-360 : wend while ang<=-180 : ang=ang+360 : wend ReflectArray(thisstep,constGraphS11Ang)=ang end if end if end if end if if msaMode$="Reflection" then call CalcReflectDerivedData thisstep 'ver116-4j gosub [PlotDataToScreen] next thisstep '[PlotDataToScreen] will have refreshed the graph at the final data point, unless 'refreshEachScan is turned off. We want to be sure a refresh gets done. if refreshEachScan=0 then call RefreshGraph 0 'Restart puts new time stamp in title, so put ours back in t3$=" ";VNADataTitle$(3);" " : if len(t3$)<35 then t3$=" ";t3$;" " call gSetTitleLine 3, t3$ 'Extra blanks for clearing in case size changed 'Reprint title without clearing; new data will cover old data 'The refresh routine will have used saved info for faster drawing, and so will 'have the time stamp from PartialRestart done in [LoadDataFromWorkArray], which we don't want. call gPrintTitle 0 #graphBox$, "flush" call gSetTitleLine 3,VNADataTitle$(3) 'Get rid of extra blanks return 'ver116-1b created [regraphDatatable] [regraphDatatable] 'Regraph datatable as we did when we collected it, applying OSL, plane adj and graphR0 transforms 'This is similar to the last part of [RestoreVNAData], but there we did not want OSL to be applied, because 'the data was assumed already to be calibration-adjusted. [regraphDatatable] makes sense only if we know all 'original calibration data is still intact, as we do when returning from the Two Port module call SignalNoCalInstalled 'To get valid cal installed, if applicable ver116-4j call uBringWindowToFront hwnd(#handle) 'bring graph to front saveTimeStamp$=gGetTitleLine$(3) suppressHardwareInitOnRestart=1 'no need for hardware init ver116-4d gosub [PartialRestart] 'We must now recreate the graph. We proceed as though we just gathered the data 'point by point for thisstep=sweepStartStep to sweepEndStep step sweepDir 'Plot this point the same as though we just gathered it. 'Apply planeadj and graph R0 transformed and put info into S21DataArray or ReflectArray if msaMode$<>"SA" then gosub [ProcessDataArrays] gosub [PlotDataToScreen] next thisstep '[PlotDataToScreen will have refreshed the graph at the final data point, unless 'refreshEachScan is turned off. We want to be sure a refresh gets done. if refreshEachScan=0 then call RefreshGraph 0 'Restart puts new time stamp in title, so put ours back in t3$=" ";saveTimeStamp$;" " : if len(t3$)<35 then t3$=" ";t3$;" " call gSetTitleLine 3, t3$ 'Extra blanks for clearing in case size changed 'Reprint title without clearing; new data will cover old data 'The refresh routine will have used saved info for faster drawing, and so will 'have the time stamp from PartialRestart done in [LoadDataFromWorkArray], which we don't want. call gPrintTitle 0 #graphBox$, "flush" call gSetTitleLine 3, saveTimeStamp$ 'Get rid of extra blanks return [menuLoadDataFile] 'ver115-5f if haltsweep=1 then gosub [FinishSweeping] filter$="Parameter files" + chr$(0) + "*.s1p" + chr$(0) + _ "Text files" + chr$(0) + "*.txt" + chr$(0) + _ "CSV files" + chr$(0) + "*.csv" + chr$(0) + _ "All files" + chr$(0) + "*.*" 'ver115-6b defaultExt$="s1p" initialDir$=touchLastFolder$+"\" initialFile$="" dataFileName$=uOpenFileDialog$(filter$, defaultExt$, initialDir$, initialFile$, "Open Data File") if dataFileName$="" then wait 'user cancelled dataHandle$=touchOpenInputFile$(dataFileName$) if dataHandle$="" then restoreErr$="File failed to open: ";dataFileName$ : wait call uParsePath dataFileName$, touchLastFolder$, dum$ 'Save folder from which file was loaded restoreFileName$=dataFileName$ : restoreFileHndl$=dataHandle$ gosub [LoadDataFileWithContext] call RequireRestart wait [LoadDataFileWithContext] 'Load data from restoreFileName$, which is already open as restoreFileHndl$. We close it when done 'Set restoreErr$ to error message or blank. 'The data may be preceded by preference info, so we read and react to that first ver115-8c cursor hourglass 'Want baseFrequency=0 unless explicitly changed by loading a context. baseFrequency=0 'ver116-4k call RememberState 'So we can see what changed 'ver115-8c gosub [LoadBasicContextsFromFile] 'Load preferences from restoreFileHndl$ if restoreErr$<>"" then notice "Error loading file: ";restoreErr$ : cursor normal: return contextLoaded=0 'will be set to 1 if any context was loaded above for i=0 to 30 if contextTypes(i)=1 then contextLoaded=1 : exit for next i if contextLoaded then gosub [DetectFullChanges] 'ver115-8c if continueCode=3 then gosub [PartialRestart] 'implement changes ver115-3c end if 'Now we proceed to the actual data. Note that the above will already have read the first line 'of the data section. If we created the data file, we would have made the first line StartContext Datatable. 'A file from an external source will likely start with a comment, or might start with actual data. In the latter case 'we need to start over at the beginning of the file, so as not to miss anything. If there is any context info 'at the start of the file, we know we created the file, so no need to back up. if contextLoaded=0 then 'No contexts were read; close and reopen the file close #restoreFileHndl$ restoreFileHndl$=touchOpenInputFile$(restoreFileName$) if restoreFileHndl$="" then restoreErr$="File failed to open: ";dataFileName$ : return end if call touchReadParams restoreFileHndl$,1 'Read data from file into uWorkArray close #restoreFileHndl$ if touchBadLine>0 then notice "File Error in Line ";touchBadLine : cursor normal : return 'touchReadParams sets touchBadLine if error if uWorkNumPoints<2 then notice "File must contain two or more points" : cursor normal : return 'If the file had more points than our arrays can handle, then resize them. 'Note this does not resize uWorkArray, which would erase its data. if uWorkNumPoints>=gMaxNumPoints() then call ResizeArrays uWorkNumPoints+10 'ver115-6b 'Note that we don't make the plane extension or R0 adjustments that [ProcessDataArrays] makes. If we 'have loaded the context with the data, we presume the data already is adjusted per the context. If we 'did not load the context, we will force plane ext and R0 to avoid need for adjustments. if contextLoaded=0 then planeadj=0 : S21JigR0=touchRef 'ver116-4j if msaMode$="Reflection" then S11BridgeR0=touchRef 'ver116-4j end if 'The data is now in uWorkArray(1,x) to uWorkArray(uWorkNumPoints, x) for i=1 to 4 'Get title from comments; line 4 is non-printing if i<=touchCommentCount then call gSetTitleLine i, touchComments$(i) else call gSetTitleLine i, "" next i 'The routine to restore data uses VNAData(), whereas we have loaded data to uWorkArry. Transfer it. VNADataNumSteps=uWorkNumPoints-1 redim VNAData(VNADataNumSteps,2) 'Make room for all steps for i=0 to VNADataNumSteps VNAData(i,0)=uWorkArray(i+1,0)/1000000 'freq (we store in MHz) VNAData(i,1)=uWorkArray(i+1,1) : VNAData(i,2)=uWorkArray(i+1,2) 'freq, dB and angle next i VNADataZ0=touchRef 'Determined from file 'ver116-4a VNADataLinear=1 'ver116-4a if VNADataNumSteps>2 and VNAData(0,0) then 'See if we have log spacing ver116-4a interFirst=VNAData(1,0)-VNAData(0,0) 'first frequency interval interLast=VNAData(VNADataNumSteps,0)-VNAData(VNADataNumSteps-1,0) if interFirst>0 then 'If the first and last interval differ by a significant percent of the first, 'we treat scan as log. Of course, for linear they really should be virtually identical. 'Note this could be confused by an imported log scan of very small range. We do not 'allow log scans with tiny ranges. if abs(interFirst-interLast)/interFirst>0.001 then VNADataLinear=0 end if end if 'set work array to minimum size. touchReadParams may have made it large call uSetMaxWorkPoints 0,3 'ver116-1b VNARestoreDoR0AndPlaneExt=0 : gosub [RestoreVNAData] 'load and graph the data ver116-4j 'Restart puts new time stamp in title, so put ours back in if touchCommentCount>2 then restartTimeStamp$=touchComments$(3) call gSetTitleLine 3, " ";restartTimeStamp$;" " 'Extra blanks for clearing in case size changed else call gSetTitleLine 3, "" end if 'Reprint title without clearing; new data will cover old data 'The refresh routine will have used saved info for faster drawing, and so will 'have the time stamp from PartialRestart done in [LoadDataFromWorkArray], which we don't want. call gPrintTitle 0 #graphBox$, "flush" redim VNAData(1,2) 'to save space VNADataNumSteps=1 cursor normal beep return '===================START CONTEXTS MODULE======================= '-------------Explanation of Contexts------------- ver114-2d 'A context file or string contains a series of lines (separated by chr$(13) in strings) containing 'information on one or more types of contexts. Data for a given type begins with the line ' "StartContext Name", where Name is the name of the context type. It ends with the end of the 'file or string, or with the line "EndContext". Routines that restore individual types do not necessarily expect 'the file or string to begin with the StartContext xxx line, which should have been processed by the caller. ' 'Some variables are stored both inside the graphing module and, under a different name, outside it. 'In those cases, only one version needs to be saved, but both versions need to be restored. '------------------------------------------------- 'ver114-2c added SweepContext$ function SweepContext$() 'Return sweep context as string 'successive lines are separated by chr$(13) newLine$=chr$(13) aSpace$=" " 'First include variables used outside the graph module s1$= "Version=B" 'This item was added in ver114-7n and changed to B in ver115-1b s1$= s1$;newLine$;"msaMode=";msaMode$ 'ver114-6f ver115-1b s1$= s1$;newLine$;"FreqMode=";freqBand 'ver115-1c ver116-4s s1$= s1$;newLine$;"BaseFreq=";baseFrequency 'ver116-4k s1$= s1$;newLine$;"SpecialGraph=";doSpecialGraph s1$=s1$;newLine$; "RLCSpec=";doSpecialRLCSpec$;";;";doSpecialCoaxName$ 'ver115-4b if useAutoWait then s1$=s1$;newLine$;"Wait=";autoWaitPrecision$ else s1$= s1$;newLine$;"Wait=";wate s1$= s1$;newLine$;"PlaneAdj=";planeadj s1$= s1$;newLine$;"Path=";Word$(path$,2) 'path$ is in form "Path N" s1$= s1$;newLine$;"SGPreset=";sgout 'ver114-4h s1$= s1$;newLine$;"Offset=";offset s1$= s1$;newLine$;"IsTG=";gentrk 'ver114-4i s1$= s1$;newLine$;"NormRev=";normrev 'ver114-4k s1$= s1$;newLine$;"VideoFilter=";videoFilter$ 'ver114-5p s1$= s1$;newLine$;"DUTDirection=";switchFR 'ver116-4d s1$= s1$;newLine$;"GraphData=";Y1DataType;aSpace$; Y2DataType 'ver115-1b deleted source constants s1$= s1$;newLine$;"Autoscale=";autoScaleY1; aSpace$; autoScaleY2 'ver114-7e s1$= s1$;newLine$;"S21Jig=";S21JigAttach$;aSpace$; S21JigR0;aSpace$;S21JigShuntDelay 'modver115-1e s1$= s1$;newLine$;"S11Bridge=";S11BridgeR0; aSpace$; S11GraphR0; aSpace$; S11JigType$ SweepContext$=s1$;newLine$;gSweepContext$() 'Add items from graph module end function [RestoreSweepContext] 'public routine to restore sweep context 'There are a couple of things we can't do within a true subroutine, so we use this routine as a wrapper 'Because this gosub routine cannot accept arguments, the following values (non-global) must be preset: ' restoreContext$ is the string containing the context ' restoreIsValidation=1 to do just validation run (i.e. don't change data); 0 otherwise 'If there is an error, and error message is placed in restoreErr$; otherwise it is made blank 'Note the StartContext line must already have been skipped. 'Caller must call RememberState before coming here and [DetectFullChanges] on return 'Get next line and increment startPos to start of the following line startPos=1 tLine$=uGetLine$(restoreContext$, startPos) oldStartPos=startPos contextVersion$="A" while tLine$<>"" origLine$=tLine$ 'ver115-1b if Upper$(Left$(tLine$,10))="ENDCONTEXT" then exit while isErr=0 equalPos=instr(tLine$,"=") 'equal sign marks end of tag if equalPos=0 then isErr=1 : exit while else tag$=Upper$(Left$(tLine$, equalPos-1)) 'tag is stuff before equal sign tLine$=Trim$(Mid$(tLine$, equalPos+1)) 'contents is stuff after equal sign end if v1=val(tLine$) 'Most of our data is numeric values select case tag$ 'Each tag represents one or several data items. These are retrieved one at a time, 'and as each is retrieved it is deleted from tLine$. Numeric items are delimited 'by spaces, tabs or commas. Text items are delimited by the double character 'contained in sep$, because they may contain spaces or commas. If this is just 'a validation run, we do not enter any of the retrieved data into our variables. 'ver114-2d cleaned up and added VNA case "VERSION" 'added by ver114-7n and ver115-1b contextVersion$=Trim$(tLine$) case "MSAMODE" 'if restoreIsValidation=0 and tLine$<>msaMode$ then changeModeTo$=tLine$ : gosub [ChangeMode] 'ver114-6f if restoreIsValidation=0 then msaMode$=tLine$ case "BASEFREQ" 'ver116-4k if restoreIsValidation=0 then baseFrequency=v1 case "FREQMODE" 'ver115-1c if restoreIsValidation=0 then freqBand=v1 'ver116-4s case "SPECIALGRAPH" if restoreIsValidation=0 then doSpecialGraph=v1 case "RLCSPEC" 'ver115-4b if restoreIsValidation=0 then doSpecialRLCSpec$=uExtractTextItem$(tLine$,";;") doSpecialCoaxName$=tLine$ end if case "WAIT" if restoreIsValidation=0 then 'ver116-1b select case tLine$ case "Fast", "Normal", "Precise" useAutoWait=1 : autoWaitPrecision$=tLine$ case else useAutoWait=0 : wate=v1 end select end if case "PLANEADJ" if restoreIsValidation=0 then planeadj=v1 case "PATH" isErr=(v1<=0 or v1>MSANumFilters) if isErr=0 and restoreIsValidation=0 then path$="Path ";v1 case "SGPRESET" if restoreIsValidation=0 then sgout=v1 'ver114-4h case "OFFSET" if restoreIsValidation=0 then offset=v1 case "ISTG" 'ver114-4i if restoreIsValidation=0 then if TGtop>0 then gentrk=v1 else gentrk=0 'Set gentrk only if we have the TG ver115-4f end if case "NORMREV" 'ver114-4i if restoreIsValidation=0 then normrev=v1 case "VIDEOFILTER" 'ver114-5p if restoreIsValidation=0 then videoFilter$=tLine$ case "DUTDIRECTION" 'ver116-4d if restoreIsValidation=0 then switchFR=v1 case "GRAPHDATA" 'In Version A there was a different format for graph data, so we will 'just use default values. if contextVersion$="A" then v1=0 : v2=0 if msaMode$="SA" then v1=constNoGraph : v2=constMagDBM 'ver115-3b if msaMode$="ScalarTrans" then v1=constNoGraph : v2=constMagDB if msaMode$="VectorTrans" then v1=constAngle : v2=constMagDB if msaMode$="Reflection" then v1=constGraphS11Ang : v2=constGraphS11DB else isErr=uExtractNumericItems(2, tLine$, " ", v1, v2, v3) 'isErr if not two items end if 'Be sure data types are valid ver115-1b. An old preference file 'may use different data codes. call FilterDataType v1,1 'ver115-3b call FilterDataType v2,2 'ver115-3b if isErr=0 and restoreIsValidation=0 then Y1DataType=v1 : Y2DataType=v2 case "AUTOSCALE" 'ver114-7e if restoreIsValidation=0 then isErr=uExtractNumericItems(2, tLine$, " ", v1, v2, v3) 'ver115-1f if (v1<>0 and v1<>1) or (v2<>0 and v2<>1) then isErr=1 if isErr=0 then autoScaleY1=v1 : autoScaleY2=v2 end if case "S21JIG" 'ver114-7e if restoreIsValidation=0 then w$=uExtractTextItem$(tLine$," ") 'ver115-1f if w$<>"Series" and w$<>"Shunt" then isErr=1 if isErr=0 then S21JigAttach$=w$ isErr=uExtractNumericItems(2, tLine$, " ", v1, v2, v3) 'ver115-1f if v1<=0 then isErr=1 'modver115-1e if isErr=0 then S21JigR0=v1 : S21JigShuntDelay=v2 'modver115-1e end if case "S11BRIDGE" 'ver114-7e modver115-1b if restoreIsValidation=0 then isErr=uExtractNumericItems(2,tLine$, " ", v1, v2, v3) 'Extract three items and leave the third, a text item if v1<=0 or v2<=0 then isErr=1 tLine$=Trim$(tLine$) : if tLine$<>"Reflect" and tLine$<>"Trans" then tLine$="Trans" 'For backward compatibility if isErr=0 then S11BridgeR0=v1 : S11GraphR0=v2 : S11JigType$=tLine$ 'ver115-1e end if case else 'Unrecognized tag. Must belong to the graph module, so we end here startPos=oldStartPos 'reset to beginning of this line exit while end select if isErr then restoreErr$="Sweep Context Error in: "; origLine$: return 'ver115-1b 'Get next line and increment startPos to start of the following line oldStartPos=startPos tLine$=uGetLine$(restoreContext$, startPos) wend 'If no error so far, process the data for the graph module restoreErr$=gRestoreSweepContext$(restoreContext$, startPos, isValidation) if restoreErr$<>"" or isValidation=1 then return 'done if error or if this is just validation run 'Now set variables that are calculated from the data just retrieved. call gGetYAxisRange 2, Y2Bot, Y2Top 'mag range ver114-4d reversed mag and phase call gGetYAxisRange 1, Y1Bot, Y1Top 'phase range globalSteps=gNumDynamicSteps() 'number of steps call gGetXAxisRange xMin, xMax call SetStartStopFreq xMin, xMax 'sets centfreq, sweepwidth 'stepfreq=(xMax-xMin)/globalSteps delver115-1a steps=globalSteps sweepDir=gGetSweepDir() 'ver114-4n call SelectFilter filtbank 'ver116-4j return function GridContext$() 'Get grid context as string s$="CustomNames=" for i=1 to 5 s$=s$;customPresetNames$(i);";:" 'use a goofy separator so user won't have used it next GridContext$=s$;chr$(13);gGridContext$() 'ver116-1b end function sub FilterDataType byref t, axisNum 'Make sure data types are valid for current msaMode$ 'Change to default values if invalid 'ver115-3b changed to do only a single variable, so we get called once per axis. select msaMode$ case "SA" if t<>constMagDBM and t<>constMagWatts and t<>constMagV and t<>constNoGraph then if axisNum<>gGetPrimaryAxis() then t=constNoGraph else t=constMagDBM 'ver115-7a end if case "ScalarTrans" if t<>constMagDB and t<>constMagRatio and t<>constInsertionLoss and t<>constNoGraph then if axisNum<>gGetPrimaryAxis() then t=constNoGraph else t=constMagDB 'ver115-7a end if case "VectorTrans" 'ver115-1i added raw mag and phase to transmission mode if t<>constMagDB and t<>constMagDBM and t<>constMagRatio and t<>constAngle _ and t<>constRawAngle and t<>constGD and t<>constInsertionLoss _ and t<>constNoGraph then 'ver115-2c if axisNum<>gGetPrimaryAxis() then t=constGraphS11Ang else t=constMagDB 'ver115-7a end if case "Reflection" if (tconstGraphS11SWR) and _ t<>constImpedMag and t<>constImpedAng and t>constReflectPower and t>constComponentQ _ and t<>constReturnLoss and t<>constNoGraph _ and t<>constAdmitMag and t<>constAdmitAng _ and t<>constConductance and t<>constSusceptance then 'ver115-4a if axisNum<>gGetPrimaryAxis() then t=constGraphS11Ang else t=constGraphS11DB 'ver115-7a end if case else t=constNoGraph end select end sub function TraceContext$() 'Return trace context as string 'successive lines are separated by chr$(13) newLine$=chr$(13) 'First include variables used outside the graph module s1$= "RefreshEachScan=";refreshEachScan s1$= s1$;newLine$;"TraceModes=";Y1DisplayMode;",";Y2DisplayMode if doCycleTraceColors then cycleNumber=1 : call gSetTraceColors cycleColorsAxis1$(1), cycleColorsAxis2$(1) 'ver116-4s to save basic trace color TraceContext$=s1$;newLine$;gTraceContext$() 'Add items from graph module end function function RestoreTraceContext$(s$, byref startPos, isValidation) 'Restore sweep context 'Returns error message if error; otherwise 0. Ignores data prior to startPos. 'startPos is updated to one past the last line we process (normally EndContext or end of string) 'if isValidation=1, we merely check for errors 'sep$ is a possibly multi-character separator to delimit text items on one line 'successive lines are separated by chr$(13) newLine$=chr$(13) aSpace$=" " sep$=";;" 'Used to separate text items nonTextDelims$=" ," + chr$(9) 'space, comma and tab are delimiters 'Get next line and increment startPos to start of the following line oldStartPos=startPos tLine$=uGetLine$(s$, startPos) oldStartPos=startPos while tLine$<>"" origLine$=tLine$ 'ver115-1b if Upper$(Left$(tLine$,10))="ENDCONTEXT" then exit while isErr=0 equalPos=instr(tLine$,"=") 'equal sign marks end of tag if equalPos=0 then isErr=1 : exit while else tag$=Upper$(Left$(tLine$, equalPos-1)) 'tag is stuff before equal sign tLine$=Trim$(Mid$(tLine$, equalPos+1)) 'contents is stuff after equal sign end if select case tag$ case "REFRESHEACHSCAN" if isValidation=0 then refreshEachScan=val(tLine$) case "TRACEMODES" isErr=uExtractNumericItems(2, tLine$, nonTextDelims$, v1, v2, v3) if isValidation=0 and isErr=0 then Y1DisplayMode=v1 : Y2DisplayMode=v2 case else 'Unrecognized tag. Must belong to the graph module, so we end here startPos=oldStartPos 'reset to beginning of this line exit while end select if isErr then RestoreTraceContext$="Trace Context Error in: "; origLine$: exit function 'ver115-1b 'Get next line and increment startPos to start of the following line oldStartPos=startPos tLine$=uGetLine$(s$, startPos) wend 'If no error so far, process the data for the graph module errMsg$=gRestoreTraceContext$(s$, startPos, isValidation) call SetCycleColors 'Set trace colors for color cycling ver116-4s RestoreTraceContext$=errMsg$ end function function RestoreGridContext$(s$, byref startPos, isValidation) 'Restore grid context 'Returns error message if error; otherwise 0. Ignores data prior to startPos. 'startPos is updated to one past the last line we process (normally EndContext or end of string) 'if isValidation=1, we merely check for errors 'Return error message if error startPos=1 tLine$=uGetLine$(s$, startPos) oldStartPos=startPos contextVersion$="A" while tLine$<>"" origLine$=tLine$ 'ver115-1b if Upper$(Left$(tLine$,10))="ENDCONTEXT" then exit while isErr=0 equalPos=instr(tLine$,"=") 'equal sign marks end of tag if equalPos=0 then isErr=1 : exit while else tag$=Upper$(Left$(tLine$, equalPos-1)) 'tag is stuff before equal sign tLine$=Trim$(Mid$(tLine$, equalPos+1)) 'contents is stuff after equal sign end if select case tag$ case "CUSTOMNAMES" 'List of custom color preset names if isValidation=0 then for i=1 to 5 customPresetNames$(i)=uExtractTextItem$(tLine$, ";:") '5 items,separated by ";:" next i end if case else 'Unrecognized tag. Must belong to the graph module, so we end here startPos=oldStartPos 'reset to beginning of this line exit while end select 'Get next line and increment startPos to start of the following line oldStartPos=startPos tLine$=uGetLine$(s$, startPos) wend 'process the data for the graph module call gGetGraphicsSize oldWidth, oldHeight 'save so we can restore errMsg$=gRestoreGridContext$(s$, startPos, isValidation) RestoreGridContext$=errMsg$ if errMsg$<>"" or isValidation=1 then exit function primaryAxisNum=gGetPrimaryAxis() 'ver115-3c call gGetMargins graphMarLeft, graphMarRight, graphMarTop, graphMarBot 'Get graph margins 'We may need to resize the graph window to match the dimensions just retrieved 'For now, we restore the previous size with the possibly new margins call gUpdateGraphObject graphBox$, oldWidth, oldHeight, graphMarLeft, graphMarRight, graphMarTop, graphMarBot call gGetSupplementalTraceColors referenceColor1$, referenceColor2$, dum1$, dum2$ 'ver116-4b if primaryAxisNum=1 then referenceColorSmith$=referenceColor1$ else referenceColorSmith$=referenceColor2$ 'ver116-4b end function function BandLineCalContextAsTextArray() 'Put line cal points into uTextPointArray$, with header info 'return number of lines placed into uTextPointArray$ 'First line begins with ! and is line 1 of the title: !Log Sweep Path N. "Log" may instead by "Linear"; N=path number 'First 3 lines are title, each preceded by ! 'Next line is sweep info 'Next is Touchstone options line 'Next is comment data headings 'Then comes each point as its own string if bandLineLinear then sweep$="!Linear Sweep; " else sweep$="!Log Sweep " uTextPointArray$(1)="! BandSweep Line Calibration Data" uTextPointArray$(2)="!" uTextPointArray$(3)="!";bandLineTimeStamp$ 'Save sweep info: log/linear ; path info (in form Path N); Jig attachment and R0 uTextPointArray$(4)=sweep$;bandLinePath$;"; S21Jig=";bandLineS21JigAttach$; "; S21JigR0="; bandLineS21JigR0 'ver115-1b uTextPointArray$(5)="# MHz S DB R 50" 'Freq in MHz, data in DB/angle format uTextPointArray$(6)="! MHz S21_DB S21_Degrees" aSpace$=" " for i=0 to globalSteps 'save freq, mag and phase uTextPointArray$(i+7)=bandLineCal(i,0);aSpace$;bandLineCal(i,1);aSpace$;bandLineCal(i,2) 'ver114-5f next i BandLineCalContextAsTextArray=globalSteps+7 'Number of lines end function function BandLineCalContext$() 'Return data points as string, with title in first 3 lines 'We do not include StartContext or EndContext lines nLines=BandLineCalContextAsTextArray() 'Assemble strings into uTextPointArray$ BandLineCalContext$=uTextArrayToString$(1,nLines) 'Assemble array of strings into one string end function sub BandLineCalContextToFile fHndl$ 'save band line cal points to file 'We do not include StartContext or EndContext lines 'fHndl$ is the handle of an already open file. We output our data 'but do not close the file. nLines=BandLineCalContextAsTextArray() 'Assemble strings into uTextPointArray$ for i=1 to nLines print #fHndl$, uTextPointArray$(i) next i end sub function BaseLineCalContextAsTextArray() 'Put line cal points into uTextPointArray$, with header info 'return number of lines placed into uTextPointArray$ 'First line begins with ! and is line 1 of the title: !Log Sweep Path N. "Log" may instead by "Linear"; N=path number 'First 3 lines are title, each preceded by ! 'Next line is sweep info 'Next is Touchstone options line 'Next is comment data headings 'Then comes each point as its own string if baseLineLinear then sweep$="!Linear Sweep; " else sweep$="!Log Sweep " uTextPointArray$(1)="! BaseLine Calibration Data" uTextPointArray$(2)="!" uTextPointArray$(3)="!";baseLineTimeStamp$ uTextPointArray$(4)=sweep$;baseLinePath$;"; S21Jig=";baseLineS21JigAttach$; "; S21JigR0="; baseLineS21JigR0 'ver115-1b uTextPointArray$(5)="# MHz S DB R 50" 'Freq in MHz, data in DB/angle format uTextPointArray$(6)="! MHz S21_DB S21_Degrees" aSpace$=" " for i=0 to globalSteps 'save freq, mag and phase uTextPointArray$(i+7)=baseLineCal(i,0);aSpace$;baseLineCal(i,1);aSpace$;baseLineCal(i,2) next i BaseLineCalContextAsTextArray=globalSteps+7 'Number of lines end function function BaseLineCalContext$() 'Return data points as string, with title in first 3 lines 'We do not include StartContext or EndContext lines nLines=BaseLineCalContextAsTextArray() 'Assemble strings into uTextPointArray$ BaseLineCalContext$=uTextArrayToString$(1,nLines) 'Assemble array of strings into one string end function sub BaseLineCalContextToFile fHndl$ 'save line cal points to file 'We do not include StartContext or EndContext lines 'fHndl$ is the handle of an already open file. We output our data 'but do not close the file. nLines=BaseLineCalContextAsTextArray() 'Assemble strings into uTextPointArray$ for i=1 to nLines print #fHndl$, uTextPointArray$(i) next i end sub function RestoreBandLineCalContext(byref s$, byref startPos) 'Restore line cal points. Return number of points 'We return number of points read, or -1 for file error 'We ignore data prior to startPos. We update startPos to the start of the next line after the line 'with "!EndContext"; or if no such line then one past end of string isErr=uArrayFromString(s$, 1, startPos, 3) 'Get data into uWorkArray; 3 data per line (freq+mag+phase) if isErr then RestoreBandLineCalContext=0 : errCode=1 : exit function 'Now transfer retrieved data from uWorkArray() to lineCalArray(). errCode=0 for i=1 to uWorkNumPoints bandLineCal(i-1,0)=uWorkArray(i, 0) 'freq bandLineCal(i-1,1)=uWorkArray(i, 1) : bandLineCal(i-1,2)=uWorkArray(i, 2) 'Mag and phase next i RestoreBandLineCalContext=uWorkNumPoints 'Now derive the sweep parameters from the array and the title ver114-5h bandLineNumSteps=uWorkNumPoints-1 bandLineStartFreq=bandLineCal(0,0) : bandLineEndFreq=bandLineCal(bandLineNumSteps,0) bandLineTimeStamp$=uWorkTitle$(3) 'uArrayFromString put date/time stamp here sweep$=uWorkTitle$(4) 'uArrayFromString put sweep info here if instr(sweep$,"Linear")>0 then bandLineLinear=1 else bandLineLinear=0 'ver115-1b added the retrieval of the following sweep info 'Get remaining sweep info from sweep$. Each item has a keyword and ends with a semi-colon or end of line bandPathNum$=uGetParamText$(sweep$, "Path ", ";") 'Gets text after "Path " to semicolon or end if bandPathNum$="" then bandLinePath$="Path 1" else bandLinePath$="Path ";bandPathNum$ bandLineS21JigAttach$=uGetParamText$(sweep$, "S21Jig=", ";") 'Gets text after S21Jig= to semicolon or end if bandLineS21JigAttach$="" then bandLineS21JigAttach$="Series" bandLineS21JigR0=val(uGetParamText$(sweep$, "S21JigR0=", ";")) 'Gets text after S21Jig= to semicolon or end if bandLineS21JigR0=0 then bandLineS21JigR0=50 end function function GetBandLineCalContextFromFile(fHndl$) 'get points from file; return number of points 'We return number of points read, or -1 for file error 'fHndl$ is the handle of an already open file. We read our data 'but do not close the file. The last line we read will be "!EndContext" isErr=uArrayFromFile(fHndl$,3) 'Get data, 3 per line if isErr then GetBandLineCalContextFromFile=-1 : baseLineNumSteps=-1 : exit function 'Move the data from uWorkArray to gGraphVal for i=1 to uWorkNumPoints bandLineCal(i-1,0)=uWorkArray(i, 0) 'freq bandLineCal(i-1,1)=uWorkArray(i, 1) : bandLineCal(i-1,2)=uWorkArray(i, 2) 'Mag and phase next i GetBandLineCalContextFromFile=uWorkNumPoints 'Now derive the sweep parameters from the array and the title ver114-5h bandLineNumSteps=uWorkNumPoints-1 bandLineStartFreq=bandLineCal(0,0) : bandLineEndFreq=bandLineCal(bandLineNumSteps,0) bandLineTimeStamp$=uWorkTitle$(3) 'uArrayFromFile put date/time stamp here sweep$=uWorkTitle$(4) 'uArrayFromFile put sweep info here if instr(sweep$,"Linear")>0 then bandLineLinear=1 else bandLineLinear=0 'ver115-1b added the retrieval of the following sweep info 'Get remaining sweep info from sweep$. Each item has a keyword and ends with a semi-colon or end of line bandPathNum$=uGetParamText$(sweep$, "Path ", ";") 'Gets text after "Path " to semicolon or end if bandPathNum$="" then bandLinePath$="Path 1" else bandLinePath$="Path ";bandPathNum$ bandLineS21JigAttach$=uGetParamText$(sweep$, "S21Jig=", ";") 'Gets text after S21Jig= to semicolon or end if bandLineS21JigAttach$="" then bandLineS21JigAttach$="Series" bandLineS21JigR0=val(uGetParamText$(sweep$, "S21JigR0=", ";")) 'Gets text after S21Jig= to semicolon or end if bandLineS21JigR0=0 then bandLineS21JigR0=50 end function function RestoreBaseLineCalContext(byref s$, byref startPos) 'Restore line cal points. Return number of points 'We return number of points read, or -1 for file error 'We ignore data prior to startPos. We update startPos to the start of the next line after the line 'with "!EndContext"; or if no such line then one past end of string isErr=uArrayFromString(s$, 1, startPos, 3) 'Get data into uWorkArray; 3 data per line (freq+mag+phase) if isErr then RestoreBaseLineCalContext=-1 : exit function 'Now transfer retrieved data from uWorkArray() to lineCalArray(). 'Make sure baseLineCal is big enough. Note that it can be bigger than data arrays, 'since it is used only by interpolating into a possibly smaller array. if uWorkNumPoints>gMaxNumPoints then redim baseLineCal(uWorkNumPoints+20, 2) 'ver114-5m for i=1 to uWorkNumPoints baseLineCal(i-1,0)=uWorkArray(i, 0) 'Freq baseLineCal(i-1,1)=uWorkArray(i, 1) : baseLineCal(i-1,2)=uWorkArray(i, 2) 'Mag and phase next i RestoreBaseLineCalContext=uWorkNumPoints 'Now derive the sweep parameters from the array and the title ver114-5h baseLineNumSteps=uWorkNumPoints-1 baseLineStartFreq=baseLineCal(0,0) : baseLineEndFreq=baseLineCal(baseLineNumSteps,0) baseLineTimeStamp$=uWorkTitle$(3) 'uArrayFromString put date/time stamp here sweep$=uWorkTitle$(4) 'uArrayFromString put sweep info here if instr(sweep$,"Linear")>0 then baseLineLinear=1 else baseLineLinear=0 'ver115-1b added the retrieval of the following sweep info 'Get remaining sweep info from sweep$. Each item has a keyword and ends with a semi-colon or end of line basePathNum$=uGetParamText$(sweep$, "Path ", ";") 'Gets text after "Path " to semicolon or end if basePathNum$="" then baseLinePath$="Path 1" else baseLinePath$="Path ";basePathNum$ baseLineS21JigAttach$=uGetParamText$(sweep$, "S21Jig=", ";") 'Gets text after S21Jig= to semicolon or end if baseLineS21JigAttach$="" then baseLineS21JigAttach$="Series" baseLineS21JigR0=val(uGetParamText$(sweep$, "S21JigR0=", ";")) 'Gets text after S21Jig= to semicolon or end if baseLineS21JigR0=0 then baseLineS21JigR0=50 end function function GetBaseLineCalContextFromFile(fHndl$) 'get points from file; return number of points 'We return number of points read, or -1 for file error 'fHndl$ is the handle of an already open file. We read our data 'but do not close the file. The last line we read will be "!EndContext" isErr=uArrayFromFile(fHndl$,3) 'Get data, 3 per line if isErr then GetBaseLineCalContextFromFile=-1 : baseLineNumSteps=-1 : exit function 'Move the data from uWorkArray to gGraphVal for i=1 to uWorkNumPoints baseLineCal(i-1,0)=uWorkArray(i, 0) 'Freq baseLineCal(i-1,1)=uWorkArray(i, 1) : baseLineCal(i-1,2)=uWorkArray(i, 2) 'Mag and phase next i GetBaseLineCalContextFromFile=uWorkNumPoints 'Now derive the sweep parameters from the array and the title ver114-5h baseLineNumSteps=uWorkNumPoints-1 baseLineStartFreq=baseLineCal(0,0) : baseLineEndFreq=baseLineCal(baseLineNumSteps,0) baseLineTimeStamp$=uWorkTitle$(3) 'uArrayFromFile put date/time stamp here sweep$=uWorkTitle$(4) 'uArrayFromFile put sweep info here if instr(sweep$,"Linear")>0 then baseLineLinear=1 else baseLineLinear=0 'ver115-1b added the retrieval of the following sweep info 'Get remaining sweep info from sweep$. Each item has a keyword and ends with a semi-colon or end of line basePathNum$=uGetParamText$(sweep$, "Path ", ";") 'Gets text after "Path " to semicolon or end if basePathNum$="" then baseLinePath$="Path 1" else baseLinePath$="Path ";basePathNum$ baseLineS21JigAttach$=uGetParamText$(sweep$, "S21Jig=", ";") 'Gets text after S21Jig= to semicolon or end if baseLineS21JigAttach$="" then baseLineS21JigAttach$="Series" baseLineS21JigR0=val(uGetParamText$(sweep$, "S21JigR0=", ";")) 'Gets text after S21Jig= to semicolon or end if baseLineS21JigR0=0 then baseLineS21JigR0=50 end function function OSLCalContextAsTextArray(isBand) 'Put cal points into uTextPointArray$, with header info 'isBand=1 means we do band cal; =0 means base cal 'return number of lines placed into uTextPointArray$ 'First line begins with ! and is line 1 of the title: !Log Sweep Path N. "Log" may instead by "Linear"; N=path number 'First 3 lines are title, each preceded by ! 'Next line is sweep info 'Next is Touchstone options line 'Next is comment data headings 'Then comes each point as its own string uTextPointArray$(1)="! OSL Calibration Data" uTextPointArray$(2)="!" if isBand then if OSLBandLinear then sweep$="!Linear Sweep; " else sweep$="!Log Sweep " uTextPointArray$(3)="!";OSLBandTimeStamp$ 'Save sweep info: log/linear ; path info (in form Path N); Jig attachment and R0 uTextPointArray$(4)=sweep$;OSLBandPath$;"; S11Jig=";OSLBandS11JigType$; "; S11BridgeR0=";S11BridgeR0; _ 'ver115-9d "; S21Jig=";OSLBandS21JigAttach$; "; S21JigR0="; OSLBandS21JigR0 'ver115-1b, ver115-1g else if OSLBaseLinear then sweep$="!Linear Sweep; " else sweep$="!Log Sweep " uTextPointArray$(3)="!";OSLBaseTimeStamp$ 'Save sweep info: log/linear ; path info (in form Path N); Jig attachment and R0 uTextPointArray$(4)=sweep$;OSLBasePath$;"; S11Jig=";OSLBaseS11JigType$; "; S11BridgeR0=";S11BridgeR0; _ 'ver115-9d "; S21Jig=";OSLBaseS21JigAttach$; "; S21JigR0="; OSLBaseS21JigR0 'ver115-1b, ver115-1g end if uTextPointArray$(5)="!" aSpace$=" " uTextPointArray$(6)="! MHz A_real A_imag B_real B_imag C_Real C_Imag RefDB RefDeg" for i=0 to globalSteps 'save freq, mag and phase if isBand then 'Band cal s$=OSLBandA(i,0);aSpace$;OSLBandA(i,1);aSpace$;OSLBandB(i,0);_ aSpace$;OSLBandB(i,1);aSpace$; OSLBandC(i,0);aSpace$;OSLBandC(i,1);aSpace$ uTextPointArray$(i+7)=OSLBandRef(i,0);aSpace$;s$;OSLBandRef(i,1);aSpace$;OSLBandRef(i,2) else 'Base cal s$=OSLBaseA(i,0);aSpace$;OSLBaseA(i,1);aSpace$;OSLBaseB(i,0);_ aSpace$;OSLBaseB(i,1);aSpace$; OSLBaseC(i,0);aSpace$;OSLBaseC(i,1);aSpace$ uTextPointArray$(i+7)=OSLBaseRef(i,0);aSpace$;s$;OSLBaseRef(i,1);aSpace$;OSLBaseRef(i,2) end if next i OSLCalContextAsTextArray=globalSteps+7 'Number of lines end function sub OSLCalContextToFile fHndl$, isBand 'save OSL cal points to file 'isBand=1 means we do band cal; =0 means base cal 'We do not include StartContext or EndContext lines 'fHndl$ is the handle of an already open file. We output our data 'but do not close the file. nLines=OSLCalContextAsTextArray(isBand) 'Assemble strings into uTextPointArray$ for i=1 to nLines print #fHndl$, uTextPointArray$(i) next i end sub function OSLGetCalContextFromFile(fHndl$, isBand) 'get points from file; return number of points 'isBand=1 means we do band cal; =0 means base cal 'We return number of points read, or -1 for file error 'fHndl$ is the handle of an already open file. We read our data 'but do not close the file. The last line we read will be "!EndContext" isErr=uArrayFromFile(fHndl$,100) 'Get data, 100 means number per line to be determined if isErr then OSLGetCalContextFromFile=-1 if isBand then OSLBandNumSteps=-1 else OSLBaseNumSteps=-1 'Indicates no data exit function end if 'Move the data from uWorkArray to gGraphVal if isBand then 'Band Cal for i=1 to uWorkNumPoints 'ver116-4n OSLBandRef(i-1,0)=uWorkArray(i, 0) 'freq OSLBandA(i-1,0)=uWorkArray(i, 1) : OSLBandA(i-1,1)=uWorkArray(i, 2) 'Coeff A real and imag OSLBandB(i-1,0)=uWorkArray(i, 3) : OSLBandB(i-1,1)=uWorkArray(i, 4) 'Coeff B real and imag OSLBandC(i-1,0)=uWorkArray(i, 5) : OSLBandC(i-1,1)=uWorkArray(i, 6) 'Coeff C real and imag OSLBandRef(i-1,1)=uWorkArray(i, 7) : OSLBandRef(i-1,2)=uWorkArray(i, 8) 'Mag and phase for ref next i OSLGetCalContextFromFile=uWorkNumPoints 'Now derive the sweep parameters from the array and the title ver114-5h if uWorkNumPoints<1 then exit function OSLBandNumSteps=uWorkNumPoints-1 OSLBandStartFreq=OSLBandRef(0,0) : OSLBandEndFreq=OSLBandRef(OSLBandNumSteps,0) OSLBandTimeStamp$=uWorkTitle$(3) 'uArrayFromFile put date/time stamp here sweep$=uWorkTitle$(4) 'uArrayFromFile put sweep info here if instr(sweep$,"Linear")>0 then OSLBandLinear=1 else OSLBandLinear=0 'ver115-1b added the retrieval of the following sweep info 'Get remaining sweep info from sweep$. Each item has a keyword and ends with a semi-colon or end of line calPathNum$=uGetParamText$(sweep$, "Path ", ";") 'Gets text after "Path " to semicolon or end if calPathNum$="" then OSLBandPath$="Path 1" else OSLBandPath$="Path ";calPathNum$ OSLBandS11JigType$=uGetParamText$(sweep$, "S11Jig=", ";") 'Gets text after S11Jig= to semicolon or end ver115-1g if OSLBandS11JigType$="" then OSLBandS11JigType$="Reflect" 'ver115-1g if OSLBandS11JigType$="Reflect" then 'ver115-9d 'If using bridge, get bridge R0 OSLBandS11BridgeR0=val(uGetParamText$(sweep$, "S11BridgeR0=", ";")) 'Gets text after S11BridgeR0= to semicolon or end if OSLBandS11BridgeR0<=0 then OSLBandS11BridgeR0=50 else 'If using S21 fixture for reflection measurements, get attachment and R0 OSLBandS21JigAttach$=uGetParamText$(sweep$, "S21Jig=", ";") 'Gets text after S21Jig= to semicolon or end if OSLBandS21JigAttach$="" then OSLBandS21JigAttach$="Series" OSLBandS21JigR0=val(uGetParamText$(sweep$, "S21JigR0=", ";")) 'Gets text after S21Jig= to semicolon or end if OSLBandS21JigR0<=0 then OSLBandS21JigR0=50 end if else 'Base for i=1 to uWorkNumPoints 'ver116-4n OSLBaseRef(i-1,0)=uWorkArray(i, 0) 'freq OSLBaseA(i-1,0)=uWorkArray(i, 1) : OSLBaseA(i-1,1)=uWorkArray(i, 2) 'Coeff A real and imag OSLBaseB(i-1,0)=uWorkArray(i, 3) : OSLBaseB(i-1,1)=uWorkArray(i, 4) 'Coeff B real and imag OSLBaseC(i-1,0)=uWorkArray(i, 5) : OSLBaseC(i-1,1)=uWorkArray(i, 6) 'Coeff C real and imag OSLBaseRef(i-1,1)=uWorkArray(i, 7) : OSLBaseRef(i-1,2)=uWorkArray(i, 8) 'Mag and phase for ref next i OSLGetCalContextFromFile=uWorkNumPoints 'Now derive the sweep parameters from the array and the title ver114-5h if uWorkNumPoints<1 then exit function OSLBaseNumSteps=uWorkNumPoints-1 OSLBaseStartFreq=OSLBaseRef(0,0) : OSLBaseEndFreq=OSLBaseRef(OSLBaseNumSteps,0) OSLBaseTimeStamp$=uWorkTitle$(3) 'uArrayFromFile put date/time stamp here sweep$=uWorkTitle$(4) 'uArrayFromFile put sweep info here if instr(sweep$,"Linear")>0 then OSLBaseLinear=1 else OSLBaseLinear=0 'ver115-1b added the retrieval of the following sweep info 'Get remaining sweep info from sweep$. Each item has a keyword and ends with a semi-colon or end of line calPathNum$=uGetParamText$(sweep$, "Path ", ";") 'Gets text after "Path " to semicolon or end OSLBaseS11JigType$=uGetParamText$(sweep$, "S11Jig=", ";") 'Gets text after S11Jig= to semicolon or end ver115-1g if OSLBaseS11JigType$="" then OSLBaseS11JigType$="Reflect" 'ver115-1g if calPathNum$="" then OSLBasePath$="Path 1" else OSLBasePath$="Path ";calPathNum$ if OSLBandS11JigType$="Reflect" then 'ver115-9d 'If using bridge, get bridge R0 OSLBaseS11BridgeR0=val(uGetParamText$(sweep$, "S11BridgeR0=", ";")) 'Gets text after S11BridgeR0= to semicolon or end if OSLBaseS11BridgeR0<=0 then OSLBaseS11BridgeR0=50 else 'If using S21 fixture for reflection measurements, get attachment and R0 OSLBaseS21JigAttach$=uGetParamText$(sweep$, "S21Jig=", ";") 'Gets text after S21Jig= to semicolon or end if OSLBaseS21JigAttach$="" then OSLBaseS21JigAttach$="Series" OSLBaseS21JigR0=val(uGetParamText$(sweep$, "S21JigR0=", ";")) 'Gets text after S21Jig= to semicolon or end if OSLBaseS21JigR0<=0 then OSLBaseS21JigR0=50 end if end if end function function GraphDataContextAsTextArray() 'Put graph data points into uTextPointArray$, with header info 'return number of lines placed into uTextPointArray$ 'First 3 lines are title, each preceded by ! 'Next line is sweep info 'Next is Touchstone options line 'Next is comment data headings 'Then comes each point as its own string uTextPointArray$(1)="!";gGetTitleLine$(1) uTextPointArray$(2)="!";gGetTitleLine$(2) uTextPointArray$(3)="!";gGetTitleLine$(3) uTextPointArray$(4)="!";gGetTitleLine$(4) 'This line has sweep info set by user; not printed as part of title ver114-5m uTextPointArray$(5)="# MHz S DB R 50" 'Freq in MHz, data in DB/angle format uTextPointArray$(6)="! MHz S21_DB S21_Degrees" 'We save frequency plus two data per point even if we only have one trace. aSpace$=" " call gGetMinMaxPointNum pMin, pMax 'ver114-6d minStep=pMin-1 : maxStep=pMax-1 for i=minStep to maxStep 'ver114-6d call gGetPointVal i+1, f, y1, y2 'point num is one more than step num. uTextPointArray$(i+7)=f;aSpace$;y2;aSpace$;y1 'Save freq, Y2, Y1 next i GraphDataContextAsTextArray=maxStep+7 end function function GraphDataContext$() 'Return data points as string, with title in first 3 lines 'We do not include !StartContext or !EndContext lines nLines=GraphDataContextAsTextArray() 'Assemble strings into uTextPointArray$ GraphDataContext$=uTextArrayToString$(1,nLines) 'Assemble array of strings into one string end function sub GraphDataContextToFile fHndl$ 'save data points to file 'We do not include StartContext or EndContext lines 'fHndl$ is the handle of an already open file. We output our data 'but do not close the file. nLines=GraphDataContextAsTextArray() 'Assemble strings into uTextPointArray$ for i=1 to nLines print #fHndl$, uTextPointArray$(i) next i end sub function RestoreGraphDataContext(byref s$, byref startPos, doTitle) 'Restore data points from s$ 'Return number of points; -1 if error 'Restore data; restore title only if doTitle=1 'We ignore data prior to startPos. We update startPos to the start of the next line after 'the point data, per uArrayFromString isErr=uArrayFromString(s$, 1, startPos, 3) 'Get data into uWorkArray; 3 data per line (freq+mag+phase) if isErr then RestoreGraphDataContext=-1 : exit function 'Now transfer retrieved data from uWorkArray() to gGraphVal(). 'TO DO--This resizing does not help other arrays, and to resize them we would need to erase them. 'If we don't have room, we should notify the user that he needs to do a sweep with more points. if uWorkNumPoints>gMaxNumPoints() then call ResizeArrays uWorkNumPoints call gSetNumDynamicSteps uWorkNumPoints-1 call gSetNumPoints 0 for i=1 to uWorkNumPoints overflow=gAddPoints(uWorkArray(i, 0), uWorkArray(i, 2), uWorkArray(i, 1)) 'Freq, Phase, Mag next i if doTitle then for i=1 to 4 call gSetTitleLine i, uWorkTitle$(i) 'Save title, which uArrayFromString retrieved ver114-5i next i end if 'Note title line 4 has info on linear/log. We don't change to match, so on a Restart we will 'not conform. But that should be taken care of in restoring the sweep context. Likewise with path info. 'Note we do not call gSetNumDynamicSteps; that must be set elsewhere. 'Caller must also separately conform datatable() with the graph data RestoreGraphDataContext=uWorkNumPoints prevDataChanged=1 end function function GetGraphDataContextFromFile(fHndl$, doTitle) 'get points from file; return number of points or -1 if error 'Restore data; restore title only if doTitle=1 'fHndl$ is the handle of an already open file. We read our data 'but do not close the file. The last line we read will be "!EndContext" isErr=uArrayFromFile(fHndl$,3) 'Get data, 3 per line if isErr then GetGraphDataContextFromFile=-1 : exit function 'Move the data from uWorkArray to gGraphVal if uWorkNumPoints>gMaxNumPoints() then call ResizeArrays uWorkNumPoints 'Make sure we have enough room call gSetNumPoints 0 for i=1 to uWorkNumPoints overflow=gAddPoints(uWorkArray(i, 0), uWorkArray(i, 2), uWorkArray(i, 1)) 'Freq, Phase, Mag next i if doTitle then for i=1 to 4 call gSetTitleLine i, uWorkTitle$(i) 'Save title, which uArrayFromString retrieved ver114-5i next i end if 'Note title line 4 has info on linear/log. We don't change to match, so on a Restart we will 'not conform. But that should be taken care of in restoring the sweep context. Likewise with path info. 'Note we do not call gSetNumDynamicSteps; that must be set elsewhere. 'Caller must also separately conform datatable() with the graph data GetGraphDataContextFromFile=uWorkNumPoints prevDataChanged=1 end function function DataTableContextAsTextArray() 'Put data points into uTextPointArray$, with header info 'We save the full datatable() even if data for some steps has not been collected yet. 'return number of lines placed into uTextPointArray$ 'First 3 lines are title, each preceded by ! 'Next line is sweep info 'Next is Touchstone options line 'Next is comment data headings 'Then comes each point as its own string uTextPointArray$(1)="!";gGetTitleLine$(1) uTextPointArray$(2)="!";gGetTitleLine$(2) uTextPointArray$(3)="!";gGetTitleLine$(3) uTextPointArray$(4)="!";gGetTitleLine$(4) 'This line has sweep info set by user; not printed as part of title ver114-5m uTextPointArray$(5)="# MHz S DB R 50" 'Freq in MHz, data in DB/angle format uTextPointArray$(6)="! MHz S21_DB S21_Degrees" 'We save frequency plus two data per point even if we only have one trace. aSpace$=" " for i=0 to globalSteps y1=datatable(i,3) y2=datatable(i,2) uTextPointArray$(i+7)=datatable(i,1);aSpace$;y2;aSpace$;y1 'Save freq, Y2, Y1 next i DataTableContextAsTextArray=maxStep+7 end function function DataTableContext$() 'Return data points as string, with title in first 3 lines 'We do not include !StartContext or !EndContext lines nLines=DataTableContextAsTextArray() 'Assemble strings into uTextPointArray$ DataTableContext$=uTextArrayToString$(1,nLines) 'Assemble array of strings into one string end function sub DataTableContextToFile fHndl$ 'save data points to file 'We save the full datatable() even if data for some steps has not been collected yet. 'We do not include StartContext or EndContext lines 'fHndl$ is the handle of an already open file. We output our data 'but do not close the file. nLines=DataTableContextAsTextArray() 'Assemble strings into uTextPointArray$ for i=1 to nLines print #fHndl$, uTextPointArray$(i) next i end sub function RestoreDataTableContext(byref s$, byref startPos, doTitle) 'Restore data points from s$ 'Return number of points; -1 if error 'Restore data; restore title only if doTitle=1 'We ignore data prior to startPos. We update startPos to the start of the next line after 'the point data, per uArrayFromString isErr=uArrayFromString(s$, 1, startPos, 3) 'Get data into uWorkArray; 3 data per line (freq+mag+phase) if isErr then RestoreDataTableContext=-1 : exit function 'Now transfer retrieved data from uWorkArray() to gGraphVal(). 'TO DO--This resizing does not help other arrays, and to resize them we would need to erase them. 'If we don't have room, we should notify the user that he needs to do a sweep with more points. if uWorkNumPoints>gMaxNumPoints() then call ResizeArrays uWorkNumPoints for i=1 to uWorkNumPoints datatable(i-1,1)=uWorkArray(i, 0) 'Frequency datatable(i-1,2)=uWorkArray(i, 1) : datatable(i-1,1)=uWorkArray(i, 2) 'Mag (Y2) first, then phase next i if doTitle then for i=1 to 4 call gSetTitleLine i, uWorkTitle$(i) 'Save title, which uArrayFromString retrieved ver114-5i next i end if 'Note title line 4 has info on linear/log. We don't change to match, so on a Restart we will 'not conform. But that should be taken care of in restoring the sweep context. Likewise with path info. 'Note we do not call gSetNumDynamicSteps; that must be set elsewhere. 'Caller must also separately conform datatable() with the graph data RestoreDataTableContext=uWorkNumPoints prevDataChanged=1 end function function GetDataTableContextFromFile(fHndl$, doTitle) 'get points from file; return number of points or -1 if error 'Restore data; restore title only if doTitle=1 'fHndl$ is the handle of an already open file. We read our data 'but do not close the file. The last line we read will be "!EndContext" isErr=uArrayFromFile(fHndl$,3) 'Get data, 3 per line if isErr then GetDataTableContextFromFile=-1 : exit function 'Move the data from uWorkArray to gGraphVal if uWorkNumPoints>gMaxNumPoints() then call ResizeArrays uWorkNumPoints 'Make sure we have enough room for i=1 to uWorkNumPoints datatable(i-1,1)=uWorkArray(i, 0) 'Frequency datatable(i-1,2)=uWorkArray(i, 1) : datatable(i-1,1)=uWorkArray(i, 2) 'Mag (Y2) first, then phase next i if doTitle then for i=1 to 4 call gSetTitleLine i, uWorkTitle$(i) 'Save title, which uArrayFromString retrieved ver114-5i next i end if 'Note title line 4 has info on linear/log. We don't change to match, so on a Restart we will 'not conform. But that should be taken care of in restoring the sweep context. Likewise with path info. 'Also note that we do not change anything in the graph module. Neither its data nor number of steps will 'necessarily match ours. It must be dealt with separately. 'We also don't set steps or globalSteps to match our number of points GetDataTableContextFromFile=uWorkNumPoints prevDataChanged=1 end function function mMarkerContext$() 'Return marker context as string 'successive lines are separated by chr$(13) newLine$=chr$(13) s$="," 'comma to separate items j$="" s1$="" for i=0 to 9 id$=markerIDs$(i) :markNum=mMarkerNum(id$) call gGetMarkerByNum markNum, pointNum, id$, trace$, style$ if pointNum>0 then s1$=s1$;j$;"Marker=" + id$;s$; pointNum; s$; trace$ 'Marker id, point number and trace j$=newLine$ end if next s1$= s1$;j$;"Selected=";selMarkerID$ j$=newLine$ s1$= s1$;newLine$;"DoGraph=";doGraphMarkers s1$= s1$;newLine$;"LROptions=";doPeaksBounded;s$;doLRRelativeTo$;s$;doLRRelativeAmount;s$;doLRAbsolute 'ver115-3f s1$= s1$;newLine$;"FiltAnalysis=";doFilterAnalysis;s$;x1DBDown;s$;x2DBDown mMarkerContext$=s1$ end function function mRestoreMarkerContext$(s$, byref startPos, isValidation) 'Restore marker info from context string 'Returns error message if error; otherwise 0. Ignores data prior to startPos. 'startPos is updated to one past the last line we process (normally EndContext or end of string) 'if isValidation=1, we merely check for errors 'sep$ is a possibly multi-character separator to delimit text items on one line 'successive lines are separated by chr$(13) call mClearMarkers 'delete existing markers ver116-2a newLine$=chr$(13) nonTextDelims$=" ," + chr$(9) 'space, comma and tab are delimiters 'Get next line and increment startPos to start of the following line oldStartPos=startPos tLine$=uGetLine$(s$, startPos) 'Get line of data oldStartPos=startPos while tLine$<>"" origLine$=tLine$ 'ver115-1b if Upper$(Left$(tLine$,10))="ENDCONTEXT" then exit while isErr=0 equalPos=instr(tLine$,"=") 'equal sign marks end of tag if equalPos=0 then isErr=1 : exit while else tag$=Upper$(Left$(tLine$, equalPos-1)) 'tag is stuff before equal sign tLine$=Trim$(Mid$(tLine$, equalPos+1)) 'contents is stuff after equal sign end if select case tag$ case "MARKER" if isValidation=0 then _ call mAddMarker Word$(tLine$,1,","),val(Word$(tLine$,2,",")),Word$(tLine$,3,",") 'id, point num, trace case "SELECTED" if isValidation=0 then selMarkerID$=tLine$ case "DOGRAPH" if isValidation=0 then doGraphMarkers=val(tLine$) case "LROPTIONS" if isValidation=0 then 'modver115-3f isErr=uExtractNumericItems(1,tLine$, nonTextDelims$,v1, v2, v3) doPeaksBounded=v1 doLRRelativeTo$=uExtractTextItem$(tLine$,",") 'ver116-2a isErr=uExtractNumericItems(2,tLine$, nonTextDelims$,v1, v2, v3) doLRRelativeAmount=v1 doLRAbsolute=v2 end if case "FILTANALYSIS" if isValidation=0 then 'modver115-3f isErr=uExtractNumericItems(1,tLine$, nonTextDelims$,v1, v2, v3) doFilterAnalysis=v1 x1DBDown=v2 x2DBDown=v3 end if case else 'Unrecognized tag. Must belong to the graph module, so we end here startPos=oldStartPos 'reset to beginning of this line exit while end select if isErr then mRestoreMarkerContext$="Marker Context Error in: "; origLine$: exit function 'ver115-1b 'Get next line and increment startPos to start of the following line oldStartPos=startPos tLine$=uGetLine$(s$, startPos) wend mRestoreMarkerContext$="" call mMarkSelect selMarkerID$ 'To display info ver114-5L end function [LoadBasicContextsFromFile] 'Load contexts from file restoreFileHndl$; set restoreErr$ to error message or "" 'User must call RememberState before coming here and then DetectFullChanges after returning, to deal with changes. 'The file must already be open. We do not close it. 'restoreFileHndl$ contains LB file handle, e.g. "#prefs" 'restoreLastLineNum will be set to the last line we read, in case the caller wants to back up one line. 'The file may contain several contexts, each starting with StartContext Name or !StartContext Name 'and ending with EndContext. Grid context should be before Sweep context. 'There may already have been other data read from the file. We start wherever Line Input reads. 'The entries of contextTypes will be set to 1 if the corresponding context was read: 'See Select statement for contextTypes values for i=0 to 30 : contextTypes(i)=0 : next i 'Clear contextTypes we actually only need four restoreErr$="" 'assume no error restoreLastLineNum=0 : foundData=0 while EOF(#restoreFileHndl$)=0 'Find next "StartContext" or "!". The exclamation point means a data section has been 'encountered that is not marked with "StartContext", which is OK but is the end of preferences contextName$="" while EOF(#restoreFileHndl$)=0 Line Input #restoreFileHndl$, tLine$ restoreLastLineNum=restoreLastLineNum+1 tLine$=Upper$(Trim$(tLine$)) if Left$(tLine$,1)="!" then foundData=1: exit while 'Exclamation means data starts tagPos=instr(tLine$, "STARTCONTEXT") if tagPos>0 then contextName$=Trim$(Mid$(tLine$, tagPos+12)) 'text after tag is context name exit while end if wend if foundData then exit while select contextName$ case "HARDWARE" errMsg$="Can't restore Hardware Context" case "GRID", "TRACE", "SWEEP", "MARKER" 'These are read into a string and then processed ver115-8c restoreContext$="" 'Assemble context into string, without StartContext and EndContext lines joint$="" while EOF(#restoreFileHndl$)=0 Line Input #restoreFileHndl$, tLine$ restoreLastLineNum=restoreLastLineNum+1 if Upper$(Trim$(tLine$))="ENDCONTEXT" then exit while restoreContext$=restoreContext$;joint$;tLine$ joint$=chr$(13) wend 'Process with proper routine select contextName$ case "GRID" contextTypes(constGrid)=1 errMsg$=RestoreGridContext$(restoreContext$,1,0) 'Actual restoration case "TRACE" errMsg$=RestoreTraceContext$(restoreContext$,1,0) contextTypes(constTrace)=1 case "SWEEP" contextTypes(constSweep)=1 restoreIsValidation=0 gosub [RestoreSweepContext] 'Actual restoration errMsg$=restoreErr$ case "MARKER" contextTypes(constMarker)=1 restoreIsValidation=0 gosub [RestoreMarkerContext] 'Actual restoration errMsg$=restoreErr$ end select if errMsg$<>"" then restoreErr$=errMsg$ : exit while case "DATATABLE" exit while 'Datatable context can mark the end, but is not error case else restoreErr$="UNKNOWN CONTEXT: ";contextName$ : exit while 'Unknown context name; may not actually be error end select wend 'Reach here when entire file has been processed up to an unknown context or a "!", or error occurred return function OpenContextFile$(fName$, inout$) 'Open specified file. Return handle or "" 'fName$ contains complete path and file name On Error goto [noFile] inout$=Upper$(Trim$(inout$)) if inout$="IN" then open fName$ for input as #contextFile else open fName$ for output as #contextFile OpenContextFile$="#contextFile" exit function [noFile] OpenContextFile$="" end function function SaveContextFile$(fName$) 'Save specified Contexts to file; return error message or "" 'fName$ contains complete path and file name 'The entries of contextTypes will be set to 1 if the corresponding context is to be saved: fHndl$=OpenContextFile$(fName$,"Out") if fHndl$="" then SaveContextFile$="Context file failed to open: ";fName$ : exit function newLine$=chr$(13) contextCount=0 if contextTypes(constHardware)=1 then contextCount=contextCount+1 : print #fHndl$, "StartContext Hardware";newLine$;configHardwareContext$();newLine$;"EndContext" if contextTypes(constGrid)=1 then contextCount=contextCount+1 : print #fHndl$, "StartContext Grid";newLine$;GridContext$();newLine$;"EndContext" 'ver115-2a if contextTypes(constTrace)=1 then contextCount=contextCount+1 : print #fHndl$, "StartContext Trace";newLine$;TraceContext$();newLine$;"EndContext" if contextTypes(constSweep)=1 then contextCount=contextCount+1 : print #fHndl$, "StartContext Sweep";newLine$;SweepContext$();newLine$;"EndContext" if contextTypes(constMarker)=1 then contextCount=contextCount+1 : print #fHndl$, "StartContext Marker";newLine$;mMarkerContext$();newLine$;"EndContext" if contextTypes(constBand)=1 then contextCount=contextCount+1 print #fHndl$, "!StartContext BandLineCal" call BandLineCalContextToFile fHndl$ print #fHndl$, "!EndContext" end if if contextTypes(constBase)=1 then contextCount=contextCount+1 print #fHndl$, "!StartContext BaseLineCal" call BaseLineCalContextToFile fHndl$ print #fHndl$, "!EndContext" end if if contextTypes(constGraphData)=1 then contextCount=contextCount+1 print #fHndl$, "!StartContext GraphData" 'ver115-1d call GraphDataContextToFile fHndl$ 'ver115-1d print #fHndl$, "!EndContext" end if if contextTypes(constModeData)=1 then 'ver115-1d added type 8 contextCount=contextCount+1 'Print the StartContext line only if preceded by some other context if contextCount>1 then print #fHndl$, "!StartContext DataTable" call CopyModeDataToVNAData 0 'ver116-4j call touchWriteOnePortParameters fHndl$, msaMode$ 'Write data to file if contextCount>1 then print #fHndl$, "!EndContext" end if close #fHndl$ SaveContextFile$="" end function sub menuSavePreferenceFile 'Save current preferences file to user-specified location. filter$="Text files" + chr$(0) + "*.txt" + chr$(0) + "All files" + chr$(0) + "*.*" 'ver115-6b defaultExt$="txt" initialDir$=DefaultDir$+"\MSA_Info\MSA_Prefs\" initialFile$="Prefs.txt" fileName$=uSaveFileDialog$(filter$, defaultExt$, initialDir$, initialFile$, "Save Preference File") if fileName$<>"" then call SavePreferenceFile fileName$ 'blank means cancelled end sub sub SavePreferenceFile fName$ 'Save current preferences file to fName$ 'Find out whether we have the MSA_Prefs folder; if not, create it files DefaultDir$+"\MSA_Info", "", fileInfo$() numFolders=val(fileInfo$(0,1)) haveFolder=0 for i=1 to numFolders if fileInfo$(i,1)="MSA_Prefs" then haveFolder=1: exit for next i if haveFolder=0 then 'Create MSA_Prefs folder if 0<>mkDir(DefaultDir$+"\MSA_Info\MSA_Prefs") then notice "Cannot create preference file." end if for i=0 to 30 : contextTypes(i)=0: next i contextTypes(constGrid)=1 'Grid contextTypes(constTrace)=1 'Trace contextTypes(constSweep)=1 'Sweep errMsg$=SaveContextFile$(fName$) if errMsg$<>"" then notice "Unable to save preferences." end sub [menuLoadPreferenceFile] 'Load user-specified preferences file. if haltsweep=1 then gosub [FinishSweeping] 'ver115-1e filter$="Text files" + chr$(0) + "*.txt" + chr$(0) + _ "All files" + chr$(0) + "*.*" 'ver115-6b defaultExt$="txt" initialDir$=DefaultDir$+"\MSA_Info\MSA_Prefs\" initialFile$="Prefs.txt" restoreFileName$=uOpenFileDialog$(filter$, defaultExt$, initialDir$, initialFile$, _ "Load Preference File") 'ver115-8c if restoreFileName$<>"" then gosub [LoadPreferenceFile] 'Blank means cancelled wait [LoadPreferenceFile] 'Load preference file in restoreFileName$; set restoreErr$ with any error message 'ver114-3f if haltsweep=1 then gosub [FinishSweeping] 'Finish current sweep cleanly restoreFileHndl$=OpenContextFile$(restoreFileName$,"In") if restoreFileHndl$="" then restoreErr$="Context file failed to open: ";restoreFileName$ : return call RememberState 'So we can see what changed 'ver115-8c gosub [LoadBasicContextsFromFile] 'Load preferences from restoreFileHndl$ close #restoreFileHndl$ if restoreErr$<>"" and doingInitialization=0 then notice "Error loading preference file: ";restoreErr$ gosub [DetectFullChanges] 'ver115-8c if continueCode=3 and doingInitialization=0 then gosub [PartialRestart] 'implement changes ver115-3c return '===================END CONTEXTS MODULE========================= '================================START DEBUG MODULE======================================= 'This module has routines to save/reload info to allow one person to partially recreate 'the state of another person's MSA to help in debugging. Saved context files can be reloaded, and 'the copied MSA_Info can be examined or used as needed. [DebugSaveData] 'Menu item to save debug data 'Data is stored in a folder called "xxDebug" in the default directory if haltsweep=1 then gosub [FinishSweeping] call DebugSaveData wait sub DebugSaveData folder$=DefaultDir$;"\xxDebug" files DefaultDir$, "", fileInfo$() 'get directory list numFolders=val(fileInfo$(0,1)) folderExists=0 for i=1 to numFolders 'search list for xxDebug if fileInfo$(i,1)="xxDebug" then folderExists=1 : exit for next i 'Create folder if it was not found. If it was found, we will overwrite its contents if folderExists=0 then if 0<>mkdir(folder$) then notice "Cannot create Debug folder." : exit sub end if call DebugSaveArrays folder$ 'Save various debug arrays as individual files 'Save preferences file for i=0 to 30 : contextTypes(i)=0: next i contextTypes(constGrid)=1 'Grid contextTypes(constTrace)=1 'Trace contextTypes(constSweep)=1 'Sweep errMsg$=SaveContextFile$(folder$;"\Prefs.txt") if errMsg$<>"" then notice "Unable to save preferences." 'Save configuration file open folder$;"\config.txt" for output as #configOut print #configOut, configHardwareContext$() 'ver114-3h close #configOut 'call DebugCopyFile DefaultDir$;"\MSA_Info\config.txt", DefaultDir$;"\xxDebug\config.txt" call DebugCopyDirectory DefaultDir$, "MSA_Info", DefaultDir$;"\xxDebug" end sub sub DebugCopyFile source$, dest$ open source$ for input as #copySource open dest$ for output as #copyDest print #copyDest, input$(#copySource, lof(#copySource)); close #copySource close #copyDest end sub sub DebugCopyDirectory sourcePath$, dirName$, destPath$ 'Copy the directory in path sourcePath$ whose name is dirName$, into the path destPath$ 'These path names do not end with slashes. dest$=destPath$;"\";dirName$ isErr=mkdir(dest$) source$=sourcePath$;"\";dirName$ files source$, "*", fileInfo$() 'get list of all files and directories 'copy the files numFiles=val(fileInfo$(0,0)) '0,0 has the number of files, which are listed first, from 1,x to numFiles,x numFolders=val(fileInfo$(0,1)) '0,1 has the number of folders, which are listd next, from numFiles+1,x to numFiles+numFolders,x for i=1 to numFiles fileName$=fileInfo$(i,0) 'file name (no path info) is in (i,0) call DebugCopyFile source$;"\";fileName$, dest$;"\";fileName$ 'copy file from source to dest next i 'We want to recursively copy all folders in this folder. However, because LB makes arrays global, 'each recursive call would use the same copy of fileInfo$(). So we save the names of the folders in local variables. 'This means there will be a max number of allowed folders, but that works for us 'folder name (no path info) is in (i,1) if numFolders>0 then folder1$=fileInfo$(numFiles+1,1) if numFolders>1 then folder2$=fileInfo$(numFiles+2,1) if numFolders>2 then folder3$=fileInfo$(numFiles+3,1) if numFolders>3 then folder4$=fileInfo$(numFiles+4,1) if numFolders>4 then folder5$=fileInfo$(numFiles+5,1) if numFolders>5 then folder6$=fileInfo$(numFiles+6,1) if numFolders>6 then folder7$=fileInfo$(numFiles+7,1) if numFolders>7 then folder8$=fileInfo$(numFiles+8,1) if numFolders>8 then folder9$=fileInfo$(numFiles+9,1) for i=1 to numFolders select i case 1 folderName$=folder1$ case 2 folderName$=folder2$ case 3 folderName$=folder3$ case 4 folderName$=folder4$ case 5 folderName$=folder5$ case 6 folderName$=folder6$ case 7 folderName$=folder7$ case 8 folderName$=folder8$ case 9 folderName$=folder9$ case else notice "Too many folders to copy." : exit sub end select call DebugCopyDirectory source$, folderName$, dest$ 'Copy the contents of the source directory next i end sub [DebugLoadData] 'Menu item to load debug data if haltsweep=1 then gosub [FinishSweeping] filter$="Text files" + chr$(0) + "*.txt" + chr$(0) + _ "All files" + chr$(0) + "*.*" 'ver115-6b defaultExt$="txt" initialDir$=DefaultDir$;"\xxDebug\" initialFile$="Prefs.txt" fName$=uOpenFileDialog$(filter$, defaultExt$, initialDir$, initialFile$, _ "Load Debug Files--Select Any File in the Debug Folder") if fName$="" then wait 'Blank means cancelled for i=len(fName$) to 1 step -1 'Delete the actual file name so we just have the directory info thisChar$=Right$(fName$,1) fName$=Left$(fName$, i-1) 'Drop last character if thisChar$="\" or thisChar$="/" then exit for 'Done when we find the separator character next i 'fName$ now has the directory name call mClearMarkers 'Load the preference file restoreFileName$=fName$;"\Prefs.txt" 'Load preference file in restoreFileName$; set restoreErr$ with any error message gosub [LoadPreferenceFile] 'ver115-8c 'Data is loaded from a folder called "xxDebug" in the default directory 'We load the array info. The configuration info 'is not used unless it is moved to the proper folder before startup. 'This takes a long time because of the huge number of data items in the hardware arrays. cursor hourglass isErr=DebugLoadArrays(fName$) cursor normal if isErr then notice "Loading Debug Info was Unsuccessful." : wait 'We must now recreate the graph from datatable(). We proceed as though we just gathered the data 'point by point for thisstep=0 to globalSteps if msaMode$<>"SA" then gosub [ProcessDataArrays] 'fill S21DataArray and/or ReflectArray ver115-8b gosub [PlotDataToScreen] 'Plot this point the same as though we just gathered it. next thisstep #graphBox$, "flush" beep wait sub DebugSaveArrays folder$ 'Save Debug arrays as separate files in folder whose complete path is in folder$ call DebugArrayToFile "magarray", folder$ call DebugArrayToFile "phaarray", folder$ call DebugArrayToFile "PLL1array", folder$ call DebugArrayToFile "PLL3array", folder$ call DebugArrayToFile "DDS1array", folder$ call DebugArrayToFile "DDS3array", folder$ call DebugArrayToFile "cmdallarray", folder$ call DebugArrayToFile "freqcoeff", folder$ call DebugArrayToFile "magcoeff", folder$ call DebugArrayToFile "linecal", folder$ call DebugArrayToFile "datatable", folder$ end sub function DebugLoadArrays(folder$) 'Save Debug arrays as separate files in folder whose complete path is in folder$ 'return 1 if error; otherwise 0 message$="Loading..." call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("magarray", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("phaarray", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("PLL1array", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("PLL3array", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("DDS1array", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("DDS3array", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("cmdallarray", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("freqcoeff", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("magcoeff", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("linecal", folder$) if isErr then LoadDebugArrays=1 : exit function call PrintMessage : message$=message$;".." isErr=DebugGetArrayFromFile("datatable", folder$) if isErr then LoadDebugArrays=1 : exit function message$="" : call PrintMessage end function function DebugArrayAsTextArray(arrayID$) 'Put data points into uTextPointArray$, with header info 'We save the full datatable() even if data for some steps has not been collected yet. 'return number of lines placed into uTextPointArray$ 'First line is "!Array=Name", where Name is arrayID$ 'Then comes each array entry as its own string uTextPointArray$(1)="!Name=";arrayID$ if arrayID$="magcoeff" then limit=100 else limit=globalSteps 'Do globalSteps steps, but only 100 for magcoeff for i=0 to limit thisLine$="" aSpace$="" 'starts out blank for each line select arrayID$ case "magarray" for item=0 to 3 thisLine$=thisLine$;aSpace$;magarray(i, item) : aSpace$=" " next item case "phaarray" for item=0 to 4 thisLine$=thisLine$;aSpace$;phaarray(i, item) : aSpace$=" " next item case "PLL1array" for item=0 to 48 thisLine$=thisLine$;aSpace$;PLL1array(i, item) : aSpace$=" " next item case "PLL3array" for item=0 to 48 thisLine$=thisLine$;aSpace$;PLL3array(i, item) : aSpace$=" " next item case "DDS1array" for item=0 to 46 thisLine$=thisLine$;aSpace$;DDS1array(i, item) : aSpace$=" " next item case "DDS3array" for item=0 to 46 thisLine$=thisLine$;aSpace$;DDS3array(i, item) : aSpace$=" " next item case "cmdallarray" for item=0 to 39 thisLine$=thisLine$;aSpace$;cmdallarray(i, item) : aSpace$=" " next item case "freqcoeff" for item=0 to 3 thisLine$=thisLine$;aSpace$;calFreqCoeffTable(i,item) : aSpace$=" " next item case "magcoeff" for item=0 to 7 thisLine$=thisLine$;aSpace$;calMagCoeffTable(i, item) : aSpace$=" " next item case "linecal" for item=0 to 2 thisLine$=thisLine$;aSpace$;lineCalArray(i, item) : aSpace$=" " next item case "datatable" for item=0 to 3 thisLine$=thisLine$;aSpace$;datatable(i, item) : aSpace$=" " next item case else notice "Invalid Debug Array Name" : exit for end select uTextPointArray$(i+2)=thisLine$ next i DebugArrayAsTextArray=limit+2 'Number of lines end function sub DebugArrayToFile arrayID$,folder$ 'save array to a file in folder$ whose complete path is in folder$ 'We name the file per arrayID$ and override any existing file nLines=DebugArrayAsTextArray(arrayID$) 'Assemble strings into uTextPointArray$ fHndl$=DebugOpenOutputFile$(arrayID$, folder$) if isErr then notice "Could not save Debug file ";arrayID$ : exit sub for i=1 to nLines thisLine$=uTextPointArray$(i) print #fHndl$, thisLine$ 'output each line next i close #fHndl$ exit sub end sub function DebugOpenInputFile$(arrayID$,folder$) 'Open file; return handle or blank if not successful fName$=folder$;"\";arrayID$;".txt" On Error goto [fileError] open fName$ for input as #DebugArrayFile DebugOpenInputFile$="#DebugArrayFile" exit function [fileError] notice "Could not open file ";arrayID$ DebugOpenInputFile$="" 'error end function function DebugOpenOutputFile$(arrayID$,folder$) 'Open file; return handle or blank if not successful fName$=folder$;"\";arrayID$;".txt" On Error goto [fileError] open fName$ for output as #DebugArrayFile DebugOpenOutputFile$="#DebugArrayFile" exit function [fileError] notice "Could not open file ";arrayID$ DebugOpenOutputFile$="" 'error end function function DebugGetArrayFromFile(arrayID$,folder$) 'get points from file; return 1 if error; otherwise 0 'Restore specified array 'We will open file, read and close. File name is the same as arrayID$; file is in folder$ fHndl$=DebugOpenInputFile$(arrayID$, folder$) if isErr then DebugGetArrayFromFile=1 : exit function isErr=uArrayFromFile(fHndl$,100) 'Get data, determine number of items from first line if isErr then DebugGetArrayFromFile=1 : close #fHndl$ : exit function 'Move the data from uWorkArray to gGraphVal if uWorkNumPoints>gMaxNumPoints() then call ResizeArrays uWorkNumPoints 'Make sure we have enough room for i=1 to uWorkNumPoints select arrayID$ case "magarray" for item=0 to 3 magarray(i-1,item)=uWorkArray(i, item) next item case "phaarray" for item=0 to 4 phaarray(i-1,item)=uWorkArray(i, item) next item case "PLL1array" for item=0 to 48 PLL1array(i-1,item)=uWorkArray(i, item) next item case "PLL3array" for item=0 to 48 PLL3array(i-1,item)=uWorkArray(i, item) next item case "DDS1array" for item=0 to 46 DDS1array(i-1,item)=uWorkArray(i, item) next item case "DDS3array" for item=0 to 46 DDS3array(i-1,item)=uWorkArray(i, item) next item case "cmdallarray" for item=0 to 39 cmdallarray(i-1,item)=uWorkArray(i, item) next item case "freqcoeff" for item=0 to 3 calFreqCoeffTable(i-1,item)=uWorkArray(i, item) next item case "magcoeff" for item=0 to 7 calMagCoeffTable(i-1,item)=uWorkArray(i, item) next item case "linecal" for item=0 to 2 lineCalArray(i-1,item)=uWorkArray(i, item) next item case "datatable" for item=0 to 3 datatable(i-1,item)=uWorkArray(i, item) next item case else notice "Invalid Debug Array Name" : exit for end select next i DebugGetArrayFromFile=0 'no error close #fHndl$ exit function end function '==================================END DEBUG MODULE======================================= ' 'ver114-5p added Interpolation Module; ver114-5q moved it to preced config module '====================START INTERPOLATION ROUTINES========================== 'The interpolation module handles linear and cubic interpolation, and deals with the fact 'that LB does not allow arrays as arguments. Three arrays are created: intSrc() contains the 'original data, which we assume for the moment is freq, mag and phase, in ascending order of freq. 'intDest() contains only frequency, and needs its mag and phase determined by interpolation. If 'cubic interpolation is used, the user calls intCreateCubicCoeffTable which fills the third array, 'intSrcCoeff(), with the eight coefficients (4 for mag, 4 for phase) that are needed to apply cubic 'interpolation. 'The user fills intSrc and intDest, calls intCreateCubicCoeffTable if necessary, and then calls 'intSrcToDest, which performs the interpolation. The user then copies the data (rounding as desired) 'from intDest() to the array where the data really belongs. The data in these arrays should not be 'relied on long-term, because another routine may make use of them. 'Angles must be in the range -180 to 180 degrees to interpolate properly. Returned angles may be 'outside that range and must be normalized as desired. 'Variables for interpolation routines dim intSrc(1000, 2), intDest(1000,2) 'Data for InterpolateTableToTable (freq, real, imag); first index runs from 1 dim intSrcCoeff(1000,7) 'Cubic coefficents (A,B,C,D) for interpolating real and imag parts from intSrc() global intSrcPoints, intDestPoints, intMaxPoints '------------------Data access routines-------------------- 'Even though our data is global, the user should access data only through these routines sub intSetMaxNumPoints maxPoints if maxPoints+5<=intMaxPoints then exit sub 'ver115-2d 'so we never shrink or waste time intMaxPoints=maxPoints+5 'ver115-2d redim intSrc(intMaxPoints,2) : redim intDest(intMaxPoints,2) redim intSrcCoeff(intMaxPoints,7) end sub sub intReset 'Reset arrays and variables for i=0 to intMaxPoints 'we don't use zero for first index, but clear it anyway intSrc(i,0)=0:intSrc(i,1)=0:intSrc(i,2)=0 intDest(i,0)=0:intDest(i,1)=0:intDest(i,2)=0 next i intSrcPoints=0 intDestPoints=0 end sub sub intClearSrc 'Set source table to zero entries intSrcPoints=0 end sub sub intClearDest 'Set destination table to zero entries intDestPoints=0 end sub sub intAddSrcEntry f, r, im 'Add entry to end of source table 'f=frequency, r=real part, im=imaginary part intSrcPoints=intSrcPoints+1 intSrc(intSrcPoints,0)=f intSrc(intSrcPoints,1)=r intSrc(intSrcPoints,2)=im end sub sub intAddDestFreq f 'Add new frequency to end of destination table intDestPoints=intDestPoints+1 intDest(intDestPoints,0)=f end sub sub intGetSrc num, byRef f, byRef r, byRef im 'Get values for source entry number num (1...) 'f=frequency, r=real part, im=imaginary part f=intSrc(num,0) r=intSrc(num,1) im=intSrc(num,2) end sub function intSrcFreq(num) 'Get frequency for source entry number num (1...) intSrcFreq=intSrc(num,0) end function sub intGetDest num, byRef f, byRef r, byRef im 'Get values for dest entry number num (1...) 'f=frequency, r=real part, im=imaginary part f=intDest(num,0) r=intDest(num,1) im=intDest(num,2) end sub function intDestFreq(num) 'Get frequency for dest entry number num (1...) intDestFreq=intDest(num,0) end function function intMaxEntries() 'Get maximum number of entries intMaxEntries=intMaxPoints end function function intSrcEntries() 'Get number of steps in source table intSrcEntries=intSrcPoints end function function intDestEntries() 'Get number of steps in destination table intDestEntries=intDestPoints end function '------------------End Data access routines-------------------- '------------------Start Interpolation routines-------------------- function intLinearInterpolateDegrees(fract, v1, v2, angleMin, angleMax) 'linearly interpolate between phase v1 and v2 based on fract 'fract is a proportion (0...1) representing how far from v1 to v2 we want to go. 'angleMin and angleMax are the min and max allowable values for angles; if the total range is at 'least 360 degrees, angleMin is actually not allowed. 'The complication with phase is that it wraps around. If the distance from v1 to v2 is shorter via wrap-around, 'we will assume that wrap-around occurred. 'This works when the real phase shift from point to point is normally small. dif=v2-v1 : if dif<0 then absDif=0-dif else absDif=dif if absDif>180 then 'change must exceed 180 degrees before we consider wrap-around 'If allowed range is 360 or less, we have wrap, which changes the angle difference by 360 range=angleMax-angleMin if range<=360 then if dif>0 then dif=dif-360 else dif=dif+360 else 'Unusual case with allowed range over 360 degrees range=360*int((angleMax-angleMin)/360) 'make range a multiple of 360 if absDif>range/2 then 'Assume wrap if change exceeds half the range if dif>0 then dif=dif-range else dif=dif+range 'change difference by range, which makes dif magnitude smaller end if end if end if res=v1+fract*dif 'At this point, interp may be outside the bounds of angleMin and angleMax if res>angleMin and res<=angleMax then intLinearInterpolateDegrees=res : exit function if res=angleMin then 'disallow angleMin value if range is at least 360 degrees if angleMax-angleMin>=360 then res=res+360 intLinearInterpolateDegrees=res : exit function end if 'Here res is below angleMin or above angleMax, so it should wrap around if range<=360 then delta=360 else delta=range if res=angleMin and wrappedRes<=angleMax then intLinearInterpolateDegrees=wrappedRes _ else intLinearInterpolateDegrees=res 'Use wrapped value if wrap put it in allowed range (which it will if range>=360) end function sub intLinearInterpolation freq, isPolar, f1,R1,I1,f2,R2,I2,byref p1, byref p2 ' linearly interpolate between points 1 and 2 (each a frequency with complex value) ' freq=frequency for which value is to be determined ' This function will return the interpolated value for the real and imaginary parts ' in p1 and p2, respectively 'Interpolated angles may end up outside the original bounds of the angles, if wrap-around occurred, 'so the user should put them back in bounds. They will be at most 360 degress out-out-bounds. fSpan=f2-f1 'If we are interpolating between identical entries, just use data from the first if fSpan=0 then p1=R1:p2=I1:exit sub ratio=(freq-f1)/fSpan 'Interpolation ratio p1=R1+ratio*(R2-R1) dif=I2-I1 if isPolar=1 then 'We are interpolating polar data, so what we are labeling as the imaginary part 'is really the angle in degrees. if dif<0 then absDif=0-dif else absDif=dif if absDif<=180 then p2=I1+ratio*dif else 'Apparent shift is more than 180 degrees, which means wrap occurred between v1 and v2. 'We shift v1 360 degrees towards v2 which reduces the magnitude of dif by 360. if dif>0 then dif=dif-360 else dif=dif+360 p2=I1+ratio*dif 'At this point, p2 may be outside the bounds of the scaling of v1 and v2. The user must 'adjust the result end if else p2=I1+ratio*dif end if end sub sub intCreateCubicCoeffTable doPart1, doPart2, isAngle, favorFlat, doingPhaseCorrection 'Create table of cubic coefficients intSrc() in intCubicCoeff ver116-1b 'We separately calculate for the specified parts of srcInt. If isAngle=1 then part2 is an angle. 'We pass favorFlat on to intCalcCubicCoeff, except if part2 is an angle we pass on favorFlat=1 for that part. 'Each entry of the cubic 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. 'Angles must be in the range -180<=angle<=180 'If doingPhaseCorrection is 1, we are interpolating the phase correction factor, 'and want to force the correction to 180 if this point phase correction is >179 or <-179. Extreme 'correction values are used to indicate that phase at that level is unreliable, so the table of 'phase corrections may have values of 180 for all ADC readings at and below a certain level. ver116-1b for i=1 to intSrcPoints if doPart1=0 then A=0 : B=0 : C=0 : D=0 else partNum=1 : partIsAngle=0 call intCalcCubicCoeff i,partNum,partIsAngle,favorFlat,A,B,C,D end if intSrcCoeff(i,0)=A :intSrcCoeff(i,1)=B intSrcCoeff(i,2)=C :intSrcCoeff(i,3)=D forcedTo180=0 if doingPhaseCorrection=1 then 'ver116-1b 'If this point is 180, force calculation to 180 checkPhase=intSrc(i,2) if checkPhase>179 or checkPhase<-179 then 'This point is 180; set coefficients so phase correction will calculate to 180 A=180 : B=0 : C=0 : D=0 forcedTo180=1 'Flag that we need no more calculation at this point end if if forcedTo180=0 then 'this point is not 180 but one of prior two points is, then treat the 180 value 'as being the same as this point. Note we may alter intSrc, but that is just a temporary 'array used only for these interpolations. if i>1 then checkPhase=intSrc(i-1,2) if checkPhase>179 or checkPhase<-179 then intSrc(i-1,2)=intSrc(i,2) end if if i>2 then checkPhase=intSrc(i-2,2) if checkPhase>179 or checkPhase<-179 then intSrc(i-2,2)=intSrc(i,2) end if end if end if if doPart2=0 then A=0 : B=0 : C=0 : D=0 else if forcedTo180=0 then 'ver116-1b partNum=2 : partIsAngle=isAngle 'For an angle, specify to "favor flat", because 'we expect the phase not to approach vertical if isAngle then doFlat=1 else doFlat=favorFlat call intCalcCubicCoeff i,partNum,partIsAngle,doFlat,A,B,C,D end if end if intSrcCoeff(i,4)=A :intSrcCoeff(i,5)=B intSrcCoeff(i,6)=C :intSrcCoeff(i,7)=D next i end sub sub intCalcCubicCoeff 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 intSrc(). '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=intSrc(pointNum-2,0) : y0=intSrc(pointNum-2,partNum) if pointNum180 then 'large difference between points 2 and 3 if dif23>0 then dif23=dif23-360 else dif23=dif23+360 'reduce magnitude of difference by 360 end if end if if absDif12>180 then 'large difference between points 1 and 2 if dif12>0 then dif12=dif12-360 else dif12=dif12+360 'reduce magnitude of difference by 360 end if if pointNum>2 then 'true if we have point 0 if dif01<0 then absDif01=0-dif01 else absDif01=dif01 if absDif01>180 then 'large difference between points 0 and 1 if dif01>0 then dif01=dif01-360 else dif01=dif01+360 'reduce magnitude of difference by 360 end if 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=dif01/(x1-x0) 'slope from point 0 to point 1 end if else inSlope=dif12/(x2-x1) 'slope from point 1 to point 2 end if outSlope=dif12/(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 pointNum= targData. 'if ceil=-1, we will look up that position with binary search. Arrays must be in 'ascending order of x values (usually frequency). 'We use cubic interpolation using the cubic coefficients which must have been 'precalculated in intSrcCoeff() if ceil=-1 then ceil=intBinarySearch(targData) 'search intSrc() to get ceil 'ceil now is the first entry >= magdata, except that if no entry meets that test, 'ceil will be one past the end. v1=0 :v2=0 if ceil>intSrcPoints then 'Off top end;use values for final intSrc() entry v1=intSrc(intSrcPoints,1) v2=intSrc(intSrcPoints,2) exit sub end if if ceil=1 then 'Off bottom end;use mag and phase correction for smallest ADC entry v1=intSrc(1,1) v2=intSrc(1,2) exit sub end if 'Evaluate cubic at x=targData dif=targData-intSrc(ceil,0) A=intSrcCoeff(ceil,0) : B=intSrcCoeff(ceil,1) C=intSrcCoeff(ceil,2) : D=intSrcCoeff(ceil,3) v1 = A+dif*(B+dif*(C+dif*D)) if wantV2=1 then A=intSrcCoeff(ceil,4) : B=intSrcCoeff(ceil,5) C=intSrcCoeff(ceil,6) : D=intSrcCoeff(ceil,7) v2 = A+dif*(B+dif*(C+dif*D)) 'TO DO--caller must put phase in proper range end if end sub function intBinarySearch(searchVal) 'Perform search of intSrc() 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 'If searchVal is beyond the highest entry, we will return intSrcPoints+1 top=intSrcPoints bot=1 span=top-bot+1 while span>4 'Do preliminary search to narrow the search area halfSpan=int(span/2) mid=bot+halfSpan thisVal=intSrc(mid,0) if thisVal=searchVal then intBinarySearch=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 thisVal=intSrc(ceil,0) if thisVal>=searchVal then intBinarySearch=ceil : exit function ceil=ceil+1 : if ceil>intSrcPoints then intBinarySearch=ceil : exit function thisVal=intSrc(ceil,0) if thisVal>=searchVal then intBinarySearch=ceil : exit function ceil=ceil+1 : if ceil>intSrcPoints then intBinarySearch=ceil : exit function thisVal=intSrc(ceil,0) if thisVal>=searchVal then intBinarySearch=ceil : exit function intBinarySearch=ceil+1 'searchVal is off the top of the table end function sub intSrcToDest isPolar, interpMode, params 'Creates a table of frequency vs. complex numbers by interpolating from another table. 'isPolar=1 if data is in polar form; otherwise 0 'interpMode=0 for linear interpolation; interpMode=1 for cubic interpolation 'params=1 means process real part only; params=2 means imag only; params=3 means both parts 'This is used to create the tables used for calibration. We may have measured data for the 'calibration standards, which may not be at the specific frequencies needed. We may also have 'already calculated the OSL coefficients, but not at the current frequency points. This is 'used to convert such data into data at the exact frequencies of the current scan. 'Since LB does not allow arrays as arguments, this has to be done with two fixed arrays. 'The original array is intSrc(point, data); the final is intDest(point, data), 'where point is the index for the entry number (0 is not used) and data is the index for 'the table data, which consists of frequency (0), real (1) and imaginary (2). (The actual 'labels "point" and "data" are not used.) 'intDest must be pre-filled with the desired frequencies, and intDestSteps must contain 'the number of frequency entries in intDest. 'intSrcSteps must contain the number of entries in intSrc (it's actually the number of points, not steps). 'Everything is written in terms of the data being real and imaginary, but it could instead 'be magnitude and angle. Different results are obtained using the different formats; the 'difference is small if the changes in the data from step to step are small, as they normally 'should be. The complication of interpolating in polar format is that the angle wraps around 'at +/- 180 degrees. If interpolating half way between -178 and +178, we don't want to get 0. 'Therefore, if isPolar=1, if the angle difference between two successive points exceeds 180, we 'assume a wrap-around occurred. 'For cubic interpolation, the cubic coefficient table must be up to date. 'Any angles we actually interpolate will be put into in the range -180srcF1 then exit for currDestPoint=i intDest(i,1)=intSrc(1,1) 'Directly transfer value from first entry intDest(i,2)=intSrc(1,2) next i if currDestPoint=intDestPoints then exit sub 'We have processed all points in intDest() ver115-4i currDestPoint=currDestPoint+1 'The next intDest() point to process 'As long as we are within the bounds of intSrc, 'interpolate to get the cal data for each step frequency. ceil=1 'This will become the point number of the first intSrc() freq 'greater than or equal to the then current intDest() frequency. for i=currDestPoint to intDestPoints destF=intDest(i,0) 'current point frequency 'Move through intSrc() until we hit a frequency >= this intDest() frequency. while destF>intSrc(ceil,0) ceil=ceil+1 'move to next point in intSrc() if ceil>intSrcPoints then exit while 'ran off end of source table wend if ceil>intSrcPoints then exit for 'ran off end 'Here ceil is the first baseLine step with a frequency>= our target step freq. 'So we interpolate between points ceil-1 and ceil. srcF1=intSrc(ceil-1,0) 'low entry in src table : freq, mag and phase srcMag1=intSrc(ceil-1,1) srcPhase1=intSrc(ceil-1,2) 'Note this may actually be imaginary part, not phase srcF2=intSrc(ceil,0) 'high entry in src table : freq, mag and phase srcMag2=intSrc(ceil,1) srcPhase2=intSrc(ceil,2) if srcF2=destF then 'If exact frequency match, just copy source data ver115-2d v1=srcMag2 : v2=srcPhase2 else 'Do the interpolation if interpMode=0 then call intLinearInterpolation destF, isPolar, srcF1, srcMag1, srcPhase1, srcF2, srcMag2, srcPhase2,v1, v2 else wantV2=1 call intCubicInterpolation destF, ceil, wantV2, v1, v2 'find v1, v2 by cubic interpolation end if end if currDestPoint=i 'Record that we have this step taken care of intDest(i,1)=v1 'Enter results in intDest; x value is already there if isPolar then if v2>180 then v2=v2-360 else if v2<=-180 then v2=v2+360 'put into range -180"" 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 [configDoNothing] 'ver116-1b wait [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.L4,"CYAN items and Auto Switch checkboxes generally must be customized.", helpLeft, helpTop+45, 350,30 'ver114-3h 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, "font ms_sans_serif 9" 'ver116-4m 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 maxpdmoutout 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 maxpdmoutout 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. ver116-4s deleted some commented-out provisions if appxLO2<=100 or appxLO2>3000 then _ configDataError$="Invalid LO2 freq." : exit function if appxLO2<>PLL2phasefreq*int(appxLO2/PLL2phasefreq) then _ configDataError$="LO2 is not a multiple of PLL2phasefreq." : exit function end function '@configAdjustDisplayedItems sub configAdjustDisplayedItems 'Adjust displayed items to reflect state of TG and VNA if configDisplayHasTG then '#config.SG, "!show" 'delver114-5i '#config.TGoff, "!show" 'delver114-5i #config.PLL3type, "show" #config.PLL3pol, "show" #config.PLL3mode, "show" #config.PLL3Ref, "!show" #config.DDS3freq, "!show" #config.DDS3bw, "!show" #config.TG, "Delete TG" #config.TGtop, "show" #config.TGTopLabel, "!show" '#config.TGOffLabel, "!show" 'delver114-5i '#config.SGLabel, "!show" 'delver114-5i #config.DDS3label, "!show" #config.PLL3label, "!show" '#config.SGLabel, "!show" 'delver114-5i '#config.TGOffLabel, "!show" 'delver114-5i else '#config.SG, "!hide" 'delver114-5i '#config.TGoff, "!hide" 'delver114-5i #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" 'delver114-5i #config.TGTopLabel, "!hide" '#config.SGLabel, "!hide" 'delver114-5i #config.DDS3label, "!hide" #config.PLL3label, "!hide" '#config.SGLabel, "!hide" 'delver114-5i '#config.TGOffLabel, "!hide" 'delver114-5i 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 function configPLLlabel$(PLL) 'ver116-4k s$=str$(PLL) if PLL=2326 then s$=s$+",4118" 'code 2326 is usef for both LMX2326 and ADF4118 if PLL=4112 then s$=s$+",4113" 'code 4112 is used for both 4112 and 4113 configPLLlabel$=s$ end function function configPLLnumber(PLL$) 'ver116-4k pos=instr(PLL$,",") if pos=0 then configPLLnumber=val(PLL$) : exit function 'single number 'For multiple numbers, such as 4112,4113 and 2316,4118, use only the first one configPLLnumber=val(Left$(PLL$,pos-1)) 'everything to right of comma end function sub configDisplayData 'Enter data from MSA variables into window #config.PLL1type, "select "; configPLLlabel$(PLL1) 'ver116-4k #config.PLL2type, "select "; configPLLlabel$(PLL2) 'ver116-4k #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 'ver116-1b added switches if switchHasRBW then #config.switchRBW, "set" else #config.switchRBW, "reset" if switchHasVideo then #config.switchVideo, "set" else #config.switchVideo, "reset" if switchHasBand then #config.switchBand, "set" else #config.switchBand, "reset" if switchHasTR then #config.switchTR, "set" else #config.switchTR, "reset" if switchHasFR then #config.switchFR, "set" else #config.switchFR, "reset" 'ver116-1b added video filter caps #config.FiltWideMag, videoFilterCaps(1,0) : #config.FiltWidePhase, videoFilterCaps(1,1) #config.FiltMidMag, videoFilterCaps(2,0) : #config.FiltMidPhase, videoFilterCaps(2,1) #config.FiltNarrowMag, videoFilterCaps(3,0) : #config.FiltNarrowPhase, videoFilterCaps(3,1) #config.FiltXNarrowMag, videoFilterCaps(4,0) : #config.FiltXNarrowPhase, videoFilterCaps(4,1) 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 "; configPLLlabel$(PLL3) 'ver116-4k #config.PLL3pol, "select ";configPLLpol$(PLL3phasepolarity) #config.PLL3Ref, PLL3phasefreq #config.PLL3mode, "select ";configPLLmodes$(PLL1mode) #config.DDS3freq, appxdds3 #config.DDS3bw, dds3filbw '#config.SG, sgpreset 'delver114-3h '#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$" : PLL1=configPLLnumber(PLL1$) 'ver116-4k #config.PLL2type, "selection? PLL2$" : PLL2=configPLLnumber(PLL2$) 'ver116-4k #config.PLL3type, "selection? PLL3$" : PLL3=configPLLnumber(PLL3$) 'ver116-4k #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.PDM, "!contents? maxpdmout" #config.Inv, "!contents? invdeg" 'ver116-1b added automated switches #config.switchRBW, "value? switchVal$" if switchVal$="set" then switchHasRBW=1 else switchHasRBW=0 #config.switchVideo, "value? switchVal$" if switchVal$="set" then switchHasVideo=1 else switchHasVideo=0 #config.switchBand, "value? switchVal$" if switchVal$="set" then switchHasBand=1 else switchHasBand=0 #config.switchTR, "value? switchVal$" if switchVal$="set" then switchHasTR=1 else switchHasTR=0 #config.switchFR, "value? switchVal$" if switchVal$="set" then switchHasFR=1 else switchHasFR=0 'ver116-1b modified video filter caps #config.FiltWideMag, "!contents? vm$" : #config.FiltWidePhase, "!contents? vp$" magCap=val(vm$) : phaseCap=val(vp$) 'Must have wide filter, so if cap is zero make it the default value if magCap<=0 then magCap=0.002 if phaseCap<=0 then phaseCap=0.011 videoFilterNames$(1)="Wide" videoFilterCaps(1,0)=magCap : videoFilterCaps(1,1)=phaseCap #config.FiltMidMag, "!contents? vm$" : #config.FiltMidPhase, "!contents? vp$" magCap=val(vm$) : phaseCap=val(vp$) if magCap<=0 or phaseCap<=0 then videoFilterNames$(2)="" else videoFilterNames$(2)="Mid" videoFilterCaps(2,0)=magCap : videoFilterCaps(2,1)=phaseCap #config.FiltNarrowMag, "!contents? vm$" : #config.FiltNarrowPhase, "!contents? vp$" magCap=val(vm$) : phaseCap=val(vp$) if magCap<=0 or phaseCap<=0 then videoFilterNames$(3)="" else videoFilterNames$(3)="Narrow" videoFilterCaps(3,0)=magCap : videoFilterCaps(3,1)=phaseCap #config.FiltXNarrowMag, "!contents? vm$" : #config.FiltXNarrowPhase, "!contents? vp$" magCap=val(vm$) : phaseCap=val(vp$) if magCap<=0 or phaseCap<=0 then videoFilterNames$(4)="" else videoFilterNames$(4)="XNarrow" videoFilterCaps(4,0)=magCap : videoFilterCaps(4,1)=phaseCap #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 'Original control board can only handle the RBW switch. if cb=0 then switchHasVideo=0 : switchHasBand=0 : switchHasTR=0 : switchHasFR=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.1 'ver114-3h 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 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 'ver114-3h added configHardwareContext$ function configHardwareContext$() 'Return hardware context as string 'successive lines are separated by chr$(13) newLine$=chr$(13) s$="ConfigVersion=";using("##.##", configModuleVersion) for i=1 to MSANumFilters 'for each filter, print a line with frequency and bandwidth s$=s$;newLine$;"Filter=";str$(MSAFilters(i,0));" ";str$(MSAFilters(i,1)) next i s$=s$;newLine$;"LPT=&H";DecHex$(globalPort) 'save port as hexidecimal s$=s$;newLine$;"masterclock=";masterclock s$=s$;newLine$;"adconv=";adconv s$=s$;newLine$;"cb=";cb s$=s$;newLine$;"dds1parser=";dds1parser s$=s$;newLine$;"appxdds1=";appxdds1 s$=s$;newLine$;"dds1filbw=";dds1filbw s$=s$;newLine$;"PLL1=";PLL1 s$=s$;newLine$;"PLL1phasefreq=";PLL1phasefreq s$=s$;newLine$;"PLL1mode=";PLL1mode s$=s$;newLine$;"PLL1phasepolarity=";PLL1phasepolarity s$=s$;newLine$;"PLL2=";PLL2 s$=s$;newLine$;"appxLO2=";appxLO2 s$=s$;newLine$;"PLL2phasefreq=";PLL2phasefreq s$=s$;newLine$;"PLL2phasepolarity=";PLL2phasepolarity s$=s$;newLine$;"TGtop=";TGtop s$=s$;newLine$;"PLL3=";PLL3 s$=s$;newLine$;"appxdds3=";appxdds3 s$=s$;newLine$;"dds3filbw=";dds3filbw s$=s$;newLine$;"PLL3phasepolarity=";PLL3phasepolarity s$=s$;newLine$;"PLL3mode=";PLL3mode s$=s$;newLine$;"PLL3phasefreq=";PLL3phasefreq s$=s$;newLine$;"hasVNA=";hasVNA s$=s$;newLine$;"maxpdmout=";maxpdmout s$=s$;newLine$;"invdeg=";invdeg 'ver116-1b added videoFilterCaps for the capacitances of four possible filters 'List name, mag cap value and phase cap value 'Prior software used "VideoFilterCaps" which is now "VideoFilters" s$=s$;newLine$;"VideoFilters=";videoFilterNames$(1); ", "; videoFilterCaps(1,0);", ";videoFilterCaps(1,1); "; "; _ videoFilterNames$(2); ", "; videoFilterCaps(2,0);", ";videoFilterCaps(2,1); "; "; _ videoFilterNames$(3); ", "; videoFilterCaps(3,0);", ";videoFilterCaps(3,1); "; "; _ videoFilterNames$(4); ", "; videoFilterCaps(4,0);", ";videoFilterCaps(4,1) 'ver116-1b s$=s$;newLine$;"Switches=";switchHasRBW;", ";switchHasVideo;", ";switchHasBand;", ";switchHasTR;", ";switchHasFR 'ver116-1b added switches configHardwareContext$=s$ end function '@configSaveFile sub configSaveFile 'Save file from config variables open configFileFullName$ for output as #configOut print #configOut, configHardwareContext$() 'ver114-3h 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 configLoadData$=configReadFile$("#configIn") 'ver114-3h 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 adconv = 16 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 'video filter caps videoFilterCaps(1,0)=0.002 : videoFilterCaps(2,0)=0.2 : videoFilterCaps(3,0)=10 : videoFilterCaps(4,0)=100 'Video mag Filters ver116-1b videoFilterCaps(1,1)=0.011 : videoFilterCaps(2,1)=0.2 : videoFilterCaps(3,1)=2.2 : videoFilterCaps(4,1)=10 'Video phase filters ver116-4g videoFilterNames$(1)="Wide" : videoFilterNames$(2)="Mid" : videoFilterNames$(3)="Narrow" : videoFilterNames$(4)="XNarrow" 'names ver116-1b 'Automated switches. Assume has RBW but nothing else. switchHasRBW=1 : switchHasVideo=0 : switchHasBand=0 : switchHasTR=0 : switchHasFR=0 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 'delver114-3h ' offset = 0 end sub function configRestoreHardwareContext$(s$, byRef startPos) 'Restore Hardware Context from string 'Returns error message or "" 'Reads Hardware Context from s$, starting at startPos. Updates startPos to the beginning 'of the line following the last one we process, or one past end of string. Lines are separated 'by chr$(13). The last line we read is "EndContext", if it exists. 'For legacy reasons, we allow certain tags which we do not process. 'The data is read from a file already opened, whose handle is in configFile$. 'The data is in the following format: '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 sLen=len(s$) while startPos<=sLen tLine$=uGetLine$(s$, startPos) 'Get line and update startPos to next line tLine$=Trim$(tLine$) 'drop extra blanks startChar$=Left$(tLine$,1) 'first real character of line if startChar$<>"" then 'valid line if Upper$(Left$(tLine$, 10))="ENDCONTEXT" then exit while 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 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", "SWEEPWIDTH", "WATE", "GLITCHTIME" 'Legacy items ver114-3h case "ADCONV" adconv=val: if val<=0 then isErr=1 case "TOPREF", "BOTREF" 'Legacy items ver114-3h 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", "OFFSET" 'Legacy items ver114-3h 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 "VIDEOFILTERCAPS" 'ver114-5p; modver114-6b obsolete ver116-1b videoFilterCaps(1,0)=val(Word$(item$,1)) : videoFilterCaps(1,1)=videoFilterCaps(1,0) videoFilterCaps(2,0)=val(Word$(item$,2)) : videoFilterCaps(2,1)=videoFilterCaps(2,0) videoFilterCaps(3,0)=val(Word$(item$,3)) : videoFilterCaps(3,1)=videoFilterCaps(3,0) videoFilterNames$(4)="" 'no XNarrow filter in original version videoFilterCaps(4,0)=0 : videoFilterCaps(4,1)=0 case "VIDEOFILTERS" 'updated version of VideoFilterCaps, which is obsolete 'ver116-1b for fNum=1 to 4 v$=uExtractTextItem$(item$, ";") 'get video filter spec--name, mag cap, phase cap if v$="" then 'fewer than four filters listed; blank the rest for j=fNum to 4 videoFilterNames$(j)="" : videoFilterCaps(j,0)=0 : videoFilterCaps(j, 1)=0 next j exit for end if filtName$=Trim$(uExtractTextItem$(v$,",")) 'name is text up to comma isErr=uExtractNumericItems(2, v$, ",", v1, v2, v3) 'get cap values returns 1 if error if filtName$<>"" and filtName$<>"Wide" and filtName$<>"Mid" and _ filtName$<>"Narrow" and filtName$<>"XNarrow" then isErr=1 if isErr=1 then exit for videoFilterNames$(fNum)=filtName$ : videoFilterCaps(fNum,0)=v1 : videoFilterCaps(fNum, 1)=v2 next fNum case "SWITCHES" 'Automated switches ver116-1b isErr=uExtractNumericItems(3,item$, ",",v1, v2, v3) 'get first 3 if isErr=0 then isErr=uExtractNumericItems(2,item$, ",",v4, v5, v6) 'get final 2 if isErr=0 then switchHasRBW=v1 : switchHasVideo=v2 : switchHasBand=v3 : _ switchHasTR=v4 : switchHasFR=v5 case "ENDCONFIGFILE" 'This used to mark the end of the configuration file case else isErr=true end select if isErr=1 then configRestoreHardwareContext$="Error in: "; tLine$ 'inValid tag or data call configInitializeDefaults exit function end if end if wend 'go to next line configRestoreHardwareContext$="" 'no error end function 'ver114-3h revised configReadFile$ function configReadFile$(configFile$) 'Read data from already opened file 'Reads configuration data. Returns error message or "". 'The data is read from a file already opened, whose handle is in configFile$. newLine$=chr$(13) s$="" while EOF(#configFile$)=0 Line Input #configFile$, tLine$ 'Read one line s$=s$;newLine$;tLine$ 'append tLine$ wend startPos=1 configReadFile$=configRestoreHardwareContext$(s$, startPos) end function 'old configReadFile$ deleted by ver114-3h '@configValidCB function configValidCB(cb) 'Return 1 if cb is configValid; otherwise 0 select case cb case 0, 1, 2, 3 'USB:01-08-2010 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 '@================En