# Simple demo script for stateye v5
# tested against

# User defined parameters

import sys
sys.path += ['../v5']
import warnings
warnings.filterwarnings('ignore')

csvfile		= 'all.csv'

#filename 	= 'HP01_BtoB_3Connector.s4p'
#filename 	= 'halfmeter_A5A6B5B6.s4p'
#filename	= 'SAS2_transmittertestload.s4p'
filename	= 'sixmeter_A5A6B5B6.s4p'

timeResolution  = 2.0e-12

#txfilename	= 'PHY_CJTPAT_clean_6G_wfm'
txfilename	= ''
responselength	= 50
startsample     = 0 # 20000
#finishsample 	= 600000 
finishsample	= 100000
timecol		= 3
sigcol		= 4
txStep		= 'extractedStep.csv'
txNoise		= 'noise.csv'

numberPorts	= 4		# number of port in touchstone file
victim_tx_P 	= 1		# ports in touchstone file for transmitter and receiver
victim_tx_N 	= 3
victim_rx_P 	= 2
victim_rx_N 	= 4
scrambled	= 1		# is analysis based on scrambled or 8b10b data
deemphasis	= 0.0		# which de-emphasis, in dB
dfetaps		= 3		# how many DFE taps
baudrate	= 6.0e9		# what baud rate
padR		= 50		# pad DC termination resistance
padCap		= 950e-15	# pad capacitance
lpf		= 10.0e9	# 1st order LPF corner frequency
pws		= 0		# pulse width shrinkage, or edge jitter in UI
DJ		= 0.15		# Deteministic pp jitter
RJ		= 0.15/14.0	# Random RMS jitter, measured using 10101010 pattern
TxNorm		= 1.0		# Normalised transmit amplitude, only relevant when tx signal is being generated
BER		= -15

# Simulation parameters (probably best not to touch)
sweepResolution = 0.01		
startCursor 	= -8
finishCursor 	= 30 		
DCextrapolation = 6

############################################################
# execution starts here. Don't change anything unless you
# know what you are doing
############################################################

# try to cleanup environment, in case this is not the first time
try :
	del mySParam
except :
	print "running for the first time"
try : 
	del myStateye
except :
	print "running for the first time"

# load and reload all necessary modules

import pdb
from numpy import *
import numpy
from pylab import *
import time
from string import rsplit, rstrip
from scipy import linalg
from re import *

import penrose 
import stateye 
import analysis 
import touchstone
import extractJitter
import getopt

############################################################
# when running from the command line, get the options used
# and overwrite the script defaults
############################################################

outfilemodifier = ''
ion()

def usage():
    print "Arguments: -s <s4p filename> [-d N][-t N][-b N][-8]"
    print "-s <s4p filename>   input .s4p file (mandatory argument)"
    print "-d N                transmitter deemphasis value (in dB); default is 0 (deempN added to output filenames)"
    print "-t N                receiver dfe taps; default is 3 (.dfeN added to output filename)"
    print "-c 8|R              8b10b encoding (.8b10b added to output filenames) or random data encoding (.rand added to output filename)"
    print "-b N                baud rate; default is 6.0e9 (.baud added to output filename)"
    print "                    default is random.  8b10b simulations take longer."
    print "An optional argument only contribues to the output filename if used - default settings do not."

try:
	opts, args = getopt.getopt(sys.argv[1:], "c:d:s:t:b:q", ["help"])
except getopt.GetoptError:
    usage()
    sys.exit(2)
for opt, arg in opts:
    if opt in ("-h", "--help"):
        usage()
        sys.exit()                  
    elif opt == "-d":  # deemp
        deemphasis = float(arg)
        outfilemodifier += '_deemp' + arg
    elif opt == "-t":  # dfetaps
        dfetaps = int(arg)
        outfilemodifier += '_dfe' + arg
    elif opt == "-c":  # scrambled/8b10b
        if arg == "8":
            scrambled = 0
            outfilemodifier += '_8b10b'
        elif arg == "r":
            scrambled = 1
            outfilemodifier += '_rand'
    elif opt == "-b":  # baudrate
        baudrate = float(arg)
        outfilemodifier += '_baud' + arg
    elif opt == "-s":  # --s4p filename
        filename = arg
    elif opt == "-q" : 	# quiet
        ioff()

resultPrefix = filename.replace(".s4p", "");
resultPrefix = filename.replace(".s8p", "");  # RE kludge

print "Major settings: \n\tfilename=%s \n\tscrambled=%d \n\tdeemphasis=%f \n\tdfetaps=%d \n\tbaudrate=%0.2e"%(filename, scrambled, deemphasis, dfetaps, baudrate)

############################################################
# Main script initialise objects		
############################################################

myStateye = stateye.stateye()

if len(txfilename)>0 :
	print 'extracting step response from measurement'
	tag = time.time()
	[inputT, outputsignalF, signalF, timestep] = penrose.penrose(txfilename,responselength,startsample,finishsample,timecol,sigcol)
	print 'finished in %0.1f sec'%(time.time()-tag)

	print 'extracting jitter from measurement'
	tag = time.time()
	[RJ,DJ] = extractJitter.extractJitter(inputT, outputsignalF, signalF, 2, RJ, timestep, responselength)
	print 'finished in %0.1f sec'%(time.time()-tag)

mySParam = touchstone.touchstone()
# load the touchstone file
print 'loading touchstone file'
tag = time.time()
mySParam.loadFile(filename,numberPorts)
print 'finished in %0.1f sec'%(time.time()-tag)

mySParam.map( [victim_tx_P,victim_tx_N,victim_rx_P,victim_rx_N ])
mySParam.cascadeSimple(padR,padCap,lpf)

print 'creating step responses'
tag = time.time()
# extract to Dc

