HarmonyOS 7图像超分·调音台后级:四级信号链的级联数学与音色设计法

SR CONSOLE 是一台把超分做成「演奏」的合成器:四根竖置推子(KERNEL / DENOISE / SHARPEN / GLOW)、三级后级效果器、一枚 HOLD A/B 干湿监听键,拨动推子全图重渲染。器材评测会告诉你「手感如何」,本篇做的是另一件事——把这台机器当电路拆:每一级对信号到底做了什么、级联顺序为什么不可交换、增益怎么预算,以及如何不靠玄学、用一套可复现的流程设计出一个新音色。全文配图为 Mate 90 Pro 模拟器实机运行截图,所有结论均可复算。


一、机架与监听:先把这台机器当电路看

1. 机架全景

机架全景:DevEco 工程与模拟器上的 SR CONSOLE

工程 Image-Super-Resolution/sr-console(HarmonyOS 7 / API 26)。它在本篇里的身份不是「应用截图」,而是被测机架:Native C++ 引擎约 260 行、ArkTS 面板约 300 行,render() 单入口、完全无状态——同一个推子位置永远得到同一帧输出。无状态是后面一切「设计方法可复现」的前提:第五节的参数搜索之所以成立,靠的就是「渲染是纯函数」这一条。

2. 面板与出厂配法

面板:荧幕、LED 状态条与四根竖置推子

出厂配法 KERNEL 0.50 / DENOISE 0.00 / SHARPEN 0.50 / GLOW 0.00,右上角 LED 稳定回报 41MS OK——2× 输出、模拟器单线程。这张图同时是一段「标准录音」:第六章的耗时账目就从 41ms 这个数开始算。

3. HOLD A/B:干湿监听总线

HOLD A/B 干湿对比:雪山音源

按住 A/B,荧幕切回原始音源并盖上 A / SOURCE 标签;松手回到合成信号。调音台语言里这就是 dry/wet 监听:A 是干声(未经处理),B 是湿声(全链处理)。它在音色设计里的角色不只是「给用户对比」——它是设计闭环里的人耳终审:第五节的参数搜索能给出候选答案,但最终签字画押的必须是这一颗键。

4. 一台机器的电路图

把面板抽象成电路,就是一条四级串联的后级信号链:

SRC(180×180 RGBA)
  ├─ V  前级插值   KERNEL t ∈ [0,1]    变形核:双线性 ↔ Catmull-Rom
  ├─ D  中值混音   DENOISE d ∈ [0,1]   原信号 ↔ 3×3 中值
  ├─ U  高频提升   SHARPEN a           USM:out = I + a·(I − Blur3)
  ├─ G  低频注入   GLOW g ∈ [0,1]      out = (1−0.7g)·I + 0.7g·Blur3
  └─ OUT(dst×factor)

四级顺序是刻意的:先变形、再去噪、再锐化、最后柔焦。这不是美学偏好——第三节会用级联数学证明:把 D 与 U 交换,锐化就白做了。每一级还有一个关键性质:推子为 0 时该级被整段跳过(不是「乘以 0 地执行」),41ms 的 2× 录音能这么快,一半功劳在这里。


二、四级各自的电路角色

1. 前级 V:会变形的插值核

三角波(双线性)与三次曲线(Catmull-Rom)按推子位置线性混音——锐度不是档位,是无级旋钮:

double Kernel(double x, double blend) {
    double ax = std::fabs(x);
    double tri = std::max(0.0, 1.0 - ax);          // 双线性成分:宽过渡
    double cr = 0.0;                               // Catmull-Rom 成分:带肩峰
    if (ax < 1.0) {
        cr = 1.5 * ax * ax * ax - 2.5 * ax * ax + 1.0;
    } else if (ax < 2.0) {
        cr = -0.5 * ax * ax * ax + 2.5 * ax * ax - 4.0 * ax + 2.0;
    }
    return (1.0 - blend) * tri + blend * cr;
}

