3. 正弦波预测模型部署

任务目标

训练一个基于LSTM的正弦波时间序列预测模型,转换为TensorFlow Lite格式,并部署到STM32F407开发板上,实现基于历史采样点的实时正弦波预测。MCU通过串口接收当前时刻的正弦波采样值,模型输出未来时刻的预测值,并通过DAC输出还原为模拟波形。

环境与依赖

  • 训练端:Python 3.8+,TensorFlow 2.10+,numpy,matplotlib(可选)
  • 转换工具:tensorflow.lite.TFLiteConverter(随TensorFlow安装)
  • 部署端:STM32F407VET6开发板,STM32CubeIDE 1.10+,STM32CubeF4固件包
  • TFLite运行时:TFLite Micro(下载并添加到工程)

实现步骤

1. 训练正弦波预测模型(Python)

生成正弦波序列数据,构造滑动窗口样本,训练一个单层LSTM网络用于预测下一个时间点的值。

import numpy as np
import tensorflow as tf

# 生成正弦波数据
fs = 100  # 采样率100Hz
t = np.arange(0, 10, 1/fs)
freq = 1.0  # 1Hz正弦波
data = np.sin(2 * np.pi * freq * t).astype(np.float32)

# 构造滑动窗口样本:用前20个点预测下一点
seq_len = 20
X, y = [], []
for i in range(len(data) - seq_len - 1):
    X.append(data[i:i+seq_len])
    y.append(data[i+seq_len])
X = np.array(X).reshape(-1, seq_len, 1)
y = np.array(y).reshape(-1, 1)

# 划分训练/验证集
split = int(0.8 * len(X))
X_train, X_val = X[:split], X[split:]
y_train, y_val = y[:split], y[split:]

# 构建LSTM模型
model = tf.keras.Sequential([
    tf.keras.layers.LSTM(16, input_shape=(seq_len, 1), return_sequences=False),
    tf.keras.layers.Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.summary()

# 训练
history = model.fit(X_train, y_train, epochs=30, batch_size=32,
                    validation_data=(X_val, y_val), verbose=1)

# 保存Keras模型
model.save('sine_lstm.h5')

2. 转换为TFLite模型

import tensorflow as tf

# 加载训练好的模型
model = tf.keras.models.load_model('sine_lstm.h5')

# 转换为TFLite
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()

# 保存为C数组格式(方便直接嵌入STM32工程)
with open('sine_model.tflite', 'wb') as f:
    f.write(tflite_model)

# 生成C头文件
c_array = ', '.join(f'0x{b:02x}' for b in tflite_model)
with open('sine_model_data.h', 'w') as f:
    f.write(f'const unsigned char sine_model_tflite[] = {{{c_array}}};\n')
    f.write(f'const unsigned int sine_model_tflite_len = {len(tflite_model)};\n')
print(f'模型大小: {len(tflite_model)} 字节')

3. STM32部署代码(C语言)

将生成的sine_model_data.h加入工程,使用TFLite Micro运行时进行推理。ADC1采样正弦波输入,DAC1输出预测结果。

#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "sine_model_data.h"

// 模型输入输出缓冲区
constexpr int kTensorArenaSize = 8 * 1024;
uint8_t tensor_arena[kTensorArenaSize];

// 历史输入缓冲区(20个点)
float input_buffer[20] = {0};
int buffer_index = 0;

// ADC/DAC句柄(由CubeMX生成)
extern ADC_HandleTypeDef hadc1;
extern DAC_HandleTypeDef hdac;

void setup_tflite() {
    static tflite::AllOpsResolver resolver;
    const tflite::Model* model = tflite::GetModel(sine_model_tflite);
    static tflite::MicroInterpreter interpreter(
        model, resolver, tensor_arena, kTensorArenaSize);
    
    // 获取输入输出张量
    TfLiteTensor* input = interpreter.input(0);
    TfLiteTensor* output = interpreter.output(0);
    
    while (1) {
        // 读取ADC采样值(0~3.3V映射到-1~1)
        HAL_ADC_Start(&hadc1);
        HAL_ADC_PollForConversion(&hadc1, 10);
        float sample = (HAL_ADC_GetValue(&hadc1) / 4095.0f) * 2.0f - 1.0f;
        
        // 更新输入缓冲区
        input_buffer[buffer_index] = sample;
        buffer_index = (buffer_index + 1) % 20;
        
        // 按时间顺序填入模型输入
        for (int i = 0; i < 20; i++) {
            int idx = (buffer_index + i) % 20;
            input->data.f[i] = input_buffer[idx];
        }
        
        // 执行推理
        interpreter.Invoke();
        
        // 获取预测值并输出到DAC(-1~1映射到0~3.3V)
        float prediction = output->data.f[0];
        uint16_t dac_value = (uint16_t)((prediction + 1.0f) / 2.0f * 4095.0f);
        HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_value);
        
        HAL_Delay(10);  // 100Hz采样率
    }
}

运行与验证

  1. 训练验证:训练完成后,在Python中加载模型对测试集进行预测,计算MSE应小于0.001,表明模型已收敛。
  2. 转换验证:使用tflite_runtime.interpreter在PC上加载sine_model.tflite,输入相同测试样本,输出应与Keras模型误差小于1e-4。
  3. 硬件验证:将信号发生器输出1Hz、1V偏置、2Vpp的正弦波接入STM32的ADC引脚。用示波器观察DAC引脚输出,应得到同频率、同幅度的正弦波,且相位超前输入约20个采样点(200ms)。
  4. 通过标准:DAC输出波形频率误差小于1%,THD小于5%,且连续运行10分钟无异常复位。

常见问题

  • 模型无法加载:确认sine_model_data.h中的数组与模型文件一致,且TFLite Micro版本与转换工具版本兼容(推荐均使用2.10+)。
  • 推理结果恒为0:检查输入张量数据排列是否按时间顺序,LSTM对输入顺序敏感。
  • DAC输出噪声大:在DAC输出端增加RC低通滤波器(截止频率约10Hz),滤除高频量化噪声。