#define _CRT_SECURE_NO_WARNINGS
#include "communication_system.h"
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <complex>
#include <random>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <QAudioOutput>
#include <QTimer>
#include <QBuffer>
#include <QtMath>
#include <QValueAxis>
#include <QChart>
#include <QLineSeries>
const float FSK_FREQ_SHIFT = 1000.0f;
int find_frame_header(const float* data, int length, const QByteArray& header);
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_PI_2
#define M_PI_2 (M_PI / 2.0)
#endif
#ifndef M_PI_4
#define M_PI_4 (M_PI / 4.0)
#endif
// ================= 初始化函数 =================
void init_transmitter(Transmitter* tx, SignalType sig_type, ModulationType mod_type,
float carrier_freq, int sample_rate) {
if (tx->samples) {
delete[] tx->samples;
}
if (tx->modulated) {
delete[] tx->modulated;
}
memset(tx, 0, sizeof(Transmitter));
tx->signal_type = sig_type;
tx->mod_type = mod_type;
tx->carrier_freq = carrier_freq;
tx->sample_rate = sample_rate;
tx->samples = new float[MAX_SAMPLES]();
tx->modulated = new float[MAX_SAMPLES]();
tx->bit_count = 0;
tx->original_bit_count = 0;
}
void init_receiver(Receiver* rx, float carrier_freq, int sample_rate) {
if (rx->received) {
delete[] rx->received;
}
if (rx->demodulated) {
delete[] rx->demodulated;
}
memset(rx, 0, sizeof(Receiver));
rx->carrier_freq = carrier_freq;
rx->sample_rate = sample_rate;
rx->received = new float[MAX_SAMPLES]();
rx->demodulated = new float[MAX_SAMPLES]();
rx->bit_count = 0;
rx->sample_count = 0;
memset(rx->decoded_text, 0, sizeof(rx->decoded_text));
memset(rx->binary_data, 0, sizeof(rx->binary_data));
}
// ================= 信号生成 =================
void generate_signal(Transmitter* tx, int duration_ms) {
int num_samples = (duration_ms * tx->sample_rate) / 1000;
if (num_samples > MAX_SAMPLES) num_samples = MAX_SAMPLES;
tx->sample_count = num_samples;
switch (tx->signal_type) {
case SINE_WAVE:
for (int i = 0; i < num_samples; i++) {
float t = static_cast<float>(i) / tx->sample_rate;
tx->samples[i] = sin(2 * M_PI * 5.0f * t);
}
break;
case SQUARE_WAVE:
for (int i = 0; i < num_samples; i++) {
float t = static_cast<float>(i) / tx->sample_rate;
tx->samples[i] = (sin(2 * M_PI * 3.0f * t) > 0 ? 1.0f : -1.0f);
}
break;
case SAWTOOTH_WAVE:
for (int i = 0; i < num_samples; i++) {
float t = static_cast<float>(i) / tx->sample_rate;
tx->samples[i] = 2.0f * (t * 4.0f - floorf(t * 4.0f + 0.5f));
}
break;
case RANDOM_DATA: {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> dist(-1.0f, 1.0f);
for (int i = 0; i < num_samples; i++) {
tx->samples[i] = dist(gen);
}
break;
}
case TEXT_DATA:
case FILE_DATA:
// 在专用函数中处理
break;
}
}
// ================= 文本数据处理 =================
void set_text_data(Transmitter* tx, const char* text) {
// 直接存储UTF-8字节序列
size_t len = strlen(text);
if (len >= MAX_TEXT_LENGTH) len = MAX_TEXT_LENGTH - 1;
memcpy(tx->text_data, text, len);
tx->text_data[len] = '\0';
tx->bit_count = 0;
// 添加帧头:0x55 (01010101)
uint8_t header = 0x55;
for (int j = 7; j >= 0; j--) {
if (tx->bit_count < MAX_BITS) {
tx->binary_data[tx->bit_count++] = (header >> j) & 1;
}
}
// 处理整个UTF-8字节序列
for (size_t i = 0; i < len; i++) {
uint8_t c = (uint8_t)tx->text_data[i];
for (int j = 7; j >= 0; j--) {
if (tx->bit_count < MAX_BITS) {
tx->binary_data[tx->bit_count++] = (c >> j) & 1;
}
}
}
// 添加帧尾:0xAA (10101010)
uint8_t footer = 0xAA;
for (int j = 7; j >= 0; j--) {
if (tx->bit_count < MAX_BITS) {
tx->binary_data[tx->bit_count++] = (footer >> j) & 1;
}
}
// 生成信号波形
tx->sample_count = tx->bit_count * static_cast<int>(SAMPLES_PER_BIT);
if (tx->sample_count > MAX_SAMPLES) {
tx->sample_count = MAX_SAMPLES;
tx->bit_count = tx->sample_count / static_cast<int>(SAMPLES_PER_BIT);
}
for (int i = 0; i < tx->bit_count; i++) {
for (int j = 0; j < static_cast<int>(SAMPLES_PER_BIT); j++) {
int idx = i * static_cast<int>(SAMPLES_PER_BIT) + j;
if (idx < MAX_SAMPLES) {
tx->samples[idx] = tx->binary_data[i] ? 1.0f : -1.0f;
}
}
}
// 汉明编码
int original_bit_count = tx->bit_count;
encode_hamming(tx->binary_data, tx->bit_count);
tx->original_bit_count = original_bit_count;
}
// ================= 文件数据处理 =================
void load_file_data(Transmitter* tx, const char* filename) {
strncpy(tx->filename, filename, 255);
tx->filename[255] = '\0';
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "无法打开文件:" << filename;
return;
}
QTextStream in(&file);
tx->sample_count = 0;
while (!in.atEnd() && tx->sample_count < MAX_SAMPLES) {
QString line = in.readLine();
bool ok;
float value = line.toFloat(&ok);
if (ok) {
tx->samples[tx->sample_count++] = value;
}
}
file.close();
}
// ================= 调制函数 =================
void modulate_signal(Transmitter* tx) {
qDebug() << "调制信号 - 类型:" << tx->mod_type
<< "载波频率:" << tx->carrier_freq
<< "采样数:" << tx->sample_count;
if (tx->signal_type == TEXT_DATA && tx->bit_count == 0) {
qWarning() << "文本数据未设置!";
return;
}
if (tx->sample_count == 0) return;
for (int i = 0; i < tx->sample_count; i++) {
float t = static_cast<float>(i) / tx->sample_rate;
float carrier = sin(2 * M_PI * tx->carrier_freq * t);
float quadrature = cos(2 * M_PI * tx->carrier_freq * t);
switch (tx->mod_type) {
case BPSK: {
float symbol = 0.0f;
if (tx->signal_type == TEXT_DATA) {
int bit_index = i / static_cast<int>(SAMPLES_PER_BIT);
if (bit_index < tx->bit_count) {
symbol = tx->binary_data[bit_index] ? 1.0f : -1.0f;
}
}
else {
symbol = tx->samples[i];
}
tx->modulated[i] = symbol * carrier;
break;
}
case QPSK: {
if (tx->signal_type == TEXT_DATA) {
int symbol_index = i / static_cast<int>(2 * SAMPLES_PER_BIT);
if (symbol_index < tx->bit_count / 2) {
int bit_index = symbol_index * 2;
int bit1 = tx->binary_data[bit_index];
int bit2 = tx->binary_data[bit_index + 1];
float I = (bit1 == 0) ? -1.0f : 1.0f;
float Q = (bit2 == 0) ? -1.0f : 1.0f;
tx->modulated[i] = I * carrier + Q * quadrature;
}
else {
tx->modulated[i] = 0.0f;
}
}
else {
tx->modulated[i] = tx->samples[i] * carrier;
}
break;
}
case FSK: {
float base_freq = tx->carrier_freq;
float freq_shift = 500.0f;
if (tx->signal_type == TEXT_DATA) {
int bit_index = i / static_cast<int>(SAMPLES_PER_BIT);
float freq = base_freq;
if (bit_index < tx->bit_count) {
freq += tx->binary_data[bit_index] ? freq_shift : -freq_shift;
}
tx->modulated[i] = sin(2 * M_PI * freq * t);
}
else {
float freq = base_freq + (tx->samples[i] > 0 ? freq_shift : -freq_shift);
tx->modulated[i] = sin(2 * M_PI * freq * t);
}
break;
}
case AM: {
float modulation_index = 0.8f;
float analog = 0.0f;
if (tx->signal_type == TEXT_DATA) {
int bit_index = i / static_cast<int>(SAMPLES_PER_BIT);
if (bit_index < tx->bit_count) {
analog = tx->binary_data[bit_index] ? 1.0f : -1.0f;
}
}
else {
analog = tx->samples[i];
}
tx->modulated[i] = (1.0f + modulation_index * analog) * carrier;
break;
}
}
}
//添加噪声
apply_noise(tx->modulated, tx->sample_count, 80.0f); // 10dB SNR
}
// ================= 解调函数 =================
void demodulate_bpsk(Receiver* rx) {
float last_filtered = 0.0f;
const float alpha = 0.1f; // 低通滤波系数
for (int i = 0; i < rx->sample_count; i++) {
float t = static_cast<float>(i) / rx->sample_rate;
float carrier = sin(2 * M_PI * rx->carrier_freq * t);
// 相干解调
float mixed = rx->received[i] * carrier;
// 低通滤波
float filtered = alpha * mixed + (1.0f - alpha) * last_filtered;
last_filtered = filtered;
rx->demodulated[i] = filtered;
// 调试输出
qDebug() << "Demodulated sample at index" << i << ": " << filtered;
}
}
void demodulate_qpsk(Receiver* rx) {
float last_i = 0.0f, last_q = 0.0f;
const float alpha = 0.1f; // 低通滤波系数
for (int i = 0; i < rx->sample_count; i++) {
float t = static_cast<float>(i) / rx->sample_rate;
float carrier = sin(2 * M_PI * rx->carrier_freq * t);
float quadrature = cos(2 * M_PI * rx->carrier_freq * t);
// I路解调
float i_mixed = rx->received[i] * carrier;
float i_filtered = alpha * i_mixed + (1.0f - alpha) * last_i;
last_i = i_filtered;
// Q路解调
float q_mixed = rx->received[i] * quadrature;
float q_filtered = alpha * q_mixed + (1.0f - alpha) * last_q;
last_q = q_filtered;
// 合并为幅度信号
rx->demodulated[i] = sqrt(i_filtered * i_filtered + q_filtered * q_filtered);
}
}
void demodulate_fsk(Receiver* rx) {
if (rx->sample_count == 0) return;
// 创建两个频率的载波表,优化计算效率
QVector<float> carrier1(rx->sample_count);
QVector<float> carrier2(rx->sample_count);
for (int i = 0; i < rx->sample_count; i++) {
float t = static_cast<float>(i) / rx->sample_rate;
carrier1[i] = qSin(2 * M_PI * rx->carrier_freq * t);
carrier2[i] = qSin(2 * M_PI * (rx->carrier_freq + FSK_FREQ_SHIFT) * t);
}
// 滑动窗口相关器实现FSK解调
const int window_size = SAMPLES_PER_BIT / 2; // 相关窗口大小
QVector<float> demod_result(rx->sample_count);
for (int i = window_size; i < rx->sample_count - window_size; i++) {
float sum1 = 0.0f;
float sum2 = 0.0f;
// 计算窗口内与两个载波的相关性
for (int j = -window_size; j <= window_size; j++) {
sum1 += rx->received[i + j] * carrier1[i + j];
sum2 += rx->received[i + j] * carrier2[i + j];
}
// 归一化并计算差分
demod_result[i] = (sum1 - sum2) / (2 * window_size + 1);
}
// 低通滤波以平滑结果
const float alpha = 0.1f;
float filtered = 0.0f;
for (int i = 0; i < rx->sample_count; i++) {
filtered = alpha * demod_result[i] + (1.0f - alpha) * filtered;
rx->demodulated[i] = filtered;
}
qDebug() << "FSK解调完成,样本数:" << rx->sample_count;
}
// 改进AM解调:使用非相干解调
void demodulate_am(Receiver* rx) {
float last_env = 0.0f;
const float alpha = 0.05f; // 包络检测系数
for (int i = 0; i < rx->sample_count; i++) {
// 计算包络
float env = fabs(rx->received[i]);
env = alpha * env + (1.0f - alpha) * last_env;
last_env = env;
// 移除DC分量
static float dc_estimate = 0.0f;
const float dc_alpha = 0.001f;
dc_estimate = (1 - dc_alpha) * dc_estimate + dc_alpha * env;
rx->demodulated[i] = env - dc_estimate;
}
// 归一化
float max_val = 0.001f;
for (int i = 0; i < rx->sample_count; i++) {
if (fabs(rx->demodulated[i]) > max_val)
max_val = fabs(rx->demodulated[i]);
}
float scale = 1.0f / max_val;
for (int i = 0; i < rx->sample_count; i++) {
rx->demodulated[i] *= scale;
}
}
void demodulate_signal(Receiver* rx) {
qDebug() << "解调信号 - 类型:" << rx->mod_type
<< "载波频率:" << rx->carrier_freq
<< "采样数:" << rx->sample_count;
if (rx->sample_count <= 0) return;
// 确保有足够内存
if (rx->demodulated == nullptr) {
rx->demodulated = new float[MAX_SAMPLES]();
}
// 根据调制类型选择解调方法
switch (rx->mod_type) {
case BPSK:
demodulate_bpsk(rx);
break;
case QPSK:
demodulate_qpsk(rx);
break;
case FSK:
demodulate_fsk(rx);
break;
case AM:
demodulate_am(rx);
break;
}
}
// ================= 解码函数 =================
void decode_signal(Receiver* rx) {
if (rx->sample_count == 0) return;
if (rx->signal_type != TEXT_DATA) return;
// 计算比特数
rx->bit_count = rx->sample_count / SAMPLES_PER_BIT;
if (rx->bit_count > MAX_BITS) rx->bit_count = MAX_BITS;
// 寻找帧头进行同步 (假设帧头为01010101)
const QByteArray frame_header = QByteArray::fromHex("55"); // 01010101
//const int header_length = frame_header.size() * 8;
int sync_offset = find_frame_header(rx->demodulated, rx->sample_count, frame_header);
if (sync_offset < 0) {
qWarning() << "帧同步失败,无法找到帧头";
return;
}
qDebug() << "帧同步成功,偏移量:" << sync_offset << "样本";
// 从同步点开始解码
int start_index = sync_offset + 8 * SAMPLES_PER_BIT;
int decoded_bits = 0;
// 使用自适应阈值解码
for (int i = 0; i < rx->bit_count; i++) {
int bit_start = static_cast<int>(start_index + i * SAMPLES_PER_BIT);
if (bit_start >= rx->sample_count) break;
// int mid_point = bit_start + SAMPLES_PER_BIT / 2;
// if (mid_point >= rx->sample_count) continue;
// 计算当前比特周期的平均值作为阈值
float sum = 0.0f;
//int valid_samples = 0;
for (int j = 0; j < SAMPLES_PER_BIT; j++) {
if (bit_start + j < rx->sample_count) {
sum += rx->demodulated[bit_start + j];
//valid_samples++;
}
}
// if (valid_samples > 0) {
float threshold = sum / SAMPLES_PER_BIT;
// 取中间点作为判决点
int mid_point = bit_start + SAMPLES_PER_BIT / 2;
float mid_value = rx->demodulated[mid_point];
rx->binary_data[i] = (mid_value > threshold) ? 1 : 0;
decoded_bits++;
}
rx->bit_count = decoded_bits;
// 汉明解码
int decoded_bit_count = decode_hamming(rx->binary_data, rx->bit_count);
if (decoded_bit_count <= 0) {
qWarning() << "汉明解码失败,无法纠正错误";
return;
}
// 转换为文本
QByteArray byteArray;
int byte_count = decoded_bit_count / 8;
// 跳过帧头(1字节)和帧尾(1字节)
int start_byte = 1;
int end_byte = byte_count - 1;
for (int i = 0; i < byte_count; i++) {
uint8_t byte = 0;
for (int j = 0; j < 8; j++) {
int bit_index = i * 8 + j;
if (bit_index < decoded_bit_count) {
byte = (byte << 1) | (rx->binary_data[bit_index] ? 1 : 0);
}
}
byteArray.append(byte);
}
QString decodedText = QString::fromUtf8(byteArray);
strncpy(rx->decoded_text, decodedText.toUtf8().constData(), MAX_TEXT_LENGTH - 1);
rx->decoded_text[MAX_TEXT_LENGTH - 1] = '\0';
qDebug() << "解码成功,文本:" << decodedText;
}
// 添加帧头搜索函数
int find_frame_header(const float* data, int length, const QByteArray& header) {
const int header_bits = header.size() * 8;
const int search_range = length - header_bits * SAMPLES_PER_BIT;
if (search_range <= 0) return -1;
// 计算帧头的理想比特值
QVector<int> header_bits_vector(header_bits);
for (int i = 0; i < header.size(); i++) {
for (int j = 0; j < 8; j++) {
header_bits_vector[i * 8 + j] = (header[i] >> (7 - j)) & 1;
}
}
// 在数据中搜索最佳匹配位置
int best_offset = -1;
float best_correlation = -FLT_MAX;
for (int offset = 0; offset < search_range; offset += SAMPLES_PER_BIT / 4) {
float correlation = 0.0f;
for (int i = 0; i < header_bits; i++) {
int bit_start = offset + i * SAMPLES_PER_BIT;
float bit_value = 0.0f;
if (bit_start + SAMPLES_PER_BIT >= length) break;
// 计算该比特周期的平均值
for (int j = 0; j < SAMPLES_PER_BIT; j++) {
//if (bit_start + j < length) {
bit_value += data[bit_start + j];
// }
}
bit_value /= SAMPLES_PER_BIT;
// 计算相关性(与理想值比较)
float expected = header_bits_vector[i] ? 1.0f : -1.0f;
correlation += bit_value * expected;
}
// 找到最佳匹配
if (correlation > best_correlation) {
best_correlation = correlation;
best_offset = offset;
}
}
// 如果相关性高于阈值,返回最佳偏移
if (best_correlation > header_bits * 0.7f) {
return best_offset;
}
return -1; // 未找到匹配
}
// ================= 汉明编解码 =================
void encode_hamming(uint8_t* data, int& bit_count) {
int original_count = bit_count;
int hamming_count = (original_count * 7) / 4;
if (hamming_count > MAX_BITS) hamming_count = MAX_BITS;
uint8_t* hamming_data = new uint8_t[MAX_BITS]();
int h_index = 0;
for (int i = 0; i < original_count; i += 4) {
if (h_index + 7 >= MAX_BITS) break;
if (i + 3 >= original_count) break;
uint8_t d1 = data[i];
uint8_t d2 = data[i + 1];
uint8_t d3 = data[i + 2];
uint8_t d4 = data[i + 3];
// 确保数据位是0或1
// d1 = data[i] ? 1 : 0;
// d2 = data[i + 1] ? 1 : 0;
// d3 = data[i + 2] ? 1 : 0;
// d4 = data[i + 3] ? 1 : 0;
// 计算校验位
uint8_t p1 = d1 ^ d2 ^ d4;
uint8_t p2 = d1 ^ d3 ^ d4;
uint8_t p3 = d2 ^ d3 ^ d4;
hamming_data[h_index++] = p1;
hamming_data[h_index++] = p2;
hamming_data[h_index++] = d1;
hamming_data[h_index++] = p3;
hamming_data[h_index++] = d2;
hamming_data[h_index++] = d3;
hamming_data[h_index++] = d4;
}
// 复制回原数组
memcpy(data, hamming_data, h_index);
bit_count = h_index;
delete[] hamming_data;
}
int decode_hamming(uint8_t* data, int bit_count) {
int decoded_count = 0;
uint8_t* decoded_data = new uint8_t[MAX_BITS]();
for (int i = 0; i < bit_count; i += 7) {
if (i + 6 >= bit_count) break;
if (decoded_count + 4 >= MAX_BITS) break;
uint8_t p1 = data[i];
uint8_t p2 = data[i + 1];
uint8_t d1 = data[i + 2];
uint8_t p3 = data[i + 3];
uint8_t d2 = data[i + 4];
uint8_t d3 = data[i + 5];
uint8_t d4 = data[i + 6];
// 确保数据位是0或1
/* p1 = data[i] ? 1 : 0;
p2 = data[i + 1] ? 1 : 0;
d1 = data[i + 2] ? 1 : 0;
p3 = data[i + 3] ? 1 : 0;
d2 = data[i + 4] ? 1 : 0;
d3 = data[i + 5] ? 1 : 0;
d4 = data[i + 6] ? 1 : 0;*/
// 计算校验子
uint8_t s1 = p1 ^ d1 ^ d2 ^ d4;
uint8_t s2 = p2 ^ d1 ^ d3 ^ d4;
uint8_t s3 = p3 ^ d2 ^ d3 ^ d4;
int error_pos = s1 + (s2 << 1) + (s3 << 2);
// 错误纠正
if (error_pos > 0) {
switch (error_pos) {
case 1: p1 ^= 1; break;
case 2: p2 ^= 1; break;
case 3: d1 ^= 1; break;
case 4: p3 ^= 1; break;
case 5: d2 ^= 1; break;
case 6: d3 ^= 1; break;
case 7: d4 ^= 1; break;
}
}
// 提取数据位
decoded_data[decoded_count++] = d1;
decoded_data[decoded_count++] = d2;
decoded_data[decoded_count++] = d3;
decoded_data[decoded_count++] = d4;
}
// 复制回原数组
memcpy(data, decoded_data, decoded_count);
delete[] decoded_data;
return decoded_count;
}
// ================= 文件操作 =================
void save_signal_to_file(const char* filename, const float* data, int count,
int sample_rate, SignalType sig_type, ModulationType mod_type) {
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "无法打开文件进行写入:" << filename;
return;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_5_9);
// 写入文件头
out << static_cast<qint32>(sample_rate);
out << static_cast<qint32>(sig_type);
out << static_cast<qint32>(mod_type);
out << static_cast<qint32>(count);
// 写入数据
for (int i = 0; i < count; i++) {
out << static_cast<float>(data[i]);
}
file.close();
}
void load_signal_from_file(const char* filename, float* data, int* count,
int* sample_rate, SignalType* sig_type, ModulationType* mod_type) {
QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "无法打开文件进行读取:" << filename;
return;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_5_9);
// 读取文件头
qint32 sr, st, mt, c;
in >> sr;
in >> st;
in >> mt;
in >> c;
*sample_rate = sr;
*sig_type = static_cast<SignalType>(st);
*mod_type = static_cast<ModulationType>(mt);
*count = (c > MAX_SAMPLES) ? MAX_SAMPLES : c;
// 读取数据
for (int i = 0; i < *count; i++) {
float value;
in >> value;
data[i] = value;
}
file.close();
}
// ================= 噪声处理 =================
void apply_noise(float* signal, int count, float snr_db) {
// 计算信号功率
float signal_power = 0.0f;
for (int i = 0; i < count; i++) {
signal_power += signal[i] * signal[i];
}
signal_power /= static_cast<float>(count);
// 计算噪声功率
float snr_linear = powf(10.0f, snr_db / 10.0f);
float noise_power = signal_power / snr_linear;
float noise_stddev = sqrtf(noise_power);
// 生成高斯噪声
std::random_device rd;
std::mt19937 gen(rd());
std::normal_distribution<float> dist(0.0f, noise_stddev);
// 添加噪声
for (int i = 0; i < count; i++) {
signal[i] += dist(gen);
}
}
// ================= GUI实现 =================
CommunicationSystemGUI::CommunicationSystemGUI(QWidget* parent)
: QMainWindow(parent),
sourceWaveformView(new QChartView(this)),
sourceSpectrumView(new QChartView(this)),
modulatedWaveformView(new QChartView(this)),
modulatedSpectrumView(new QChartView(this)),
receivedWaveformView(new QChartView(this)),
receivedSpectrumView(new QChartView(this)),
demodulatedWaveformView(new QChartView(this)),
audioInput(nullptr),
audioOutput(nullptr)
{
// 初始化窗口
setWindowTitle("数字通信系统");
resize(1200, 800);
// 创建主布局
QWidget* centralWidget = new QWidget(this);
QVBoxLayout* mainLayout = new QVBoxLayout(centralWidget);
setCentralWidget(centralWidget);
// 创建分割器
QSplitter* mainSplitter = new QSplitter(Qt::Vertical, centralWidget);
mainLayout->addWidget(mainSplitter);
// 创建控制面板
QWidget* controlWidget = new QWidget();
QHBoxLayout* controlLayout = new QHBoxLayout(controlWidget);
// 创建发送方控制组
createTransmitterGroup();
controlLayout->addWidget(transmitterGroup);
// 创建接收方控制组
createReceiverGroup();
controlLayout->addWidget(receiverGroup);
mainSplitter->addWidget(controlWidget);
// 创建波形显示区域
createWaveformDisplays();
mainSplitter->addWidget(waveformFrame);
// 设置分割器比例
mainSplitter->setSizes({ 200, 600 });
// 创建状态栏
statusBar = new QStatusBar();
setStatusBar(statusBar);
// 创建状态栏组件
transmitStatusLabel = new QLabel("发送状态: 空闲");
receiveStatusLabel = new QLabel("接收状态: 空闲");
transmitProgressBar = new QProgressBar();
transmitProgressBar->setRange(0, 100);
transmitProgressBar->setFixedWidth(150);
transmitProgressBar->setTextVisible(true);
receiveProgressBar = new QProgressBar();
receiveProgressBar->setRange(0, 100);
receiveProgressBar->setFixedWidth(150);
receiveProgressBar->setTextVisible(true);
// 添加到状态栏
statusBar->addPermanentWidget(transmitStatusLabel);
statusBar->addPermanentWidget(transmitProgressBar);
statusBar->addPermanentWidget(receiveStatusLabel);
statusBar->addPermanentWidget(receiveProgressBar);
// 确保接收器内存分配正确
receiver.received = new float[MAX_SAMPLES]();
receiver.demodulated = new float[MAX_SAMPLES]();
// 初始化通信模块
init_transmitter(&transmitter, SINE_WAVE, BPSK, CARRIER_FREQ, SAMPLE_RATE);
init_receiver(&receiver, CARRIER_FREQ, SAMPLE_RATE);
// 初始化音频设备
initAudio();
}
CommunicationSystemGUI::~CommunicationSystemGUI() {
delete[] transmitter.samples;
delete[] transmitter.modulated;
delete[] receiver.received;
delete[] receiver.demodulated;
delete audioInput;
delete audioOutput;
}
void CommunicationSystemGUI::createTransmitterGroup() {
transmitterGroup = new QGroupBox("发送方");
QGridLayout* layout = new QGridLayout(transmitterGroup);
// 信号类型
layout->addWidget(new QLabel("信号类型:"), 0, 0);
signalTypeCombo = new QComboBox();
signalTypeCombo->addItem("正弦波", SINE_WAVE);
signalTypeCombo->addItem("方波", SQUARE_WAVE);
signalTypeCombo->addItem("锯齿波", SAWTOOTH_WAVE);
signalTypeCombo->addItem("随机数据", RANDOM_DATA);
signalTypeCombo->addItem("文本数据", TEXT_DATA);
signalTypeCombo->addItem("文件数据", FILE_DATA);
layout->addWidget(signalTypeCombo, 0, 1);
// 调制类型
layout->addWidget(new QLabel("调制类型:"), 1, 0);
modulationTypeCombo = new QComboBox();
modulationTypeCombo->addItem("BPSK", BPSK);
modulationTypeCombo->addItem("QPSK", QPSK);
modulationTypeCombo->addItem("FSK", FSK);
modulationTypeCombo->addItem("AM", AM);
layout->addWidget(modulationTypeCombo, 1, 1);
// 载波频率
layout->addWidget(new QLabel("载波频率(Hz):"), 2, 0);
carrierFreqEdit = new QLineEdit(QString::number(CARRIER_FREQ));
carrierFreqEdit->setValidator(new QDoubleValidator(100, 10000, 2, this));
layout->addWidget(carrierFreqEdit, 2, 1);
// 文本输入
layout->addWidget(new QLabel("文本数据:"), 3, 0, 1, 2);
textDataEdit = new QTextEdit();
textDataEdit->setMaximumHeight(60);
layout->addWidget(textDataEdit, 4, 0, 1, 2);
// 按钮
setTextButton = new QPushButton("设置文本");
loadFileButton = new QPushButton("加载文件");
generateButton = new QPushButton("生成信号");
modulateButton = new QPushButton("调制");
transmitButton = new QPushButton("传输");
saveSignalButton = new QPushButton("保存信号");
layout->addWidget(setTextButton, 5, 0);
layout->addWidget(loadFileButton, 5, 1);
layout->addWidget(generateButton, 6, 0);
layout->addWidget(modulateButton, 6, 1);
layout->addWidget(transmitButton, 7, 0);
layout->addWidget(saveSignalButton, 7, 1);
// 连接信号槽
connect(signalTypeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CommunicationSystemGUI::onSignalTypeChanged);
connect(setTextButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onSetTextData);
connect(loadFileButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onLoadFileData);
connect(generateButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onGenerateSignal);
connect(modulateButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onModulateSignal);
connect(transmitButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onTransmitSignal);
connect(saveSignalButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onSaveSignal);
}
void CommunicationSystemGUI::createReceiverGroup() {
receiverGroup = new QGroupBox("接收方");
QGridLayout* layout = new QGridLayout(receiverGroup);
// 按钮
loadSignalButton = new QPushButton("加载信号");
receiveButton = new QPushButton("接收");
demodulateButton = new QPushButton("解调");
decodeButton = new QPushButton("解码");
saveReceivedButton = new QPushButton("保存接收");
saveDecodedButton = new QPushButton("保存解码");
layout->addWidget(loadSignalButton, 0, 0);
layout->addWidget(receiveButton, 0, 1);
layout->addWidget(demodulateButton, 1, 0);
layout->addWidget(decodeButton, 1, 1);
layout->addWidget(saveReceivedButton, 2, 0);
layout->addWidget(saveDecodedButton, 2, 1);
// 解码文本显示
decodedTextEdit = new QTextEdit();
decodedTextEdit->setReadOnly(true);
decodedTextEdit->setMaximumHeight(80);
layout->addWidget(new QLabel("解码文本:"), 3, 0, 1, 2);
layout->addWidget(decodedTextEdit, 4, 0, 1, 2);
// 连接信号槽
connect(loadSignalButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onLoadSignal);
connect(receiveButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onReceiveSignal);
connect(demodulateButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onDemodulateSignal);
connect(decodeButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onDecodeSignal);
connect(saveReceivedButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onSaveReceived);
connect(saveDecodedButton, &QPushButton::clicked, this, &CommunicationSystemGUI::onSaveDecoded);
}
void CommunicationSystemGUI::createWaveformDisplays() {
waveformFrame = new QFrame();
QGridLayout* gridLayout = new QGridLayout(waveformFrame);
// 第一行:源信号波形(左)和调制信号波形(右)
sourceWaveformView = new QChartView();
modulatedWaveformView = new QChartView();
gridLayout->addWidget(new QLabel("源信号波形"), 0, 0);
gridLayout->addWidget(sourceWaveformView, 1, 0);
gridLayout->addWidget(new QLabel("调制信号波形"), 0, 1);
gridLayout->addWidget(modulatedWaveformView, 1, 1);
// 第二行:接收信号波形(左)和解调信号波形(右)
receivedWaveformView = new QChartView();
demodulatedWaveformView = new QChartView();
gridLayout->addWidget(new QLabel("接收信号波形"), 2, 0);
gridLayout->addWidget(receivedWaveformView, 3, 0);
gridLayout->addWidget(new QLabel("解调信号波形"), 2, 1);
gridLayout->addWidget(demodulatedWaveformView, 3, 1);
// 设置行和列的比例
gridLayout->setRowStretch(1, 1);
gridLayout->setRowStretch(3, 1);
gridLayout->setColumnStretch(0, 1);
gridLayout->setColumnStretch(1, 1);
}
void CommunicationSystemGUI::initAudio() {
QAudioFormat format;
format.setSampleRate(SAMPLE_RATE);
format.setChannelCount(1);
format.setSampleSize(32);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::Float);
// 输入设备
QAudioDeviceInfo inputDevice = QAudioDeviceInfo::defaultInputDevice();
if (!inputDevice.isFormatSupported(format)) {
qWarning() << "输入设备不支持请求的格式,使用最接近的匹配";
format = inputDevice.nearestFormat(format);
}
if (!inputDevice.isFormatSupported(format)) {
qWarning() << "默认格式不支持,使用最接近的格式";
format = inputDevice.nearestFormat(format);
}
audioInput = new QAudioInput(inputDevice, format, this);
// 输出设备
QAudioDeviceInfo outputDevice = QAudioDeviceInfo::defaultOutputDevice();
if (outputDevice.isNull()) {
qWarning() << "未找到音频输出设备";
return;
}
if (!outputDevice.isFormatSupported(format)) {
qWarning() << "默认格式不支持,使用最接近的格式";
format = outputDevice.nearestFormat(format);
}
audioOutput = new QAudioOutput(outputDevice, format, this);
}
// ================= 核心功能实现 =================
void CommunicationSystemGUI::onGenerateSignal() {
transmitter.signal_type = static_cast<SignalType>(signalTypeCombo->currentData().toInt());
transmitter.mod_type = static_cast<ModulationType>(modulationTypeCombo->currentData().toInt());
transmitter.carrier_freq = carrierFreqEdit->text().toFloat();
if (transmitter.signal_type == TEXT_DATA) {
onSetTextData();
}
else if (transmitter.signal_type == FILE_DATA) {
onLoadFileData();
}
else {
generate_signal(&transmitter, 1000); // 1秒信号
plotSignal(sourceWaveformView, transmitter.samples,
transmitter.sample_count, "源信号波形");
}
showStatusMessage("信号生成完成");
}
void CommunicationSystemGUI::onModulateSignal() {
if (transmitter.sample_count == 0) {
QMessageBox::warning(this, "错误", "请先生成信号");
return;
}
modulate_signal(&transmitter);
plotSignal(modulatedWaveformView, transmitter.modulated,
transmitter.sample_count, "调制信号波形");
showStatusMessage("信号调制完成");
}
void CommunicationSystemGUI::onSetTextData() {
QString text = textDataEdit->toPlainText();
if (text.isEmpty()) {
QMessageBox::warning(this, "错误", "请输入文本");
return;
}
// 使用QString确保正确处理中文
QByteArray utf8Data = text.toUtf8();
set_text_data(&transmitter, utf8Data.constData());
set_text_data(&transmitter, text.toUtf8().constData());
plotSignal(sourceWaveformView, transmitter.samples,
transmitter.sample_count, "文本信号波形");
showStatusMessage("文本数据已设置");
}
void CommunicationSystemGUI::onLoadFileData() {
QString filename = QFileDialog::getOpenFileName(this, "打开数据文件");
if (!filename.isEmpty()) {
load_file_data(&transmitter, filename.toUtf8().constData());
plotSignal(sourceWaveformView, transmitter.samples,
transmitter.sample_count, "文件数据波形");
showStatusMessage("文件数据已加载");
}
}
void CommunicationSystemGUI::onDemodulateSignal() {
if (receiver.sample_count == 0) {
QMessageBox::warning(this, "错误", "没有可解调的信号");
return;
}
// 传递发送方的信号类型和调制类型
receiver.signal_type = transmitter.signal_type;
receiver.mod_type = transmitter.mod_type;
demodulate_signal(&receiver);
plotSignal(demodulatedWaveformView, receiver.demodulated,
receiver.sample_count, "解调信号波形");
// 如果是文本信号,自动解码
if (receiver.signal_type == TEXT_DATA) {
onDecodeSignal();
}
showStatusMessage("信号解调完成");
}
void CommunicationSystemGUI::onDecodeSignal() {
if (receiver.sample_count == 0) {
QMessageBox::warning(this, "错误", "没有可解码的信号");
return;
}
decode_signal(&receiver);
if (strlen(receiver.decoded_text) > 0) {
decodedTextEdit->setPlainText(receiver.decoded_text);
showStatusMessage("解码成功");
}
else {
decodedTextEdit->setPlainText("解码失败:请检查调制设置和信号质量");
showStatusMessage("解码失败");
}
}
void CommunicationSystemGUI::onSaveSignal() {
if (transmitter.sample_count == 0) {
QMessageBox::warning(this, "错误", "没有可保存的信号");
return;
}
QString filename = QFileDialog::getSaveFileName(this, "保存信号", "", "信号文件 (*.sig)");
if (!filename.isEmpty()) {
save_signal_to_file(filename.toUtf8().constData(), transmitter.modulated,
transmitter.sample_count, transmitter.sample_rate,
transmitter.signal_type, transmitter.mod_type);
showStatusMessage("信号已保存: " + filename);
}
}
void CommunicationSystemGUI::onLoadSignal() {
QString filename = QFileDialog::getOpenFileName(this, "加载信号", "", "信号文件 (*.sig)");
if (!filename.isEmpty()) {
load_signal_from_file(filename.toUtf8().constData(), receiver.received,
&receiver.sample_count, &receiver.sample_rate,
&receiver.signal_type, &receiver.mod_type);
plotSignal(receivedWaveformView, receiver.received,
receiver.sample_count, "接收信号波形");
showStatusMessage("信号已加载: " + filename);
}
}
void CommunicationSystemGUI::onSaveReceived() {
if (receiver.sample_count == 0) {
QMessageBox::warning(this, "错误", "没有可保存的接收信号");
return;
}
QString filename = QFileDialog::getSaveFileName(this, "保存接收信号", "", "信号文件 (*.sig)");
if (!filename.isEmpty()) {
save_signal_to_file(filename.toUtf8().constData(), receiver.received,
receiver.sample_count, receiver.sample_rate,
receiver.signal_type, receiver.mod_type);
showStatusMessage("接收信号已保存: " + filename);
}
}
void CommunicationSystemGUI::onSaveDecoded() {
if (receiver.signal_type == TEXT_DATA) {
QString filename = QFileDialog::getSaveFileName(this, "保存解码文本", "", "文本文件 (*.txt)");
if (!filename.isEmpty()) {
QFile file(filename);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
out << receiver.decoded_text;
file.close();
showStatusMessage("解码文本已保存: " + filename);
}
}
}
else {
QString filename = QFileDialog::getSaveFileName(this, "保存解码信号", "", "数据文件 (*.dat)");
if (!filename.isEmpty()) {
QFile file(filename);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
for (int i = 0; i < receiver.sample_count; i++) {
out << receiver.demodulated[i] << "\n";
}
file.close();
showStatusMessage("解码信号已保存: " + filename);
}
}
}
}
void CommunicationSystemGUI::onSignalTypeChanged(int index) {
SignalType type = static_cast<SignalType>(signalTypeCombo->itemData(index).toInt());
textDataEdit->setEnabled(type == TEXT_DATA);
setTextButton->setEnabled(type == TEXT_DATA);
loadFileButton->setEnabled(type == FILE_DATA);
}
void CommunicationSystemGUI::onTransmitSignal() {
if (audioOutput && transmitter.sample_count > 0) {
// 更新状态
transmitStatusLabel->setText("发送状态: 传输中");
transmitProgressBar->setValue(0);
// 准备输出缓冲区
QBuffer* outputBuffer = new QBuffer(this);
outputBuffer->open(QIODevice::ReadWrite);
// 计算传输时间(毫秒)
float duration = (transmitter.sample_count * 1000.0f) / transmitter.sample_rate;
outputBuffer->write(reinterpret_cast<const char*>(transmitter.modulated),
transmitter.sample_count * sizeof(float));
outputBuffer->seek(0);
// 开始播放
audioOutput->start(outputBuffer);
showStatusMessage("开始传输信号...");
// 启动传输计时器
transmitTimer.start();
// 设置进度更新定时器
QTimer* progressTimer = new QTimer(this);
connect(progressTimer, &QTimer::timeout, [=]() {
int elapsed = transmitTimer.elapsed();
int progress = qMin(100, static_cast<int>((elapsed / duration) * 100));
transmitProgressBar->setValue(progress);
if (progress >= 100) {
progressTimer->stop();
progressTimer->deleteLater();
transmitStatusLabel->setText("发送状态: 完成");
showStatusMessage("信号传输完成");
}
});
progressTimer->start(100); // 每100ms更新一次
}
else {
QMessageBox::warning(this, "错误", "音频输出设备未初始化或没有可传输的信号");
}
}
void CommunicationSystemGUI::onReceiveSignal() {
if (audioInput) {
// 更新状态
receiveStatusLabel->setText("接收状态: 接收中");
receiveProgressBar->setValue(0);
// 准备输入缓冲区
inputBuffer.setData(QByteArray());
inputBuffer.open(QIODevice::WriteOnly);
// 开始录音
audioInput->start(&inputBuffer);
showStatusMessage("开始接收信号...");
// 设置进度更新定时器
QTimer* progressTimer = new QTimer(this);
connect(progressTimer, &QTimer::timeout, [=]() {
int elapsed = receiveTimer.elapsed();
int progress = qMin(100, static_cast<int>((elapsed / 5000.0) * 100));
receiveProgressBar->setValue(progress);
if (progress >= 100) {
progressTimer->stop();
progressTimer->deleteLater();
receiveStatusLabel->setText("接收状态: 完成");
// === 新增:处理接收到的音频数据 ===
inputBuffer.close();
QByteArray audioData = inputBuffer.data();
if (!audioData.isEmpty()) {
// 转换为浮点数组
const float* rawData = reinterpret_cast<const float*>(audioData.constData());
int numSamples = audioData.size() / sizeof(float);
// 设置接收器的信号类型和调制类型
receiver.signal_type = transmitter.signal_type;
receiver.mod_type = transmitter.mod_type;
receiver.sample_rate = transmitter.sample_rate;
// 存储到接收器
receiver.sample_count = numSamples;
for (int i = 0; i < receiver.sample_count; i++) {
receiver.received[i] = rawData[i];
}
// 绘制接收信号
plotSignal(receivedWaveformView, receiver.received,
receiver.sample_count, "接收信号波形");
showStatusMessage(QString("接收完成,共 %1 个样本").arg(receiver.sample_count));
onDemodulateSignal();
}
else {
showStatusMessage("未接收到任何数据");
}
}
});
progressTimer->start(100);
receiveTimer.start();
}
else {
QMessageBox::warning(this, "错误", "音频输入设备未初始化");
}
}
// 添加处理接收到的音频数据的函数
void CommunicationSystemGUI::processReceivedAudio() {
inputBuffer.close();
if (audioData.size() == 0) {
showStatusMessage("未接收到任何数据");
return;
}
// 将接收到的数据转换为浮点数组
const float* rawData = reinterpret_cast<const float*>(audioData.constData());
int numSamples = audioData.size() / sizeof(float);
if (numSamples > MAX_SAMPLES) {
numSamples = MAX_SAMPLES;
showStatusMessage("警告:接收数据超出最大样本数,已截断");
}
// 复制到接收器
receiver.sample_count = numSamples;
receiver.signal_type = transmitter.signal_type; // 设置信号类型
receiver.mod_type = transmitter.mod_type; // 设置调制类型
for (int i = 0; i < numSamples; i++) {
receiver.received[i] = rawData[i];
}
// 绘制接收信号
plotSignal(receivedWaveformView, receiver.received, receiver.sample_count, "接收信号波形");
showStatusMessage(QString("接收完成,共 %1 个样本").arg(numSamples));
// 清空数据为下次接收准备
audioData.clear();
}
// ================= 辅助函数 =================
void CommunicationSystemGUI::plotSignal(QChartView* chartView, float* data, int count, const QString& title) {
// 严格检查输入参数
if (!chartView || !data || count <= 0) {
qWarning() << "无效的绘图参数";
return;
}
// 创建新的series
QLineSeries* series = new QLineSeries();
// 计算步长以减少点数
int step = std::max(1, count / 1000);
if (step < 1) step = 1;
// 添加数据点
for (int i = 0; i < count; i += step) {
series->append(i, data[i]);
}
// 创建新图表
QChart* chart = new QChart();
chart->addSeries(series);
chart->setTitle(title);
// 创建并设置X轴
QValueAxis* axisX = new QValueAxis();
axisX->setTitleText("采样点");
axisX->setRange(0, count);
chart->addAxis(axisX, Qt::AlignBottom);
series->attachAxis(axisX);
// 创建并设置Y轴
QValueAxis* axisY = new QValueAxis();
axisY->setTitleText("幅度");
// 自动计算Y轴范围
auto minmax = std::minmax_element(data, data + count);
float minVal = *minmax.first;
float maxVal = *minmax.second;
// 确保有合理的范围
if (fabs(maxVal - minVal) < 0.001f) {
minVal -= 1.0f;
maxVal += 1.0f;
}
else {
// 扩展10%的范围
float range = maxVal - minVal;
minVal -= range * 0.1f;
maxVal += range * 0.1f;
}
axisY->setRange(minVal, maxVal);
chart->addAxis(axisY, Qt::AlignLeft);
series->attachAxis(axisY);
// 设置图表到视图
chartView->setChart(chart);
chartView->setRenderHint(QPainter::Antialiasing);
}
void CommunicationSystemGUI::showStatusMessage(const QString& message) {
statusBar->showMessage(message, 5000); // 显示5秒
}1.修改修改下QPSK,FSK,AM调制代码,因为调制出来的波形和源信号波形相差太远。2.如果发送的是文本数据,那么还是同样的点击调制方式接收端点击解调吗?如果是这样那么解码的意义在哪里?如果发送端不是点击调制方式,接收端点击解码方式,那么发送端是不是要有一个按键进行编码而不是只有调制波形?
最新发布