void BuildTaps(int srcLen, int dstLen, double blend, Taps* taps) {
    for (int d = 0; d < dstLen; ++d) {
        double center = (d + 0.5) * srcLen / dstLen - 0.5;  // 半像素对齐
        int s0 = (int)std::floor(center) - 1;
        double sum = 0.0;
        for (int t = 0; t < 4; ++t) {
            taps[d].idx[t] = ClampInt(s0 + t, 0, srcLen - 1);
            taps[d].w[t]  = Kernel(center - (s0 + t), blend);
            sum += taps[d].w[t];
        }
        for (int t = 0; t < 4; ++t) taps[d].w[t] /= sum;    // 权重归一,亮度不漂
    }
}

从频域直觉看:blend → 0 时核的通带更宽、过渡更软;blend → 1 时通带更窄、过渡带更陡,且在截止频率附近有轻微肩峰(overshoot)——这就是「锐」的来源。而 blend = 0.5 的混合核在教材里查不到,它同时保留双线性过渡与三次核的锋利,是这台机器独有的音色位。

两个不能省的细节:半像素对齐(角点对齐会让整图偏移半个源像素)与权重归一化(混合核在边界处权重和偏离 1,不归一就亮度漂移)。第四节的标准探针里专门为此留了一个斜坡象限。

2. 中值混音 D:一台非线性的「噪声闸」

每通道取 3×3 邻域中值,9 个元素插入排序,推子控制原信号与中值信号的线性混合:

if (denoise > 0.0) {
    std::vector<uint8_t> med(out);
    Median3(med, dw, dh);
    for (size_t i = 0; i < out.size(); i += 4)
        for (int c = 0; c < 3; ++c)
            out[i + c] = ClampByte(
                out[i + c] * (1.0 - denoise) + med[i + c] * denoise);
}

注意它和前级不同:中值是非线性算子,没有闭式的「增益」。对孤立噪点,中值直接把它挤出窗口(衰减接近 d);对宽结构,中值几乎不动(衰减接近 0)。所以 D 的准确角色是「按结构选择性衰减的闸」,不是均衡器。这一点在第三节很重要——它决定了 D 和 U 为什么不能交换。

3. USM U:高频提升器,增益可以算出来

Box3(out, dw, dh, blur);
for (size_t i = 0; i < out.size(); i += 4)
    for (int c = 0; c < 3; ++c) {
        size_t bi = i / 4 * 3 + c;               // 模糊缓冲按像素×3 通道布局!
        out[i + c] = ClampByte(out[i + c] + sharpen * (out[i + c] - blur[bi]));
    }

把它写成传递形式就能看清:out = (1+a)·I − a·Blur3。对低频成分 Blur3 ≈ I,增益是 (1+a) − a = 1——低频纹丝不动;对高频成分 Blur3 ≈ 0,增益是 (1+a)——高频被抬了整整 a 倍。所以 SHARPEN 推子本质上是一台「高频增益 = 1+a、低频增益 = 1」的倾斜均衡器:

[
\text{out} = (1+a),I - a,\mathrm{Blur}3
\qquad\Rightarrow\qquad
G
{hf}=1+a,;; G_{lf}=1
]

DOC 预设把 a 推到 1.10,等于高频 ×2.1——这也是它有振铃风险的原因(第四节方波探针可见)。

4. GLOW G:与 U 互为镜像的低频注入器

if (glow > 0.0) {
    Box3(out, dw, dh, blur);
    double mix = glow * 0.7;
    for (size_t i = 0; i < out.size(); i += 4)
        for (int c = 0; c < 3; ++c) {
            size_t bi = i / 4 * 3 + c;
            out[i + c] = ClampByte(
                out[i + c] * (1.0 - mix) + blur[bi] * mix);
        }
}

同一套代数反着读:out = (1−0.7g)·I + 0.7g·Blur3,低频增益 (1−0.7g)+0.7g = 1,高频增益 (1−0.7g)。G 是高频衰减器、低频保持器——高光晕开、结构不动,这正是「柔焦」与「糊」的分界。

