打印

LED阵列动态随机显示效果,把随机过程改成马尔科夫链的方式。

[复制链接]
27|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2025-5-22 13:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式



改过后如下代码:
// 马尔科夫链状态结构体(修正字段类型)
struct MarkovState {
  uint8_t baseHue;     // 改为8位存储
  uint8_t speed;       // 速度范围1-5
  int8_t direction;    // 风向
  uint8_t intensity;   // 强度范围
};

// 初始化状态(调整参数)
MarkovState currentState = {200, 3, 1, 150}; // 提高初始baseHue

// 简化转移概率矩阵
const uint8_t transitionProb[4][4] = {
  {80, 10, 5, 5},   
  {15, 70, 10, 5},  
  {10, 5, 80, 5},  
  {5, 5, 5, 85}   
};

// 噪声参数
uint16_t z = 0;
const uint8_t scale = 30;
const uint8_t blurAmount = 64;


// 马尔科夫状态转移实现
void applyMarkovTransition() {
  uint8_t randVal = random8();
  uint8_t probSum = 0;
  
  // 选择要改变的状态维度
  uint8_t targetDim = 0;
  for(; targetDim<4; targetDim++) {
    probSum += transitionProb[targetDim][targetDim];
    if(randVal < probSum) break;
  }
  
  // 执行状态转移(有限差分法)
  switch(targetDim) {
    case 0: // 基础色调变化
      currentState.baseHue += random8(3) - 1; // ±1微调
      currentState.baseHue = constrain(currentState.baseHue, 180, 255);
      break;
      
    case 1: // 速度变化
      currentState.speed = constrain(
        currentState.speed + random8(3) - 1, 1, 5);
      break;
      
    case 2: // 方向变化
      if(random8() < 30) currentState.direction *= -1;
      break;
      
    case 3: // 强度变化
      currentState.intensity = constrain(
        currentState.intensity + random8(21) - 10, 100, 200);
      break;
  }
}

// 基于状态的图案生成
void generateWindPattern() {
  for(uint8_t y=0; y<MATRIX_HEIGHT; y++) {
    for(uint8_t x=0; x<MATRIX_WIDTH; x++) {
      uint8_t noise = inoise8(
        (x * scale) / 2 + (currentState.direction * z),
        y * scale + z/2,
        currentState.intensity * 10
      );
      
      // 修正色调计算(添加循环处理)
      uint8_t hue = currentState.baseHue + map(noise, 0,255, -20,20);
      hue = (hue < 180) ? hue + 75 : hue; // 确保在180-255范围
      
      // 修正亮度计算(移除错误处理)
      uint8_t val = map(noise, 50, 205, 30, 230);
      val = constrain(val, 30, 230); // 硬约束
      
      leds[XY(x,y)] = CHSV(hue, 230, val);
    }
  }
  
  blur2d(leds, MATRIX_WIDTH, MATRIX_HEIGHT, blurAmount);
  z += currentState.speed;
}



void wind_vision() {
  static uint32_t lastUpdate = 0;
  static uint8_t hueShift = 0;

  if(millis() - lastUpdate > 50) { // 降低更新频率
    lastUpdate = millis();
   
    // 马尔科夫状态转移
    applyMarkovTransition();
   
    // 生成动态风场
    generateWindPattern();
   
    FastLED.show();
  }
}


使用特权

评论回复

相关帖子

沙发
keer_zu|  楼主 | 2025-5-22 15:44 | 只看该作者
修正后,虽然不再不连续的画面跳变,连续了,但是很碎片化

// 马尔科夫链增强平滑版本
struct MarkovState {
  uint8_t baseHue;     // 当前色相
  uint8_t targetHue;   // 目标色相(新增)
  uint8_t speed;
  uint8_t targetSpeed; // 新增目标速度
  int8_t direction;
  float directionF;    // 新增浮点方向(用于平滑过渡)
  uint8_t intensity;
};

