در زنجیرهٔ تحلیل گفتار، تبدیل فوریه پایانِ تصمیم‌های پیش‌پردازش نیست. هنوز باید مشخص کنیم کدام خانه‌های طیف با چه وزنی در یک ویژگی جمع شوند. بانکی که روی کاغذ چند مثلث دارد، ممکن است روی شبکهٔ فرکانسیِ انتخاب‌شده ردیفِ کاملاً صفر بسازد. این درس بانک کوچکی را با دادهٔ مصنوعی می‌سازد تا همین خطا، تفاوت توان و دامنه و قرارداد مقیاس روشن شوند؛ نه برای آموزش یا ارزیابی یک مدل گفتار.

۱. شبکهٔ فرکانس و قرارداد توان

خانه‌های منظم با مرزهای روشن برای وزن‌دهی
تصویر مفهومی: خانه‌های منظم با مرزهای روشن برای وزن‌دهی؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

ورودی برنامه طیفِ ازپیش‌ساخته‌شده است، نه فایل صوتی. هر ستون یک قاب و هر ردیف یک خانهٔ فرکانسیِ بخش یک‌طرفه است. طول تبدیل را زوج می‌گیریم؛ تعداد ردیف‌ها نصف طول به‌علاوهٔ یک است. با فاصلهٔ زمانیِ معکوس نرخ نمونه‌برداری، قرارداد rfftfreq در NumPy خانه‌ها را از صفر تا نایکوئیستِ مثبت برحسب هرتز مشخص می‌کند.

برای شاهد دستی، نرخ ۵۶۰۰ نمونه در ثانیه و طول هشت را انتخاب می‌کنیم؛ پس فاصلهٔ خانه‌ها ۷۰۰ هرتز و مراکز به‌ترتیب صفر، ۷۰۰، ۱۴۰۰، ۲۱۰۰ و ۲۸۰۰ هرتزند. این نرخ فقط شبکهٔ محاسبه را تعریف می‌کند؛ دادهٔ این درس از میکروفون نیامده و هیچ ویژگیِ استاندارد شبکهٔ تلفن از آن نتیجه نمی‌گیریم.

مقادیر ورودی، مربعِ دامنه‌های مصنوعیِ بی‌واحدند. آن‌ها را برای اختصار توان می‌نامیم، اما چگالی طیفیِ توان، وات یا فشار صوتِ کالیبره‌شده نیستند. ضریبِ طول تبدیل، بهرهٔ پنجره و دوبرابرکردن سهم فرکانس‌های داخلی در این داده تعریف نشده‌اند. بنابراین جمع وزن‌دار نیز یک ویژگیِ بی‌واحد است؛ نباید برچسبِ انرژی فیزیکی یا توان واقعی تماس بگیرد.

درس بازسازی قاب‌های هم‌پوشان با STFT دربارهٔ تبدیل، فاز، مرز و وزن بازسازی بود. اینجا تبدیل جلو یا معکوس اجرا نمی‌کنیم و فاز ورودی نداریم. مسئلهٔ تازه، نگاشتِ خانه‌های فرکانسی به چند جمع وزن‌دار است؛ آزمونِ خوبِ بازسازی در درس قبلی، درستیِ این نگاشت را به‌تنهایی تضمین نمی‌کند.

۲. مقیاس HTK و مثلث‌های روی محور هرتز

فاصلهٔ انتخاب گره‌ها با شکل مثلث‌ها یکسان نیست
تصویر مفهومی: فاصلهٔ انتخاب گره‌ها با شکل مثلث‌ها یکسان نیست؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

در این قرارداد فقط گونهٔ HTK را برمی‌گزینیم: m(f)=2595*log10(1+f/700)، با فرکانس برحسب هرتز. عدد ۷۰۰ نیز مقیاسِ هرتزی دارد؛ قراردادنِ مقدارِ کیلوهرتزی بدون تبدیل واحد، همان نگاشت نیست. برای معکوس، رابطهٔ f=700*(10**(m/2595)-1) به کار می‌رود.

به تعداد باندها به‌علاوهٔ دو، گرهٔ هم‌فاصله روی محور مل می‌چینیم و آن‌ها را به هرتز برمی‌گردانیم. سپس برای هر سه گرهٔ متوالی، وزن روی محور هرتز از صفر به یک و دوباره به صفر می‌رسد. در نتیجه، هم‌فاصله بودنِ گره‌ها روی مل به معنیِ فاصلهٔ یکسانِ هرتزی یا خطی بودنِ شیب‌ها روی مل نیست. پیاده‌سازی برای کاهش حذف عددی نزدیک صفر، شکلِ هم‌ارزِ مبتنی بر log1p/expm1 را حساب می‌کند.