# extract the differential transfer function, given the port definitions
mySParam.extractTransfer(1,2,5,6)
mySParam.addDC(DCextrapolation)
	
# generation the step, and interpolate down to necessary resolution
print 'generating time step'
if len(txfilename)>0 :
	mySParam.getStep(timeResolution, txStep, txNoise,0)
else :
	mySParam.getStep(timeResolution, [], [],TxNorm)

# calculate how many time steps in one UI
UI = int(floor(1.0/baudrate/timeResolution))

# load the steo response into stateye objects
myStateye.loadStep(mySParam.step, UI, pws)
print 'finished in %0.1f sec'%(time.time()-tag)

# calculated the FIR tap for de-emphasis
fir = -(1.0 - 10**(-deemphasis / 20)) / 2.0

# create states and transition edges
print 'creating transitions'
tag = time.time()
if scrambled :
	myStateye.create2TapFIR( [1.0+fir, fir], dfetaps)
else :
	myStateye.create8b10b_2TapFIR( [1.0+fir, fir], dfetaps)
print 'finished in %0.1f sec'%(time.time()-tag)

# calculate the ISI pdf
print 'calcing pdf'
tag = time.time()
noise_x = [0]
noise_y = [1]
myStateye.calcpdf(sweepResolution,startCursor,finishCursor,DJ,RJ,noise_x,noise_y)
print 'finished in %0.1f sec'%(time.time()-tag)

if 1 :
	# initially the transfer function
	figure()
	plot(mySParam.frequency,20*log10(absolute(mySParam.t)))
	hold(1)
	plot(mySParam.frequency[-len(mySParam.rl):],20*log10(absolute(mySParam.rl)))
	plot(mySParam.frequency[-len(mySParam.rl):],20*log10(absolute(mySParam.h)))
	legend(['Victim','Return Loss','Damping'],'center right')
	xlabel('Frequency [Hz]')
	ylabel('Sdd21 [dB]')
	title('Channel Response')
	grid(1)
	axis([0,baudrate*2,-40,0])
	savefig(resultPrefix + outfilemodifier + '_spectrum.png')
	
	# pulse and step response
	figure()
	hold(0)
	x = []
	y = []
	y2 = []
	for cursor in arange(startCursor,finishCursor,0.01) :
		x += [cursor]
		y += [myStateye.pulse[myStateye.cursor2index(0,cursor)]]
		y2 += [myStateye.inputStep[myStateye.cursor2index(0,cursor+2)]]
	
	plot(x,y)
	hold(1)
	plot(x,y2)
	grid(1)
	xlabel('Time [UI]')
	ylabel('Amplitude [V]')
	title('Post channel Pulse and Step Response')
	savefig(resultPrefix + outfilemodifier + '_pulse_step.png')
		
	# jitter statistical eye
	figure()
	pdf_pj_log = ( log10(transpose(myStateye.pdf_pj)+1.0e-17) )
	contourf(myStateye.sweep, myStateye.binaxis , pdf_pj_log,arange(-15,0,0.5))
	maxamp = 0.0
	minamp = myStateye.midBin
	
	for _a in transpose(pdf_pj_log)[2:-2] :
		_maxamp = min(find(_a[myStateye.midBin:] > BER ))	
		_minamp = max(find(_a[:myStateye.midBin] > BER ))	
		if _maxamp > maxamp :
			maxamp = _maxamp
		if _minamp < minamp :
			minamp = _minamp
	amplitude = myStateye.binaxis[myStateye.midBin + maxamp]-myStateye.binaxis[minamp] 
	print 'Amplitude is %0.3f'%(amplitude)
	Jmin = max(find( pdf_pj_log[myStateye.midBin][:len(myStateye.sweep)/2] > BER ))
	Jmax = min(find( pdf_pj_log[myStateye.midBin][len(myStateye.sweep)/2:] > BER )) + len(myStateye.sweep)/2

	jitter = 1.0 - (myStateye.sweep[Jmax] - myStateye.sweep[Jmin])
	print 'Jitter is %0.3f'%(jitter)
	
	amplitude = myStateye.binaxis[myStateye.midBin + maxamp]-myStateye.binaxis[minamp] 
	
	print 'Amplitude is %0.3f'%(amplitude)
	print 'Jitter is %0.3f'%(jitter)
	
	grid(1)
	eyeLeft = find( max( pdf_pj_log[myStateye.midBin][:len(myStateye.sweep)/2] ) == pdf_pj_log[myStateye.midBin][:len(myStateye.sweep)/2] )[0]
	eyeRght = find( max( pdf_pj_log[myStateye.midBin][len(myStateye.sweep)/2:] ) == pdf_pj_log[myStateye.midBin][len(myStateye.sweep)/2:] )[0] + len(myStateye.sweep)/2
	axisMax = myStateye.binaxis[ max(find(transpose(pdf_pj_log)[0]>-17)) ]
	axisMin = myStateye.binaxis[ min(find(transpose(pdf_pj_log)[0]>-17)) ]
	axis([myStateye.sweep[eyeLeft],myStateye.sweep[eyeRght],axisMin*1.2,axisMax*1.2])
	xlabel('Time [UI]')
	ylabel('Amplitude [V]')
	title('Eye Opening %0.3fV, Jitter %0.3fUIpp\nTx=%0.3fmV, BER=10%d'%(amplitude, jitter,TxNorm,BER))
	savefig(resultPrefix + outfilemodifier + '_stateye.png')
				


f = open(csvfile,'a')
f.writelines('\"%s\", \"%s\", %d, %f, %d, %e, %f, %f\n'%(resultPrefix, filename, scrambled, deemphasis, dfetaps, baudrate, amplitude, jitter))
f.close()


