' TYPE          Automation
' LANGUAGE      VBScript
' DESCRIPTION   dScope Series III Automation script for computing and plotting user 
'				traces with mean/min/max at each point from range of user selected sweep traces.
' S/W Version	Written and tested with dScope Series III 1.40a 32bit on XP SP3 - no configurations supplied.
' REVISIONS	    First version 11 Feb 2011 IAH

' NOTES			- Only will work with sweep results because it makes use of the create trace from sweep method.
'				- May have issues with sensed sweeps if the number and position of points is not consistent
'				- Takes units and number of points etc from the first found sweep trace of selected type
'				- Determines trace units and, for log units does both linear and log averaging

' *** Declarations ***
Option Explicit ' Must declare all variables before using them
Dim bRet, iRet		'Boolean and integer returns from functions
Dim i, j            'Integers for counting loops
Dim max()     		'array to hold max values - agnostic to units as these are handled by dScope
Dim min()     		'array to hold max values
Dim mean()     		'array to hold mean values
Dim logmean()		'array to hold logmean values (arithmetic mean of log units / geometric mean of lin units)	
Dim xVal()			'array to hold x axis values
Dim dYVal			'Current Y value
Dim iPoints			'Number of points in the trace
Dim iCount			'Count of number of traces	
Dim sTraceID        'ID of current trace
Dim iMaxTraceID, iMinTraceID, iMeanTraceID, iLogMeanTraceID	'IDs of user traces for results
Dim bMainOn			'True if main/first sweep trace is turned on at processing time
Dim iSelChan		'Selected channel
Dim iSelResult		'Selected result
Dim iListRef		'Integer for the current list item selected
Dim ListData()		'Array of data about list items	(1=tracetype/2 = channel, listref)
Dim SelTraces()		'Array of which traces IDs were turned on when the sweep_stats sub ran
Dim strTraceName	'Name of currently selected sweep result trace type (as in droplist)

Dim strTitle        'Title for boxe title bars etc.
Dim strLong			'Long string for constructing messages etc.
Dim bLogUnits		'true if Y axis in in log units
Dim bEnableLogMean	'True to plot log mean / geometric mean - can disable this feature
Dim Menu			'scriptdlg gui 
Dim iFormwidth		'width of menu form object in pixels
Dim iRH				'Row height in pixels
Dim iBW				'Button width in pixels

'Some arrays to make looping possible configurations easier
Dim iChannel(2)		'Channel dScope constants
iChannel(1) = CHANNEL_A
iChannel(2) = CHANNEL_B

Dim iChanName(2)	'Channel names
iChanName(1) = "Ch A"
iChanName(2) = "Ch B"

Dim iTraceType(4) 	'Sweep result dScope constants
iTraceType(1) = TRACETYPE_SWEEP1
iTraceType(2) = TRACETYPE_SWEEP2
iTraceType(3) = TRACETYPE_SWEEP3
iTraceType(4) = TRACETYPE_SWEEP4

Dim strTraceType(4)	'Text names of sweep result constants
strTraceType(1) = "Sweep result 1"
strTraceType(2) = "Sweep result 2"
strTraceType(3) = "Sweep result 3"
strTraceType(4) = "Sweep result 4"


'==========================================================
'INITIALISATION
'==========================================================
strTitle = "Sweep Statistics"
icount = 0
iFormWidth = 330
iRH = 20
iBW	= 105

'Disable log mean if not required by setting this to false
bEnableLogMean = false


' *** Main body of script ***
'==========================================================
Sub dScope_Main
'==========================================================

	Call Create_Menu    
    
	'this script is event driven:  it loads a GUI and then stays here, 
	'running on events until the GUI is closed
	
    Automation.AUT_StopScript()

End Sub ' dScope_Main


' *** Event handlers ***
'==========================================================
Sub Create_Menu
'==========================================================
' *** Create_Menu draws the main GUI using dScope ScriptDlg.dll

    Set Menu = CreateObject("ScriptDlg.Form")
    With Menu
    	.InitEventHandler(Menu)
    	.DynamicallyResize = False
    	.Modal = True
    	.Xpos = 20
    	.Ypos = 120
    	.Width = iFormwidth
    	.HorizontalSpacing = 1
    	.VerticalSpacing = 1
    	.Title = strTitle
    	.Setfont "Arial", 8, 0

    	'Status box
    	.AddStatic "Status", "Ready", iformWidth - 5, 20 
    	.Status.Setbackgroundcolour 0,0,0
    	.Status.SetTextColour 0, 255, 255
    	.newrow()
 