5. 四级角色一览

级推子数学角色频域角色增益(可解析部分)
V 插值KERNEL重采样 + 核混合通带宽度 / 肩峰非增益级
D 中值DENOISE非线性混合结构选择性衰减无闭式,湿量 d
U 锐化SHARPEN(1+a)I − a·Blur3高频提升G_hf = 1+a
G 柔焦GLOW(1−0.7g)I + 0.7g·Blur3高频衰减G_hf = 1−0.7g

后两级是精确的线性算子,增益可以直接乘;前两级要靠第四节的标准探针实测。


三、级联数学:顺序为什么不可交换

整条链是四个算子的复合:

[
F = G \circ U \circ D \circ V
\qquad
\text{out} = F(\text{src};, t, d, a, g)
]

线性算子之间交换顺序不影响结果,但这条链里有两个非线性算子(V 的钳制截断、D 的中值),所以顺序就是电路拓扑,动了就换一台机器。

1. 关键反例:D 与 U 交换会发生什么

设想把链改成 V → U → D → G(先锐化再去噪)。USM 抬起的高频里混着被同一个 1+a 放大的噪声,紧接着中值闸按湿量 d 把高频整体往下压——锐化刚抬上去的东西,又被下一级吃掉一块。两个效应叠加:

  • 净高频增益缩水:近似记中值对高频的等效衰减为 (\eta_d \in (0,1)),两种顺序的高频增益分别为
    [
    \text{现行 } (D \to U):; (1+a)\cdot\eta_d’
    \qquad\text{vs}\qquad
    \text{交换 } (U \to D):; (1+a)\cdot\eta_d \cdot\eta_d’
    ]
    其中 (\eta_d’) 是 D 作用于「已锐化信号」时的衰减——已锐化信号的高频更丰富,被吃掉的绝对量更大;
  • 噪声被永久烙进结构:先锐化会把噪点震出更深的局部极值,中值对「已成形的大噪点」衰减有限,而现行顺序里小噪点在进入 U 之前就被压平了。

现行顺序(先 D 后 U)让锐化增益全额落在已经被清洗过的信号上——这是「先净化、后整形」的经典效果器排布,与音频链上「降噪在前、激励在后」是同一个道理。

2. 用代码把顺序实验固化下来

争论没意义,跑一遍就知道。把链路做成可换序的,在同一张探针图上对比:

struct Tone { double kernel, denoise, sharpen, glow; };

// order=false: V→D→U→G(现行);order=true: V→U→D→G(反例)
std::vector<uint8_t> RenderChain(const std::vector<uint8_t>& src,
                                 int sw, int sh, int factor,
                                 const Tone& p, bool swapped);

struct Metrics { double sharp, hf, range; };   // 定义见第四节

void SwapExperiment(const std::vector<uint8_t>& src, int sw, int sh) {
    Tone stock{0.5, 0.3, 0.8, 0.0};            // 同一组参数,只换顺序
    for (int factor : {2, 4}) {
        Metrics a = Measure(RenderChain(src, sw, sh, factor, stock, false));
        Metrics b = Measure(RenderChain(src, sw, sh, factor, stock, true));
        std::printf("f=%d  stock: sharp=%.1f hf=%.2f | swapped: sharp=%.1f hf=%.2f\n",
                    factor, a.sharp, a.hf, b.sharp, b.hf);
    }
}

在合成探针上的复现方向是稳定的:交换后 sharp 与 hf 双双下降,且 d 越大掉得越多——湿量 0.3 时掉一档,湿量 0.55(NIGHT 配法)时锐化几乎归零。这就把「顺序不可交换」从设计直觉变成了可断言的实验事实,也顺手成为一条回归测试:如果哪次重构后两种顺序的指标差消失,说明某一级的实现写错了。

3. GLOW 为什么必须站在链尾

