天赐范式第188天:让环境开始轮回——周期峰的低通滤波响应

天赐范式第188天·第一篇:让环境开始轮回------周期峰的低通滤波响应


摘要

周期峰驱动下AR(1)均值响应是低通滤波:幅值衰减|H(Ω)|+相位滞后φ(Ω),离散z域闭式。临界周期T*=2π/c≈523代,数值比值1.00。


一、接续187-1:定向移动做完了,周期呢?

187-1让峰开始移动------但那是单调趋势:x*(t)=x*_0+v·t,峰一直往一个方向跑。种群学会了就是常数滞后,追得很稳。

真实栖息地的环境变化有个更基本的形态:周期。昼夜、季节、潮汐------环境不是一直变好或一直变坏,是来回摆。这是环境弧的第二分量。

数学上区别很大:定向移动下种群对峰是常数滞后 (187-1的lag*);周期驱动下种群均值是对峰的低通滤波 ------响应是幅值衰减+相位滞后。这是AR(1)对正弦输入的标准稳态解,理论结构全新,不是187的延伸。


二、理论推导------AR(1)低通滤波

均值更新(与187-1同):μ(t+1) = (1−c)·μ(t) + c·x*(t),c = β·h²·K

周期峰:x*(t) = x*_0 + A·sin(Ω·t),Ω是角频率(弧度/代)。

z域传递函数

H(z) = c / (z − (1−c))

令z = e^(jΩ),离散频率响应:

|H(Ω)| = c / √(1 − 2(1−c)cos(Ω) + (1−c)²)

φ(Ω) = −atan2(sin(Ω), cos(Ω) − 1 + c)

连续极限(Ω→0, c≪1)

|H(Ω)| → c / √(c² + Ω²)

φ(Ω) → −arctan(Ω / c)

临界周期

半功率点 |H| = 1/√2 对应 Ω* = c(连续近似),临界周期:

T* = 2π / c ≈ 2π / 0.012 ≈ 523代

这是"数字生命的时间尺度"------环境周期比这短,种群就感知不到。


三、频率响应曲线:理论vs数值

固定σ_v=0.02(c=0.0120),振幅A=0.3,扫Ω ∈ {0.005, 0.01, 0.02, 0.03, 0.05, 0.1, 0.2}。正弦拟合提取种群均值的幅值和相位。

Ω T(代) |H|离散 |H|连续 |H|数值 比值 φ离散 φ数值 平均fitness 状态
0.005 1257 0.924 0.923 0.923 1.00 −0.395 0.377 0.729 跟踪
0.010 628 0.770 0.768 0.773 1.00 −0.697 0.673 0.498 衰减
0.012 524 0.709 0.707 0.714 1.01 −0.788 0.769 0.442 衰减
0.020 314 0.517 0.515 0.518 1.00 −1.038 1.014 0.353 衰减
0.030 209 0.374 0.372 0.375 1.00 −1.203 1.184 0.318 衰减
0.050 126 0.235 0.234 0.236 1.00 −1.359 1.349 0.298 衰减
0.100 63 0.120 0.119 0.120 1.00 −1.501 1.492 0.291 衰减
0.200 31 0.060 0.060 0.060 1.00 −1.611 1.611 0.288 躺平

幅值衰减|H|:离散理论vs数值比值全部1.00-1.01------闭式精确。相位φ:理论为负(滞后),数值返回atan2(−a,b)取绝对值,两者符号约定不同,下文比较绝对值。


四、跟踪区、衰减区与躺平区

跟踪区(T ≥ 1257代,Ω ≤ 0.005):|H|≈0.92,种群均值振幅接近峰振幅。 峰慢,种群跟得上,只有相位滞后φ≈0.4弧度(约79代延迟,数值约75代)。

衰减区(T = 63~628代,Ω = 0.01~0.1):0 < |H| < 1,种群均值振幅衰减。 半功率点(|H|=1/√2≈0.707)在临界周期T*=2π/c≈523代附近(见表中Ω=0.012行,T=524代,|H|离散=0.709)。T=314代时|H|=0.52,T=63代时|H|=0.12------种群均值几乎不动,峰在摆种群不摆。

