fale
unknown
python
2 years ago
12 kB
6
Indexable
import sys import PyQt5.QtWidgets import pyqtgraph as pg import numpy as np from scipy.io import wavfile from scipy.fft import fft import csv class SignalGenerator: def __init__(self, sampling_rate, duration): self.sampling_rate = sampling_rate self.duration = duration def generate_sine(self, frequency, amplitude): t = np.linspace(0, self.duration, int(self.sampling_rate * self.duration), endpoint=False) signal = amplitude * np.sin(2 * np.pi * frequency * t) return t, signal def generate_square(self, frequency, amplitude): t = np.linspace(0, self.duration, int(self.sampling_rate * self.duration), endpoint=False) signal = amplitude * np.sign(np.sin(2 * np.pi * frequency * t)) return t, signal def generate_sawtooth(self, frequency, amplitude): t = np.linspace(0, self.duration, int(self.sampling_rate * self.duration), endpoint=False) signal = amplitude * (2 * (frequency * t - np.floor(0.5 + frequency * t))) return t, signal def generate_triangle(self, frequency, amplitude): t = np.linspace(0, self.duration, int(self.sampling_rate * self.duration), endpoint=False) signal = amplitude * np.abs((2 * (frequency * t - np.floor(0.5 + frequency * t))) - 1) return t, signal def generate_white_noise(self, amplitude): signal = amplitude * np.random.uniform(-1, 1, int(self.sampling_rate * self.duration)) t = np.linspace(0, self.duration, int(self.sampling_rate * self.duration), endpoint=False) return t, signal #wykres transformaty furiera def plot_fourier_transform(self, signal, title, plot_widget): N = len(signal) T = 1 / self.sampling_rate yf = fft(signal) xf = np.fft.fftfreq(N, T)[:N // 2] plot_widget.plot(xf, 2.0 / N * np.abs(yf[0:N // 2])) plot_widget.setTitle(title) plot_widget.setLabel('bottom', 'Częstotliwość (Hz)') plot_widget.setLabel('left', 'Amplituda') plot_widget.setXRange(0, 3000) plot_widget.setYRange(0, 0.0125) plot_widget.getAxis('bottom').setTicks([[(i, str(i)) for i in range(0, 3001, 500)]]) plot_widget.getAxis('left').setTicks([[(i, str(i)) for i in np.arange(0, 0.0126, 0.0025)]]) plot_widget.show() #zapisywanie do wav i csv def save_to_wav(self, t, signal, filename): if signal is not None: scaled_data = np.int16(signal / np.max(np.abs(signal)) * 32767) scaled_data = scaled_data.flatten() # Spłaszcz dane, jeśli są wielowymiarowe wavfile.write(filename, self.sampling_rate, scaled_data) def save_fourier_to_csv(self, signal, filename): if signal is not None: N = len(signal) T = 1 / self.sampling_rate yf = fft(signal) xf = np.fft.fftfreq(N, T)[:N // 2] with open(filename, 'w', newline='') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(['Częstotliwość', 'Amplituda']) for freq, amp in zip(xf, 2.0 / N * np.abs(yf[0:N // 2])): csvwriter.writerow( [freq.item(), amp.item()]) # Użyj item() do pobrania wartości z jednoelementowej tablicy NumPy class SignalGeneratorGUI(PyQt5.QtWidgets.QMainWindow): def __init__(self): super().__init__() self.generator = SignalGenerator(44100, 5) self.t = None # Add this line to store time data self.signal = None # Add this line to store signal data self.central_widget = PyQt5.QtWidgets.QWidget() self.setCentralWidget(self.central_widget) self.init_ui() def init_ui(self): # Layouts main_layout = PyQt5.QtWidgets.QHBoxLayout() # Left-side layout for signal options options_layout = PyQt5.QtWidgets.QVBoxLayout() #wybor fali # Signal Type signal_type_label = PyQt5.QtWidgets.QLabel("Typ sygnału:") self.signal_type_combo = PyQt5.QtWidgets.QComboBox() self.signal_type_combo.addItems(['Sine', 'Square', 'Triangle', 'Sawtooth', 'White Noise']) options_layout.addWidget(signal_type_label) options_layout.addWidget(self.signal_type_combo) #podawanie parametrow spinboxy # Sampling Rate sampling_rate_label = PyQt5.QtWidgets.QLabel("Częstotliwość próbkowania (Hz):") self.sampling_rate_spin = PyQt5.QtWidgets.QSpinBox() self.sampling_rate_spin.setValue(44100) self.sampling_rate_spin.setRange(0, 100000) self.sampling_rate_spin.setSingleStep(1) options_layout.addWidget(sampling_rate_label) options_layout.addWidget(self.sampling_rate_spin) # Duration duration_label = PyQt5.QtWidgets.QLabel("Długość trwania (s):") self.duration_spin = PyQt5.QtWidgets.QSpinBox() self.duration_spin.setValue(0) self.duration_spin.setRange(0, 100000) self.duration_spin.setSingleStep(1) options_layout.addWidget(duration_label) options_layout.addWidget(self.duration_spin) # Frequency frequency_label = PyQt5.QtWidgets.QLabel("Częstotliwość (Hz):") self.frequency_double_spin = PyQt5.QtWidgets.QDoubleSpinBox() self.frequency_double_spin.setValue(0) self.frequency_double_spin.setRange(0, 100000) self.frequency_double_spin.setSingleStep(1) options_layout.addWidget(frequency_label) options_layout.addWidget(self.frequency_double_spin) # Amplitude amplitude_label = PyQt5.QtWidgets.QLabel("Amplituda:") self.amplitude_double_spin = PyQt5.QtWidgets.QDoubleSpinBox() self.amplitude_double_spin.setValue(0) self.amplitude_double_spin.setRange(0, 100000) self.amplitude_double_spin.setSingleStep(1) options_layout.addWidget(amplitude_label) options_layout.addWidget(self.amplitude_double_spin) # Generate Button generate_button = PyQt5.QtWidgets.QPushButton("Generuj sygnał") generate_button.clicked.connect(self.generate_signal) options_layout.addWidget(generate_button) # Connect SpinBox valueChanged signals self.sampling_rate_spin.valueChanged.connect(self.update_signal) self.duration_spin.valueChanged.connect(self.update_signal) self.frequency_double_spin.valueChanged.connect(self.update_signal) self.amplitude_double_spin.valueChanged.connect(self.update_signal) # Right-side layout for plots and tables plots_layout = PyQt5.QtWidgets.QHBoxLayout() #tabelka z czasem i amplituda a powinno byc z czasem i zbiorem wartosci # Table for time domain self.table = PyQt5.QtWidgets.QTableWidget() self.table.setColumnCount(2) self.table.setHorizontalHeaderLabels(['Czas', 'Zbiór wartości']) plots_layout.addWidget(self.table) # Middle layout for plots middle_layout = PyQt5.QtWidgets.QVBoxLayout() # Plot self.plot_widget = pg.PlotWidget() self.plot_widget.setLabel('bottom', 'Czas (s)') self.plot_widget.setLabel('left', 'Amplituda') middle_layout.addWidget(self.plot_widget) # Fourier Transform Plot self.fourier_plot_widget = pg.PlotWidget() self.fourier_plot_widget.setLabel('bottom', 'Częstotliwość (Hz)') self.fourier_plot_widget.setLabel('left', 'Amplituda') middle_layout.addWidget(self.fourier_plot_widget) plots_layout.addLayout(middle_layout) main_layout.addLayout(options_layout) main_layout.addLayout(plots_layout) #pryzciski do zapisywania do wav i csv # Menu Bar menubar = self.menuBar() file_menu = menubar.addMenu('Plik') # Save to WAV save_wav_action = PyQt5.QtWidgets.QAction('Zapisz do WAV', self) save_wav_action.triggered.connect(self.save_to_wav) file_menu.addAction(save_wav_action) # Save to CSV save_csv_action = PyQt5.QtWidgets.QAction('Zapisz do CSV', self) save_csv_action.triggered.connect(self.save_to_csv) file_menu.addAction(save_csv_action) self.central_widget.setLayout(main_layout) self.setWindowTitle("Generator Sygnałów") self.show() def update_signal(self): # Funkcja wywoływana po zmianie wartości w spinboxach if self.t is not None and self.signal is not None and len(self.t) > 0 and len(self.signal) > 0: # Aktualizacja Table self.table.setRowCount(len(self.t)) for i in range(len(self.t)): self.table.setItem(i, 0, PyQt5.QtWidgets.QTableWidgetItem(str(self.t[i]))) self.table.setItem(i, 1, PyQt5.QtWidgets.QTableWidgetItem(str(self.signal[i]))) # Aktualizacja Plot self.plot_widget.clear() self.plot_widget.plot(self.t, self.signal, pen='b') # Aktualizacja Fourier Transform Plot self.fourier_plot_widget.clear() self.generator.plot_fourier_transform(self.signal, 'Fourier Transform', self.fourier_plot_widget) def generate_signal(self): # Generowanie sygnału na podstawie aktualnych wartości spinboxów signal_type = self.signal_type_combo.currentText() frequency = self.frequency_double_spin.value() amplitude = self.amplitude_double_spin.value() duration = self.duration_spin.value() sampling_rate = self.sampling_rate_spin.value() self.t, self.signal = [], [] # Reset danych if signal_type == 'Sine': self.t, self.signal = self.generator.generate_sine(frequency, amplitude) elif signal_type == 'Square': self.t, self.signal = self.generator.generate_square(frequency, amplitude) elif signal_type == 'Triangle': self.t, self.signal = self.generator.generate_triangle(frequency, amplitude) elif signal_type == 'Sawtooth': self.t, self.signal = self.generator.generate_sawtooth(frequency, amplitude) elif signal_type == 'White Noise': self.t, self.signal = self.generator.generate_white_noise(amplitude) self.update_signal() # Wywołanie funkcji aktualizującej po wygenerowaniu nowych danych t, signal = self.generator.generate_sine(frequency, amplitude) # Default to sine for simplicity # Update Table self.table.setRowCount(len(self.t)) for i in range(len(self.t)): self.table.setItem(i, 0, PyQt5.QtWidgets.QTableWidgetItem(str(self.t[i]))) self.table.setItem(i, 1, PyQt5.QtWidgets.QTableWidgetItem(str(self.signal[i]))) # Update Plot self.plot_widget.clear() self.plot_widget.plot(self.t, self.signal, pen='b') # Update Fourier Transform Plot self.fourier_plot_widget.clear() self.generator.plot_fourier_transform(self.signal, 'Fourier Transform', self.fourier_plot_widget) def save_to_wav(self): filename, _ = PyQt5.QtWidgets.QFileDialog.getSaveFileName(self, 'Zapisz do pliku WAV', '', 'Wave Files (*.wav);;All Files (*)') if filename: self.generator.save_to_wav(self.t, self.signal, filename) def save_to_csv(self): filename, _ = PyQt5.QtWidgets.QFileDialog.getSaveFileName(self, 'Zapisz do pliku CSV', '', 'CSV Files (*.csv);;All Files (*)') if filename: self.generator.save_fourier_to_csv(self.signal, filename) if __name__ == '__main__': app = PyQt5.QtWidgets.QApplication(sys.argv) window = SignalGeneratorGUI() sys.exit(app.exec_())
Editor is loading...
Leave a Comment