مستندات نسخهٔ ۰٫۱۱٫۰ librosa دربارهٔ فرکانس‌های mel وجود گونه‌های متفاوت را روشن می‌کند؛ پیش‌فرضِ آن کتابخانه اسلِینی است. بنابراین نامِ مل به‌تنهایی برای بازتولید کافی نیست. این درس آن کتابخانه را اجرا نکرده است و برابریِ بیتی با خروجی یا همهٔ حالت‌های رابط آن ادعا نمی‌کند.

مثلثِ پیوسته قلهٔ یک دارد؛ وزن‌های نمونه‌برداری‌شده الزاماً به آن قله نمی‌رسند. هیچ ردیفی را دوباره بر بیشینه یا جمع خودش تقسیم نمی‌کنیم. قرارداد بانک فیلتر librosa نرمال‌سازیِ مساحت را از حالتِ مثلث با قلهٔ یک جدا می‌کند؛ اینجا حالت دوم را صریح انتخاب کرده‌ایم و ضریبِ معکوسِ پهنای باند نداریم.

۳. کد بانک و جمع وزن‌دار توان

توان در ظرف‌های جدا با وزن‌های مشخص جمع می‌شود
تصویر مفهومی: توان در ظرف‌های جدا با وزن‌های مشخص جمع می‌شود؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

فایل mel_filterbank.py با پایتون ۳٫۱۴٫۵ و نام‌پای ۲٫۴٫۶ واقعاً اجرا شده است. نرخ، عدد صحیح واقعیِ ۲۰۰۰ تا ۴۸۰۰۰؛ طول، عدد زوجِ چهار تا ۱۲۸؛ و تعداد باندها یک تا ۲۴ است. مقدار بولی به‌جای عدد پذیرفته نمی‌شود. کمینه و بیشینهٔ فرکانس باید متناهی، نامنفی، مرتب و حداکثر برابر نایکوئیست باشند؛ گره‌های هم‌افتاده در دقت شناور نیز رد می‌شوند.

"""Original bounded HTK-mel power aggregation; no librosa or speech model."""
from dataclasses import dataclass
import json
import math
import platform

import numpy as np


@dataclass(frozen=True)
class Bank:
    frequencies_hz: np.ndarray
    edges_hz: np.ndarray
    weights: np.ndarray
    empty_bands: tuple[int, ...]


def _integer(value, lo, hi, name):
    if type(value) is not int or not lo <= value <= hi:
        raise ValueError(name)


def make_bank(sr, n_fft, n_mels, fmin=0.0, fmax=None):
    """Even FFT only; triangles linear in Hz and NOT area normalized."""
    _integer(sr, 2000, 48000, "sr in Hz")
    _integer(n_fft, 4, 128, "n_fft")
    _integer(n_mels, 1, 24, "n_mels")
    if n_fft % 2:
        raise ValueError("even n_fft required")
    if fmax is None:
        fmax = sr / 2.0
    for value in (fmin, fmax):
        if type(value) not in (int, float) or not 0 <= value <= sr / 2:
            raise ValueError("frequency bounds in Hz")
    if not fmin < fmax:
        raise ValueError("fmin < fmax required")
    # log1p/expm1 evaluate the stated HTK formula without small-f cancellation.
    c = 2595.0 / math.log(10.0)
    mel_edges = np.linspace(c * math.log1p(fmin / 700.0),
                            c * math.log1p(fmax / 700.0), n_mels + 2)
    edges = 700.0 * np.expm1(mel_edges / c)
    edges[0], edges[-1] = float(fmin), float(fmax)
    if not np.all(np.diff(edges) > 0):
        raise ValueError("edges collapse at floating-point precision")
    frequencies = np.fft.rfftfreq(n_fft, d=1.0 / sr)
    left = (frequencies[None, :] - edges[:-2, None]) / np.diff(edges)[:-1, None]
    right = (edges[2:, None] - frequencies[None, :]) / np.diff(edges)[1:, None]
    weights = np.maximum(0.0, np.minimum(left, right))
    empty = tuple(int(i) for i in np.flatnonzero(~np.any(weights > 0, axis=1)))
    # These are fresh arrays. Frozen dataclass is NOT deep array immutability.
    return Bank(frequencies, edges, weights, empty)