'     	.AddProgress "Progbar", iFormWidth - 5, 10
'     	.Progbar.Range = 100
'     	.newrow()
'     	    	
'     	.addstatic "headings", " TEST", iFormwidth, 18
'     	.headings.setfont "arial", 7 ,1
' 		.headings.settextcolour 255,255,255
'     	.headings.setbackgroundcolour 0, 112, 127
'     	.newrow()

		'Droplist of available sweep result traces
		.adddroplist "traceset", (iBW + 3) * 2 - 47
		.traceset.SetEvent_OnSelChanged GetRef("traceset_onchange")
		.traceset.tooltiptext = "Select the trace result to work with"
		
		'Button to reload available sweep results
    	.AddPushButton "Reload", "Reload", -1, iRH
    	.Reload.SetEvent_OnClick GetRef("Reload_Onclick")
    	.Reload.tooltiptext = "Reload list of available sweep results"
    	
    	'The go button
    	.AddPushButton "Go", "Run Statistics", iBW, iRH
    	.Go.SetEvent_OnClick GetRef("Go_Onclick")
    	.Go.tooltiptext = "Calculate min, max and mean of selected traces"
    	.Go.setbackgroundcolour 100,255,100
    	.newrow()
    	
    	'Button to turn off all traces of the selected type
    	.AddPushButton "All_Off", "Traces Off", iBW, iRH
    	.All_Off.SetEvent_OnClick GetRef("All_Off_Onclick")
    	.All_Off.tooltiptext = "Turn all the result traces off, leaving only stats"
    	
    	'Button to turn on all traces of the selected type
    	.AddPushButton "All_On", "Traces On", iBW, iRH
    	.All_On.SetEvent_OnClick GetRef("All_On_Onclick")
    	.All_On.tooltiptext = "Turn all the result traces on"
    	
    	'Button to turn on the selection of traces that were included in the last run
    	.AddPushButton "Sel_On", "Last Used Traces", iBW, iRH
    	.Sel_On.SetEvent_OnClick GetRef("Sel_On_Onclick")
    	.Sel_On.tooltiptext = "Turn all the last used traces on"
    	.Sel_on.enabled = false
    	.newrow()
    	
    End with	
    	
	Call Reload_onclick()  'Populate the drop-list of available sweep results
	Call Traceset_OnChange() 'Set the current selection
	
	menu.status.text = "Select the sweep result to work with..."
    	
    Menu.display()
    	
	'script stops here and responds to events until window is closed
	
	Set Menu = Nothing

	    	
End Sub 'create_menu


'==========================================================
Sub Traceset_OnChange()
'==========================================================
	'Runs on change of selection in sweep result droplist
	
	'Get the current selection
	menu.traceset.GetItemData menu.traceset.cursel, iListRef
	menu.traceset.Getstring (menu.traceset.cursel), strTraceName
	menu.status.text = strTraceName & " selected"
	
	'Disable the last used trace button: it's no longer usable
	menu.Sel_on.enabled = false

End Sub 'Traceset_OnChange()


'==========================================================
Sub Reload_Onclick()
'==========================================================
	'Runs on click of the reload button

    Menu.traceset.removeallstrings()
    iListRef = 0
    redim ListData (2, iListRef)
    
    'Work through all the possible combinations of trace type and channel and add those that are found
    'to the droplist
	For i = 1 to 2 'channels
		for j = 1 to ubound(iTraceType) 'tracetype
			if not TraceWindow.TW_GetFirstTraceOfType(iTraceType(j), iChannel(i)) = TRACE_NULL_ID then
				iListRef = iListRef + 1
				redim Preserve ListData(2,iListRef)
				ListData(1,iListRef) = iTraceType(j)
				ListData(2,iListRef) = iChannel(i)
				Menu.traceset.AddString strTraceType(j) & " (" & iChanName(i) & ")", iListRef
			end if
		next	
	next	
	if iListRef = 0 then 
		menu.status.text = "No sweep traces found"
		menu.All_on.enabled = false
	else
		menu.traceset.cursel = 0
		menu.status.text = "Available sweeps reloaded"
	end if	
	iCount = 0
	menu.Sel_on.enabled = false


