活动介绍

通过面板发送信号值始终为0,修改后输出完整代码

时间: 2025-08-21 07:26:56 浏览: 4
<think>好的,我现在需要解决用户的问题,即通过CANoe发送信号值始终为0的问题,并输出完整的代码示例,涉及setSignal函数和timer的使用。首先,我需要回顾之前的对话,了解用户的需求和之前的回答,以便保持一致性和准确性。 用户之前提供的代码中,他们尝试使用sysvar来触发事件,当sysvar::CUX::Up等于1时,设置信号CSA3::PageUpSwtSts为1,并启动定时器timer50ms。然而,用户指出修改后的代码仍然发送值为0的信号。这可能是因为在定时器回调中,他们只是重复发送Up消息,而没有更新信号值,或者在初始化时信号值被默认设置为0,没有正确更新。 首先,我需要分析可能导致信号值始终为0的原因。常见的原因包括:信号未正确初始化、定时器回调中没有更新信号值、消息未正确配置DLC、或信号未正确关联到消息。此外,检查setSignal函数的使用是否正确,因为该函数需要正确的消息和信号名称,以及环境变量的配置是否正确。 接下来,用户需要完整的代码示例,使用setSignal和timer。setSignal函数通常用于在Environment节点中设置信号值,而可能需要结合环境变量或系统变量来触发信号的发送。同时,定时器的使用需要确保周期性地更新信号值并发送消息。 根据之前的回答,用户可能已经尝试了使用定时器和消息输出,但可能遗漏了信号值的持续更新。例如,在定时器事件中,应该再次设置信号值,以确保每次发送消息时信号值为1,而不是仅在初始触发时设置一次。 另外,用户之前的代码中使用了output(Up),但未明确Up消息是否已经正确关联到信号CSA3::PageUpSwtSts。需要确保消息的定义和信号在数据库(DBC)中正确配置,并且消息的发送通道和ID正确。 现在,我需要构建一个示例代码,使用setSignal函数和定时器,确保信号值每次发送时为1,而不是0。步骤可能包括: 1. 在variables部分声明消息对象和定时器。 2. 在sysvar事件中启动定时器,并在定时器回调中持续设置信号值。 3. 使用setSignal函数将信号值设为1,并通过output发送消息。 4. 确保消息的DLC正确,并且信号正确映射到消息。 需要注意的是,setSignal函数可能需要特定的上下文,例如在Environment节点中使用,而用户之前的代码可能是在测试模块或其他地方。因此,可能需要确认节点类型和函数可用性。 此外,可能需要使用环境变量来触发信号的发送,或者在sysvar变化时更新信号值,并在定时器中持续发送。例如,当sysvar::CUX::Up变为1时,启动定时器,并在每个定时器周期中设置信号为1并发送消息,确保即使其他操作重置信号值,定时器也会不断将其设为1。 最后,检查代码中的潜在问题,例如在sysvar变为0时取消定时器,这可能导致信号停止发送,但用户的问题可能是在定时器触发时信号值仍为0,因此需要确保在定时器回调中每次都显式设置信号值,而不是依赖之前的状态。 总结解决方案步骤: - 确保在定时器回调中每次设置信号值为1。 - 正确初始化消息的DLC和信号关联。 - 使用setSignal或直接设置消息信号值并输出消息。 - 验证消息和信号在CANoe中的配置是否正确。</think>根据您提供的代码和需求,以下是解决信号值始终为0的完整方案及代码实现: ### 问题分析 原代码中存在三个关键问题: 1. `setSignal`调用后未立即发送消息 2. 定时器回调中未更新信号值 3. 消息长度(dlc)未正确初始化[^1] ### 完整解决方案 ```c /*@!Encoding:936*/ variables { msTimer timer50ms; message CAN1.YourMessageName msg_0x244; // 替换为DBC中消息定义 } on sysvar sysvar::CUX::Up { if (@sysvar::CUX::Up == 1) { // 设置信号值并立即发送 setSignal(CAN1::GW::CSA3::PageUpSwtSts, 1); // 设置物理信号 msg_0x244.CSA3::PageUpSwtSts = 1; // 设置消息信号 output(msg_0x244); // 启动周期发送定时器 setTimerCyclic(timer50ms, 50); } else { cancelTimer(timer50ms); } } on timer timer50ms { // 每次定时触发时重新赋值 msg_0x244.CSA3::PageUpSwtSts = 1; // 防止信号值被重置 output(msg_0x244); } on preStart { // 消息初始化(必须步骤) msg_0x244.dlc = 8; // 根据DBC设置数据长度 msg_0x244.id = 0x244; // 设置CAN ID msg_0x244.CSA3::PageUpSwtSts = 0; // 初始值设定 } ``` ### 关键修改说明 1. **双重赋值机制** 同时使用`setSignal`和直接消息赋值,确保信号值在物理层和消息层都有效 2. **定时器冗余更新** 在定时器回调中强制刷新信号值,避免总线其他节点覆盖 3. **消息预初始化** 在`preStart`事件中明确设定消息ID、DLC和初始值,避免未定义行为[^1] ### 验证步骤 1. 在CANoe中打开Trace窗口 2. 过滤ID 0x244的消息 3. 触发sysvar::CUX::Up变量 4. 观察信号值应保持1且持续发送 ### 注意事项 1. 消息名称`YourMessageName`需与DBC中定义完全一致 2. 如果使用环境变量传输信号,需添加`on envVar`事件处理 3. 定时周期50ms需满足总线负载率要求
阅读全文

相关推荐

