FrequencyExtractWidget.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. from PyQt4 import QtCore, QtGui
  2. from ..base import kcgwidget as kcgw
  3. from ..base.globals import glob as global_objects
  4. from ..base.backend import board
  5. from ..base.backend.board import available_boards
  6. from .. import config
  7. import pyqtgraph as pg
  8. from math import ceil
  9. import numpy as np
  10. import socket
  11. <<<<<<< HEAD
  12. import sys
  13. =======
  14. >>>>>>> da4c26e... Added ethernet socket to FrequencyExtractWidget
  15. from .PlotWidget import SubPlotWidget
  16. __widget_id__ = None
  17. class FrequencyExtractWidget(kcgw.KCGWidgets):
  18. def __init__(self, unique_id, parent):
  19. super(FrequencyExtractWidget, self).__init__()
  20. self.id = unique_id
  21. self.par = parent
  22. #ToDo: Maybe find valid data from the get-go?
  23. self.data = None
  24. self.board_config = board.get_board_config(available_boards[0])
  25. self.board_config.observe(self, self.dataSetChanged, 'lastDataSet')
  26. self.numADCs = self.board_config.get('adc_number')
  27. #Use a VBox. Top half should be the SubPlotWidget, bottom
  28. #half should be the controls
  29. self.layout = QtGui.QVBoxLayout()
  30. self.plotBox = QtGui.QVBoxLayout()
  31. self.plot = SubPlotWidget()
  32. self.region = pg.LinearRegionItem(values=[10,20])
  33. self.plot.plotItem.addItem(self.region)
  34. self.region.sigRegionChangeFinished.connect(self.doPlot)
  35. self.line = pg.InfiniteLine(angle=0, label='Y={value:0.2f}',
  36. labelOpts={'movable': True})
  37. self.plot.plotItem.addItem(self.line)
  38. self.line.hide()
  39. self.plotBox.addWidget(self.plot)
  40. #Controls for the plot
  41. self.controlsBox = QtGui.QHBoxLayout()
  42. self.adcSelect = QtGui.QComboBox(self)
  43. for i in range(self.numADCs):
  44. self.adcSelect.addItem("ADC {}".format(i+1))
  45. self.adcSelect.currentIndexChanged.connect(self.doPlot)
  46. self.bucketSelect = QtGui.QComboBox(self)
  47. self.bucketSelect.addItem("Mean")
  48. for i in range(184):
  49. self.bucketSelect.addItem("Bucket {}".format(i+1))
  50. self.bucketSelect.currentIndexChanged.connect(self.doPlot)
  51. self.fromBox = self.createSpinbox(0, 100000000, interval=100, connect=self.doPlot)
  52. self.toBox = self.createSpinbox(0, 100000000, start_value=1000, interval=100, connect=self.doPlot)
  53. self.controlsBox.addWidget(self.adcSelect)
  54. self.controlsBox.addWidget(self.bucketSelect)
  55. self.controlsBox.addStretch()
  56. self.controlsBox.addWidget(self.createLabel(text="From:"))
  57. self.controlsBox.addWidget(self.fromBox)
  58. self.controlsBox.addWidget(self.createLabel(text="To:"))
  59. self.controlsBox.addWidget(self.toBox)
  60. self.frequencyTools = QtGui.QHBoxLayout()
  61. self.freqText = QtGui.QLineEdit(self)
  62. self.isFreqValid = False
  63. self.frequencyTools.addWidget(self.createLabel(text="Frequency:"))
  64. self.frequencyTools.addWidget(self.freqText)
  65. self.ethernetControls = QtGui.QHBoxLayout()
  66. self.ethernetControls.addWidget(self.createLabel("IP:"))
  67. self.ip = QtGui.QLineEdit(self)
  68. self.ethernetControls.addWidget(self.ip)
  69. self.ethernetControls.addWidget(self.createLabel("Port:"))
  70. self.port = self.createSpinbox(1024, 65535)
  71. self.port.setValue(56000)
  72. self.ethernetControls.addWidget(self.port)
  73. self.ethButton = self.createButton("Connect", connect=self.connectEthernet)
  74. self.ethernetControls.addWidget(self.ethButton)
  75. self.socketConnected = False
  76. self.layout.addLayout(self.plotBox)
  77. self.layout.addLayout(self.controlsBox)
  78. self.layout.addLayout(self.frequencyTools)
  79. self.layout.addLayout(self.ethernetControls)
  80. self.setLayout(self.layout)
  81. self.setWindowTitle("Frequency Extract")
  82. def connectEthernet(self):
  83. if not self.socketConnected:
  84. #closing the socket also frees the underlying File-Descriptor,
  85. #so we need to create a new socket every time we want to create
  86. #a new connection
  87. self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  88. try:
  89. socket.inet_aton(self.ip.text())
  90. except OSError:
  91. print("Malformed IP: %s"%self.ip.text())
  92. return
  93. try:
  94. self.socket.connect((self.ip.text(), self.port.value()))
  95. self.socketConnected = True
  96. self.ethButton.setText("Disconnect")
  97. except:
  98. print("Failed to connect to %s"%self.ip.text())
  99. self.socket = None
  100. else:
  101. self.socket.close()
  102. self.socketConnected = False
  103. self.ethButton.setText("Connect")
  104. def sendFreqEth(self, freq):
  105. if not self.socketConnected:
  106. return
  107. #We work in the kHz domain
  108. freq /= 1000
  109. offset = 10
  110. step = 0.08
  111. max = (offset + (step * 127))
  112. if (freq > max) or (freq < offset):
  113. print("Frequency outside range: %.2fkhZ - %.2fkHz! Won't send..."%(offset,max))
  114. return
  115. tmp = freq - offset - step
  116. count = 0
  117. while tmp > 0:
  118. tmp -= step
  119. count += 1
  120. #bytes converts an array of integers into their shortest possible
  121. #bytewise representation.
  122. try:
  123. self.socket.sendall(bytes([count]))
  124. except:
  125. print("Failed to send... closing down connection")
  126. self.socket.close()
  127. self.socketConnected = False
  128. def dataSetChanged(self, data=None):
  129. self.data = data
  130. self.doPlot()
  131. def doPlot(self):
  132. if not self.data:
  133. return
  134. #PlotWidget's "plot" function expects the fft_mode to have two entries
  135. #which we don't need here. So we need to shift our index by +2 in order
  136. #to accomodate for the two missing options in the bucket_select ComboBox
  137. fft_mode = self.bucketSelect.currentIndex() + 2
  138. adc = self.adcSelect.currentIndex()
  139. self.fftData = self.data.fft(adc=self.adcSelect.currentIndex(),
  140. frm=self.fromBox.value(),
  141. to=self.toBox.value(),
  142. drop_first_bin=True,
  143. nobunching=False)
  144. self.plot.plot(
  145. self.fftData,
  146. autorange=False,
  147. xvalueborders=[self.data.fftFreqDist(), self.data.fftMaxFreq()],
  148. fft_mode=fft_mode,
  149. log=False)
  150. self.plot.plotItem.setLabel('left', 'Spectral Intensity')
  151. #I am cheating a little bit and getting the readily processed data
  152. #from the plotItems, so I don't have to process, convert, format, etc.
  153. #the fftData again. We already did that in the SubPlotWidget.plot
  154. #function, so no need to do it again. Just steal the data from the
  155. #plotItems!
  156. self.fftYValues = self.plot.plotItemPlot[0].yData
  157. self.fftXValues = self.plot.plotItemPlot[0].xData
  158. region = self.region.getRegion()
  159. #Clip to valid data ranges
  160. rLeft = ceil(region[0]) if region[0] >=0 else 0
  161. rRight = ceil(region[1]) if region[1] < len(self.fftYValues) else len(self.fftYValues)
  162. #Make sure the region is within the boundaries of our data array
  163. if rLeft >= len(self.fftYValues) or rRight < 0:
  164. self.freqText.setText("Region boundaries out of data range")
  165. self.line.hide()
  166. self.isFreqValid = False
  167. self.freqText.setText("NaN")
  168. return
  169. #If the region is not really a region, ignore it
  170. if rLeft == rRight:
  171. self.freqText.setText("Region too small")
  172. self.line.hide()
  173. self.isFreqValid = False
  174. self.freqText.setText("NaN")
  175. return
  176. chunk = self.fftYValues[rLeft:rRight]
  177. maxVal = np.max(chunk)
  178. maxIndexInChunk = np.where(chunk == maxVal)
  179. self.line.setValue(maxVal)
  180. self.line.show()
  181. #np.where returns a tuple of indices (because it supports
  182. #multidimensional arrays). But since we know that our array is only
  183. #1-Dimensional, we can simply pick only the first dimension
  184. maxIndexInChunk = maxIndexInChunk[0]
  185. indexInData = rLeft + maxIndexInChunk
  186. #We are basically just repeating what the plot item also did to
  187. #determine the X-Axis labeling, and use it calculate the X-Value
  188. #at the index we have identified
  189. xAxisScale = (self.data.fftMaxFreq() - self.data.fftFreqDist()) / float(self.fftYValues.shape[0])
  190. self.freqText.setText(str(self.fftXValues[indexInData][0]*xAxisScale))
  191. self.isFreqValid = True
  192. self.sendFreqEth(self.fftXValues[indexInData][0]*xAxisScale)
  193. def closeEvent(self, event):
  194. global __widget_id__
  195. __widget_id__ = None
  196. del self.par.widgets[self.id]
  197. self.board_config.unobserve(self, 'lastDataSet')
  198. def addFrequencyExtractWidget():
  199. global __widget_id__
  200. if __widget_id__:
  201. global_objects.get_global('area').widgets[__widget_id__].setFocus()
  202. else:
  203. nid = kcgw.idg.genid()
  204. __widget_id__ = nid
  205. w = FrequencyExtractWidget(nid, global_objects.get_global('area'))
  206. global_objects.get_global('area').newWidget(w, "Frequency Extract", nid, widget_type=4)
  207. kcgw.register_widget(QtGui.QIcon(config.icon_path("sproject.svg")), "Frequency Extract", addFrequencyExtractWidget, "Ctrl+e")