matlab 根据大端序(Big Endian)和小端序(Little Endian)读取SEG-Y文件

在 MATLAB 中处理SEG-Y(SGY)文件时大端序(Big Endian)小端序(Little Endian)来表示数据。

  • 大端序(Big Endian):‘ieee-be'
  • 小端序(Little Endian):‘ieee-le'

SEG-Y 文件

  • 字节序标志位置:SEG-Y 文件第 3211 字节
    • 如果字节序标志为0x01,文件使用大端序
    • 如果字节序标志为0x00,文件使用小端序

MATLAB没有内建的函数直接支持SEG-Y文件的字节序识别和处理,但你可以手动读取文件头中的字节序标志,并使用fopenfread函数根据字节,代码如下:

% 打开 SEG-Y 文件(使用 'r' 只读模式)
fileID = fopen('your_segy_file.sgy', 'r');

% 读取文件头的前3200字节(文件头信息)
header = fread(fileID, 3200, 'uint8');

% 提取第3211字节(字节序标志)
endianFlag = header(3211);

% 根据字节序标志判断字节序
if endianFlag == 1
    disp('文件使用大端序(Big Endian)。');
    endian = 'ieee-be';  % 大端序
else
    disp('文件使用小端序(Little Endian)。');
    endian = 'ieee-le';  % 小端序
end

% 关闭文件头部分
fclose(fileID);

% 使用正确的字节序模式重新打开文件(根据 endian 变量设置字节序)
fileID = fopen('your_segy_file.sgy', 'r', endian);

% 读取 SEG-Y 文件的数据段(假设数据在 3200 字节之后)
% 这里假设数据类型为 32 位浮点数
data = fread(fileID, 'float32');

% 关闭文件
fclose(fileID);

% 显示部分读取的数据
disp(data(1:5));  % 显示前 5 个读取的数据

后续

定义:在计算机系统体系结构中用来描述在多字节数中各个字节的存储顺序。相关概念还有MSB(Most Significant Bit/Byte)和LSB(Least Significant Bit/Byte)。在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian和Little-Endian。引用标准的Big-Endian和Little-Endian的定义如下:
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
PS:有些文章中称低位字节为最低有效位,高位字节为最高有效位。
                           
                        
原文链接:https://blog.youkuaiyun.com/weiyiwen1982/article/details/124151025