MODBUS_RTU通讯协议(客户) 1.字元结构 1.1 10―bit字元框(FOR ASCII) 资料格式 8. N .1 START BIT 0 1 2 3 4 5 6 7 STOP BIT 8-data bits 10-bits character fram 1.2 11―bit字元框(FOR RTU) 资料格式 8. N .2 START BIT 0 1 2 3 4 5 6 7 STOP BIT STOP BIT 8-data bits 11-bits character fram 资料格式 8. E .1 START BIT 0 1 2 3 4 5 6 7 Even Parity STOP BIT 8-data bits 11-bits character fram 资料格式 8. O. 1 START BIT 0 1 2 3 4 5 6 7 Odd Parity STOP BIT 8-data bits 11-bits character fram 波特率:1200,2400,4800,9600,19200 2.通信资料格式 RTU模式 START 保持无输入讯号≧ 20ms Adress 通信位址:8-bit 二进制位址。00H为广播地址,使用广播地址时只能接一台控制器。 Function 功能码:8-bit 二进制位址 DATA(n-1) 资料内容: n8-bit 资料内容 …… DATA 0 CRC CHK Low CRC 检查码: 由2个8-bit二进制码组成 CRC CHK High END Hi 保持无输入讯号≧20ms 2.3功能码: 03H:读出暂存器内容 06H:写入一个WORD至寄存器 08H:回路侦测 2.3.1功能码08H:回路侦测。 RTU 模式:询问格式: 回应格式: Address 01H Address 01H Function 08H Function 08H Sub-Func-Hi 00H (任意) Sub-Func-Hi 00H Sub-Func-Lo 00H (任意) Sub-Func-Lo 00H Data Content 12H (任意) Data Content 12H 34H (任意) 34H CRC Lo EDH CRC Lo EDH CRC Hi 7CH CRC Hi 7CH 2.3.2功能码03H:读出暂存器内容。 例如:从起始暂存器(位址0000)读出2个连续资料内容,假设寄存器(0000)=0100H,(0001)=00F0H。 RTU模式:询问格式: 回应格式 Address 01H Address 01H Function 03H Function 03H Data Addr 00H Number of data (count by byte) 04H 00H Number of data (count by word) 00H Content of data (Address 0000) 01H 02H 00H CRC Low C4H Content of data (Address 0001) 00H CRC Hight 0BH F0H CRC CHK Low FBH CRC CHK Hight 8BH 2.3.3功能码06H:写入一个WORD至暂存器。 例如:对驱动器位址01H,写入03E8H到参数0010H。 询问格式: 回应格式: Address 01H Address 01H Function 06H Function 06H Data Addr 00H Data Addr 00H 10H 10H Data Content 03H Data Content 03H E8H E8H CRC Low 88H CRC CHK Low 88H CRC Hight B1H CRC CHK Hight B1H 2.4.错误通讯时的额外回应: 当控制器做通信连接时,如果产生错误,此时控制器会回应错误码且将Function code AND 80H回应给主控系统,让主控系统知道有错误产生。参考错误通信时错误码的意义 RTU模式: Address 01H Function 86H Except code 02H CRC CHR Low C3H CRC CHR Hight A1H 错误码的意义: 错误码 说明 01 功能码错误; 控制器可以辨识的功能码为03H,06H,08H 02 寄存器地址错误; 资料的位址控制器无法辨识 03 资料内容值错误 资料内容值太大或者太小,不是控制器所能辨识的内容值 04 控制器无法处理; 控制器对此命令,无法执行 09 CRC或者LRC校验错误 10 奇偶校验错误 12 接收数据低于规定长度 13 接收数据超过规定长度 其中将原功能号AND 80H后返回。并在Except code中返回错误码(见右上表格) 2.5 RTU模式的检查码(CRC Check) 检查码由Address到Data content结束。其运算规则如下: 步骤1:令16-bit暂存器(CRC暂存器)=FFFFH。 步骤2:Exclusive OR第一个8-bite byte的讯息指令与低位元16-bite CRC暂存器,做Exclusive OR,将结果存入CRC暂存器内。 步骤3:右移位CRC暂存器,将0填入高位元处。 步骤4:检查右移的值,如果是0,将步骤3的新值存入CRC暂存器内,否则Exclusive OR A001H与CRC暂存器,将结果存入CRC暂存器内。 步骤5:重复步骤3~步骤4,将8-bit全部运算完成。 步骤6:重复步骤2~步骤5,取下一个8-bit的讯息指令,直到所有讯息指令运算完成。最后,得到的CRC暂存器的值,即是CRC的检查码。值得注意的是CRC的检查码必须交换放置於讯息指令的检查码中。 以下为用c语言所写的crc检查码运算范例: unsigned char *data; unsigned char length; unsigned int crc_chk(unsigned char *data,unsigned char length) { int j;unsigned int reg_crc=0xffff; while(length--){ reg_crc^=*data++; for(j=0;j<8;j++){ if(reg_crc&0x01){ reg_crc=(reg_crc>>1)^0xa001;} else{ reg_crc=reg_crc>>1; } } } return reg_crc; } 3:通讯参数修改:同时按住SET键加上移位键4秒以上,出现LK代码,按数字键使LK数值为118,再:按SET键进入通讯参数设置(SET键即功能键)。 意义 参数名 说 明 通讯地址 Ad 0-32 0:广播地址 通讯波特率 bA 2:4800 3:9600 4:19200 通讯格式 Fo 3:MODBUS-RTU(8,N,2) 4:MODBUS-RTU(8,E,1) 5:MODBUS-RTU(8,O,1)6: MODBUS-RTU(8,N,1) 4.参数位址定义: 0x0000: 温度测量值 只能读 0x0001: 湿度测量值 只能读 0x0002: 读:剩余运行时间。 写:写入0,关闭手动输出;写入1,打开手动输出。比如照明,循环。 0x0003/0x0004:温度设定值 可读可写。 0x0006: 定时设定值 可读可写。 0x000a: 读:.0 超过允许最高温度报警 .1温度上偏差报警 .2温度传感器故障 .6 温度下偏差报警 .15 总报警 写:写入1 在鸣叫和静音之间切换。 0x000b: 读:0x000b.11=1运行 =0停止 写:写入1,启动或停止运行 读:0x000b.8=1 手动输出打开 =0 手动输出关闭。 0x000d: 转速测量值 只读 0x0012: CO2浓度测量值 只读 0x0013: 压力测量值 只读 0x0018: 转速设定值 可读可写 0x0019: 湿度设定值 可读可写 0x001a: 第一组光照设定值 可读可写 0x001b: CO2设定值 可读可写 0x001c: O2设定值 可读可写 0x001d: 压力设定值 可读可写 0x001e: 第二组光照设定值 可读可写 0x001f: 第三组光照设定值 可读可写 0x00e8 O2氧浓度测量值 只读 0x00f8: 连读 上位机发送:通讯地址+03H+00H+F8H+00H+14H+CRC(L)+CRC(H)。此处0x00F8必须优先。 控制器返回:通讯地址+03H+28H+运行时间高位+运行时间低位+设定时间高位+设定时间低位+测量温度高位+测量温度低位+设定温度高位+设定温度低位+测量湿度高位+测量湿度低位+设定湿度高位+设定湿度低位+第二组光照级数+第一组光照级数+第三组光照级数+第一组光照级数+测量转速高位+测量转速低位+设定转速高位+设定转速低位+测量CO2浓度高位+测量CO2浓度低位+设定CO2浓度高位+设定CO2浓度低位+测量O2浓度高位+测量O2浓度低位+设定O2浓度高位+设定O2浓度低位+测量压力高位+测量压力低位+设定压力高位+设定压力低位+备份1高位+备份1低位+备份2高位+备份2低位+备份3高位+备份3低位+备份4高位+备份4低位+ CRC(L)+CRC(H). 按照这个修改代码,并完善功能

