-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgenerateResults.py
230 lines (183 loc) · 8.16 KB
/
generateResults.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
###########################################################################
#
# StatOpt Simulator
# by Jeremy Cosson-Martin, Jhoan Salinas of
# Ali Sheikholeslami's group
# Ported to Python 3 by Savo Bajic
# Department of Electrical and Computer Engineering
# University of Toronto
# Copyright Material
# For personal use only
#
###########################################################################
# This function generates the final simulation results. It determines the
# data levels and measures the eye openings.
#
# Inputs:
# simSettings: structure containing simulation settings
# simResults: structure containing simulation results
#
###########################################################################
from userSettingsObjects import simulationSettings, nothing
from initializeSimulation import simulationStatus
import numpy as np
import scipy.signal as spsig
def generateResults(simSettings: simulationSettings, simResults: simulationStatus):
# Measure data levels
measureDataLevs(simSettings, simResults)
# Measure eye openning
measureEyeSizes(simSettings, simResults)
# Measure eye position
measureEyePositions(simSettings, simResults)
# Measure channel operating margin
measureCOM(simResults)
###########################################################################
# This function finds the location of each data level. It does so by
# setting the minimum peak spacing at 2. This spacing is increased until
# the correct number of data peaks is observed.
###########################################################################
def measureDataLevs(simSettings: simulationSettings, simResults: simulationStatus):
# Import variables
yAxis = simSettings.general.yAxis.value
yAxisLength = simSettings.general.yAxisLength.value
levelCount = simSettings.general.levelNumb.value
successful = simResults.results.successful
if successful:
PDF = simResults.eyeGeneration.PDF.final.combined
BER = simResults.eyeGeneration.BER
# Find data levels
try:
spacing = 2
locations, _ = spsig.find_peaks(PDF[:,BER.eyeLocs.X], distance=spacing)
while(len(locations)>levelCount):
spacing = spacing+2
locations, _ = spsig.find_peaks(PDF[:,BER.eyeLocs.X], distance=spacing)
if len(locations) != levelCount:
print('Warning: Cannot find data levels!')
successful = False
except:
locations = np.ceil(np.ones((levelCount,))*yAxisLength/2)
successful = False
else:
locations = np.ceil(np.ones((levelCount,))*yAxisLength/2)
# Get values
dLevs = np.zeros_like(locations, dtype=float)
for interation, loc in enumerate(locations):
dLevs[interation] = yAxis[int(loc)]
# Save results
simResults.results.dLevs = dLevs
simResults.results.successful = successful
###########################################################################
# This function determines the eye dimensions.
###########################################################################
def measureEyeSizes(simSettings: simulationSettings, simResults: simulationStatus):
# Import variables
samplePeriod = simSettings.general.samplePeriod.value
symbolPeriod = simSettings.general.symbolPeriod.value
yIncrement = simSettings.general.yIncrement.value
targetBER = simSettings.general.targetBER.value
eyeLocs = simResults.eyeGeneration.BER.eyeLocs
bathTubX = simResults.eyeGeneration.BER.bathTubX
bathTubY = simResults.eyeGeneration.BER.bathTubY
successful = simResults.results.successful
BER = targetBER
eyeDims = nothing()
if successful:
# Find worst BER eye
BER = targetBER
for index in range(len(eyeLocs.Y)):
BER = np.maximum(BER, bathTubY[eyeLocs.Y[index]])
# Find height and width of each eye
for eye in range(len(eyeLocs.Y)):
# Get labels for common datapoints
tubLabel = 'tub' + str(eye)
eyeLabel = 'eye' + str(eye)
# Set in middle of eye
top = eyeLocs.Y[eye]
bottom = eyeLocs.Y[eye]
right = eyeLocs.X
left = eyeLocs.X
# Find size of each eye
while bathTubY[top]<BER and top<(len(bathTubY)-1): top = top+1
while bathTubY[bottom]<BER and bottom>0: bottom = bottom-1
while bathTubX.__dict__[tubLabel][right]<BER and right<(len(bathTubX.__dict__[tubLabel])-1): right = right+1
while bathTubX.__dict__[tubLabel][left]<BER and left>0: left = left-1
height = (top-bottom)*yIncrement
width = (right-left)*samplePeriod
widthUI = width/symbolPeriod
area = height*width
eyeDims.__dict__[eyeLabel] = nothing()
eyeDims.__dict__[eyeLabel].height = height
eyeDims.__dict__[eyeLabel].width = width
eyeDims.__dict__[eyeLabel].widthUI = widthUI
eyeDims.__dict__[eyeLabel].area = area
# Ensure not a false reading
if top == len(bathTubY) or bottom==0:
successful = False
print('Warning: Cannot determine eye limits.')
else:
# Default eyedims
eyeDims.eye0 = nothing()
eyeDims.eye0.height = 0
eyeDims.eye0.width = 0
eyeDims.eye0.widthUI = 0
eyeDims.eye0.area = 0
# Save results
simResults.results.BER = BER
simResults.results.eyeDimensions = eyeDims
simResults.results.successful = successful
###########################################################################
# This function takes the pre-calculated eye positions and converts the
# vales to voltage, time and phase
###########################################################################
def measureEyePositions(simSettings: simulationSettings, simResults: simulationStatus):
# Import variables
yAxis = simSettings.general.yAxis.value
xAxis = simSettings.general.xAxisCenter.value
samplePeriod = simSettings.general.samplePeriod.value
samplesPerSymb = simSettings.general.samplesPerSymb.value
successful = simResults.results.successful
# Calculate position
level = 0
time = 0
phase = 0
if successful:
eyeLocs = simResults.eyeGeneration.BER.eyeLocs
level = np.zeros_like(eyeLocs.Y, dtype=float)
for iter, loc in enumerate(eyeLocs.Y):
level[iter] = yAxis[loc]
time = xAxis[eyeLocs.X]
phase = round(time/(samplePeriod*samplesPerSymb)*360, 1)
# Save results
simResults.results.eyeLocs = nothing()
simResults.results.eyeLocs.level = level
simResults.results.eyeLocs.time = time
simResults.results.eyeLocs.phase = phase
###########################################################################
# This function measures the channel operating margin. The BER is set from
# setting.
###########################################################################
def measureCOM(simResults: simulationStatus):
# Import variables
dLevs = simResults.results.dLevs
eyes = simResults.results.eyeDimensions
successful = simResults.results.successful
# Calculate only if successful
com = -1e3 # set default very negative (no eye openning)
if successful:
eyeNames = eyes.__dict__
# Loop through eyes
for index in range(len(eyeNames)):
# Calculate COM for eye
signalHeight = dLevs[index+1]-dLevs[index]
eyeHeight = eyes.__dict__['eye' + str(index)].height
noiseHeight = signalHeight-eyeHeight
try:
comTmp = 20*np.log10(signalHeight/noiseHeight)
except:
print("Issue getting COM with signalHeight of {0:f} and noiseHeight of {1:f}. Setting COM for this to -1000.".format(signalHeight, noiseHeight))
comTmp = -1000
# Save worst COM
if index == 0 or comTmp < com: com = comTmp
# Save results
simResults.results.com = com