MarkovState currentState = {200, 200, 3, 3, 1, 1.0f, 150};
const uint8_t transitionProb[4][4] = {
  {90, 5, 3, 2},     // 提高保持色相的概率
  {10, 85, 3, 2},    // 降低速度变化频率
  {5, 5, 88, 2},     // 增强方向稳定性
  {3, 2, 2, 93}      // 提高强度保持率
};

uint32_t z = 0;       // 改为32位防溢出
const float DIRECTION_TRANSITION = 0.1f; // 方向过渡系数

void applyMarkovTransition() {
  static uint32_t lastChange = 0;
  const uint32_t CHANGE_INTERVAL = 3000; // 延长状态变化间隔
  
  if(millis() - lastChange < CHANGE_INTERVAL) return;
  lastChange = millis();

  uint8_t randVal = random8();
  uint8_t probSum = 0;
  uint8_t targetDim = 0;
  
  // 概率累计方式优化
  while(targetDim < 4 && randVal > (probSum += transitionProb[targetDim][targetDim])) {
    targetDim++;
  }

  // 有限渐变状态转移
  switch(targetDim) {
    case 0: // 色相渐变
      currentState.targetHue = constrain(currentState.baseHue + random8(-8, 9), 180, 255);
      break;
      
    case 1: // 速度渐变
      currentState.targetSpeed = constrain(currentState.speed + random8(-1, 2), 1, 5);
      break;
      
    case 2: // 方向平滑过渡
      currentState.directionF = -currentState.directionF; // 缓慢反转
      break;
      
    case 3: // 强度渐变
      currentState.intensity = constrain(currentState.intensity + random8(-8, 9), 100, 200);
      break;
  }
}

void smoothUpdateStates() {
  // 色相线性插值
  currentState.baseHue = lerp8by8(currentState.baseHue, currentState.targetHue, 10);
  
  // 速度指数平滑
  currentState.speed = (currentState.speed * 7 + currentState.targetSpeed * 1) / 8;
  
  // 方向浮点过渡
  currentState.directionF += (currentState.direction - currentState.directionF) * DIRECTION_TRANSITION;
}

void generateWindPattern() {
  const float dirFactor = currentState.directionF; // 使用浮点方向因子


  for(uint8_t y=0; y<MATRIX_HEIGHT; y++) {
    for(uint8_t x=0; x<MATRIX_WIDTH; x++) {
      // 改进的噪声参数(增加Z轴细分)
      uint8_t noise = inoise8(
        (x * 25) + (z * dirFactor * 0.7f),
        y * 35 + z * 0.3f,
        currentState.intensity * 8 + (z >> 6)
      );
      
      // 循环色相映射(替代硬约束)
      uint8_t hue = currentState.baseHue + map(noise, 0,255, -15,15);
      hue = 180 + ((hue - 180) % 76); // 180-255循环
      
      // 亮度S曲线处理
      uint8_t val = cubicwave8(noise);
      val = map(val, 30, 225, 50, 220);  // 压缩两端
      
      leds[XY(x,y)] = CHSV(hue, 235, val);
    }
  }
  
   // 使用标准二维模糊 + 逐行模糊替代方案
  blur2d(leds, MATRIX_WIDTH, MATRIX_HEIGHT, 64);
  
  // 手动实现行模糊
  for(uint8_t y=0; y<MATRIX_HEIGHT; y++) {
    CRGB* rowStart = &leds[XY(0, y)];
    blur1d(rowStart, MATRIX_WIDTH, 32);
  }
  
  z += currentState.speed;
}

void wind_vision() {
  static uint32_t lastUpdate = 0;
  
  if(millis() - lastUpdate > 33) { // 30FPS
    lastUpdate = millis();
   
    smoothUpdateStates();  // 先更新状态
    applyMarkovTransition();
    generateWindPattern();
   
    // 添加残影效果
    fadeToBlackBy(leds, NUM_LEDS, 220);
    FastLED.show();
  }
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1439

主题

12764

帖子

53

粉丝