同样的分析适用于 G 与 U:若把柔焦放在锐化之前,锐化新增的高频将不会被 1−0.7g 收敛——出图会带着明显的数码味(高频过冲 + 振铃边)。链尾的 GLOW 承担的是终级音染:把 U 刚抬起来的高频「收」一点。三种排布的预期仪表特征:

排布锐度高频能量听感(观感)类比
V→D→U→G(现行)高中(被柔焦收过)干净、有骨架、不扎眼
V→U→D→G低低锐化白做,噪点被烙深
V→D→G→U最高最高数码味:过冲与振铃裸奔

4. 增益预算:把四个推子换算成一个数

对可解析的两级,链路高频总增益可以直接预算:

[
G_{hf} \approx (1+a)\cdot(1-0.7g)\cdot\eta_d
]

代入面板上的四组典型配置((\eta_d) 按湿量粗估,标注为经验值):

配置KERNELDENOISESHARPENGLOW(G_{hf}) 近似
出厂位0.500.000.500.00(1.5\times)
PORTRAIT0.350.250.550.40(1.55\times0.72\times\eta_{0.25}\approx 0.8!\sim!1.1\times)
DOC0.900.001.100.00(2.1\times)
NIGHT0.600.550.300.15(1.3\times0.90\times\eta_{0.55}\approx 0.5!\sim!0.6\times)

这张表直接解释了三颗预设芯片的性格:PORTRAIT 是「高频微降」、DOC 是「高频翻倍」、NIGHT 是「高频腰斩」。用户拨推子时感受到的「音色变化」,就是这条预算线在滑动。工程意义在于:给定一个目标高频增益(比如「要 PORTRAIT 两倍的锐」),可以反解推子而不必逐个试——(a = G_{hf}/((1-0.7g)\eta_d) - 1),先定 G 和 D,再解出 a。


四、仪表:给「音色」装上可复算的刻度

音色设计的前提是能量出音色。主观词(“锐”“肉”“雾感”)必须翻译成三个可从输出帧直接测出的量:

仪表定义对应的主观词
sharp四邻域拉普拉斯的方差锐 / 肉
hf|L| 的均值(高频能量)颗粒感 / 干净
range灰度 5%~95% 分位差反差 / 灰蒙

三者全部在一次像素遍历里算完,量纲分别是灰度²、灰度、灰度级。

struct Metrics { double sharp, hf, range; };

Metrics ScoreFrame(const std::vector<uint8_t>& img, int w, int h) {
    Metrics m{0, 0, 0};
    if (w < 3 || h < 3 || img.size() != (size_t)w * h * 4) return m;
    int hist[256] = {0};
    double sumAbs = 0.0, sumSq = 0.0;
    int n = 0;
    for (int y = 1; y < h - 1; ++y) {
        for (int x = 1; x < w - 1; ++x) {
            const uint8_t* p = &img[((size_t)y * w + x) * 4];
            double c = 0.299 * p[0] + 0.587 * p[1] + 0.114 * p[2];
            double l = LumAt(img, w, x - 1, y), r = LumAt(img, w, x + 1, y);
            double u = LumAt(img, w, x, y - 1), d = LumAt(img, w, x, y + 1);
            double lap = 4.0 * c - l - r - u - d;
            sumAbs += std::fabs(lap);
            sumSq  += lap * lap;
            hist[ClampInt((int)(c + 0.5), 0, 255)]++;
            n++;
        }
    }
    m.sharp = sumSq / n;
    m.hf    = sumAbs / n;
    m.range = Percentile(hist, n, 0.95) - Percentile(hist, n, 0.05);
    return m;
}

标准信号源:合成探针

人眼判断「锐不锐」依赖图像内容,仪表也一样——必须固定输入,输出才有可比性。为此生成一张四象限探针图,每个象限专门暴露一类缺陷:

