PLL implementation
This commit is contained in:
99
QAM/debug.py
99
QAM/debug.py
@ -1,32 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtWidgets, QtCore
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import sys, os
|
||||
|
||||
def plot_constellations(ref_file, rx_file, title="Constellation comparison"):
|
||||
# Charger et forcer 2D
|
||||
ref_data = np.atleast_2d(np.loadtxt(ref_file))
|
||||
rx_data = np.atleast_2d(np.loadtxt(rx_file))
|
||||
|
||||
x_ref, y_ref = ref_data[:,0], ref_data[:,1]
|
||||
x_rx, y_rx = rx_data[:,0], rx_data[:,1]
|
||||
REF_FILE = "constellation_ref.dat"
|
||||
RX_FILE = "constellation.dat"
|
||||
|
||||
plt.figure(figsize=(6,6))
|
||||
plt.scatter(x_ref, y_ref, color='blue', s=50, marker='o', label='Référence')
|
||||
plt.scatter(x_rx, y_rx, color='red', s=50, marker='x', label='Reçu')
|
||||
def load_points(filename):
|
||||
if os.path.exists(filename):
|
||||
return np.loadtxt(filename)
|
||||
else:
|
||||
return np.zeros((0,2))
|
||||
|
||||
# Ajustement automatique des limites
|
||||
all_x = np.concatenate([x_ref, x_rx])
|
||||
all_y = np.concatenate([y_ref, y_rx])
|
||||
margin = 0.1 * max(np.ptp(all_x), np.ptp(all_y))
|
||||
plt.xlim(min(all_x)-margin, max(all_x)+margin)
|
||||
plt.ylim(min(all_y)-margin, max(all_y)+margin)
|
||||
# -------------------- Application --------------------
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
win = pg.GraphicsLayoutWidget(show=True, title="Constellation Viewer")
|
||||
win.resize(900, 900)
|
||||
win.setBackground('#0a0a0a') # fond noir profond
|
||||
|
||||
plt.xlabel('In-phase (I)')
|
||||
plt.ylabel('Quadrature (Q)')
|
||||
plt.title(title)
|
||||
plt.grid(False)
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
plt.legend()
|
||||
plt.show()
|
||||
plot = win.addPlot()
|
||||
plot.setAspectLocked(True) # axes égaux
|
||||
|
||||
plot_constellations("constellation_ref.dat", "constellation.dat", title="Constellation QAM")
|
||||
# -------------------- Axes stylés --------------------
|
||||
plot.getAxis('left').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('bottom').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('left').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.getAxis('bottom').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.setLabel('left', 'Quadrature (Q)', color='#EEE', size='12pt')
|
||||
plot.setLabel('bottom', 'In-phase (I)', color='#EEE', size='12pt')
|
||||
|
||||
# -------------------- Grille subtile --------------------
|
||||
grid = pg.GridItem()
|
||||
grid.setPen(pg.mkPen('#444', width=1, style=QtCore.Qt.DotLine))
|
||||
plot.addItem(grid)
|
||||
|
||||
# -------------------- Chargement initial des points --------------------
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
|
||||
# Points sans contour
|
||||
ref_plot = plot.plot(ref_data[:,0], ref_data[:,1],
|
||||
pen=None,
|
||||
symbol='o',
|
||||
symbolSize=10, # cercles un peu plus gros
|
||||
symbolBrush=pg.mkBrush('#1E90FF'), # bleu vif
|
||||
symbolPen=None,
|
||||
name='Référence')
|
||||
|
||||
rx_plot = plot.plot(rx_data[:,0], rx_data[:,1],
|
||||
pen=None,
|
||||
symbol='x',
|
||||
symbolSize=6, # croix plus petites
|
||||
symbolBrush=pg.mkBrush('#FF4500'), # orange vif
|
||||
symbolPen=None,
|
||||
name='Reçu')
|
||||
|
||||
# Légende stylée
|
||||
legend = plot.addLegend()
|
||||
for item in legend.items:
|
||||
item[1].setPen(pg.mkPen('#FFF', width=2))
|
||||
|
||||
# -------------------- Timer pour mise à jour dynamique --------------------
|
||||
def update():
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
ref_plot.setData(ref_data[:,0], ref_data[:,1])
|
||||
rx_plot.setData(rx_data[:,0], rx_data[:,1])
|
||||
|
||||
timer = QtCore.QTimer()
|
||||
timer.timeout.connect(update)
|
||||
timer.start(500) # ms
|
||||
|
||||
# -------------------- Anti-aliasing --------------------
|
||||
pg.setConfigOptions(antialias=True)
|
||||
|
||||
# -------------------- Exécution --------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user