#include "widget.h" #include "ui_widget.h" #include <QFileDialog> #include <QDateTime> #include <QTextStream> #include <QSerialPortInfo> #include <QMessageBox> #include <QTimer> #include <QSerialPort> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) , sendIndex(0) , totalBytes(0) , currentState(STATE_IDLE) { ui->setupUi(this); QStringList serialNamePort; serialport = new QSerialPort(this); timerSerial = new QTimer(this); ackTimer = new QTimer(this); // 连接信号槽 connect(serialport, SIGNAL(readyRead()), this, SLOT(serialport_readyread())); connect(timerSerial, SIGNAL(timeout()), this, SLOT(TimerUpdate())); connect(ackTimer, &QTimer::timeout, this, &Widget::handleAckTimeout); // 搜索一个文件夹中的串口号 foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { serialNamePort << info.portName(); } ui->comboBox->addItems(serialNamePort); } Widget::~Widget() { delete ui; } void Widget::on_openseriButton_clicked() { QSerialPort::BaudRate baudrate = QSerialPort::Baud115200; // 设置波特率115200 QSerialPort::DataBits databits = QSerialPort::Data8; // 数据位8 QSerialPort::StopBits stopbits = QSerialPort::OneStop; // 停止位1 QSerialPort::Parity checkbits = QSerialPort::NoParity; // 无校验 serialport->setPortName(ui->comboBox->currentText()); // 设置串口号 serialport->setBaudRate(baudrate); // 设置波特率 serialport->setDataBits(databits); // 设置数据位 serialport->setStopBits(stopbits); // 设置停止位 serialport->setParity(checkbits); // 设置校验位 if (serialport->open(QIODevice::ReadWrite)) { // 判断是否打开成功 QMessageBox::information(this, "提示", "打开成功"); } else { QMessageBox::critical(this, "提示", "打开失败"); } } void Widget::on_refuseButton_clicked() { QStringList serialNamePort; ui->comboBox->clear(); foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { serialNamePort << info.portName(); } ui->comboBox->addItems(serialNamePort); } void Widget::on_closeButton_2_clicked() { sendIndex=0; timerSerial->stop(); serialport->close(); } void Widget::on_pushButton_clicked() { QFileDialog* f = new QFileDialog(this); f->setWindowTitle("选择数据文件*.bin"); f->setNameFilter("*.bin"); f->setViewMode(QFileDialog::Detail); ui->lineEdit->clear(); ui->textEdit->clear(); QString filePath; if (f->exec() == QDialog::Accepted) filePath = f->selectedFiles()[0]; ui->lineEdit->setText(filePath); ui->textEdit->append("文件路径:" + filePath); // 文件信息 QFileInfo info(filePath); ui->textEdit->append(QString("文件大小:%1 byte").arg(info.size())); ui->textEdit->append(QString("文件名称:%1").arg(info.fileName())); ui->textEdit->append(QString("创建时间:%1").arg(info.created().toString("yyyy-MM-dd hh:mm:ss"))); ui->textEdit->append(QString("修改时间:%1").arg(info.lastModified().toString("yyyy-MM-dd hh:mm:ss"))); // 文件内容 QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { ui->textEdit->append("文件打开失败"); return; } QByteArray fileContent = file.readAll(); file.close(); delete f; // 以十六进制格式显示文件内容 // QString hexContent = fileContent.toHex(' '); // ui->textEdit->append("文件内容(十六进制格式):"); // ui->textEdit->append(hexContent); // 准备发送的数据 dataToSend = fileContent; sendIndex = 0; totalBytes = dataToSend.size(); } const quint16 HEAD_CODE = 0xA55A; const quint8 TYPE = 0xE1; const quint8 CMD = 0x12; // FLASH_WRITE_BUFF_SEG const int PAYLOAD = 128; // 每帧真正写 Flash 的字节数 // void Widget::on_pushButton_2_clicked() // { // // 判断文件是否已选择 // if (totalBytes == 0) { // ui->textEdit->append("未选择文件文件为空"); // return; // } // // 判断串口是否已打开 // if (!serialport->isOpen()) { // ui->textEdit->append("串口未打开"); // return; // } // timerSerial->start(100); // 每秒发送一次 // } void Widget::TimerUpdate() { if (sendIndex >= totalBytes) { ui->textEdit->append("文件发送完成"); timerSerial->stop(); return; } /*------------------------------------------------- * 1. 计算当前块号(从 0 开始) *------------------------------------------------*/ quint16 block = sendIndex / PAYLOAD; // 第几块 /*------------------------------------------------- * 2. 取本帧要发的 128 字节(最后一帧可能不足 128) *------------------------------------------------*/ int bytesToSend = qMin(PAYLOAD, totalBytes - sendIndex); QByteArray userData = dataToSend.mid(sendIndex, bytesToSend); /*------------------------------------------------- * 3. 构造完整帧 *------------------------------------------------*/ QByteArray frame; QDataStream ds(&frame, QIODevice::WriteOnly); ds.setByteOrder(QDataStream::BigEndian); ds << HEAD_CODE; // 2 字节 ds << quint8(5 + userData.size()); // Length = 固定5 + 数据长度 + 校验 ds << TYPE; // 1 字节 ds << CMD; // 1 字节 ds << block; // 2 字节(Data0+Data1) ds.writeRawData(userData.constData(), userData.size()); // 128 或更少 /*------------------------------------------------- * 4. 计算校验 * SUM = TYPE + CMD + Data0 + Data1 + ... + DataN *------------------------------------------------*/ quint8 sum = TYPE + CMD; sum += (block & 0xFF); // Data0 sum += ((block >> 8) & 0xFF); // Data1 for (int i = 0; i < userData.size(); ++i) sum += static_cast<quint8>(userData.at(i)); ds << sum; // 1 字节校验 /*------------------------------------------------- * 5. 真正写到串口 *------------------------------------------------*/ qint64 bytesWritten = serialport->write(frame); if (bytesWritten == -1) { ui->textEdit->append("发送失败: " + serialport->errorString()); timerSerial->stop(); return; } /*------------------------------------------------- * 6. 更新进度 *------------------------------------------------*/ sendIndex += bytesToSend; // 注意:是用户数据长度,不是帧长度 ui->textEdit->append(QString("已发送 %1 / %2 字节") .arg(sendIndex).arg(totalBytes)); double percentage = (sendIndex * 100.0 / totalBytes); ui->progressBar->setValue(static_cast<int>(percentage)); ui->progressBar->setFormat(QString::number(percentage, 'f', 1) + "%"); /*------------------------------------------------- * 7. 可选:等待真正发完(非阻塞) *------------------------------------------------*/ serialport->flush(); // 如之前讨论,可保留或改为 waitForBytesWritten } // 点击发送按钮 - 启动握手 void Widget::on_pushButton_2_clicked() { if (currentState != STATE_IDLE) { ui->textEdit->append("传输已在进行中"); return; } if (totalBytes == 0) { ui->textEdit->append("未选择文件文件为空"); return; } if (!serialport->isOpen()) { ui->textEdit->append("串口未打开"); return; } // 计算总块数 totalBlocks = (totalBytes + PAYLOAD - 1) / PAYLOAD; ui->textEdit->append(QString("文件总块数: %1").arg(totalBlocks)); // 发送握手请求 sendHandshakeRequest(); // 进入等待握手响应状态 currentState = STATE_WAIT_HANDSHAKE; retryCount = 0; ackTimer->start(1000); // 1秒超时 } // 发送握手请求帧 void Widget::sendHandshakeRequest() { QByteArray frame; QDataStream ds(&frame, QIODevice::WriteOnly); ds.setByteOrder(QDataStream::BigEndian); ds << HEAD_CODE; // 2字节帧头 ds << quint8(0x05); // 长度字段 (固定5字节) ds << quint8(TYPE); // 1字节类型 ds << quint8(0x11); // 1字节命令 ds << quint8(0x88); // 长度字段 (固定5字节) ds << quint8(0x88); // 长度字段 (固定5字节) ds << calculateChecksum(frame); // 1字节校验 serialport->write(frame); ui->textEdit->append("发送握手请求..."); } // 处理单片机响应 void Widget::serialport_readyread() { QByteArray data = serialport->readAll(); processReceivedData(data); } // 处理接收到的数据 void Widget::processReceivedData(const QByteArray& data) { static QByteArray buffer; buffer.append(data); ui->textEdit->append("收到数据"); // 检查是否收到完整帧 (最小帧长=6字节) while (buffer.size() >= 4) { // 检查帧头 ui->textEdit->append((QString("接收:"+buffer))); if (static_cast<quint8>(buffer[0]) != (0x5A) || static_cast<quint8>(buffer[1]) != (0xA5)) { buffer.remove(0, 1); // 移除非帧头字节 continue; } // 获取长度字段 quint8 length = static_cast<quint8>(buffer[2]); // 检查是否收到完整帧 if (buffer.size() < static_cast<int>(length + 3)) { break; // 等待更多数据 } // 提取完整帧 QByteArray frame = buffer.left(length + 3); buffer.remove(0, length + 3); // 验证校验 if (!validateChecksum(frame)) { ui->textEdit->append("校验错误,丢弃帧"); continue; } // 解析帧类型 quint8 frameType = static_cast<quint8>(frame[4]); // 根据当前状态处理帧 switch (currentState) { case STATE_WAIT_HANDSHAKE: if (frameType == HANDSHAKE_ACK) { handleHandshakeAck(); } break; case STATE_WAIT_START_ACK: if (frameType == HANDSHAKE_ACK) { // 确认开始传输 startTransfer(); } break; case STATE_TRANSFERRING: if (frameType == DATA_REQUEST) { handleDataRequest(frame); } break; case STATE_COMPLETED: if (frameType == END_FRAME) { quint8 IAP_STATE= static_cast<quint8>(frame[6]); if(IAP_STATE==1) ui->textEdit->append("升级成功"); else if(IAP_STATE==2) ui->textEdit->append("校验错误"); currentState = STATE_IDLE; } break; default: if (frameType == 00) { quint8 IAP_Ver= static_cast<quint8>(frame[6]); ui->textEdit->append(QString("当前版本 %1").arg(IAP_Ver)); currentState = STATE_IDLE; } break; } } } // 处理握手确认 void Widget::handleHandshakeAck() { ackTimer->stop(); ui->textEdit->append("收到握手确认"); // 发送开始传输帧 sendStartFrame(); currentState = STATE_TRANSFERRING; ackTimer->start(1000); // 1秒超时 } // 发送开始传输帧 void Widget::sendStartFrame() { QByteArray frame; QDataStream ds(&frame, QIODevice::WriteOnly); ds.setByteOrder(QDataStream::BigEndian); ds << HEAD_CODE; // 2字节帧头 ds << quint8(0x05); // 长度字段 (固定7字节) ds << quint8(TYPE); // 1字节类型 ds << quint8(0x11); // 1字节命令 ds << quint8(0x99); // 2字节总块数 ds << quint8(0x99); // 2字节总块数 ds << calculateChecksum(frame); // 1字节校验 serialport->write(frame); ui->textEdit->append("发送开始传输帧..."); } // 处理数据请求 void Widget::handleDataRequest(const QByteArray& frame) { // 解析请求的块号 quint16 blockNumber; QDataStream ds(frame.mid(5, 2)); // 跳过帧头(2)+长度(1)+类型(1)+命令(1) ds.setByteOrder(QDataStream::BigEndian); ds >> blockNumber; ui->textEdit->append(QString("收到数据请求: 块号 %1").arg(blockNumber)); // ===== 修改开始 ===== // 检查块号是否超出范围 if (blockNumber >= totalBlocks) { // 如果是预期的下一包请求(块号=总块数) if (blockNumber == totalBlocks) { ui->textEdit->append("收到结束请求,发送结束帧"); sendEndFrame(); currentState = STATE_IDLE; } // 如果是无效的超范围请求 else { sendErrorFrame("无效块号: " + QString::number(blockNumber)); } return; } // ===== 修改结束 ===== // 发送请求的数据块 sendDataFrame(blockNumber); // ===== 删除以下代码 ===== // if (blockNumber == totalBlocks - 1) { // currentState = STATE_COMPLETED; // sendEndFrame(); // } } // 发送数据帧 void Widget::sendDataFrame(quint16 blockNumber) { // 计算数据偏移 int offset = blockNumber * PAYLOAD; int bytesToSend = qMin(PAYLOAD, totalBytes - offset); QByteArray payload = dataToSend.mid(offset, bytesToSend); // 构造帧 QByteArray frame; QDataStream ds(&frame, QIODevice::WriteOnly); ds.setByteOrder(QDataStream::BigEndian); // 计算长度 (TYPE+CMD+块号+数据+校验) quint8 length = 1 + 1 + 2 + payload.size() + 1; ds << HEAD_CODE; // 2字节帧头 ds << length; // 1字节长度 ui->textEdit->append(QString("发送长度 %1").arg(length)); ds << quint8(TYPE); // 1字节类型 ds << quint8(DATA_FRAME); // 1字节命令 ds << blockNumber; // 2字节块号 ds.writeRawData(payload.constData(), payload.size()); // 数据 // 计算校验 quint8 sum = 0; const char* dataStart = frame.constData() + 3; // 从长度字段后开始 for (int i = 0; i < length; i++) { sum += static_cast<quint8>(dataStart[i]); } ds << sum; // 发送帧 serialport->write(frame); // 更新进度 double percentage = ((blockNumber + 1) * 100.0) / totalBlocks; ui->progressBar->setValue(static_cast<int>(percentage)); ui->progressBar->setFormat(QString::number(percentage, 'f', 1) + "%"); } // 发送结束帧 void Widget::sendEndFrame() { QByteArray frame; QDataStream ds(&frame, QIODevice::WriteOnly); ds.setByteOrder(QDataStream::BigEndian); ds << HEAD_CODE; // 2字节帧头 ds << quint8(0x05); // 长度字段 (固定5字节) ds << quint8(TYPE); // 1字节类型 ds << quint8(END_FRAME); // 1字节命令 ds << quint8(0x01); // 1字节命令 ds << quint8(0x01); // 1字节命令 ds << calculateChecksum(frame); // 1字节校验 serialport->write(frame); ui->textEdit->append("发送结束帧..."); ui->textEdit->append("文件传输完成"); // 重置状态 currentState = STATE_IDLE; } // 超时处理 void Widget::handleAckTimeout() { switch (currentState) { case STATE_WAIT_HANDSHAKE: if (retryCount < 3) { ui->textEdit->append("握手响应超时,重试..."); sendHandshakeRequest(); retryCount++; } else { ui->textEdit->append("握手失败,超过重试次数"); currentState = STATE_IDLE; } break; case STATE_WAIT_START_ACK: if (retryCount < 3) { ui->textEdit->append("开始确认超时,重试..."); sendStartFrame(); retryCount++; } else { ui->textEdit->append("开始传输失败,超过重试次数"); currentState = STATE_IDLE; } break; default: ackTimer->stop(); break; } } // 发送错误帧 void Widget::sendErrorFrame(const QString& message) { QByteArray frame; QDataStream ds(&frame, QIODevice::WriteOnly); ds.setByteOrder(QDataStream::BigEndian); QByteArray msgData = message.toUtf8(); quint8 length = 1 + 1 + msgData.size() + 1; ds << HEAD_CODE; // 2字节帧头 ds << length; // 长度字段 ds << TYPE; // 1字节类型 ds << ERROR_FRAME; // 1字节命令 ds.writeRawData(msgData.constData(), msgData.size()); // 错误信息 // 计算校验 quint8 sum = 0; const char* dataStart = frame.constData() + 3; // 从长度字段后开始 for (int i = 0; i < length; i++) { sum += static_cast<quint8>(dataStart[i]); } ds << sum; serialport->write(frame); ui->textEdit->append("发送错误帧: " + message); // 重置状态 currentState = STATE_IDLE; ackTimer->stop(); } // 计算校验 quint8 Widget::calculateChecksum(const QByteArray& frame) { if (frame.size() < 4) return 0; quint8 sum = 0; // 从长度字段开始计算 (偏移2字节) for (int i = 3; i < frame.size(); i++) { sum += static_cast<quint8>(frame[i]); } return sum; } // 验证校验 bool Widget::validateChecksum(const QByteArray& frame) { if (frame.size() < 5) return false; quint8 calculatedSum = 0; // 从长度字段开始计算 (偏移2字节),跳过最后的校验字节 for (int i = 3; i < frame.size()-1; i++) { calculatedSum += static_cast<quint8>(frame[i]); } quint8 receivedSum = static_cast<quint8>(frame[frame.size() - 1]); return calculatedSum == receivedSum; } void Widget::startTransfer() { // 实现代码 // 例如:发送握手请求 // sendHandshakeRequest(); }
07-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值