#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.如果发送的是文本数据,那么还是同样的点击调制方式接收端点击解调吗?如果是这样那么解码的意义在哪里?如果发送端不是点击调制方式,接收端点击解码方式,那么发送端是不是要有一个按键进行编码而不是只有调制波形?

#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); // 在 communication_system.cpp 文件顶部添加(#include 之后) const QByteArray FRAME_HEADER = QByteArray::fromHex("55555555AA"); // 01010101 交替的帧头 #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; // 处理整个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; } } } // 生成信号波形 const float symbol_transition = 0.2f; // 符号过渡时间比例 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) break; float position = static_cast<float>(j) / SAMPLES_PER_BIT; float symbol = tx->binary_data[i] ? 1.0f : -1.0f; // 在符号边界添加平滑过渡 if (j < symbol_transition * SAMPLES_PER_BIT) { // 与前一个符号的过渡 float prev_symbol = (i > 0) ? (tx->binary_data[i - 1] ? 1.0f : -1.0f) : symbol; float factor = j / (symbol_transition * SAMPLES_PER_BIT); tx->samples[idx] = prev_symbol * (1 - factor) + symbol * factor; } else if (j > (1 - symbol_transition) * SAMPLES_PER_BIT) { // 与下一个符号的过渡 float next_symbol = (i < tx->bit_count - 1) ? (tx->binary_data[i + 1] ? 1.0f : -1.0f) : symbol; float factor = (j - (1 - symbol_transition) * SAMPLES_PER_BIT) / (symbol_transition * SAMPLES_PER_BIT); tx->samples[idx] = symbol * (1 - factor) + next_symbol * factor; } else { tx->samples[idx] = symbol; } } } // 汉明编码 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, 50.0f); // 10dB SNR } // ================= 解调函数 ================= // 改进的BPSK解调函数 - 使用Costas环载波恢复 void demodulate_bpsk(Receiver* rx) { const float loop_gain = 0.01f; // 环路增益 float phase_estimate = 0.0f; float freq_offset = 0.0f; float last_filtered = 0.0f; const float alpha = 0.05f; // 低通滤波系数 // Costas环载波跟踪 for (int i = 0; i < rx->sample_count; i++) { float t = static_cast<float>(i) / rx->sample_rate; // 生成本地载波 float local_carrier_i = sin(2 * M_PI * rx->carrier_freq * t + phase_estimate); float local_carrier_q = cos(2 * M_PI * rx->carrier_freq * t + phase_estimate); // 相干解调 float I = rx->received[i] * local_carrier_i; float Q = rx->received[i] * local_carrier_q; // 低通滤波 I = alpha * I + (1 - alpha) * last_filtered; last_filtered = I; // 相位误差检测 float phase_error = 0.0f; if (fabs(I) > 0.001f) { // 避免除零 phase_error = Q / I; } // 频率和相位更新 freq_offset += loop_gain * phase_error; phase_estimate += loop_gain * phase_error + freq_offset; // 限幅相位估计 while (phase_estimate > M_PI) phase_estimate -= 2 * M_PI; while (phase_estimate < -M_PI) phase_estimate += 2 * M_PI; rx->demodulated[i] = I; // I路为解调输出 } } 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; } } // 添加在 communication_system.cpp 文件中 void equalize_signal(Receiver* rx) { // 简单的均衡:归一化信号幅度 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; } } // 添加在 communication_system.cpp 文件中 void resolve_phase_ambiguity(Receiver* rx) { // 简单的相位模糊解决方案 // 检查第一个符号的极性(假设应为正) if (rx->sample_count > 10) { float first_symbol = rx->received[static_cast<int>(SAMPLES_PER_BIT / 2)]; if (first_symbol < 0) { // 翻转整个信号 for (int i = 0; i < rx->sample_count; i++) { rx->received[i] = -rx->received[i]; } } } } // 添加在 communication_system.cpp 文件中 float interpolate(const float* data, int index, float fraction) { if (index < 0) return data[0]; if (index >= MAX_SAMPLES - 1) return data[MAX_SAMPLES - 1]; return data[index] + fraction * (data[index + 1] - data[index]); } 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](); } // 添加接收端同步处理 synchronize_receiver(rx); // 根据调制类型选择解调方法 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; } // 添加均衡处理 equalize_signal(rx); } // 综合同步函数 void synchronize_receiver(Receiver* rx) { // 1. 频率同步 compensate_cfo(rx); // 2. 符号定时同步 timing_recovery(rx); // 3. 帧同步 int sync_offset = find_frame_header(rx->received, rx->sample_count, FRAME_HEADER); if (sync_offset > 0) { // 对齐信号 memmove(rx->received, rx->received + sync_offset, (rx->sample_count - sync_offset) * sizeof(float)); rx->sample_count -= sync_offset; } // 4. 相位同步 resolve_phase_ambiguity(rx); } // 载波频率偏移补偿 void compensate_cfo(Receiver* rx) { const int training_length = 16; // 训练序列长度 float phase_diff = 0.0f; int count = 0; for (int i = 0; i < training_length - 1; i++) { float phase1 = atan2(rx->received[i + 1], rx->received[i]); float phase2 = atan2(rx->received[i + training_length / 2 + 1], rx->received[i + training_length / 2]); phase_diff += phase2 - phase1; count++; } if (count > 0) { phase_diff /= count; float cfo = phase_diff * rx->sample_rate / (2 * M_PI * training_length / 2); // 补偿频率偏移 for (int i = 0; i < rx->sample_count; i++) { float t = static_cast<float>(i) / rx->sample_rate; float phase_comp = 2 * M_PI * cfo * t; rx->received[i] = rx->received[i] * cos(phase_comp); } } } // 精确的定时恢复 void timing_recovery(Receiver* rx) { const int samples_per_symbol = static_cast<int>(SAMPLES_PER_BIT); float timing_offset = 0.0f; float error = 0.0f; const float mu = 0.01f; // 收敛因子 // 早-迟门定时恢复 for (int i = 1; i < rx->sample_count - samples_per_symbol; i += samples_per_symbol) { float early = rx->received[i - 1]; float late = rx->received[i + 1]; float on_time = rx->received[i]; error = early * on_time - late * on_time; timing_offset += mu * error; // 应用插值 int adjusted_index = i + static_cast<int>(timing_offset); if (adjusted_index >= 0 && adjusted_index < rx->sample_count) { float fraction = timing_offset - floor(timing_offset); rx->received[i] = interpolate(rx->received, adjusted_index, fraction); } } } // ================= 解码函数 ================= 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("55555555AA"); // 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() << "帧同步失败,尝试重新采样..."; // 降低采样率重试 QVector<float> resampled; const int new_rate = rx->sample_rate / 2; for (int i = 0; i < rx->sample_count; i += 2) { resampled.append(rx->demodulated[i]); } sync_offset = find_frame_header(resampled.data(), resampled.size(), frame_header); } qDebug() << "帧同步成功,偏移量:" << sync_offset << "样本"; // 从同步点开始解码 int start_index = sync_offset + SAMPLES_PER_BIT; // 跳过帧头 // 使用自适应阈值解码 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 / valid_samples; // 修复后的行:确保索引为整数类型 float mid_value = rx->demodulated[mid_point]; rx->binary_data[i] = (mid_value > threshold) ? 1 : 0; } } // 汉明解码 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; 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_bytes = header.size(); const int sync_length = 32; // 同步序列长度(位) const int sample_per_bit = static_cast<int>(SAMPLES_PER_BIT); //if (search_range <= 0) return -1; // 创建理想帧头波形 QVector<float> sync_pattern(sync_length * sample_per_bit); int bit = 1; for (int i = 0; i < sync_length; i++) { bit = (i % 2 == 0) ? bit : !bit; // 交替10 for (int j = 0; j < sample_per_bit; j++) { sync_pattern[i * sample_per_bit + j] = bit ? 1.0f : -1.0f; } } // 使用互相关搜索 int best_offset = -1; float max_correlation = -FLT_MAX; const int search_range = length - sync_pattern.size(); for (int offset = 0; offset < search_range; offset += sample_per_bit / 4) { float signal_energy = 0.0f; float corr = 0.0f; for (int i = 0; i < sync_pattern.size(); i++) { corr += data[offset + i] * sync_pattern[i]; signal_energy += data[offset + i] * data[offset + i]; } // 归一化互相关 float norm_corr = corr / sqrt(signal_energy * sync_pattern.size()); if (norm_corr > max_correlation) { max_correlation = norm_corr; best_offset = offset; } } // 阈值判定(经验值) // float threshold = header_waveform.size() * 0.6f; return (max_correlation > 0.6f) ? best_offset : -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.输入输出波形相同;2.输入文本数据与输出解码相同。实现数字通信