End Sub 'Reload_Onclick()


'==========================================================
Sub All_Off_Onclick()
'==========================================================
	'Runs when the Traces Off button is clicked

	'Get all the traces of the currently selected type and turn them off
	if not TraceWindow.TW_GetFirstTraceOfType(ListData(1, iListRef), ListData(2, iListRef)) = TRACE_NULL_ID then
		Trace.TRACE_On = false
		do
			if TraceWindow.TW_GetNextTraceOfType(ListData(1, iListRef)) = TRACE_NULL_ID then
				exit do
			else	
				Trace.TRACE_On = false
			end if	
		Loop
	end if
	
	menu.status.text = "All " & strTraceName & " traces turned off"
		
		
End Sub 'All_Off_Onclick()


'==========================================================
Sub All_On_Onclick()
'==========================================================
	'Runs when the Traces on button is clicked

	'Get all the traces of the currently selected type and turn them on
	if not TraceWindow.TW_GetFirstTraceOfType(ListData(1, iListRef), ListData(2, iListRef)) = TRACE_NULL_ID then
		Trace.TRACE_On = true
		do
			if TraceWindow.TW_GetNextTraceOfType(ListData(1, iListRef)) = TRACE_NULL_ID then
				exit do
			else	
				Trace.TRACE_On = true
			end if	
		Loop
	end if
	
	menu.status.text = "All " & strTraceName & " traces turned on"

End Sub 'All_On_Onclick()


'==========================================================
Sub Sel_On_Onclick()
'==========================================================
	'Runs when the used Traces on button is clicked

	'work through all the traces of the selected type and determine if they are listed as having
	'been selected when the last stats process was run
	Dim bFound		'true if the current trace is in the list of used traces
	sTraceID = TraceWindow.TW_GetFirstTraceOfType(ListData(1, iListRef), ListData(2, iListRef))  
	if not sTraceID = TRACE_NULL_ID then 'we've got a trace
	
		'check if it's in the list of used traces
		bFound = false
		for i = 1 to ubound(SelTraces)		
			if STraceID = SelTraces(i) then 
				bFound = true
				Exit for
			end if
		next
		
		'If it was found in the list, turn it on	
		Trace.TRACE_On = bFound
		
		do
			'repeat the above process for all the remaining traces of the same type
			sTraceID = TraceWindow.TW_GetNextTraceOfType(ListData(1, iListRef))
			if sTraceID = TRACE_NULL_ID then exit do
			
			bFound = false
			for i = 1 to ubound(SelTraces)		
				if STraceID = SelTraces(i) then 
					bFound = true
					Exit for
				end if
			next	
			Trace.TRACE_On = bFound
		Loop
	end if

	if iCount > 0 then 
		menu.status.text = "Last used " & strTraceName & " trace selection turned on"
	else
		menu.status.text = "No traces have been selected..."
	end if	


End Sub 'Sel_On_Onclick()


'==========================================================
Sub Go_Onclick()
'==========================================================
	'Runs on the "Run statistics" button click

    'Remove all previous user traces on the same channel as the currently selected sweep result
    'They will get re-created in the sweep_stats sub
	sTraceID = TraceWindow.TW_GetFirstTraceOfType(TRACETYPE_USER, ListData(2, iListRef))
    Do While sTraceID <> TRACE_NULL_ID
    	TraceWindow.TW_RemoveTrace(sTraceID)
    	sTraceID = TraceWindow.TW_GetFirstTraceOfType(TRACETYPE_USER, ListData(2, iListRef))
    Loop 
    
	menu.status.text = "Previous user traces removed"

	'Run the sweep stats process on the currently selected sweep result type
	Call Sweep_stats

End Sub 'Go_Onclick()


