LED阵列动态随机显示效果,把随机过程改成马尔科夫链的方式。
改过后如下代码:
// 马尔科夫链状态结构体(修正字段类型)
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 = {
{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;
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 = 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();
}
}
修正后,虽然不再不连续的画面跳变,连续了,但是很碎片化
// 马尔科夫链增强平滑版本
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 = {
{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++;
}
// 有限渐变状态转移
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 = CHSV(hue, 235, val);
}
}
// 使用标准二维模糊 + 逐行模糊替代方案
blur2d(leds, MATRIX_WIDTH, MATRIX_HEIGHT, 64);
// 手动实现行模糊
for(uint8_t y=0; y<MATRIX_HEIGHT; y++) {
CRGB* rowStart = &leds;
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();
}
}
页:
[1]