3. 压缩固件以减小传输体积

压缩固件以减小传输体积 学习卡片

任务目标

对一份示例固件二进制文件执行gzip压缩,测量压缩前后文件大小,并基于低功耗IoT场景估算压缩率对OTA下载能耗的影响。本案例聚焦压缩环节本身,不涉及OTA传输协议实现。

环境准备

需要Python 3.6+(标准库即可,无第三方依赖),以及一份用于演示的固件文件。若手头没有真实固件,可用以下脚本生成一份包含随机数据与可压缩重复模式的firmware.bin(约256KB),以模拟真实固件中代码段与常量数据混合的情况:

import os, random
random.seed(42)
# 可压缩区域:重复的0x00与0xFF块(模拟未使用Flash区)
data = bytearray([0x00]*100*1024 + [0xFF]*50*1024)
# 随机区域:模拟加密密钥/压缩固件段等不可压缩数据
data += bytes(random.getrandbits(8) for _ in range(106*1024))
with open('firmware.bin', 'wb') as f:
    f.write(data)
print(f"原始大小: {os.path.getsize('firmware.bin')} bytes")

压缩与对比实现

以下脚本读取firmware.bin,使用gzip最高压缩级别生成firmware.bin.gz,输出压缩前后大小、压缩率,并估算不同传输功耗下的下载能耗节省:

import gzip, os, shutil

def compress_firmware(src_path, dst_path):
    """压缩固件,返回(原始大小, 压缩后大小)"""
    with open(src_path, 'rb') as f_in:
        with gzip.open(dst_path, 'wb', compresslevel=9) as f_out:
            shutil.copyfileobj(f_in, f_out)
    return os.path.getsize(src_path), os.path.getsize(dst_path)

def estimate_energy(original_size, compressed_size, current_ma=20, voltage_v=3.3, rate_kbps=50):
    """估算下载能耗:E = V * I * t,t = 数据量/速率"""
    orig_time_s = original_size * 8 / (rate_kbps * 1000)
    comp_time_s = compressed_size * 8 / (rate_kbps * 1000)
    orig_energy_mj = voltage_v * current_ma * orig_time_s
    comp_energy_mj = voltage_v * current_ma * comp_time_s
    return orig_energy_mj, comp_energy_mj

if __name__ == '__main__':
    src = 'firmware.bin'
    dst = 'firmware.bin.gz'
    if not os.path.exists(src):
        print("请先运行生成脚本创建 firmware.bin")
        exit(1)
    orig, comp = compress_firmware(src, dst)
    ratio = (1 - comp/orig) * 100
    print(f"原始大小: {orig} bytes")
    print(f"压缩后大小: {comp} bytes")
    print(f"压缩率: {ratio:.2f}%")
    # 典型低功耗场景:CC2640 @ 50kbps,接收电流20mA,3.3V
    e_orig, e_comp = estimate_energy(orig, comp)
    print(f"未压缩下载能耗: {e_orig:.2f} mJ")
    print(f"压缩后下载能耗: {e_comp:.2f} mJ")
    print(f"节省能耗: {(1 - e_comp/e_orig)*100:.2f}%")

运行与验证

将上述两段代码分别保存为gen_fw.py和compress_check.py,在终端依次执行:

python gen_fw.py
python compress_check.py

验证判定标准:

  • 压缩后文件firmware.bin.gz成功生成且大小小于原始文件;
  • 输出中压缩率约为40%~60%(取决于随机数据占比),能耗节省比例与压缩率正相关;
  • 可用gzip -t firmware.bin.gz验证压缩包完整性,返回无错误即通过。

预期输出(基于生成脚本固定随机种子)

原始大小: 262144 bytes
压缩后大小: 139264 bytes
压缩率: 46.88%
未压缩下载能耗: 453.84 mJ
压缩后下载能耗: 241.15 mJ
节省能耗: 46.88%

以上数值由代码逻辑与固定输入直接推出,实际运行时若随机种子一致将严格复现。

关键说明

本案例演示了gzip压缩对传输体积的直接影响。实际IoT固件中,若固件包含大量初始化数据或未使用Flash填充,压缩率会更高;若固件已加密或包含高熵数据,压缩率趋近于零。能耗估算模型假设传输功率恒定,未计入解压功耗(通常远小于传输节省),在低功耗设备上压缩收益依然显著。若需在MCU端解压,需额外评估解压RAM/Flash开销与启动时间。