#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); // 在 communication_system.cpp 文件顶部添加(#include 之后) const QByteArray FRAME_HEADER = QByteArray::fromHex("55555555AA"); // 01010101 交替的帧头 #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) { // 创建预定义的帧头和帧尾 const QByteArray frame_header = QByteArray::fromHex("55AA55AA55AA"); // 预定义帧头 const QByteArray frame_footer = QByteArray::fromHex("AA55AA55AA55"); // 预定义帧尾 QByteArray data; data.append(frame_header); data.append(text); data.append(frame_footer); // 设置数据 size_t len = data.size(); if (len >= MAX_TEXT_LENGTH) len = MAX_TEXT_LENGTH - 1; memcpy(tx->text_data, data.constData(), len); tx->text_data[len] = '\0'; tx->bit_count = 0; // 转换为二进制 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; } } } // 汉明编码 int original_bit_count = tx->bit_count; encode_hamming(tx->binary_data, tx->bit_count); tx->original_bit_count = original_bit_count; // 生成信号波形 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); } // 使用升余弦滤波器生成更平滑的基带信号 static const float rc_alpha = 0.35f; // 滚降因子 static const int rc_span = 6; // 符号跨度 for (int i = 0; i < tx->sample_count; i++) { float t = (i % static_cast<int>(SAMPLES_PER_BIT)) * 1.0f / SAMPLES_PER_BIT - 0.5f; float rc_value = 0.0f; for (int k = -rc_span; k <= rc_span; k++) { int bit_idx = i / SAMPLES_PER_BIT + k; if (bit_idx < 0 || bit_idx >= tx->bit_count) continue; float bit_value = tx->binary_data[bit_idx] ? 1.0f : -1.0f; float t_shift = t - k; if (fabs(t_shift) < 1e-5) { // 避免除以0 rc_value += bit_value; } else { float sinc = sin(M_PI * t_shift) / (M_PI * t_shift); float rolloff = cos(M_PI * rc_alpha * t_shift) / (1 - 4 * pow(rc_alpha * t_shift, 2)); rc_value += bit_value * sinc * rolloff; } } tx->samples[i] = rc_value; } } // ================= 文件数据处理 ================= 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, 50.0f); // 10dB SNR } // ================= 解调函数 ================= // 改进的BPSK解调函数 - 使用Costas环载波恢复 void demodulate_bpsk(Receiver* tx) { for (int i = 0; i < tx->sample_count; i++) { float t = i * 1.0f / tx->sample_rate; // 使用判决点值而不是所有采样点 int bit_idx = i / SAMPLES_PER_BIT; if (bit_idx >= tx->bit_count) { tx->demodulated[i] = 0.0f; } else { float symbol = tx->binary_data[bit_idx] ? 1.0f : -1.0f; tx->demodulated[i] = symbol * sin(2 * M_PI * tx->carrier_freq * t); } } } 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; } } // 添加在 communication_system.cpp 文件中 void equalize_signal(Receiver* rx) { // 简单的均衡:归一化信号幅度 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; } } // 添加在 communication_system.cpp 文件中 void resolve_phase_ambiguity(Receiver* rx) { // 简单的相位模糊解决方案 // 检查第一个符号的极性(假设应为正) if (rx->sample_count > 10) { float first_symbol = rx->received[static_cast<int>(SAMPLES_PER_BIT / 2)]; if (first_symbol < 0) { // 翻转整个信号 for (int i = 0; i < rx->sample_count; i++) { rx->received[i] = -rx->received[i]; } } } } // 添加在 communication_system.cpp 文件中 float interpolate(const float* data, int index, float fraction) { if (index < 0) return data[0]; if (index >= MAX_SAMPLES - 1) return data[MAX_SAMPLES - 1]; return data[index] + fraction * (data[index + 1] - data[index]); } 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](); } // 深度同步接收信号 deep_synchronization(rx); // 根据调制类型选择解调方法 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; } // 自适应均衡 equalize_signal(rx); } // 深度同步算法 void deep_synchronization(Receiver* rx) { // 1. 幅度归一化 float max_amp = 0.01f; for (int i = 0; i < rx->sample_count; i++) { if (fabs(rx->received[i]) > max_amp) { max_amp = fabs(rx->received[i]); } } float scale = 1.0f / max_amp; for (int i = 0; i < rx->sample_count; i++) { rx->received[i] *= scale; } // 2. 载波同步 const int frame_length = 64; // 训练序列长度 if (rx->sample_count > frame_length * 2) { // 寻找最大相关点进行载波同步 int max_corr_index = 0; float max_corr = -1.0f; for (int i = 0; i < frame_length; i++) { float corr = 0.0f; for (int j = 0; j < frame_length; j++) { float ref = sin(2 * M_PI * rx->carrier_freq * (j + i) / rx->sample_rate); corr += rx->received[j] * ref; } if (fabs(corr) > max_corr) { max_corr = fabs(corr); max_corr_index = i; } } // 调整接收信号的相位 memmove(rx->received, rx->received + max_corr_index, (rx->sample_count - max_corr_index) * sizeof(float)); rx->sample_count -= max_corr_index; } // 3. 符号定时恢复 const int spb = SAMPLES_PER_BIT; // 每个符号的样本数 const int window_size = spb / 4; // 定时误差检测窗口 float epsilon = 0.0f; // 定时偏移估计 float mu = 0.01f; // 步长因子 // 改进的Gardner定时恢复算法 for (int i = window_size; i < rx->sample_count - spb - window_size; i += spb) { float late = rx->received[i + spb / 2 + 1]; float early = rx->received[i + spb / 2 - 1]; float center = rx->received[i + spb / 2]; // 计算定时误差 float error = (late - early) * center; // 更新定时偏移估计 epsilon += mu * error; // 应用插值重采样 float fractional = epsilon - floor(epsilon); rx->received[i] = interpolate(rx->received, i + (int)epsilon, fractional); } } // 综合同步函数 void synchronize_receiver(Receiver* rx) { // 1. 频率同步 compensate_cfo(rx); // 2. 符号定时同步 timing_recovery(rx); // 3. 帧同步 int sync_offset = find_frame_header(rx->received, rx->sample_count, FRAME_HEADER); if (sync_offset > 0) { // 对齐信号 memmove(rx->received, rx->received + sync_offset, (rx->sample_count - sync_offset) * sizeof(float)); rx->sample_count -= sync_offset; } // 4. 相位同步 resolve_phase_ambiguity(rx); } // 载波频率偏移补偿 void compensate_cfo(Receiver* rx) { const int training_length = 16; // 训练序列长度 float phase_diff = 0.0f; int count = 0; for (int i = 0; i < training_length - 1; i++) { float phase1 = atan2(rx->received[i + 1], rx->received[i]); float phase2 = atan2(rx->received[i + training_length / 2 + 1], rx->received[i + training_length / 2]); phase_diff += phase2 - phase1; count++; } if (count > 0) { phase_diff /= count; float cfo = phase_diff * rx->sample_rate / (2 * M_PI * training_length / 2); // 补偿频率偏移 for (int i = 0; i < rx->sample_count; i++) { float t = static_cast<float>(i) / rx->sample_rate; float phase_comp = 2 * M_PI * cfo * t; rx->received[i] = rx->received[i] * cos(phase_comp); } } } // 精确的定时恢复 void timing_recovery(Receiver* rx) { const int samples_per_symbol = static_cast<int>(SAMPLES_PER_BIT); float timing_offset = 0.0f; float error = 0.0f; const float mu = 0.01f; // 收敛因子 // 早-迟门定时恢复 for (int i = 1; i < rx->sample_count - samples_per_symbol; i += samples_per_symbol) { float early = rx->received[i - 1]; float late = rx->received[i + 1]; float on_time = rx->received[i]; error = early * on_time - late * on_time; timing_offset += mu * error; // 应用插值 int adjusted_index = i + static_cast<int>(timing_offset); if (adjusted_index >= 0 && adjusted_index < rx->sample_count) { float fraction = timing_offset - floor(timing_offset); rx->received[i] = interpolate(rx->received, adjusted_index, fraction); } } } // ================= 解码函数 ================= 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("55555555AA"); // 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() << "帧同步失败,尝试重新采样..."; // 降低采样率重试 QVector<float> resampled; const int new_rate = rx->sample_rate / 2; for (int i = 0; i < rx->sample_count; i += 2) { resampled.append(rx->demodulated[i]); } sync_offset = find_frame_header(resampled.data(), resampled.size(), frame_header); } qDebug() << "帧同步成功,偏移量:" << sync_offset << "样本"; // 从同步点开始解码 int start_index = sync_offset + SAMPLES_PER_BIT; // 跳过帧头 // 使用自适应阈值解码 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 / valid_samples; // 修复后的行:确保索引为整数类型 float mid_value = rx->demodulated[mid_point]; rx->binary_data[i] = (mid_value > threshold) ? 1 : 0; } } // 汉明解码 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; 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 spb = SAMPLES_PER_BIT; // 创建理想的帧头模板 std::vector<float> template_signal(header_bits * spb); for (int i = 0; i < header_bits; i++) { int byte_idx = i / 8; int bit_idx = i % 8; int bit = (header[byte_idx] >> (7 - bit_idx)) & 1; float symbol = bit ? 1.0f : -1.0f; // 升余弦整形 for (int j = 0; j < spb; j++) { float t = j * 1.0f / spb; template_signal[i * spb + j] = symbol * sin(M_PI * t); } } // 使用归一化互相关寻找最佳位置 int best_offset = -1; float max_corr = -FLT_MAX; for (int offset = 0; offset < length - template_signal.size(); offset++) { float signal_energy = 0.0f; float template_energy = 0.0f; float correlation = 0.0f; for (int i = 0; i < template_signal.size(); i++) { float s = data[offset + i]; float t = template_signal[i]; signal_energy += s * s; template_energy += t * t; correlation += s * t; } // 归一化互相关 float norm_corr = correlation / sqrt(signal_energy * template_energy + 1e-5); if (norm_corr > max_corr) { max_corr = norm_corr; best_offset = offset; } } // 应用阈值(需要根据实际情况调整) const float threshold = 0.75f; return (max_corr > threshold) ? best_offset : -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秒 } 还是不行,波形不一致,解码失败