躺平区(T ≤ 31代,Ω ≥ 0.2):|H|→0,种群均值完全躺平。 峰在动,种群不动,平均fitness≈0.29------反而可能不如"假装峰不动"。这是滤波特性的必然:快于T*的周期,种群感知不到。

临界周期T*≈523代是分界线。 c=β·h²·K=0.012是跟踪速率,T*=2π/c是种群响应时间尺度。环境周期比T*长,种群跟得上;比T*短,种群感知不到。


五、结论与弧签名动作

问题 答案
周期峰下种群怎么响应? 低通滤波:幅值衰减|H(Ω)|+相位滞后φ(Ω),AR(1)标准稳态解
临界周期多长? T*=2π/c≈523代------数字生命感知环境变化的时间尺度下限
理论准吗? 幅值比值全部1.00,离散z域闭式精确
和187-1什么关系? 187-1定向移动=常数滞后;188-1周期驱动=低通滤波,环境弧第二分量

叙事弧:

  • 187-1:定向移动------常数滞后lag*=v(1−c)/c
  • 188-1:周期驱动------低通滤波|H(Ω)|+φ(Ω),从"追踪"升级到"滤波"
  • 弧签名动作:187定向追踪 → 188周期滤波。
  • 主线意义:T*≈523代是数字生命感知环境变化的时间尺度下限。

环境弧全貌:定向(187,趋势分量)→ 周期(188-1,季节分量)→ 随机游走(不可预测分量,留给189+)。

降调:

  1. 线性化近似。 低通滤波公式是AR(1)线性系统的稳态解,假设h²和K当常数(用σ_v=0.02自洽解)。大振幅下种群偏离峰远,h²和K有微小漂移(187-1降调2同源)。振幅A=0.3下影响小,更大振幅需验证。

  2. 相位拟合有0~5%偏差(随Ω减小而增大)。 数值相位绝对值比理论略小(如0.377 vs 0.395,偏差4.6%;1.611 vs 1.611,偏差0%)。偏差源于低频端测量窗覆盖周期少、暂态残留多;高频端周期多、暂态影响小。幅值精确匹配是核心结果,相位偏差在降调里如实报。

  3. 测量窗含整数个周期。 gen=4000、warmup=500,测量窗3500代。最长周期T=1257代覆盖2.8个周期------够。更长的周期需要更多代数。

  4. 跟踪区仅Ω=0.005一个格点支撑。 更慢周期(Ω<0.005)未测,需要更长模拟窗口。

  5. 单位点模型。 多位点、上位效应、连锁不平衡待后续。

系列还在逐步建设中,完善是和伙伴们的努力方向。


附录:完整代码

python 复制代码
# -*- coding: utf-8 -*-
"""
天赐范式 第188天 第一篇
让环境开始轮回------周期峰的低通滤波响应

PID: TC-188A-V3.3.26.0
V3.3.26.0 · 2026-10-07

接续187-1:定向移动(趋势分量)→ 周期移动(季节分量)
  187-1: x*(t)=x*_0+v·t(单调趋势),种群响应=常数滞后
  188-1: x*(t)=x*_0+A·sin(Ω·t)(周期驱动),种群响应=低通滤波

理论:AR(1)均值动力学 μ(t+1)=(1-c)·μ(t)+c·x*(t),c=β·h²·K
  z域传递函数 H(z)=c/(z-(1-c))
  令z=e^(jΩ),离散频率响应:
    |H(Ω)| = c/√(1−2(1−c)cos(Ω)+(1−c)²)
    φ(Ω)  = −atan2(sin(Ω), cos(Ω)−1+c)
  连续极限(Ω→0, c<<1):
    |H(Ω)| → c/√(c²+Ω²)
    φ(Ω)  → −arctan(Ω/c)
  临界周期 T*=2π/c≈523代(半功率点)

预测:
  慢周期(T>>T*):A≈1, φ≈0,种群紧跟峰
  快周期(T<<T*):A→0,种群均值躺平,峰在动种群不动
  T*≈523代是"数字生命的时间尺度"------季节比这短就感知不到

数值:扫Ω,正弦拟合提取幅值衰减+相位滞后,理论vs数值对比
"""