'==========================================================
Sub Sweep_stats
'==========================================================
	'Get all the traces of the currently selected type, see if they are turned on, if they are, 
	'check they have the right number of sweep points - add to stats if so.  If not, turn off trace.
	
	sTraceID = TraceWindow.TW_GetFirstTraceOfType(ListData(1, iListRef), ListData(2, iListRef))
	if not sTraceID = TRACE_NULL_ID then 
	
		icount = 0
		iPoints = Trace.TRACE_GetNumPoints()
		'work out if the main trace is turned on - we need it to be turned on 
		'later to create traces from it, so we need to know if we need to turn it off again
		bMainOn = Trace.TRACE_On
		
		'Work out if the Y axis units of the current trace are linear or log
		Select case Trace.TRACE_YUnit
		case UNIT_DBFS, UNIT_DBU, UNIT_DBV, UNIT_DBM, UNIT_DBSPL, UNIT_DBR, UNIT_RELATIVE_DB
			bLogUnits = true
		case else
			bLogUnits = false
		end select	

		'Redim the arrays to hold the stats values	
		Redim SelTraces(1)
		Redim max(iPoints)
		Redim min(iPoints)
		redim mean(iPoints)
		REdim logmean(iPoints)
		Redim xVal(iPoints)
		
		'Retrieve the X axis values: these are needed for plotting the user traces later
		for i = 0 to iPoints - 1
			xVal(i) = Trace.TRACE_GetXValueAt(i)
		next	
		
		'Set up the arrays with the values from the first trace if it's turned on
		if Trace.TRACE_On then 
			'get all the points into the arrays:
			for i = 0 to iPoints - 1
				dYVal = Trace.TRACE_GetYValueAt(i)
				min(i) = dYVal
				max(i) = dYVal
				logmean(i) = dYVal
				if bLogUnits then dYVal = 10 ^ (dYVal/20)
				mean(i) = dYVal
			next
			icount = iCount + 1
			Redim preserve SelTraces(iCount)
			SelTraces(iCount) = sTraceID
		end if	
		
		'Loop through all the remaining traces of the selected type
		Do 
			sTraceID = TraceWindow.TW_GetNextTraceOfType(ListData(1, iListRef))
			
			'Exit if no further traces of type are found
			if sTraceID = TRACE_NULL_ID then exit do
			
			'If the trace is turned on and it has the right number of points, add it to the stats
			if Trace.TRACE_On then 
				
				if iPoints = Trace.TRACE_GetNumPoints() then 
					if icount = 0 then 
						'this is the first trace we're using: 
						'get all the points directly into the arrays
						for i = 0 to iPoints - 1
							dYVal = Trace.TRACE_GetYValueAt(i)
							min(i) = dYVal
							max(i) = dYVal
							logmean(i) = dYVal
							if bLogUnits then dYVal = 10 ^ (dYVal/20)
							mean(i) = dYVal
						next
						icount = iCount + 1
					else 'this is not the first trace - add to stats
						for i = 0 to iPoints - 1
							dYVal = Trace.TRACE_GetYValueAt(i)
							if dYVal > max(i) then max(i) = dYVal
							if dYVal < min(i) then min(i) = dYVal
				    		logmean(i) = ((logmean(i) * (iCount - 1)) + dYVal)/iCount
				    		'If log units, convert to lin for averaging
							if bLogUnits then dYVal = 10 ^ (dYVal/20)
				    		mean(i) = ((mean(i) * (iCount - 1)) + dYVal)/iCount
					    next	
						icount = iCount + 1
					end if	
					
					'Add a reference to this trace ID to the list of selected traces
					Redim preserve SelTraces(iCount)
					SelTraces(iCount) = sTraceID
					
					'probably won't see this as it'll go past too fast (unless it gets stuck)
					menu.status.text = "Added trace " & sTraceID & ", total = " & iCount
				else
					'Wrong number of trace points - turn off the trace so it's not included - no warning.
					Trace.TRACE_On = false
				end if
			end if	'trace on
		
		Loop
		
		
		if iCount > 0 then  'We have stats to plot - should this be if > 1?
		
			'Get the first sweep result of selected type:  we'll use it to copy from
			sTraceID = TraceWindow.TW_GetFirstTraceOfType(ListData(1, iListRef), ListData(2, iListRef))
			Trace.TRACE_On = true 'only while we create new traces:
			
			'Create new traces to hold the stats
			iMinTraceID = TraceWindow.TW_CreateTraceFromSweepTrace(ListData(1, iListRef), ListData(2, iListRef))
			if not iMinTraceID = TRACE_NULL_ID then 
				Trace.TRACE_Name = strTraceName &  " Min"
				Trace.TRACE_SetColour 00, 255, 00
				iMaxTraceID = TraceWindow.TW_CreateTraceFromSweepTrace(ListData(1, iListRef), ListData(2, iListRef))
				Trace.TRACE_Name = strTraceName &  " Max"
				Trace.TRACE_SetColour 255, 00, 00
				iMeanTraceID = TraceWindow.TW_CreateTraceFromSweepTrace(ListData(1, iListRef), ListData(2, iListRef))
				Trace.TRACE_Name = strTraceName &  " Mean"
				Trace.TRACE_SetColour 255, 200, 00
				
				'if enabled and the units are log, create the log-mean trace
				'this is the arithmetic mean of the readings in dB which is the same as the 
				'geometric mean of the readings in linear units
				if bEnableLogMean and bLogUnits then
					iLogMeanTraceID = TraceWindow.TW_CreateTraceFromSweepTrace(ListData(1, iListRef), ListData(2, iListRef))
					Trace.TRACE_Name = "Mean dB / geometric mean"
					Trace.TRACE_SetColour 155, 255, 00
				end if	
				
			else
				msgbox "Failed to create trace from sweep trace", vbexclamation, strTitle
				exit sub
			end if	
			
			'Put back the first trace to the state we found it in (on or off)
			sTraceID = TraceWindow.TW_GetFirstTraceOfType(ListData(1, iListRef), ListData(2, iListRef))
			Trace.Trace_On = bMainOn
			
			'Plot points for minimum trace
			if  TraceWindow.TW_SetCurrentTrace(iMinTraceID, false) then 
				For i = 0 to iPoints - 1
			        bRet = Trace.TRACE_SetPoint(i ,xVal(i), min(i), False)
			    Next
			    Trace.TRACE_DrawTrace()	
		    end if
		    
		    'If enabled and the units are log, plot the log mean trace
		    if bEnableLogMean and bLogunits then 
	    		if TraceWindow.TW_SetCurrentTrace(iLogMeanTraceID, false) then 
					For i = 0 to iPoints - 1
				        bRet = Trace.TRACE_SetPoint(i ,xVal(i), logmean(i), False)
				    Next
				    Trace.TRACE_DrawTrace()	
				end if
			END IF
		    
			'Plot the linear mean trace
			if TraceWindow.TW_SetCurrentTrace(iMeanTraceID, false) then 
				'if log units, we have averaged lin - convert back to log for display
				if bLogUnits then
					for i = 0 to iPoints - 1
						mean(i) = 20 * (log(mean(i))/Log(10))
					next
				end if	
				For i = 0 to iPoints - 1
			        bRet = Trace.TRACE_SetPoint(i ,xVal(i), mean(i), False)
			    Next
			    Trace.TRACE_DrawTrace()	
			end if
			
			'Plot the max trace
			If TraceWindow.TW_SetCurrentTrace(iMaxTraceID, false) then 
				For i = 0 to iPoints - 1
			        bRet = Trace.TRACE_SetPoint(i ,xVal(i), max(i), False)
			    Next
			    Trace.TRACE_DrawTrace()	
			end if 
			
			'Enable the "last used traces" button as we now know what they are
			menu.Sel_on.enabled = true
			
			'Status message to say how many traces were included
			menu.status.text = iCount & " traces processed"

		else 'iCount = 0
			'No traces of the selected kind were found
			menu.status.text = "No traces set to be included - please turn some on"
			strLong = "NO TRACES SELECTED" & vbcrlf & vbcrlf 
			strLong = strLong & "Only " & strTraceName & " traces that are turned on are included in " & vbcrlf
			strLong = strLong & "the statistics.  There appear to be none turned on." 
			msgbox strLong, vbexclamation, strtitle
		end if	
		
	else 'failed to find first trace of selected type
		'Since the selected type was found in the "Reload" sub, it must have been removed. 
		strLong = "TRACES NOT FOUND" & vbcrlf & vbcrlf 
		strLong = strLong & "The script was looking for a " & strTraceName & " trace and didn't find it. "
		strLong = strLong & "It has probably been removed or the configuration changed since the script "
		strLong = strLong & "loaded the list of available sweep results.  Please reload the list."
		msgbox strLong, vbexclamation, strtitle
	end if	'trace exists

End sub 'Sweep_stats

'END