最新推荐

recommend-type

基于Python实现的信息检索与文本挖掘综合搜索引擎系统-包含网络爬虫模块-网页内容解析与分词处理-索引构建与数据库存储-Web查询服务与结果展示-用于课程大作业与学术研究-技术栈.zip

jdk1.8基于Python实现的信息检索与文本挖掘综合搜索引擎系统_包含网络爬虫模块_网页内容解析与分词处理_索引构建与数据库存储_Web查询服务与结果展示_用于课程大作业与学术研究_技术栈.zip
recommend-type

企业网络结构设计与拓扑图的PKT文件解析

企业网络拓扑设计是网络架构设计的一个重要组成部分,它涉及到企业内部网络的布局结构,确保信息传递的高效和网络安全。网络拓扑设计需要详细规划网络中每个组件的位置、连接方式、设备类型等关键要素。在设计过程中,通常会使用网络拓扑图来形象地表示这些组件和它们之间的关系。 网络拓扑设计中重要的知识点包括: 1. 拓扑图的类型:网络拓扑图主要有以下几种类型,每一种都有其特定的应用场景和设计要求。 - 总线拓扑:所有设备都连接到一条共享的主干线上,信息在全网中广播。适合小型网络,维护成本低,但故障排查较为困难。 - 星型拓扑:所有设备通过点对点连接到一个中心节点。便于管理和监控,中心节点的故障可能导致整个网络瘫痪。 - 环形拓扑:每个节点通过专用链路形成一个闭合环路。信息单向流动,扩展性较差,对单点故障敏感。 - 网状拓扑:网络中的设备通过多条路径连接,提供极高的冗余性。适合大型网络,成本较高。 2. 网络设备的选择:网络设备包括路由器、交换机、防火墙、无线接入点等。设计时需根据实际需求选择适合的设备类型和配置。 3. IP地址规划:合理的IP地址分配能确保网络的有序运行,包括私有地址和公有地址的规划,子网划分,以及IP地址的动态分配(DHCP)和静态分配。 4. 网络安全设计:保护企业网络不受攻击至关重要。包括设置防火墙规则、配置入侵检测系统(IDS)、实施访问控制列表(ACL)等安全策略。 5. 网络冗余和负载均衡:为防止网络中的单点故障,设计时需要考虑使用冗余技术和负载均衡技术,例如多线路接入、链路聚合、VRRP(虚拟路由器冗余协议)等。 6. 物理布线规划:这是指网络中的物理连接方式和布线方案,通常根据实际建筑环境和网络设备位置来决定,包括线缆的种类和长度限制等。 7. 虚拟化和云计算:在现代企业网络设计中,虚拟化技术和云计算服务的集成也变得越来越重要,需要合理规划服务器资源和云服务接口。 从提供的文件描述来看,包含了详细的网络结构设计和拓扑图PKT文件,以及源代码。这说明该课设文件不仅包括了网络拓扑图的视觉展示,还涉及到了实际的网络配置和编程实现。PKT文件可能指的是Packet Tracer(网络模拟软件)生成的网络拓扑文件, Packet Tracer 是Cisco开发的网络模拟工具,用户可以通过它创建网络拓扑图并模拟网络设备之间的数据通信。 由于文件名仅标注为“课设”,我们无法得知具体的课程名称或者网络拓扑设计的具体案例。不过,可以推测这份文件可能是一个教学材料或课程设计项目,旨在帮助学生或者网络工程师通过实践来加深对网络拓扑设计的理解和应用。其中包含的源代码可能是用于配置网络设备(如路由器和交换机的命令脚本),或者是一些网络应用的编程实现,比如网络监控工具或者数据分析脚本等。
recommend-type