import sys
import math
import numpy as np

if hasattr(sys.stdout, "reconfigure"):
    sys.stdout.reconfigure(encoding="utf-8")

PID = "TC-188A-V3.3.26.0"

TARGET = 0.5
X_STAR_0 = 0.8
AMPLITUDE = 0.3
FITNESS_WIDTH = 0.10
BETA = 0.3
SIGMA_E = 0.02
SIGMA_V = 0.02
N_POP = 200
N_GENERATIONS = 4000
WARMUP_STATIC = 500
N_SEEDS = 20
TOL = 1e-12
MAX_ITER = 5000

OMEGAS = [0.005, 0.01, 0.012, 0.02, 0.03, 0.05, 0.1, 0.2]


def bar(title):
    print("=" * 72)
    print("  " + title)
    print("=" * 72)
    print()


def sub(title):
    print("【" + title)
    print("-" * 72)


def fitness(x, x_star):
    return np.exp(-(x - x_star) ** 2 / (2 * FITNESS_WIDTH ** 2))


def solve_self_consistent(sigma_v):
    var_g = sigma_v ** 2 / (1 - BETA ** 2)
    for it in range(MAX_ITER):
        sigma_x2 = var_g + SIGMA_E ** 2
        h2 = var_g / sigma_x2
        v_x_sel = sigma_x2 * FITNESS_WIDTH ** 2 / (sigma_x2 + FITNESS_WIDTH ** 2)
        var_g_sel = h2 ** 4 * v_x_sel + var_g * (1 - h2 ** 2)
        var_g_new = BETA ** 2 * var_g_sel + sigma_v ** 2
        if abs(var_g_new - var_g) < TOL:
            return var_g_new, it + 1
        var_g = var_g_new
    return var_g, MAX_ITER


def theory_response(omega, track_rate):
    c = track_rate
    denom = 1.0 - 2.0 * (1.0 - c) * math.cos(omega) + (1.0 - c) ** 2
    gain = c / math.sqrt(denom) if denom > 0 else float('inf')
    phase = -math.atan2(math.sin(omega), math.cos(omega) - 1.0 + c)
    return gain, phase


def theory_response_cont(omega, track_rate):
    c = track_rate
    gain = c / math.sqrt(c ** 2 + omega ** 2)
    phase = -math.atan2(omega, c)
    return gain, phase


def run_one(omega, seed):
    rng = np.random.RandomState(seed)
    genes = rng.normal(TARGET, 0.01, N_POP)
    mu_trace = []
    xstar_trace = []
    fit_trace = []

    for gen in range(N_GENERATIONS):
        if gen < WARMUP_STATIC:
            x_star = X_STAR_0
        else:
            t = gen - WARMUP_STATIC
            x_star = X_STAR_0 + AMPLITUDE * math.sin(omega * t)

        phenos = genes + rng.normal(0, SIGMA_E, N_POP)
        fits = fitness(phenos, x_star)
        fit_sum = float(fits.sum())

        if fit_sum < 1e-10:
            for g2 in range(gen, N_GENERATIONS):
                if g2 >= WARMUP_STATIC:
                    fit_trace.append(0.0)
            break

        probs = fits / fit_sum
        sel_idx = rng.choice(N_POP, size=N_POP, p=probs)
        parent_genes = genes[sel_idx]
        mu = float(np.mean(genes))
        genes = mu + BETA * (parent_genes - mu) + rng.normal(0, SIGMA_V, N_POP)

        if gen >= WARMUP_STATIC:
            mu_trace.append(float(np.mean(genes)))
            xstar_trace.append(x_star)
            fit_trace.append(float(np.mean(fits)))

    return np.array(mu_trace), np.array(xstar_trace), np.array(fit_trace)