def project_power(power, sr, n_fft, n_mels, fmin=0.0, fmax=None):
    """Input shape (FFT bins, frames); synthetic squared amplitude, not PSD."""
    bank = make_bank(sr, n_fft, n_mels, fmin, fmax)
    if (type(power) is not np.ndarray or power.dtype != np.dtype("float64")
            or power.ndim != 2 or power.shape[0] != n_fft // 2 + 1
            or not 1 <= power.shape[1] <= 8):
        raise ValueError("float64 power shape (bins, 1..8 frames)")
    if not np.all(np.isfinite(power)) or not np.all((power >= 0) & (power <= 1e6)):
        raise ValueError("finite power in [0, 1e6]")
    if bank.empty_bands:
        raise ValueError(f"empty discrete bands: {bank.empty_bands}")
    return bank.weights @ power


def scalar_reference(sr, n_fft, n_mels, low=0.0, high=None):
    """Independent geometric interpolation of 1+f/700; scalar piecewise loops."""
    if high is None:
        high = sr / 2.0
    edges = [700.0 * ((1 + low / 700.0) ** (1 - j / (n_mels + 1))
                     * (1 + high / 700.0) ** (j / (n_mels + 1)) - 1)
             for j in range(n_mels + 2)]
    edges[0], edges[-1] = low, high
    rows = []
    for a, b, c in zip(edges, edges[1:], edges[2:]):
        row = []
        for k in range(n_fft // 2 + 1):
            f = k * sr / n_fft
            if f <= a or f >= c:
                w = 0.0
            elif f <= b:
                w = (f - a) / (b - a)
            else:
                w = (c - f) / (c - b)
            row.append(w)
        rows.append(row)
    return np.array(rows, dtype=np.float64)


def rejects(call):
    try:
        call()
    except ValueError:
        return True
    return False


def main():
    checks = {}
    bank = make_bank(5600, 8, 1, 0, 2100)
    expected = np.array([[0, 1, .5, 0, 0]], dtype=np.float64)
    checks["literal_frequency_grid_and_triangle"] = bool(
        np.array_equal(bank.frequencies_hz, [0, 700, 1400, 2100, 2800])
        and np.allclose(bank.edges_hz, [0, 700, 2100], atol=1e-12, rtol=0)
        and np.allclose(bank.weights, expected, atol=1e-12, rtol=0))
    power = np.array([[9], [4], [16], [25], [36]], dtype=np.float64)
    score = project_power(power, 5600, 8, 1, 0, 2100)
    checks["literal_weighted_power_is_twelve"] = bool(
        np.allclose(score, [[12]], atol=1e-12, rtol=0))
    amplitude_score = project_power(np.sqrt(power), 5600, 8, 1, 0, 2100)
    checks["magnitude_is_not_power"] = bool(
        np.allclose(amplitude_score, [[4]], atol=1e-12, rtol=0)
        and not np.allclose(score, amplitude_score))
    checks["amplitude_scale_two_means_power_scale_four"] = bool(
        np.allclose(project_power(4 * power, 5600, 8, 1, 0, 2100), 4 * score,
                    atol=1e-12, rtol=0))
    count, worst = 0, 0.0
    for sr in (5600, 8000, 16000):
        for n_fft in (4, 8, 16, 32, 64, 128):
            for bands in (1, 2, 3, 6, 12, 24):
                for lo, hi in ((0, sr / 2), (700, 2100)):
                    actual = make_bank(sr, n_fft, bands, lo, hi)
                    reference = scalar_reference(sr, n_fft, bands, lo, hi)
                    error = float(np.max(np.abs(actual.weights - reference)))
                    worst = max(worst, error)
                    assert np.allclose(actual.weights, reference, atol=1e-11, rtol=0)
                    assert actual.empty_bands == tuple(
                        i for i, row in enumerate(reference) if not np.any(row > 0))
                    count += 1
    checks["scalar_geometric_piecewise_oracle_216_banks"] = count == 216
    coarse = make_bank(8000, 8, 12)
    checks["coarse_grid_empty_bands_are_explicit"] = bool(
        coarse.empty_bands and all(not np.any(coarse.weights[i]) for i in coarse.empty_bands)
        and rejects(lambda: project_power(np.ones((5, 1)), 8000, 8, 12)))
    fine = make_bank(8000, 128, 12)
    checks["finer_grid_has_support_for_this_fixture"] = fine.empty_bands == ()
    checks["dc_nyquist_endpoint_weights_are_zero"] = bool(
        np.all(fine.weights[:, 0] == 0) and np.all(fine.weights[:, -1] == 0))
    checks["continuous_peak_does_not_force_sampled_peak_one"] = bool(
        np.all(fine.weights >= 0) and np.all(fine.weights <= 1)
        and np.any(np.max(fine.weights, axis=1) < .99))
    p = np.arange(17 * 3, dtype=np.float64).reshape(17, 3)
    b = make_bank(8000, 32, 3)
    out = project_power(p, 8000, 32, 3)
    direct = np.array([[math.fsum(float(b.weights[i, k]) * float(p[k, t])
                                for k in range(17)) for t in range(3)] for i in range(3)])
    checks["multiple_frames_independent_scalar_weighted_sums"] = bool(
        out.shape == (3, 3) and np.allclose(out, direct, atol=1e-11, rtol=0))
    zero = project_power(np.zeros((17, 2)), 8000, 32, 3)
    checks["zero_spectrum_and_positive_linearity"] = bool(
        np.array_equal(zero, np.zeros((3, 2)))
        and np.allclose(project_power(2 * p + 3, 8000, 32, 3),
                        2 * out + project_power(np.full_like(p, 3), 8000, 32, 3),
                        atol=1e-11, rtol=0))
    before = p.copy()
    out[0, 0] = -99
    mutable_bank = make_bank(5600, 8, 1, 0, 2100)
    mutable_bank.weights[0, 1] = 99
    checks["no_input_alias_and_no_stale_bank_shared_arrays"] = bool(
        np.array_equal(p, before)
        and np.allclose(make_bank(5600, 8, 1, 0, 2100).weights, expected,
                        atol=1e-12, rtol=0))
    checks["integer_configuration_types_and_bounds"] = all([
        rejects(lambda v=v: make_bank(v, 8, 1)) for v in (True, 8000.0, 1999, 48001, 10**400)
    ] + [rejects(lambda v=v: make_bank(8000, v, 1)) for v in (True, 3, 5, 130)]
      + [rejects(lambda v=v: make_bank(8000, 8, v)) for v in (False, 0, 25, 1.0)])
    checks["frequency_bounds_and_numerically_collapsed_edges"] = all([
        rejects(lambda lo=lo, hi=hi: make_bank(8000, 8, 2, lo, hi))
        for lo, hi in ((-1, 4000), (0, 4001), (1000, 1000), (True, 3000),
                       (0, float("nan")), (float("inf"), 4000), (0, 10**400),
                       (0, 5e-324))])
    invalid = [p.tolist(), p.astype(np.float32), p.astype(np.int64), p.astype(complex),
               np.ones(17), np.ones((3, 17)), np.ones((17, 0)), np.ones((17, 9)),
               np.full((17, 1), -1.0), np.full((17, 1), float("nan")),
               np.full((17, 1), float("inf")), np.full((17, 1), 1e6 + 1)]
    checks["power_exact_array_dtype_shape_range_finite"] = all(
        rejects(lambda x=x: project_power(x, 8000, 32, 3)) for x in invalid)
    cap = project_power(np.full((65, 8), 1e6), 48000, 128, 1)
    checks["inclusive_caps_produce_finite_bounded_output"] = bool(
        cap.shape == (1, 8) and np.all(np.isfinite(cap)) and np.all(cap <= 65e6))
    assert all(type(v) is bool and v for v in checks.values()), checks
    result = {
        "python": platform.python_version(), "numpy": np.__version__,
        "librosa_executed": False, "scipy_executed": False,
        "checks": checks, "checks_passed": len(checks),
        "literal": {"sr_hz": 5600, "n_fft": 8, "fmax_hz": 2100,
                    "frequencies_hz": bank.frequencies_hz.tolist(),
                    "edges_hz": bank.edges_hz.tolist(), "weights": bank.weights.tolist(),
                    "power": power[:, 0].tolist(), "weighted_power": float(score[0, 0]),
                    "weighted_magnitude": float(amplitude_score[0, 0])},
        "coarse_empty_bands_zero_based": list(coarse.empty_bands),
        "fine_empty_bands_zero_based": list(fine.empty_bands),
        "scalar_oracle_banks_one_group": count, "scalar_oracle_max_abs_error": worst,
        "limits": "Synthetic squared amplitude; no PSD calibration, FFT/audio/model run, area normalization, MFCC, accuracy or performance guarantee."
    }
    print(json.dumps(result, ensure_ascii=False, indent=2, allow_nan=False))


if __name__ == "__main__":
    main()

آرایهٔ توان باید واقعاً ndarray با نوع float64 و شکلِ خانه‌های فرکانس در یک تا هشت قاب باشد. مقادیر منفی، نامتناهی یا بزرگ‌تر از یک‌میلیون پذیرفته نمی‌شوند. این کران‌ها محدودهٔ تمرین‌اند، نه مشخصاتِ عمومی صوت. بعد از اعتبارسنجی، ضرب ماتریسیِ وزن‌ها در توان، خروجیِ باندها در قاب‌ها را می‌دهد و ورودی را تغییر نمی‌دهد.

طبق توضیح melspectrogram دربارهٔ ورودی آماده، باید معلوم باشد طیف از قبل توان شده یا هنوز دامنه است. تابعِ ما هیچ‌چیز را خودکار مربع نمی‌کند. دوبرابر کردنِ دامنه یعنی چهاربرابر شدنِ ورودیِ توان و خروجیِ وزن‌دار؛ دوبرابر کردنِ خودِ آرایهٔ توان فقط خروجی را دوبرابر می‌کند. این دو آزمایش یکسان نیستند.

۴. شاهد دستی و فیلترِ بدون پشتیبانی

مثلث باریک ممکن است میان خانه‌های شبکه بماند
تصویر مفهومی: مثلث باریک ممکن است میان خانه‌های شبکه بماند؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

یک باند با حد پایین صفر و حد بالای ۲۱۰۰ هرتز، گره‌های صفر، ۷۰۰ و ۲۱۰۰ هرتز می‌سازد؛ زیرا عبارتِ داخل لگاریتم در این سه نقطه یک، دو و چهار است. روی شبکهٔ پنج‌خانه‌ایِ بخش اول، وزن‌ها صفر، یک، نیم، صفر و صفر می‌شوند. برای توان‌های ۹، چهار، شانزده، ۲۵ و ۳۶، پاسخ دستی برابر دوازده است: چهار به‌علاوهٔ نصفِ شانزده.

اگر به‌اشتباه دامنه‌های متناظر، یعنی سه، دو، چهار، پنج و شش را جمعِ وزن‌دار کنیم، پاسخ چهار می‌شود. همچنین هم‌پوشانیِ مثلث‌ها مجوز نامیدنِ خروجی به‌عنوان مجموعِ تمام توان نیست؛ لبه‌ها و قراردادِ وزن مهم‌اند. در حالتِ حد پایینِ صفر و حد بالای نایکوئیست، وزنِ خودِ دو خانهٔ انتهایی صفر است؛ آن‌ها قلهٔ هیچ باندی نیستند.

برای مرجع مستقل، به‌جای ساختِ گره با تبدیلِ جلو و معکوس، کمیتِ 1+f/700 را هندسی درون‌یابی می‌کنیم و وزن هر خانه را با شرط‌های تکه‌ای می‌سنجیم. ۲۱۶ بانک با اندازه‌ها و حدود متفاوت، در یک گروه بررسی شدند؛ بیشترین اختلاف حدود 1.01e-14 بود. تلورانس مطلقِ 1e-11 برای همین نمونه‌های محدود انتخاب شده و کرانِ عمومی خطا نیست.

در نرخ ۸۰۰۰ و طول هشت با دوازده باند، اندیس‌های صفر، یک، دو، سه، چهار و هفت کاملاً خالی‌اند. ساختِ بانک این فهرست را گزارش می‌کند، ولی تابعِ محاسبهٔ ویژگی آن را رد می‌کند. با طول ۱۲۸، همین نمونه باند خالی ندارد؛ این شاهد تضمین نمی‌کند که افزایش طول برای هر قرارداد کافی باشد. صفرِ ناشی از نبودِ پشتیبانی نباید با مشاهدهٔ سکوت یکی گرفته شود.

{
  "python": "3.14.5",
  "numpy": "2.4.6",
  "librosa_executed": false,
  "scipy_executed": false,
  "checks": {
    "literal_frequency_grid_and_triangle": true,
    "literal_weighted_power_is_twelve": true,
    "magnitude_is_not_power": true,
    "amplitude_scale_two_means_power_scale_four": true,
    "scalar_geometric_piecewise_oracle_216_banks": true,
    "coarse_grid_empty_bands_are_explicit": true,
    "finer_grid_has_support_for_this_fixture": true,
    "dc_nyquist_endpoint_weights_are_zero": true,
    "continuous_peak_does_not_force_sampled_peak_one": true,
    "multiple_frames_independent_scalar_weighted_sums": true,
    "zero_spectrum_and_positive_linearity": true,
    "no_input_alias_and_no_stale_bank_shared_arrays": true,
    "integer_configuration_types_and_bounds": true,
    "frequency_bounds_and_numerically_collapsed_edges": true,
    "power_exact_array_dtype_shape_range_finite": true,
    "inclusive_caps_produce_finite_bounded_output": true
  },
  "checks_passed": 16,
  "literal": {
    "sr_hz": 5600,
    "n_fft": 8,
    "fmax_hz": 2100,
    "frequencies_hz": [
      0.0,
      700.0,
      1400.0,
      2100.0,
      2800.0
    ],
    "edges_hz": [
      0.0,
      700.0,
      2100.0
    ],
    "weights": [
      [
        0.0,
        1.0,
        0.5,
        0.0,
        0.0
      ]
    ],
    "power": [
      9.0,
      4.0,
      16.0,
      25.0,
      36.0
    ],
    "weighted_power": 12.0,
    "weighted_magnitude": 4.0
  },
  "coarse_empty_bands_zero_based": [
    0,
    1,
    2,
    3,
    4,
    7
  ],
  "fine_empty_bands_zero_based": [],
  "scalar_oracle_banks_one_group": 216,
  "scalar_oracle_max_abs_error": 1.0061396160665481e-14,
  "limits": "Synthetic squared amplitude; no PSD calibration, FFT/audio/model run, area normalization, MFCC, accuracy or performance guarantee."
}

۵. چهار پرسش و مرز تفسیر ویژگی‌ها

خروجی بانک ویژگی از ارزیابی سامانه جدا می‌ماند
تصویر مفهومی: خروجی بانک ویژگی از ارزیابی سامانه جدا می‌ماند؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

پرسش اول: چرا پاسخ دستی دوازده است و نه چهار؟ پاسخ: ورودیِ اعلام‌شده مربعِ دامنه است؛ باند فقط چهار و نیمِ شانزده را می‌گیرد. چهار پاسخِ جمعِ وزن‌دارِ دامنه‌هاست و نمایندهٔ قرارداد دیگری است.

پرسش دوم: چرا ردیفِ سالم همیشه وزنِ یک ندارد؟ پاسخ: مرکز مثلث ممکن است میان دو خانه بیفتد؛ نمونه‌برداری از قله عبور نمی‌کند. تقسیمِ خودسرانه بر بیشینه، قراردادِ تازه‌ای می‌سازد و مقایسهٔ ویژگی‌ها را تغییر می‌دهد.

پرسش سوم: با باند خالی، صفر را خروجی معتبر بگیریم؟ پاسخ: در سیاستِ این تمرین خیر؛ ابتدا شبکه یا تعداد باندها را بازبینی می‌کنیم. برنامه همهٔ ردیف‌ها، حتی ردیفِ شروع‌شده از صفر، را می‌سنجد. این سیاستِ پذیرشِ ماست و رفتار هشدارِ کتابخانه‌ای دیگر معرفی نمی‌شود.

پرسش چهارم: این خروجی همان ضرایبِ کپستروم یا کیفیت تشخیص گفتار است؟ پاسخ: خیر؛ لگاریتم، تبدیل کسینوسی، مدلِ آموزش‌دیده یا دادهٔ گفتاری نداریم. درسِ مقیاس و بازسازیِ DCT نیز به‌تنهایی این بانک را به زنجیرهٔ کاملِ ویژگی تبدیل نمی‌کند. برای کاربرد واقعی باید کل زنجیره و وظیفهٔ نهایی جدا ارزیابی شوند.

شانزده گروهِ معنادار اجرا شده‌اند؛ تعدادِ بانک‌های مرجع یا تکرار اجرای داور، گروهِ تازه محسوب نمی‌شود. منابع در ۲۶ مهر ۱۴۰۵ خوانده شدند؛ نسخهٔ صفحه‌ها با نسخهٔ اجرای واقعی جدا ثبت شده و تاریخِ انتشارِ اولیهٔ نامعلوم حدس زده نشده است. این آموزشِ پایهٔ تألیفی، ادعای خبر تازه، اجرای لیبروزا یا متلب، بازسازی صوت، کیفیت شنیداری یا سرعت دستگاه ندارد.

منابع و مطالعهٔ بیشتر

بررسی منابع: ۲۶ مهر ۱۴۰۵. تحلیل‌ها و پیشنهادهای اجرایی، جمع‌بندی نویسنده‌اند.