【技术解读】:5个步骤深入自定义你的Winform窗口

# 摘要 本文全面概述了Winform窗口自定义开发的关键方面,涵盖了从基础操作到高级功能开发以及性能调优的各个方面。文章首先介绍了Winform窗口的基本操作、设计元素及响应式设计实现方法。随后,深入探讨了自定义控件创建、多线程处理以及插件机制等高级功能开发技术。为了优化交互体验,文中还阐述了用户输入处理、动画效果集成以及高级用户界面交互技术。此外,文章详细讨论了窗口的国
recommend-type

ARM/x86/c86 的具体区别

<think>好的,用户之前问过国产化服务器和操作系统,现在又想知道ARM、x86、x86的具体区别。看起来用户可能是在做技术选型或者需要了解不同架构的优缺点,以便在实际项目中选择合适的硬件和系统。 首先,用户提到的c86可能是个笔误,应该是x86。需要确认这一点,避免误解。然后需要分别从架构、设计理念、应用场景、性能、生态等方面对比ARM和x86。另外,用户可能对国产芯片如鲲鹏、飞腾等基于ARM的处理器感兴趣,所以需要联系之前的回答,说明这些国产芯片的架构背景。 接下来,需要检查技术细节的准确性,比如指令集类型、功耗、扩展性、授权模式等。还要考虑用户可能的实际需求,比如是否需要低功耗设备
recommend-type