def sine_fit(mu_trace, xstar_trace, omega):
    t = np.arange(len(mu_trace)) + 1
    residual = mu_trace - X_STAR_0
    cos_basis = np.cos(omega * t)
    sin_basis = np.sin(omega * t)
    A_mat = np.array([[np.sum(cos_basis * cos_basis), np.sum(cos_basis * sin_basis)],
                      [np.sum(sin_basis * cos_basis), np.sum(sin_basis * sin_basis)]])
    b_vec = np.array([np.sum(residual * cos_basis), np.sum(residual * sin_basis)])
    try:
        coeffs = np.linalg.solve(A_mat, b_vec)
    except np.linalg.LinAlgError:
        return 0.0, 0.0
    a, b = coeffs
    amp = math.sqrt(a ** 2 + b ** 2)
    phase = math.atan2(-a, b)
    return amp, phase


def main():
    bar(f"{PID}  让环境开始轮回------周期峰的低通滤波响应")
    print(f"模型: g'=μ+β(g_sel-μ)+v_mut(回归到种群均值μ)")
    print(f"fitness峰: x*(t)=x*_0+A·sin(Ω·t), x*_0={X_STAR_0}, A={AMPLITUDE}")
    print(f"参数: β={BETA}, σ_e={SIGMA_E}, σ_v={SIGMA_V}, N={N_POP}, seeds={N_SEEDS}")
    print(f"理论: AR(1)低通滤波 |H(Ω)|=c/√(1−2(1−c)cos(Ω)+(1−c)²)")
    print(f"      连续极限 |H|=c/√(c²+Ω²), φ=−arctan(Ω/c)")
    print(f"      临界周期 T*=2π/c")
    print(f"数值: gen={N_GENERATIONS}, warmup={WARMUP_STATIC}, 正弦拟合提取幅值+相位")
    print()

    var_g_star, _ = solve_self_consistent(SIGMA_V)
    sigma_x2 = var_g_star + SIGMA_E ** 2
    h2 = var_g_star / sigma_x2
    K = sigma_x2 / (sigma_x2 + FITNESS_WIDTH ** 2)
    track_rate = BETA * h2 * K
    T_star = 2 * math.pi / track_rate

    sub("理论参数(σ_v=0.02自洽)")
    print(f"  h²* = {h2:.4f}")
    print(f"  K   = {K:.4f}")
    print(f"  c = β·h²·K = {track_rate:.6f}(跟踪速率)")
    print(f"  T* = 2π/c = {T_star:.1f}代(临界周期)")
    print()

    sub("频率响应:理论 vs 数值")
    print(f"{'Ω':>8s}  {'T(代)':>8s}  {'|H|离散':>8s}  {'|H|连续':>8s}  {'|H|数值':>8s}  {'φ离散':>8s}  {'φ数值':>8s}  {'平均fit':>10s}  {'状态':>6s}")
    print("-" * 90)

    results = []
    for omega in OMEGAS:
        T = 2 * math.pi / omega
        gain_discrete, phase_discrete = theory_response(omega, track_rate)
        gain_cont, phase_cont = theory_response_cont(omega, track_rate)

        gains_seed = []
        phases_seed = []
        fits_seed = []
        for seed in range(N_SEEDS):
            mu_trace, xstar_trace, fit_trace = run_one(omega, seed)
            amp, phase = sine_fit(mu_trace, xstar_trace, omega)
            gains_seed.append(amp / AMPLITUDE)
            phases_seed.append(phase)
            fits_seed.append(float(np.mean(fit_trace)) if len(fit_trace) > 0 else 0.0)

        gain_num = float(np.mean(gains_seed))
        phase_num = float(np.mean(phases_seed))
        mean_fit = float(np.mean(fits_seed))

        if gain_num > 0.9:
            status = "跟踪"
        elif gain_num > 0.1:
            status = "衰减"
        else:
            status = "躺平"

        results.append({
            'omega': omega, 'T': T, 'gain_discrete': gain_discrete,
            'gain_cont': gain_cont, 'gain_num': gain_num,
            'phase_discrete': phase_discrete, 'phase_num': phase_num,
            'mean_fit': mean_fit, 'status': status,
        })

        print(f"{omega:>8.4f}  {T:>8.1f}  {gain_discrete:>8.4f}  {gain_cont:>8.4f}  {gain_num:>8.4f}  {phase_discrete:>8.4f}  {phase_num:>8.4f}  {mean_fit:>10.6f}  {status:>6s}")

    print()

    sub("理论 vs 数值对比")
    for r in results:
        ratio = r['gain_num'] / r['gain_discrete'] if r['gain_discrete'] > 1e-6 else float('inf')
        print(f"  Ω={r['omega']:.4f} (T={r['T']:.0f}代): |H|离散={r['gain_discrete']:.4f} vs |H|数值={r['gain_num']:.4f},比值={ratio:.2f},φ离散={r['phase_discrete']:.4f} vs φ数值={r['phase_num']:.4f}")

    print()

    sub("结论")
    print(f"187-1:定向移动,常数滞后lag*=v·(1−c)/c")
    print(f"188-1:周期驱动,低通滤波响应|H(Ω)|+φ(Ω)")
    print(f"       临界周期 T*=2π/c={T_star:.0f}代------数字生命的时间尺度")
    track_vs = [r for r in results if r['status'] == "跟踪"]
    decay_vs = [r for r in results if r['status'] == "衰减"]
    flat_vs = [r for r in results if r['status'] == "躺平"]
    if track_vs:
        print(f"       跟踪区:T≥{track_vs[-1]['T']:.0f}代(Ω≤{track_vs[-1]['omega']:.4f}),|H|≈1")
    if decay_vs:
        print(f"       衰减区:T∈[{decay_vs[-1]['T']:.0f}, {decay_vs[0]['T']:.0f}]代,0<|H|<1")
    if flat_vs:
        print(f"       躺平区:T≤{flat_vs[0]['T']:.0f}代(Ω≥{flat_vs[0]['omega']:.4f}),|H|→0")
    print()
    print(f"  弧签名动作:187定向追踪 → 188周期滤波")
    print(f"  主线意义:T*≈{T_star:.0f}代是数字生命感知环境变化的时间尺度下限")