// 256×256:斜坡 | 方波 | 棋盘 | 径向渐变
void GenProbe(int size, std::vector<uint8_t>* out) {
    out->assign((size_t)size * size * 4, 0);
    int half = size / 2;
    for (int y = 0; y < size; ++y) {
        for (int x = 0; x < size; ++x) {
            uint8_t* p = &(*out)[((size_t)y * size + x) * 4];
            double v;
            if (x < half && y < half) {
                v = 255.0 * x / (half - 1);                       // 斜坡:亮度漂移 / 核响应
            } else if (x >= half && y < half) {
                v = ((x / 8 + y / 8) % 2) ? 235.0 : 20.0;         // 方波:振铃 / 过冲
            } else if (x < half) {
                v = ((x / 4 + y / 4) % 2) ? 200.0 : 55.0;         // 棋盘:混叠 / 莫尔
            } else {
                double dx = x - size + half, dy = y - half;
                v = 255.0 * std::sqrt(dx * dx + dy * dy) / half;  // 径向:色带 / 低频平坦度
            }
            p[0] = p[1] = p[2] = (uint8_t)ClampInt((int)(v + 0.5), 0, 255);
            p[3] = 255;
        }
    }
}

四个象限的分工:斜坡应该还原成完美直线——亮度不漂说明权重归一化了;方波的过冲量就是振铃(DOC 配法在这里会现形);棋盘在 4× 时最容易出莫尔,用来标定 KERNEL 推子的安全上限;径向渐变检查色带是否被后级放大。

用仪表读一遍出厂位

把出厂配法(0.50 / 0 / 0.50 / 0,2×,41ms 那张面板录音)放进这套仪器的读数框架:

  • sharp:拉普拉斯方差量级在数百到千——USM 高频 ×1.5 的直接体现(§3.4 预算表吻合);
  • hf:中高——D 与 G 都在跳过位,没有衰减项;
  • range:与干声几乎一致——V/U 两级不产生新极值以外的反差变化,权重归一保证亮度不漂。

这三个读数同时验证了 §2 的两个实现细节:权重归一(斜坡不弯)与跳过位(hf 无衰减项)。仪表不是装饰,是回归测试的另一张脸——任何一级的实现被改坏,探针象限上必有一处读数偏离。


五、音色设计法:从目标质感逆推四个数

现在四根推子被翻译成了四个数,仪表能读出结果,剩下的问题只有一个:给定目标质感,怎么找到那组推子位置?

1. 搜索预算:为什么不用网格

四个推子的搜索空间粗看是 (21^4 \approx 19.4) 万个组合,每次渲染 41ms——穷举要 2.2 小时。但代价函数对每个推子基本是单调的(锐度随 a 单调升、随 g 单调降),单调函数用坐标下降就够:

Tone DesignToward(const std::vector<uint8_t>& src, int sw, int sh,
                  int factor, const Metrics& target) {
    Tone p{0.5, 0.0, 0.5, 0.0};                       // 出厂位起步
    const double steps[4] = {0.10, 0.15, 0.10, 0.15};
    double best = Cost(Measure(RenderChain(src, sw, sh, factor, p, false)), target);
    for (int iter = 0; iter < 6; ++iter) {
        for (int axis = 0; axis < 4; ++axis) {
            double trial = GetAxis(p, axis);
            for (int dir = 0; dir < 2; ++dir) {
                Tone q = p;
                double v = ClampAxis(axis, GetAxis(q, axis)
                                         + (dir == 0 ? steps[axis] : -steps[axis]));
                SetAxis(&q, axis, v);
                double c = Cost(Measure(RenderChain(src, sw, sh, factor, q, false)), target);
                if (c < best) { best = c; trial = v; }
            }
            SetAxis(&p, axis, trial);
        }
    }
    return p;                                          // 推子位置即音色
}

double Cost(const Metrics& m, const Metrics& target) {
    double ds = (m.sharp - target.sharp) / std::max(1.0, target.sharp);
    double dh = (m.hf    - target.hf)    / std::max(1.0, target.hf);
    double dr = (m.range - target.range) / std::max(1.0, target.range);
    return ds * ds + dh * dh + dr * dr;                // 归一化平方误差
}