最新Swift语言iOS开发实战教程免费下载

标题《Intermediate_swift_ios_12_book》表明了本书是一本关于Swift语言以及iOS 12平台的中阶开发教程。在Swift语言方面,它侧重于深入探讨和实践,旨在帮助读者提升在iOS开发方面的技能水平。自从2014年苹果公司首次推出Swift语言以来,它就成为了开发iOS、macOS、watchOS和tvOS应用的首选语言。Swift语言以其安全、快速、现代的特性逐渐取代了Objective-C,成为苹果生态系统中的主流开发语言。iOS 12作为苹果公司推出的最新操作系统版本,它引入了许多新特性,比如ARKit 2、MeasureKit和新的Screen Time功能,因此开发者需要学习和适应这些变化以充分利用它们。 描述强调了这本书是由Appcoda出版的,Appcoda是一家专注于提供高质量iOS和Swift编程教程的在线平台。通过Appcoda出版的教程,读者通常能够获得紧跟行业标准和实践的教学材料。此书被推荐给希望学习使用最新的Swift语言进行iOS开发的人群。这暗示了该书涵盖了iOS 12的新特性和API,这些内容对于想要掌握最新开发技术的开发者来说至关重要。 标签"ios swift programming practice"则进一步明确了这本书的三个主要知识点:iOS开发、Swift编程和编程实践。这些标签指向了iOS开发的核心技能和知识领域。iOS开发涉及到使用Xcode作为主要的开发环境,掌握使用Interface Builder构建用户界面,以及理解如何使用UIKit框架来创建和管理用户界面。Swift编程则集中在语言本身,包括其基本语法、类型系统、面向协议编程、闭包、泛型等高级特性。编程实践则强调实际编写代码的能力,如编写可测试、可维护和高性能的代码,以及如何使用设计模式来解决常见的开发问题。 文件名称列表中的"Intermediate swift ios12 book.epub"指出了该教程的电子书格式。EPUB是一种广泛使用的电子书标准格式,它支持可调整的布局,使得内容在不同尺寸的屏幕上都可阅读。EPUB格式允许用户在各种阅读设备上阅读书籍,如平板电脑、智能手机、电子书阅读器等。而文件名"._Intermediate swift ios12 book.epub"前面的点和下划线可能表明这是一个隐藏文件或在某种特定环境下被创建的临时文件。 综上所述,知识点涉及: 1. Swift语言基础:Swift是一种安全、快速、现代的编程语言,由苹果公司开发,用于iOS、macOS、watchOS和tvOS应用的开发。Swift语言的特性包括语法简洁、类型安全、内存管理自动化、对闭包和泛型的支持等。 2. iOS 12平台特性:iOS 12作为当时较新的操作系统版本,提供了许多新API和功能,如ARKit 2、MeasureKit等。开发者需要掌握如何在应用中利用这些API实现增强现实(AR)、时间管理等高级功能。 3. Xcode和UIKit框架:Xcode是iOS开发的主要集成开发环境(IDE),它提供了代码编辑器、调试工具、性能分析工具以及用户界面构建器等工具。UIKit框架是构建iOS应用用户界面的基础框架,它提供了丰富的用户界面组件和控件。 4. Swift高级特性和编程实践:学习Swift的高级特性有助于编写高效和可维护的代码。这包括理解闭包的使用、泛型编程、面向协议的设计等。同时,学习和实践良好的编程习惯,如编写可测试的代码、应用设计模式、以及遵循苹果的编码规范和最佳实践。 5. Appcoda及其教程特点:Appcoda是一家提供高质量iOS和Swift编程教程的平台,其教学材料通常紧跟技术发展和行业标准,很适合用于自我学习和提升技能。
recommend-type

【核心攻略】:掌握Winform界面构建的10大黄金法则

# 摘要 Winform界面构建是开发桌面应用程序的重要组成部分,本文从界面布局、数据管理、性能优化、安全性以及进阶技术等多方面进行深入探讨。第一章提供了一个概览,接下来的章节分别详细阐述了如何设计高效的Winform布局,包括布局容器的选择与嵌套布局策略;如何通过数据绑定简化数据管理并保证数据的正确性;以及如何优化界面性能,提高渲染效率并
recommend-type

给我讲解一下boost升压电路

<think>嗯,用户想了解Boost升压电路的工作原理和应用场景。首先,我需要回忆一下Boost电路的基本结构。根据引用[1],Boost升压电路由控制IC、功率电感和MOSFET组成,非同步Boost架构可能更简单,适合用来解释原理。那它的工作原理是怎样的呢? 记得Boost电路属于开关电源,通过开关管的通断来控制电感储能和释放。当MOSFET导通时,电流流过电感,电感开始储能,此时二极管截止,电容负责维持输出电压。而当MOSFET关闭时,电感电流不能突变,会产生反向电动势,这时候电感的电压加上输入电压,通过二极管给电容充电,从而提升输出电压。这个过程需要控制IC来调节开关的占空比,以维
recommend-type

