def runAnalysis(self): if self.rbtn_data_vswr.isChecked(): suffix = "" data = [] for d in self.app.data11: data.append(d.vswr) elif self.rbtn_data_resistance.isChecked(): suffix = " \N{OHM SIGN}" data = [] for d in self.app.data11: data.append(d.impedance().real) elif self.rbtn_data_reactance.isChecked(): suffix = " \N{OHM SIGN}" data = [] for d in self.app.data11: data.append(d.impedance().imag) elif self.rbtn_data_s21_gain.isChecked(): suffix = " dB" data = [] for d in self.app.data21: data.append(d.gain) else: logger.warning("Searching for peaks on unknown data") return if len(data) == 0: return if self.rbtn_peak_positive.isChecked(): idx_peak = np.argmax(data) elif self.rbtn_peak_negative.isChecked(): idx_peak = np.argmin(data) else: # Both is not yet in logger.warning("Searching for peaks," " but neither looking at positive nor negative?") return self.peak_frequency.setText( format_frequency(self.app.data11[idx_peak].freq)) self.peak_value.setText(str(round(data[idx_peak], 3)) + suffix) if self.checkbox_move_marker.isChecked() and len( self.app.markers) >= 1: self.app.markers[0].setFrequency( str(self.app.data11[idx_peak].freq)) self.app.markers[0].frequencyInput.setText( format_frequency(self.app.data11[idx_peak].freq))
def updateLabels(self, s11data: List[RFTools.Datapoint], s21data: List[RFTools.Datapoint]): if self.location == -1: return self.store(self.location, s11data, s21data) s11 = s11data[self.location] imp = s11.impedance() cap_str = format_capacitance(RFTools.impedance_to_capacitance(imp, s11.freq)) ind_str = format_inductance(RFTools.impedance_to_inductance(imp, s11.freq)) imp_p = RFTools.serial_to_parallel(imp) cap_p_str = format_capacitance(RFTools.impedance_to_capacitance(imp_p, s11.freq)) ind_p_str = format_inductance(RFTools.impedance_to_inductance(imp_p, s11.freq)) if imp.imag < 0: x_str = cap_str else: x_str = ind_str if imp_p.imag < 0: x_p_str = cap_p_str else: x_p_str = ind_p_str self.label['actualfreq'].setText(format_frequency(s11.freq)) self.label['admittance'].setText(format_complex_imp(imp_p)) self.label['impedance'].setText(format_complex_imp(imp)) self.label['parc'].setText(cap_p_str) self.label['parl'].setText(ind_p_str) self.label['parlc'].setText(x_p_str) self.label['parr'].setText(format_resistance(imp_p.real)) self.label['returnloss'].setText( format_gain(s11.gain, self.returnloss_is_positive)) self.label['s11groupdelay'].setText( format_group_delay(RFTools.groupDelay(s11data, self.location))) self.label['s11mag'].setText(format_magnitude(abs(s11.z))) self.label['s11phase'].setText(format_phase(s11.phase)) self.label['s11polar'].setText( str(round(abs(s11.z), 2)) + "∠" + format_phase(s11.phase)) self.label['s11q'].setText(format_q_factor(s11.qFactor())) self.label['s11z'].setText(format_resistance(abs(imp))) self.label['serc'].setText(cap_str) self.label['serl'].setText(ind_str) self.label['serlc'].setText(x_str) self.label['serr'].setText(format_resistance(imp.real)) self.label['vswr'].setText(format_vswr(s11.vswr)) if len(s21data) == len(s11data): s21 = s21data[self.location] self.label['s21gain'].setText(format_gain(s21.gain)) self.label['s21groupdelay'].setText( format_group_delay(RFTools.groupDelay(s21data, self.location) / 2)) self.label['s21mag'].setText(format_magnitude(abs(s21.z))) self.label['s21phase'].setText(format_phase(s21.phase)) self.label['s21polar'].setText( str(round(abs(s21.z), 2)) + "∠" + format_phase(s21.phase))
def runAnalysis(self): self.reset() pass_band_location = self.app.markers[0].location logger.debug("Pass band location: %d", pass_band_location) if len(self.app.data.s21) == 0: logger.debug("No data to analyse") self.result_label.setText("No data to analyse.") return if pass_band_location < 0: logger.debug("No location for %s", self.app.markers[0].name) self.result_label.setText( f"Please place {self.app.markers[0].name} in the passband.") return pass_band_db = self.app.data.s21[pass_band_location].gain logger.debug("Initial passband gain: %d", pass_band_db) initial_cutoff_location = -1 for i in range(pass_band_location, len(self.app.data.s21)): db = self.app.data.s21[i].gain if (pass_band_db - db) > 3: # We found a cutoff location initial_cutoff_location = i break if initial_cutoff_location < 0: self.result_label.setText("Cutoff location not found.") return initial_cutoff_frequency = self.app.data.s21[initial_cutoff_location].freq logger.debug("Found initial cutoff frequency at %d", initial_cutoff_frequency) peak_location = -1 peak_db = self.app.data.s21[initial_cutoff_location].gain for i in range(0, initial_cutoff_location): db = self.app.data.s21[i].gain if db > peak_db: peak_db = db peak_location = i logger.debug("Found peak of %f at %d", peak_db, self.app.data.s11[peak_location].freq) self.app.markers[0].setFrequency(str(self.app.data.s21[peak_location].freq)) self.app.markers[0].frequencyInput.setText(str(self.app.data.s21[peak_location].freq)) cutoff_location = -1 pass_band_db = peak_db for i in range(peak_location, len(self.app.data.s21)): db = self.app.data.s21[i].gain if (pass_band_db - db) > 3: # We found the cutoff location cutoff_location = i break cutoff_frequency = self.app.data.s21[cutoff_location].freq cutoff_gain = self.app.data.s21[cutoff_location].gain - pass_band_db if cutoff_gain < -4: logger.debug( "Cutoff frequency found at %f dB" " - insufficient data points for true -3 dB point.", cutoff_gain) logger.debug("Found true cutoff frequency at %d", cutoff_frequency) self.cutoff_label.setText( f"{format_frequency(cutoff_frequency)}" f" ({round(cutoff_gain, 1)} dB)") self.app.markers[1].setFrequency(str(cutoff_frequency)) self.app.markers[1].frequencyInput.setText(str(cutoff_frequency)) six_db_location = -1 for i in range(cutoff_location, len(self.app.data.s21)): db = self.app.data.s21[i].gain if (pass_band_db - db) > 6: # We found 6dB location six_db_location = i break if six_db_location < 0: self.result_label.setText("6 dB location not found.") return six_db_cutoff_frequency = self.app.data.s21[six_db_location].freq self.six_db_label.setText( format_frequency(six_db_cutoff_frequency)) ten_db_location = -1 for i in range(cutoff_location, len(self.app.data.s21)): db = self.app.data.s21[i].gain if (pass_band_db - db) > 10: # We found 6dB location ten_db_location = i break twenty_db_location = -1 for i in range(cutoff_location, len(self.app.data.s21)): db = self.app.data.s21[i].gain if (pass_band_db - db) > 20: # We found 6dB location twenty_db_location = i break sixty_db_location = -1 for i in range(six_db_location, len(self.app.data.s21)): db = self.app.data.s21[i].gain if (pass_band_db - db) > 60: # We found 60dB location! Wow. sixty_db_location = i break if sixty_db_location > 0: sixty_db_cutoff_frequency = self.app.data.s21[sixty_db_location].freq self.sixty_db_label.setText( format_frequency(sixty_db_cutoff_frequency)) elif ten_db_location != -1 and twenty_db_location != -1: ten = self.app.data.s21[ten_db_location].freq twenty = self.app.data.s21[twenty_db_location].freq sixty_db_frequency = ten * \ 10 ** (5 * (math.log10(twenty) - math.log10(ten))) self.sixty_db_label.setText( f"{format_frequency(sixty_db_frequency)} (derived)") else: self.sixty_db_label.setText("Not calculated") if (ten_db_location > 0 and twenty_db_location > 0 and ten_db_location != twenty_db_location): octave_attenuation, decade_attenuation = self.calculateRolloff( ten_db_location, twenty_db_location) self.db_per_octave_label.setText( str(round(octave_attenuation, 3)) + " dB / octave") self.db_per_decade_label.setText( str(round(decade_attenuation, 3)) + " dB / decade") else: self.db_per_octave_label.setText("Not calculated") self.db_per_decade_label.setText("Not calculated") self.result_label.setText( "Analysis complete (" + str(len(self.app.data.s11)) + " points)")
def runAnalysis(self): max_dips_shown = self.max_dips_shown data = [d.vswr for d in self.app.data.s11] # min_idx = np.argmin(data) # # logger.debug("Minimum at %d", min_idx) # logger.debug("Value at minimum: %f", data[min_idx]) # logger.debug("Frequency: %d", self.app.data.s11[min_idx].freq) # # if self.checkbox_move_marker.isChecked(): # self.app.markers[0].setFrequency(str(self.app.data.s11[min_idx].freq)) # self.app.markers[0].frequencyInput.setText(str(self.app.data.s11[min_idx].freq)) threshold = self.input_vswr_limit.value() minimums = self.find_minimums(data, threshold) logger.debug("Found %d sections under %f threshold", len(minimums), threshold) results_header = self.layout.indexOf(self.results_label) logger.debug("Results start at %d, out of %d", results_header, self.layout.rowCount()) for _ in range(results_header, self.layout.rowCount()): self.layout.removeRow(self.layout.rowCount() - 1) if len(minimums) > max_dips_shown: self.layout.addRow( QtWidgets.QLabel("<b>More than " + str(max_dips_shown) + " dips found. Lowest shown.</b>")) dips = [] for m in minimums: start, lowest, end = m dips.append(data[lowest]) best_dips = [] for _ in range(max_dips_shown): min_idx = np.argmin(dips) best_dips.append(minimums[min_idx]) dips.remove(dips[min_idx]) minimums.remove(minimums[min_idx]) minimums = best_dips self.minimums = minimums if len(minimums) > 0: for m in minimums: start, lowest, end = m if start != end: logger.debug("Section from %d to %d, lowest at %d", start, end, lowest) self.layout.addRow( "Start", QtWidgets.QLabel( format_frequency(self.app.data.s11[start].freq))) self.layout.addRow( "Minimum", QtWidgets.QLabel( f"{format_frequency(self.app.data.s11[lowest].freq)}" f" ({round(data[lowest], 2)})")) self.layout.addRow( "End", QtWidgets.QLabel( format_frequency(self.app.data.s11[end].freq))) self.layout.addRow( "Span", QtWidgets.QLabel( format_frequency(self.app.data.s11[end].freq - self.app.data.s11[start].freq))) else: self.layout.addRow( "Low spot", QtWidgets.QLabel( format_frequency(self.app.data.s11[lowest].freq))) self.layout.addWidget(PeakSearchAnalysis.QHLine()) # Remove the final separator line self.layout.removeRow(self.layout.rowCount() - 1) else: self.layout.addRow( QtWidgets.QLabel("No areas found with VSWR below " + str(round(threshold, 2)) + "."))
def compare(self, old, new, fields=None): ''' Compare data to help changes NB must be same sweep ( same index must be same frequence ) :param old: :param new: ''' fields = fields or [ ("freq", str), ] def no_compare(): return {k: "-" for k, _ in fields} old_idx = sorted(old.keys()) # 'odict_keys' object is not subscriptable new_idx = sorted(new.keys()) diff = {} i_max = min(len(old_idx), len(new_idx)) i_tot = max(len(old_idx), len(new_idx)) if i_max == i_tot: logger.debug("may be the same antenna ... analyzing") else: logger.warning("resonances changed from %s to %s", len(old_idx), len(new_idx)) logger.debug("Trying to compare only first %s resonances", i_max) split = 0 max_delta_f = 1000000 # 1M for i, k in enumerate(new_idx): my_diff = {} logger.info("Risonance %s at %s", i, format_frequency(new[k]["freq"])) if len(old_idx) <= i + split: diff[i] = no_compare() continue delta_f = new[k]["freq"] - old[old_idx[i + split]]["freq"] if abs(delta_f) < max_delta_f: logger.debug("can compare") else: logger.debug("can't compare, %s is too much ", format_frequency(delta_f)) if delta_f > 0: logger.debug("possible missing band, ") if len(old_idx) > (i + split + 1): if abs(new[k]["freq"] - old[old_idx[i + split + 1]]["freq"]) < max_delta_f: logger.debug("new is missing band, compare next ") split += 1 # FIXME: manage 2 or more band missing ?!? else: logger.debug("new band, non compare ") diff[i] = no_compare() continue else: logger.debug("new band, non compare ") diff[i] = no_compare() split -= 1 continue for d, fn in fields: my_diff[d] = fn(new[k][d] - old[old_idx[i + split]][d]) logger.info("Delta %s = %s", d, my_diff[d]) diff[i] = my_diff for i in range(i_max, i_tot): # add missing in old ... if any diff[i] = no_compare() return diff
def runAnalysis(self): self.reset() # self.results_label = QtWidgets.QLabel("<b>Results</b>") # max_dips_shown = self.max_dips_shown description = self.input_description.text() if description: filename = os.path.join("/tmp/", "{}.csv".format(description)) else: filename = None crossing = self._get_crossing() logger.debug("Found %d sections ", len(crossing)) results_header = self.layout.indexOf(self.results_label) logger.debug("Results start at %d, out of %d", results_header, self.layout.rowCount()) for _ in range(results_header, self.layout.rowCount()): self.layout.removeRow(self.layout.rowCount() - 1) # if len(crossing) > max_dips_shown: # self.layout.addRow(QtWidgets.QLabel("<b>More than " + str(max_dips_shown) + # " dips found. Lowest shown.</b>")) # self.crossing = crossing[:max_dips_shown] if len(crossing) > 0: extended_data = [] for m in crossing: start, lowest, end = m my_data = self._get_data(lowest) extended_data.append(my_data) if start != end: logger.debug("Section from %d to %d, lowest at %d", start, end, lowest) self.layout.addRow( "Resonance", QtWidgets.QLabel( f"{format_frequency(self.app.data.s11[lowest].freq)}" f" ({format_complex_imp(self.app.data.s11[lowest].impedance())})" )) else: self.layout.addRow( "Resonance", QtWidgets.QLabel( format_frequency(self.app.data.s11[lowest].freq))) self.layout.addWidget(PeakSearchAnalysis.QHLine()) # Remove the final separator line self.layout.removeRow(self.layout.rowCount() - 1) if filename and extended_data: with open(filename, 'w', newline='') as csvfile: fieldnames = extended_data[0].keys() writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for row in extended_data: writer.writerow(row) else: self.layout.addRow(QtWidgets.QLabel("No resonance found"))
def runAnalysis(self): self.reset() pass_band_location = self.app.markers[0].location logger.debug("Pass band location: %d", pass_band_location) if len(self.app.data21) == 0: logger.debug("No data to analyse") self.result_label.setText("No data to analyse.") return if pass_band_location < 0: logger.debug("No location for %s", self.app.markers[0].name) self.result_label.setText( f"Please place {self.app.markers[0].name} in the passband.") return pass_band_db = self.app.data21[pass_band_location].gain logger.debug("Initial passband gain: %d", pass_band_db) initial_lower_cutoff_location = -1 for i in range(pass_band_location, -1, -1): if (pass_band_db - self.app.data21[i].gain) > 3: # We found a cutoff location initial_lower_cutoff_location = i break if initial_lower_cutoff_location < 0: self.result_label.setText("Lower cutoff location not found.") return initial_lower_cutoff_frequency = self.app.data21[initial_lower_cutoff_location].freq logger.debug("Found initial lower cutoff frequency at %d", initial_lower_cutoff_frequency) initial_upper_cutoff_location = -1 for i in range(pass_band_location, len(self.app.data21), 1): if (pass_band_db - self.app.data21[i].gain) > 3: # We found a cutoff location initial_upper_cutoff_location = i break if initial_upper_cutoff_location < 0: self.result_label.setText("Upper cutoff location not found.") return initial_upper_cutoff_frequency = self.app.data21[initial_upper_cutoff_location].freq logger.debug("Found initial upper cutoff frequency at %d", initial_upper_cutoff_frequency) peak_location = -1 peak_db = self.app.data21[initial_lower_cutoff_location].gain for i in range(initial_lower_cutoff_location, initial_upper_cutoff_location, 1): db = self.app.data21[i].gain if db > peak_db: peak_db = db peak_location = i logger.debug("Found peak of %f at %d", peak_db, self.app.data[peak_location].freq) lower_cutoff_location = -1 pass_band_db = peak_db for i in range(peak_location, -1, -1): if (pass_band_db - self.app.data21[i].gain) > 3: # We found the cutoff location lower_cutoff_location = i break lower_cutoff_frequency = self.app.data21[lower_cutoff_location].freq lower_cutoff_gain = self.app.data21[lower_cutoff_location].gain - pass_band_db if lower_cutoff_gain < -4: logger.debug("Lower cutoff frequency found at %f dB" " - insufficient data points for true -3 dB point.", lower_cutoff_gain) logger.debug("Found true lower cutoff frequency at %d", lower_cutoff_frequency) self.lower_cutoff_label.setText( f"{format_frequency(lower_cutoff_frequency)}" f" ({round(lower_cutoff_gain, 1)} dB)") self.app.markers[1].setFrequency(str(lower_cutoff_frequency)) self.app.markers[1].frequencyInput.setText(str(lower_cutoff_frequency)) upper_cutoff_location = -1 pass_band_db = peak_db for i in range(peak_location, len(self.app.data21), 1): if (pass_band_db - self.app.data21[i].gain) > 3: # We found the cutoff location upper_cutoff_location = i break upper_cutoff_frequency = self.app.data21[upper_cutoff_location].freq upper_cutoff_gain = self.app.data21[upper_cutoff_location].gain - pass_band_db if upper_cutoff_gain < -4: logger.debug("Upper cutoff frequency found at %f dB" " - insufficient data points for true -3 dB point.", upper_cutoff_gain) logger.debug("Found true upper cutoff frequency at %d", upper_cutoff_frequency) self.upper_cutoff_label.setText( f"{format_frequency(upper_cutoff_frequency)}" f" ({round(upper_cutoff_gain, 1)} dB)") self.app.markers[2].setFrequency(str(upper_cutoff_frequency)) self.app.markers[2].frequencyInput.setText(str(upper_cutoff_frequency)) span = upper_cutoff_frequency - lower_cutoff_frequency center_frequency = math.sqrt( lower_cutoff_frequency * upper_cutoff_frequency) q = center_frequency / span self.span_label.setText(format_frequency(span)) self.center_frequency_label.setText( format_frequency(center_frequency)) self.quality_label.setText(str(round(q, 2))) self.app.markers[0].setFrequency(str(round(center_frequency))) self.app.markers[0].frequencyInput.setText(str(round(center_frequency))) # Lower roll-off lower_six_db_location = -1 for i in range(lower_cutoff_location, -1, -1): if (pass_band_db - self.app.data21[i].gain) > 6: # We found 6dB location lower_six_db_location = i break if lower_six_db_location < 0: self.result_label.setText("Lower 6 dB location not found.") return lower_six_db_cutoff_frequency = self.app.data21[lower_six_db_location].freq self.lower_six_db_label.setText( format_frequency(lower_six_db_cutoff_frequency)) ten_db_location = -1 for i in range(lower_cutoff_location, -1, -1): if (pass_band_db - self.app.data21[i].gain) > 10: # We found 6dB location ten_db_location = i break twenty_db_location = -1 for i in range(lower_cutoff_location, -1, -1): if (pass_band_db - self.app.data21[i].gain) > 20: # We found 6dB location twenty_db_location = i break sixty_db_location = -1 for i in range(lower_six_db_location, -1, -1): if (pass_band_db - self.app.data21[i].gain) > 60: # We found 60dB location! Wow. sixty_db_location = i break if sixty_db_location > 0: if sixty_db_location > 0: sixty_db_cutoff_frequency = self.app.data21[sixty_db_location].freq self.lower_sixty_db_label.setText( format_frequency(sixty_db_cutoff_frequency)) elif ten_db_location != -1 and twenty_db_location != -1: ten = self.app.data21[ten_db_location].freq twenty = self.app.data21[twenty_db_location].freq sixty_db_frequency = ten * \ 10 ** (5 * (math.log10(twenty) - math.log10(ten))) self.lower_sixty_db_label.setText( f"{format_frequency(sixty_db_frequency)} (derived)") else: self.lower_sixty_db_label.setText("Not calculated") if ten_db_location > 0 and twenty_db_location > 0 and ten_db_location != twenty_db_location: octave_attenuation, decade_attenuation = self.calculateRolloff( ten_db_location, twenty_db_location) self.lower_db_per_octave_label.setText( str(round(octave_attenuation, 3)) + " dB / octave") self.lower_db_per_decade_label.setText( str(round(decade_attenuation, 3)) + " dB / decade") else: self.lower_db_per_octave_label.setText("Not calculated") self.lower_db_per_decade_label.setText("Not calculated") # Upper roll-off upper_six_db_location = -1 for i in range(upper_cutoff_location, len(self.app.data21), 1): if (pass_band_db - self.app.data21[i].gain) > 6: # We found 6dB location upper_six_db_location = i break if upper_six_db_location < 0: self.result_label.setText("Upper 6 dB location not found.") return upper_six_db_cutoff_frequency = self.app.data21[upper_six_db_location].freq self.upper_six_db_label.setText( format_frequency(upper_six_db_cutoff_frequency)) six_db_span = upper_six_db_cutoff_frequency - lower_six_db_cutoff_frequency self.six_db_span_label.setText( format_frequency(six_db_span)) ten_db_location = -1 for i in range(upper_cutoff_location, len(self.app.data21), 1): if (pass_band_db - self.app.data21[i].gain) > 10: # We found 6dB location ten_db_location = i break twenty_db_location = -1 for i in range(upper_cutoff_location, len(self.app.data21), 1): if (pass_band_db - self.app.data21[i].gain) > 20: # We found 6dB location twenty_db_location = i break sixty_db_location = -1 for i in range(upper_six_db_location, len(self.app.data21), 1): if (pass_band_db - self.app.data21[i].gain) > 60: # We found 60dB location! Wow. sixty_db_location = i break if sixty_db_location > 0: sixty_db_cutoff_frequency = self.app.data21[sixty_db_location].freq self.upper_sixty_db_label.setText( format_frequency(sixty_db_cutoff_frequency)) elif ten_db_location != -1 and twenty_db_location != -1: ten = self.app.data21[ten_db_location].freq twenty = self.app.data21[twenty_db_location].freq sixty_db_frequency = ten * \ 10 ** (5 * (math.log10(twenty) - math.log10(ten))) self.upper_sixty_db_label.setText( f"{format_frequency(sixty_db_frequency)} (derived)") else: self.upper_sixty_db_label.setText("Not calculated") if ten_db_location > 0 and twenty_db_location > 0 and ten_db_location != twenty_db_location: octave_attenuation, decade_attenuation = self.calculateRolloff( ten_db_location, twenty_db_location) self.upper_db_per_octave_label.setText( f"{round(octave_attenuation, 3)} dB / octave") self.upper_db_per_decade_label.setText( f"{round(decade_attenuation, 3)} dB / decade") else: self.upper_db_per_octave_label.setText("Not calculated") self.upper_db_per_decade_label.setText("Not calculated") if upper_cutoff_gain < -4 or lower_cutoff_gain < -4: self.result_label.setText( f"Analysis complete ({len(self.app.data)} points)\n" f"Insufficient data for analysis. Increase segment count.") else: self.result_label.setText( f"Analysis complete ({len(self.app.data)} points)")