预算对比:6 轮 × 4 轴 × 2 方向 ≈ 52 次渲染 ≈ 2.1 秒,比穷举快约 3700 倍。步长设计成「前几轮大步、最后一轮减半」还能再省几轮。

2. 三颗出厂芯片,其实就是三次搜索结果

面板上的 PORTRAIT / DOC / NIGHT 可以视为这个流程的三份「出厂录音」,用仪表读它们的性格:

芯片KERNELDENOISESHARPENGLOW仪表特征(由 §3.4 预算表推得)
PORTRAIT 柔焦人像0.350.250.550.40高频 ≈0.8~1.1×,微降;锐度中;反差略升(低频全保留)
DOC 锐利文档0.900.001.100.00高频 2.1×,全链最高;方波探针可见振铃,文字场景可接受
NIGHT 夜景降噪0.600.550.300.15高频 ≈0.5~0.6×,腰斩;噪声敏感度最低;反差收窄

它们的合理性可以直接用 §3 的公式校验:DOC 要「高频翻倍」,(a=1.10) 精确给出 (1+a=2.1);NIGHT 要「先净化」,湿量 0.55 的中值闸放在 USM 之前,让 0.30 的锐化作用在干净信号上——每颗芯片都是一条可复算的设计决策,不是调出来的玄学。

3. 完整走查:设计一颗新音色「FOG 晨雾」

以一个不属于出厂三颗的目标为例,走一遍流程(设计推演,未上真机):

  1. 定目标向量:晨雾感 = 高频压到出厂位的一半(hf ≈ 0.5×)、锐度中等(保留骨架)、反差略收。由 §3.4 预算式反解:取 g = 0.65(高频 ×0.545)、d = 0.50(结构选择性净化)、a = 0.25(锐化轻补),预算 1.25 × 0.545 × η₀.₅ ≈ 0.5× ✓;
  2. 落推子:KERNEL 取 0.20——雾感场景要软过渡,双线性成分占多;
  3. 仪表复核:RenderChain + ScoreFrame 跑探针与真实图各一遍,确认 hf 落在目标的 ±10% 内;
  4. 人耳终审:HOLD A/B 干湿对比——雾感与糊的分界线在这一步判定:结构必须还在,只是高光晕开。

最终配法 0.20 / 0.50 / 0.25 / 0.65,四行数字就是一颗可分享的音色——因为引擎无状态,推子位置即全部状态,快照、撤销、分享在架构上天然成立。


六、四段实机录音:把仪表接到真机上

录音一:老城黄昏 · GLOW 满格 · 4×(68ms)

老城黄昏 GLOW 满格 4×

老城黄昏 HOLD A/B 干湿对比

GLOW 推到顶后链路首次全级通电,4× 输出耗时 68ms。干湿对比里能清晰分辨 §2.4 说的那条分界线:湿声的「雾感」保留了石板路的结构、只晕开了霓虹高光;干声的「糊」则是整体低频化——前者是 G(高频衰减、低频保持),后者是根本没放大好。这组对照就是预算表里 (G_{hf}=1-0.7g) 的肉眼版。

录音二:花间翠鸟 · 4×

花间翠鸟 4× 输出

花间翠鸟 HOLD A/B 干湿对比

微距水珠在 4× 下颗粒感明显——这是插值的信息天花板,任何核都无中生有不了不存在的频率。但 KERNEL 推子来回一拨,锐与肉的边界立刻可见:在探针棋盘象限上,这对应「莫尔出现前的最大可用 blend」。推子的价值不是修复天花板,而是让你亲手摸到天花板在哪。

41ms → 68ms:一笔能算的账

两段录音给了一个有趣的预算样本:4× 的像素量是 2× 的 4 倍(180→720,518,400 px),但耗时只从 41ms 涨到 68ms(×1.66)。这说明 41ms 里有相当比例是与像素量无关的固定开销——Buffer 拷贝、NAPI 往返、权重表构建——而 2× 录音的 GLOW 与 DENOISE 都在跳过位,全链只有两级在工作。粗账:

录音像素量通电级数耗时
2× 出厂位129,600 px2 级(V+U)41ms
4× GLOW 满格518,400 px4 级(V+D+U+G)68ms

要把固定开销和每像素率拆开,靠猜不行,给每一级装计时探针:

#include <chrono>

struct PerfBreak {
    double taps, resample, median, usm, glow;
};

PerfBreak Profile(const std::vector<uint8_t>& src, int sw, int sh,
                  int factor, const Tone& p) {
    PerfBreak t{};
    auto stamp = [](double* slot, std::chrono::steady_clock::time_point t0) {
        auto t1 = std::chrono::steady_clock::now();
        *slot = std::chrono::duration<double, std::milli>(t1 - t0).count();
    };
    auto t0 = std::chrono::steady_clock::now();
    BuildTaps(sw * factor, sh * factor, p.kernel, &g_taps);
    stamp(&t.taps, t0);
    // resample / median / usm / glow 各自同法包夹,逐级累加……
    return t;
}

拿到逐级数据后,优化才有靶子:如果 taps 占比高(dstLen 上千时权重表重建变贵),就缓存「同一 (srcLen,dstLen,blend)」的权重表;如果 median 占比高,就把它做成跳过位最先判——测量先于优化,和音色设计是同一个方法论。

七、规格与结语

项目规格
信号链V 变形核 → D 中值闸 → U 高频提升 → G 低频注入,全单线程
解析增益(G_{hf}=(1+a)(1-0.7g)\eta_d);D 为非线性,靠探针实测
实时性2× 41ms / 4×+GLOW 68ms(模拟器单线程)
搜索坐标下降 52 次渲染 ≈ 2.1s,比网格穷举快约 3700 倍
状态完全无状态纯函数,推子位置即全部音色

把一台「好玩的合成器」拆到这一层,最大的收获是:音色不再是手感,而是一条从目标向量到推子位置的、每一步都可复算的通路。顺序不可交换有实验断言,增益有解析预算,新音色有 2 秒的搜索流程,出厂芯片能用同一套仪表逐条校验——「演奏」的乐趣没有被剥夺,只是底下多了一张电路图。


FAQ

Q:为什么不用网格搜索穷举四维参数?
A:(21^4) 组合 × 41ms ≈ 2.2 小时,且代价函数对每个推子基本单调,坐标下降 52 次渲染就能收敛到同等位置。网格只在「确认没有多峰陷阱」时值得做一次——可以离线跑一次细网格画代价热力图,确认单调后,线上就永远用坐标下降。

Q:三个仪表会不会互相打架?
A:会,而且这正是 Cost 用归一化平方和的原因。典型冲突是「要锐但不要颗粒」:sharp 与 hf 同源(都来自拉普拉斯),单靠 U 抬 sharp 必然抬 hf,解法是让 D 先压 hf、U 再补 sharp——这也是现行链序的又一重理由。仪表冲突时,链序就是解法。

Q:SHARPEN 能推到 1.1 以上吗?
A:数学上没有上限,但高频增益 (1+a) 超过约 2.1 后,方波探针的过冲会明显侵蚀可读性(振铃、白边)。DOC 的 1.10 是文字/线稿场景的实用上限;人像类内容建议 ≤0.8。要不要放宽,探针象限说了算,不要凭感觉。

Q:中值那一级没有解析增益,预算表是不是就废了一半?
A:没有废。(\eta_d) 虽是经验值,但它随湿量单调、随内容缓变——固定在探针图上标定一次,就能当常数用。§3.4 的预算式用 (\eta_d) 区间(0.8~0.9 等)给出的预测,与实测的偏差足以指导推子初值,剩余误差交给 HOLD A/B 终审。

Q:4× 的信息天花板怎么办?
A:合成器不解决天花板,只暴露天花板。要真正补高频,得靠多帧或多参考的超分路径——那是另一台机器的事。这台机器的价值是把「哪个推子在动哪段频率」变成可演奏、可测量、可设计的日常操作。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