全国国道矢量数据下载与arcgis软件应用

根据提供的文件信息,我们可以生成以下知识点: ### 地理信息系统(GIS) 地理信息系统,简称GIS,是一种特定的、全面的信息系统,它用来捕捉、存储、操纵、分析、管理和呈现地理数据。GIS技术可以对空间数据进行分析,以解决各种地理问题。在GIS中,空间数据通常包括矢量数据和栅格数据。矢量数据是一种图形化的数据格式,用于表示地图上的点、线、面等要素。 ### 国道数据 国道数据特指中国境内的国道信息,国道是指国家主要干线公路,具有连接城市、具有较大运输量、承担全国公路运输主要任务的特点。国道数据可以包括道路的位置、长度、宽度、类型、交通流量等信息。在地理信息系统中,国道数据的准确性对于路线规划、交通管理、城市规划等多个领域至关重要。 ### 矢量数据 矢量数据是GIS中的一个关键概念,它利用几何图形(如点、线、多边形等)来表示真实世界中的物体或区域。矢量数据与栅格数据相对,栅格数据通过像素阵列来表示信息,而矢量数据则通过坐标表示形状和位置。矢量数据具备以下几个特点: - 可无限放大缩小而不失真。 - 在空间分析和拓扑运算方面具有优势。 - 数据量相对较小,易于编辑和管理。 - 可以更好地表达地理要素的属性信息。 ### ArcGIS软件 ArcGIS是由美国Esri公司开发的地理信息系统软件,是业界广泛使用的一套GIS软件平台。ArcGIS提供了众多的工具来捕捉、分析、管理、展示地理信息。用户可以利用ArcGIS进行数据编辑、地图制作、地理分析、数据管理和应用开发等多种操作。ArcGIS支持多种数据格式,包括我们这里提到的矢量数据格式。 ### SHP文件格式 SHP文件格式是一种流行的矢量数据文件格式,它是由Esri公司在其ArcGIS产品中创建的一种空间数据存储格式,用于存储空间和属性信息。SHP文件包含了构成矢量图形的几何形状(点、线、面)和相关的属性信息。每个SHP文件通常都伴随着DBF文件(属性表)和.prj文件(定义空间参考系统的文件)。SHP格式由于其广泛的支持和开放性,成为了交换GIS数据的常用格式之一。 ### 全国国道数据的应用 全国国道数据在GIS中的应用非常广泛,包括但不限于: - **交通规划**:分析国道的通行能力,规划新的交通线路,优化现有路线。 - **应急响应**:在自然灾害或紧急情况中,用于规划救援路线和物资分配。 - **市政建设**:帮助规划城市扩展、土地利用以及基础设施建设。 - **旅游规划**:制定旅游路线,提升旅游服务的便捷性和舒适度。 - **车辆导航**:为导航系统提供精确的道路数据,帮助驾驶者快速到达目的地。 ### 数据处理与分析 利用ArcGIS等GIS软件,用户可以对全国国道数据进行一系列的空间分析和处理。包括但不限于以下几点: - **缓冲区分析**:分析国道周边一定范围内的情况,如人口分布、环境影响等。 - **网络分析**:进行道路连通性分析,为交通管理提供决策支持。 - **叠加分析**:将国道数据与其他地理数据层进行叠加,提取有用信息。 - **数据转换**:将国道数据转换为不同格式或投影,以适应不同的GIS平台或系统。 ### 数据共享与标准化 为了促进数据的共享和再利用,国家和地方制定了相应的GIS数据标准和规范。通过标准化的数据格式,不同的机构和组织可以交换数据,从而在更广泛的范围内发挥GIS数据的作用。对于全国国道数据而言,使用标准格式和协议可以提高数据的互操作性,便于进行区域间的协作与信息交流。 总结来说,全国国道数据作为一种重要的地理信息资源,对于国家交通网络的建设和管理具有重要的参考价值。通过GIS软件,特别是ArcGIS,用户可以充分利用矢量数据格式的优点,进行深入的数据分析和应用开发,从而更好地服务于社会经济发展和公众的日常需要。
recommend-type

Creo 1.0曲面设计宝典:提升模型质量的光顺技巧

# 摘要 本文旨在全面介绍Creo软件在曲面设计领域的应用,涵盖了从理论基础到高级技巧的全方位知识。首先,文章概述了Creo曲面设计的概念和重要性,随后深入探讨了曲面光顺的理论基础,包括曲面的连续性和曲率分析方法,以及光顺技术的数学原理。接着,文章通过实例操作演示了如何在Creo中高效执行曲面光顺,并分享了提高光顺效率的技巧。进一步地,介绍了优化曲面设计的高级技巧,重点在于复杂曲面建模策略和模型优化方法。最后,探讨了曲面设计评审与质量控制的最佳实践,并对曲面设计技术未来的发展趋势进行了展望,强调了新兴技术和人工智能的潜在应用。 # 关键字 Creo曲面设计;曲面光顺;曲面连续性;曲面曲率分析
recommend-type

DevEco Studio 如何全局加分号的快捷键

<think>好的,用户想了解在DevEco Studio中如何设置全局添加分号的快捷键。首先,我需要回忆一下DevEco Studio的快捷键设置方式,因为它是基于IntelliJ平台的,所以可能和Android Studio或者IDEA类似。 根据用户提供的引用内容,特别是引用[2]提到在Android Studio中可以使用Ctrl+Shift+Enter快速补全分号。但用户现在是在DevEco Studio中寻找类似功能。我需要确认DevEco Studio是否有相同的快捷键,或者需要自定义设置。 首先,全局添加分号可能指的是在代码中自动补全分号,尤其是在行尾添加。这通常与代码补全