| 
									
										
										
										
											2020-06-25 17:52:30 +00:00
										 |  |  | #  NanoVNASaver | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  A python program to view and export Touchstone data from a NanoVNA | 
					
						
							|  |  |  | #  Copyright (C) 2019, 2020  Rune B. Broberg | 
					
						
							|  |  |  | #  Copyright (C) 2020 NanoVNA-Saver Authors | 
					
						
							| 
									
										
										
										
											2019-08-29 13:10:35 +00:00
										 |  |  | # | 
					
						
							|  |  |  | #  This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | #  it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | #  the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | #  (at your option) any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | #  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | #  GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | #  along with this program.  If not, see <https://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2019-09-16 13:47:37 +00:00
										 |  |  | import logging | 
					
						
							| 
									
										
										
										
											2019-08-29 13:42:35 +00:00
										 |  |  | import math | 
					
						
							| 
									
										
										
										
											2019-08-28 18:20:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-01 13:14:25 +00:00
										 |  |  | import numpy as np | 
					
						
							| 
									
										
										
										
											2019-10-26 07:54:19 +00:00
										 |  |  | import scipy.signal as signal | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  | from PyQt5 import QtWidgets, QtCore | 
					
						
							| 
									
										
										
										
											2019-08-28 18:20:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-16 13:47:37 +00:00
										 |  |  | logger = logging.getLogger(__name__) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-03 20:04:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  | class TDRWindow(QtWidgets.QWidget): | 
					
						
							| 
									
										
										
										
											2019-10-13 21:10:01 +00:00
										 |  |  |     updated = QtCore.pyqtSignal() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  |     def __init__(self, app: QtWidgets.QWidget): | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         super().__init__() | 
					
						
							|  |  |  |         self.app = app | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.td = [] | 
					
						
							|  |  |  |         self.distance_axis = [] | 
					
						
							| 
									
										
										
										
											2019-10-26 07:54:19 +00:00
										 |  |  |         self.step_response = [] | 
					
						
							|  |  |  |         self.step_response_Z = [] | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.setWindowTitle("TDR") | 
					
						
							| 
									
										
										
										
											2019-10-02 08:07:38 +00:00
										 |  |  |         self.setWindowIcon(self.app.icon) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  |         QtWidgets.QShortcut(QtCore.Qt.Key_Escape, self, self.hide) | 
					
						
							| 
									
										
										
										
											2019-09-21 11:13:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         layout = QtWidgets.QFormLayout() | 
					
						
							|  |  |  |         self.setLayout(layout) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown = QtWidgets.QComboBox() | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Jelly filled (0.64)", 0.64) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Polyethylene (0.66)", 0.66) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("PTFE (Teflon) (0.70)", 0.70) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Pulp Insulation (0.72)", 0.72) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Foam or Cellular PE (0.78)", 0.78) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Semi-solid PE (SSPE) (0.84)", 0.84) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Air (Helical spacers) (0.94)", 0.94) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.insertSeparator(self.tdr_velocity_dropdown.count()) | 
					
						
							| 
									
										
										
										
											2019-09-26 11:14:42 +00:00
										 |  |  |         # Lots of cable types added by Larry Goga, AE5CZ | 
					
						
							| 
									
										
										
										
											2019-09-22 11:42:05 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG-6/U PE 75\N{OHM SIGN} (Belden 8215) (0.66)", 0.66) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("RG-6/U Foam 75\N{OHM SIGN} (Belden 9290) (0.81)", 0.81) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("RG-8/U PE 50\N{OHM SIGN} (Belden 8237) (0.66)", 0.66) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG-8/U Foam (Belden 8214) (0.78)", 0.78) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("RG-8/U (Belden 9913) (0.84)", 0.84) | 
					
						
							| 
									
										
										
										
											2019-09-15 20:20:47 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG-8X (Belden 9258) (0.82)", 0.82) | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem( | 
					
						
							|  |  |  |             "RG-11/U 75\N{OHM SIGN} Foam HDPE (Belden 9292) (0.84)", 0.84) | 
					
						
							| 
									
										
										
										
											2019-09-22 11:42:05 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG-58/U 52\N{OHM SIGN} PE (Belden 9201) (0.66)", 0.66) | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem( | 
					
						
							|  |  |  |             "RG-58A/U 54\N{OHM SIGN} Foam (Belden 8219) (0.73)", 0.73) | 
					
						
							| 
									
										
										
										
											2019-09-22 11:42:05 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG-59A/U PE 75\N{OHM SIGN} (Belden 8241) (0.66)", 0.66) | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem( | 
					
						
							|  |  |  |             "RG-59A/U Foam 75\N{OHM SIGN} (Belden 8241F) (0.78)", 0.78) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG-174 PE (Belden 8216)(0.66)", 0.66) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("RG-174 Foam (Belden 7805R) (0.735)", 0.735) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("RG-213/U PE (Belden 8267) (0.66)", 0.66) | 
					
						
							| 
									
										
										
										
											2019-09-15 20:20:47 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG316 (0.695)", 0.695) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("RG402 (0.695)", 0.695) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("LMR-240 (0.84)", 0.84) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("LMR-240UF (0.80)", 0.80) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("LMR-400 (0.85)", 0.85) | 
					
						
							| 
									
										
										
										
											2019-09-15 20:20:47 +00:00
										 |  |  |         self.tdr_velocity_dropdown.addItem("LMR400UF (0.83)", 0.83) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Davis Bury-FLEX (0.82)", 0.82) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         self.tdr_velocity_dropdown.insertSeparator(self.tdr_velocity_dropdown.count()) | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.addItem("Custom", -1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.setCurrentIndex(1)  # Default to PE (0.66) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.tdr_velocity_dropdown.currentIndexChanged.connect(self.updateTDR) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         layout.addRow(self.tdr_velocity_dropdown) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.tdr_velocity_input = QtWidgets.QLineEdit() | 
					
						
							|  |  |  |         self.tdr_velocity_input.setDisabled(True) | 
					
						
							|  |  |  |         self.tdr_velocity_input.setText("0.66") | 
					
						
							|  |  |  |         self.tdr_velocity_input.textChanged.connect(self.app.dataUpdated) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         layout.addRow("Velocity factor", self.tdr_velocity_input) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.tdr_result_label = QtWidgets.QLabel() | 
					
						
							|  |  |  |         layout.addRow("Estimated cable length:", self.tdr_result_label) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         layout.addRow(self.app.tdr_chart) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def updateTDR(self): | 
					
						
							|  |  |  |         c = 299792458 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:54:19 +00:00
										 |  |  |         # TODO: Let the user select whether to use high or low resolution TDR? | 
					
						
							|  |  |  |         FFT_POINTS = 2**14 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 08:45:43 +00:00
										 |  |  |         if len(self.app.data11) < 2: | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.tdr_velocity_dropdown.currentData() == -1: | 
					
						
							|  |  |  |             self.tdr_velocity_input.setDisabled(False) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.tdr_velocity_input.setDisabled(True) | 
					
						
							|  |  |  |             self.tdr_velocity_input.setText(str(self.tdr_velocity_dropdown.currentData())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             v = float(self.tdr_velocity_input.text()) | 
					
						
							|  |  |  |         except ValueError: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 08:45:43 +00:00
										 |  |  |         step_size = self.app.data11[1].freq - self.app.data11[0].freq | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         if step_size == 0: | 
					
						
							|  |  |  |             self.tdr_result_label.setText("") | 
					
						
							| 
									
										
										
										
											2019-09-16 19:41:01 +00:00
										 |  |  |             logger.info("Cannot compute cable length at 0 span") | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         s11 = [] | 
					
						
							| 
									
										
										
										
											2020-07-09 08:45:43 +00:00
										 |  |  |         for d in self.app.data11: | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |             s11.append(np.complex(d.re, d.im)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 08:45:43 +00:00
										 |  |  |         window = np.blackman(len(self.app.data11)) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         windowed_s11 = window * s11 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:54:19 +00:00
										 |  |  |         self.td = np.abs(np.fft.ifft(windowed_s11, FFT_POINTS)) | 
					
						
							|  |  |  |         step = np.ones(FFT_POINTS) | 
					
						
							|  |  |  |         self.step_response = signal.convolve(self.td, step) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:54:19 +00:00
										 |  |  |         self.step_response_Z = 50 * (1 + self.step_response) / (1 - self.step_response) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:54:19 +00:00
										 |  |  |         time_axis = np.linspace(0, 1/step_size, FFT_POINTS) | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         self.distance_axis = time_axis * v * c | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  |         # peak = np.max(td) | 
					
						
							|  |  |  |         #  We should check that this is an actual *peak*, and not just a vague maximum | 
					
						
							| 
									
										
										
										
											2019-09-13 15:08:20 +00:00
										 |  |  |         index_peak = np.argmax(self.td) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-15 13:29:09 +00:00
										 |  |  |         cable_len = round(self.distance_axis[index_peak]/2, 3) | 
					
						
							|  |  |  |         feet = math.floor(cable_len / 0.3048) | 
					
						
							|  |  |  |         inches = round(((cable_len / 0.3048) - feet)*12, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 15:56:54 +00:00
										 |  |  |         self.tdr_result_label.setText(f"{cable_len}m ({feet}ft {inches}in)") | 
					
						
							| 
									
										
										
										
											2019-09-15 13:29:09 +00:00
										 |  |  |         self.app.tdr_result_label.setText(str(cable_len) + " m") | 
					
						
							| 
									
										
										
										
											2019-10-13 21:10:01 +00:00
										 |  |  |         self.updated.emit() |