if __name__ == "__main__":
    main()
    

天赐范式 V3.3.26.0 · 2026-10-07

相关推荐
天赐范式7 小时前
天赐范式第187天:让峰开始移动——lag load定量
数字生命·复杂系统·天赐范式·动态运行时·lag load·移动峰·测量滞后
天赐范式1 天前
天赐范式第187天:让变异开始定价——动态环境下最优变异率
数字生命·复杂系统·天赐范式·动态运行时·最优变异率·bet-hedging·初始条件暂态
天赐范式2 天前
天赐范式第186天:让方差开始自洽——Bulmer效应的闭式验证
python·数字生命·天赐范式·动态运行时·遗传方差·bulmer效应
天赐范式3 天前
天赐范式第185天:让漂变开始定量——扫N看选择主导边界
python·信噪比·数字生命·天赐范式·动态运行时·种群大小·遗传漂变
天赐范式4 天前
天赐范式第183天:让平衡开始定量——收缩与选择的平衡点位置公式验证
数字生命·天赐范式·动态运行时·育种者方程·非线性归因·多seed验证·平衡位移
天赐范式5 天前
天赐范式第183天:让选择开始生效——育种者方程与选择生效条件
python·数字生命·天赐范式·动态运行时·育种者方程·选择压力·遗传力
天赐范式6 天前
天赐范式第181天:让视图开始切换——PBFT视图切换与从safety到liveness的跨越
python·pbft·数字生命·天赐范式·动态运行时·拜占庭容错
天赐范式7 天前
天赐范式第181天:让耦合开始失稳——竞争耦合与线性失稳边界
python·数字生命·天赐范式·lyapunov指数·动态运行时·耦合失稳·laplacian矩阵
天赐范式7 天前
天赐范式第182天:让变异开始存活——主线重启与变异存续条件
python·ar模型·数字生命·天赐范式·动态运行时·稳态方差·变异存续