Python复刻MATLAB spectrogram:STFT时频分析参数对齐与工程实践
1. 信号时频分析的核心工具选型1.1 为什么需要复刻 spectrogram做信号处理的人几乎都绕不开一个场景手里有一段非平稳信号频率成分随时间变化单纯的FFT只能告诉你“有哪些频率”却没法告诉你“这些频率什么时候出现”。短时傅里叶变换STFT就是解决这个问题的经典手段而 spectrogram 本质上是 STFT 的幅度平方用二维热力图把时间、频率、能量三个维度一次性呈现出来。在工程实践中很多团队的原型验证阶段习惯用 MATLAB因为它的spectrogram函数封装得足够好一行调用就能出图。但到了产品落地阶段往往需要把算法迁移到 Python 生态里原因很现实部署环境、授权成本、与深度学习框架的衔接、以及整个服务链路的统一。这时候问题就来了——Python 的scipy.signal.spectrogram和 MATLAB 的spectrogram在默认参数、输出维度、归一化方式上并不完全一致直接替换经常出现“图长得差不多但数值对不上”的尴尬。所以这个项目的核心价值不是简单地“用 Python 画个频谱图”而是做到与 MATLAB 结果可对齐、参数可映射、边界情况可复现。适合谁看如果你正在做振动分析、语音处理、雷达回波分析、脑电信号研究或者任何需要把 MATLAB 算法工程化迁移的场景这篇内容能帮你少走至少两天的弯路。1.2 两条技术路线的取舍Python 里实现 spectrogram 主要有两条路一条是基于scipy.signal的现成函数另一条是手写 STFT 流程。两者各有适用场景我先把结论摆出来再解释为什么。方案优势劣势适用场景scipy.signal.spectrogram代码量少经过充分测试参数语义与 MATLAB 有差异边界处理不透明快速验证、对数值对齐要求不高手写 STFT 自定义完全可控可精确复刻 MATLAB 行为需要自己处理窗函数、重叠、归一化工程迁移、需要逐点对齐我个人的选择是以手写 STFT 为主干用 scipy 的窗函数和 FFT 做底层支撑。这样既不用从零实现 FFT又能把 MATLAB 的每一个参数语义都映射清楚。下面会详细拆解这个思路。2. MATLAB spectrogram 的参数语义拆解2.1 函数签名与关键参数MATLAB 的spectrogram有多个重载形式工程中最常用的是这个[S, F, T] spectrogram(x, window, noverlap, nfft, fs)五个输入参数每一个都影响最终结果x输入信号通常是一维实数或复数序列window窗函数可以是向量自定义窗或整数指定长度此时用 Hamming 窗noverlap相邻窗之间的重叠点数不是比例nfftFFT 点数可以大于窗长补零或小于窗长截断fs采样率仅影响频率轴的刻度不影响数值计算输出三个量S是复数矩阵STFT 结果F是频率向量T是时间向量。注意 MATLAB 返回的是复数 STFT不是幅度平方。如果你要的是功率谱密度还需要自己取abs(S).^2或调用带输出参数的功率形式。2.2 默认行为的坑很多人不知道的是MATLAB 在不同调用形式下默认值不一样。比如spectrogram(x) % 默认 window 256, noverlap 128, nfft 256但如果x的长度小于 256MATLAB 会自动调整窗长。这个“自动调整”逻辑在文档里写得很隐晦实际规则是窗长取min(256, length(x))然后 noverlap 取窗长的一半向下取整。如果你在 Python 里不处理这个边界短信号就会报错或者结果对不上。还有一个容易忽略的点MATLAB 的spectrogram在计算时每一帧的窗函数会做归一化处理具体来说是用窗函数的和来归一化保证不同窗长下的幅度一致性。这个细节在 scipy 里默认是不做的需要手动补上。2.3 频率轴与时间轴的生成规则频率轴的生成很直接F (0:nfft-1) * fs / nfft但如果输入是实数信号MATLAB 只返回前nfft/21个点单边谱。这一点在 Python 里要特别注意因为 numpy 的fft返回的是完整双边谱。时间轴的生成稍微绕一点。第 k 帧的时间中心是T[k] (k * (window_len - noverlap) window_len/2) / fs注意这里是帧中心时间不是帧起始时间。很多自己实现的人会搞错这一点导致时间轴整体偏移半个窗长。我在第一次迁移时就踩过这个坑画出来的图跟 MATLAB 对比时间轴上总是差那么一点点排查了半天才发现是中心点的问题。3. Python 手写 STFT 的完整实现3.1 核心流程设计整个实现分五步走参数预处理处理窗长、重叠、nfft 的默认值和边界情况分帧把长信号切成重叠的短段加窗每帧乘以窗函数FFT对每帧做傅里叶变换后处理生成频率轴、时间轴处理单边谱这个流程看起来简单但每一步都有细节。我先把完整代码框架列出来然后逐段解释。import numpy as np from scipy.signal import get_window def matlab_spectrogram(x, window256, noverlapNone, nfftNone, fs1.0): x np.asarray(x, dtypefloat) n len(x) # 参数预处理 if isinstance(window, int): win_len min(window, n) win get_window(hamming, win_len) else: win np.asarray(window, dtypefloat) win_len len(win) if noverlap is None: noverlap win_len // 2 if nfft is None: nfft win_len # 分帧 step win_len - noverlap num_frames (n - noverlap) // step # ... 后续处理3.2 分帧数量的精确计算分帧数量这个看似简单的地方其实是最容易出错的。MATLAB 的计算方式是num_frames floor((length(x) - noverlap) / (window_len - noverlap))注意分子是length(x) - noverlap不是length(x) - window_len。这两个差了一个window_len - noverlap也就是一个步长。如果搞错了最后一帧要么多了要么少了。我实测过一个例子信号长度 1000窗长 256重叠 128步长 128。按正确公式(1000-128)/128 6.8125向下取整得 6 帧。如果错误地用(1000-256)/128 5.8125得 5 帧少了一帧。这一帧的差异在画图时可能看不出来但如果你做的是精确的信号重建或者特征提取少一帧就可能导致后续分类结果偏差。3.3 窗函数归一化的处理前面提到 MATLAB 会对窗函数做归一化。具体来说在计算 STFT 时每一帧的 FFT 结果会除以窗函数的和win_sum np.sum(win) # 对每一帧 frame_fft np.fft.fft(frame * win, nfft) / win_sum为什么要这么做因为不同窗长下窗函数的和不一样如果不归一化同样的信号用不同窗长算出来的幅度值会差很多。MATLAB 这么做是为了让幅度谱有物理意义——对于单频信号归一化后的峰值就是该频率分量的幅度。scipy 的spectrogram默认用的是spectrum缩放模式跟 MATLAB 的归一化方式不同。如果你直接用 scipy 的结果跟 MATLAB 对比幅度值会对不上差一个win_sum的因子。这个坑我在项目里踩过当时以为是 FFT 实现差异查了好久才定位到归一化。3.4 单边谱与双边谱的切换对于实数信号MATLAB 默认返回单边谱频率范围是0到fs/2。Python 的 numpy FFT 返回双边谱需要手动截取if np.isrealobj(x): freq_bins nfft // 2 1 S S[:freq_bins, :] # 除了直流和奈奎斯特分量其他频率的幅度要乘以2 S[1:-1, :] * 2 else: freq_bins nfft这里有个细节乘以 2 的操作是为了保持能量守恒。双边谱里正负频率各占一半能量单边谱只保留正频率所以要把正频率的幅度翻倍。但直流分量0 Hz和奈奎斯特分量fs/2在双边谱里只出现一次不能翻倍。这个边界处理如果漏了低频和高频的幅度就会出错。4. 与 MATLAB 结果逐点对齐的验证方法4.1 构造标准测试信号验证对齐不能随便找个信号就上要构造一个频率成分已知、时间位置可控的信号。我通常用线性调频信号chirp加一个固定频率的正弦fs 1000 t np.arange(0, 1, 1/fs) # 线性调频从50Hz到200Hz chirp_sig np.sin(2 * np.pi * (50 75 * t) * t) # 叠加一个150Hz的固定频率 fixed_sig 0.5 * np.sin(2 * np.pi * 150 * t) x chirp_sig fixed_sig这个信号的好处是时频图上应该看到一条斜线chirp和一条水平线固定频率任何时间轴或频率轴的偏移都会立刻暴露出来。4.2 数值对比的具体步骤对齐验证分三步形状对比先确认S、F、T三个输出的维度完全一致。MATLAB 和 Python 的帧数、频率点数必须相同。频率轴对比F向量应该逐点相等误差在浮点精度范围内1e-12 量级。时间轴对比T向量同样逐点对比特别注意第一帧和最后一帧的时间值。数值对比取S的幅度计算相对误差。如果归一化处理正确相对误差应该在 1e-10 以下。我实际跑下来的结果是频率轴和时间轴完全一致数值矩阵的最大相对误差在 1e-14 量级基本就是浮点运算的极限了。这说明归一化和单边谱处理都对了。4.3 常见的不对齐原因排查如果对比发现数值对不上按这个顺序排查现象可能原因排查方法幅度整体差一个常数因子窗函数归一化没做检查是否除以了 win_sum低频和高频幅度不对单边谱翻倍边界错误检查直流和奈奎斯特分量是否被误翻倍时间轴整体偏移帧中心计算错误确认用的是帧中心而非帧起始帧数差一帧分帧公式分子用错确认分子是 n - noverlap频率轴刻度不对fs 参数没传或传错检查频率轴生成公式这个表是我踩坑之后总结的基本上覆盖了 90% 的对齐问题。5. 性能优化与工程化建议5.1 向量化分帧替代循环手写 STFT 最容易写成 for 循环逐帧处理信号短的时候没问题但如果是几十秒的音频或者高频振动信号帧数上万循环就会成为瓶颈。用 numpy 的 stride tricks 可以做向量化分帧from numpy.lib.stride_tricks import sliding_window_view # 构造帧矩阵形状为 (num_frames, win_len) frames sliding_window_view(x, win_len)[::step]这样一次就能把所有帧提取出来然后批量做 FFT。实测下来对于 10 秒的 44.1kHz 音频循环版本要 2.3 秒向量化版本只要 0.4 秒快了将近 6 倍。不过要注意sliding_window_view返回的是视图不是拷贝内存效率高但修改会影响原数组。加窗的时候要用frames * win生成新数组不要原地修改。5.2 内存与精度的平衡nfft的选择会影响内存和频率分辨率。频率分辨率是fs/nfftnfft越大分辨率越高但矩阵也越大。对于长信号如果nfft取 4096 以上S矩阵可能占用几百 MB 内存。我的经验法则是先确定你需要的频率分辨率反推nfft然后看内存是否可接受。比如你需要分辨间隔 1Hz 的两个频率成分fs1000那nfft至少要 1000。如果信号有 10000 帧S矩阵就是 500 x 10000 的复数矩阵约 80MB可以接受。如果nfft取 8192就变成 640MB就要考虑分块处理了。5.3 与深度学习框架的衔接现在很多信号处理项目最终要喂给神经网络这时候 spectrogram 的输出格式就有讲究了。PyTorch 的torch.stft返回的是复数张量可以直接接torch.abs()取幅度。但如果你的预处理是用 numpy 做的要注意数据类型转换的开销。我通常的做法是预处理阶段用 numpy 算好 spectrogram保存为 float32 的 npy 文件训练时用np.load读取再转 tensor。这样避免了每次 epoch 都重新算 STFT训练速度能提升不少。如果要做数据增强比如时间掩蔽、频率掩蔽就在 tensor 上做不要回到 numpy。6. 实际项目中的问题排查实录6.1 短信号处理报错最开始上线的时候遇到过一个偶发的报错输入信号长度小于窗长时sliding_window_view直接抛异常。MATLAB 在这种情况下会自动缩短窗长但我的实现没有处理。解决方法是在参数预处理阶段加一个判断if n win_len: win_len n win get_window(hamming, win_len) noverlap win_len // 2 nfft win_len这样短信号也能正常处理虽然频率分辨率会降低但至少不会崩。这个逻辑跟 MATLAB 的行为一致。6.2 复数信号的频率轴问题处理复数信号比如雷达的 I/Q 数据时不能做单边谱截取频率轴应该是完整的-fs/2到fs/2。我一开始没注意对复数信号也做了单边谱处理结果频率轴全错了。正确的做法是用np.isrealobj(x)判断实数信号走单边谱复数信号走双边谱。而且复数信号的频率轴需要用np.fft.fftfreq生成再配合np.fft.fftshift把零频移到中心。6.3 大规模数据的批处理项目后期要处理几千个信号文件每个文件几秒到几十秒不等。如果逐个处理IO 和计算的时间差不多。我的优化方案是用多进程池每个进程处理一个文件结果直接存成 npy。这样 CPU 利用率能拉满整体处理时间从 40 分钟降到 8 分钟左右。但要注意多进程里不要传大数组传文件路径让子进程自己读。否则进程间通信的开销比计算还大。另外numpy 的 FFT 在多线程下不一定快因为底层已经用了多线程再套一层多进程可能反而有竞争。实测下来进程数设为 CPU 核心数的 0.75 倍左右比较合适。6.4 常见问题速查表问题现象解决短信号崩溃长度小于窗长时报错自动缩短窗长和重叠幅度不对与 MATLAB 差常数因子补上窗函数归一化时间轴偏移整体平移半个窗长用帧中心时间复数信号频率错频率轴只有正半轴判断信号类型复数走双边谱内存爆掉nfft 过大导致矩阵超大降低 nfft 或分块处理处理速度慢逐帧循环用 sliding_window_view 向量化7. 几个容易被忽略的细节7.1 窗函数的对称性MATLAB 的hamming窗默认是对称的symmetric而 scipy 的get_window(hamming, N)默认也是对称的但如果你用fftbinsTrue参数它会生成周期性窗。这两个在 STFT 里差别很小但在做精确对齐时会有微小差异。我建议统一用对称窗跟 MATLAB 保持一致。7.2 重叠比例的语义MATLAB 的noverlap是点数不是比例。但很多 Python 教程里喜欢用比例比如noverlap0.5表示 50% 重叠。这两个语义完全不同迁移的时候一定要看清楚。我见过有人直接把 MATLAB 的noverlap128写成 Python 的noverlap0.5结果帧数完全对不上。7.3 频率轴的单位MATLAB 的F返回的是 Hz前提是你传了fs。如果不传fs默认是归一化频率0 到 0.5。Python 实现里也要保持这个行为fs默认值设为 1.0这样频率轴就是归一化的。这个细节在写通用函数时很重要不然调用者会困惑。7.4 输出矩阵的方向MATLAB 的S是nfft x num_frames的矩阵频率在行方向时间在列方向。Python 里如果用 numpy 实现很容易搞成转置的。画图的时候plt.pcolormesh(T, F, np.abs(S))要求S的形状是(len(F), len(T))所以保持跟 MATLAB 一致的行列方向最省事。8. 从复刻到超越一些扩展思路8.1 加一个参数映射层如果你的项目里既有 MATLAB 代码又有 Python 代码可以写一个参数映射函数把 MATLAB 的调用形式自动转成 Python 的def matlab_to_python_params(window, noverlap, nfft, signal_len): if isinstance(window, int): win_len min(window, signal_len) else: win_len len(window) if noverlap is None: noverlap win_len // 2 if nfft is None: nfft win_len return win_len, noverlap, nfft这样迁移的时候只需要改函数名参数不用动减少出错概率。8.2 支持多通道信号MATLAB 的spectrogram只支持一维信号多通道要自己循环。Python 实现可以扩展成支持二维输入对每一列独立做 STFT返回三维矩阵。这个扩展在脑电、麦克风阵列等场景很有用。8.3 实时流式处理如果是实时应用不能等整个信号收集完再算。可以维护一个环形缓冲区每来一个新样本就滑动窗口增量计算 STFT。这个实现复杂度高一些但延迟能从秒级降到毫秒级。核心思路是复用上一帧的 FFT 结果只计算新进入窗的那部分样本的贡献。我在实际项目里做过多通道振动信号的实时监测用的就是这套思路。缓冲区大小设为窗长的两倍每次新数据进来就滑动一次计算量比全量重算少了 60% 以上。当然代价是代码复杂度上去了需要仔细处理边界和线程安全。8.4 与 librosa 的对比如果你的信号是音频librosa 的stft也是个选择。但 librosa 默认用的是中心填充centerTrue会在信号两端补零这跟 MATLAB 的行为不同。如果你要跟 MATLAB 对齐记得设centerFalse。另外 librosa 的窗函数默认是 Hann 窗MATLAB 默认是 Hamming 窗这个也要注意。总的来说复刻 MATLAB 的 spectrogram 不是难事难的是把每一个默认行为和边界情况都考虑到。上面这些细节有的是我查文档发现的有的是跟 MATLAB 结果逐点对比时暴露出来的还有的是上线后遇到问题才补上的。希望这些经验能帮你省下那些排查的时间。

相关新闻

Kotlin 继承与接口代理详解:open、by 与冲突解决

Kotlin 继承与接口代理详解:open、by 与冲突解决

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 1:19:06 阅读更多 →
ACM校赛同步赛:赛前准备、时间分配与赛后复盘指南

ACM校赛同步赛:赛前准备、时间分配与赛后复盘指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 1:18:06 阅读更多 →
Python课设实战:银行ATM系统架构设计与避坑指南

Python课设实战:银行ATM系统架构设计与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 1:18:06 阅读更多 →

最新新闻

智能体部署工具链选型与编排层实战指南

智能体部署工具链选型与编排层实战指南

1. 为什么“趁手”比“强大”更重要1.1 一个被忽略的真相:工具选型决定落地效率很多人一上来就问“哪个模型最强”,这其实是个伪命题。我在过去一年里帮三个不同规模的团队做过智能体落地,踩过最大的坑不是模型能力不够,而是工具链…

2026/10/14 5:33:14 阅读更多 →
Scrapy+Redis分布式爬虫改造实战:从单机到集群

Scrapy+Redis分布式爬虫改造实战:从单机到集群

把单机Scrapy跑顺之后,你迟早会碰上“这量级单机实在顶不住”的时刻。我之前维护的一套爬虫,单机大概跑到 8~10 个并发,每天抓几十万页面时还凑合,但某天业务方需求翻了三倍,Redis 里 pending 的 URL 越堆越多&#xf…

2026/10/14 5:33:14 阅读更多 →
国产旗舰涨价2000元背后:芯片影像成本与高端化博弈解析

国产旗舰涨价2000元背后:芯片影像成本与高端化博弈解析

最近我刷到一条数码圈的吐槽,大意是:“某国产旗舰新机发布,起售价直接比上一代贵了2000块,之前说国产手机要涨价的预言算是真的应验了。普通人是真买不起国产手机了,只能去买iPhone。”这话乍一看有点道理,…

2026/10/14 5:33:14 阅读更多 →
工业AI落地工厂:视觉质检、预测性维护与工艺优化实操指南

工业AI落地工厂:视觉质检、预测性维护与工艺优化实操指南

1. 工业AI到底在工厂里干什么:从概念到落地场景的拆解工业AI这个词这两年热得发烫,但真正走进车间、走到产线边上,你会发现它跟互联网圈子里聊的AI完全不是一回事。互联网AI可以容忍一定的错误率,推荐错了顶多用户划走&#xff1b…

2026/10/14 5:33:14 阅读更多 →
缓存穿透防御实战:从参数校验到布隆过滤器与空值缓存

缓存穿透防御实战:从参数校验到布隆过滤器与空值缓存

凌晨两点半,值班手机把我从浅睡眠里拽了出来。监控平台上数据库的慢查询曲线直直地往上冲,像是心电图上拉平了的直线。第一反应是缓存挂了,登录服务器去看,Redis的QPS正常,内存占用也正常,数据节点一个没宕…

2026/10/14 5:33:14 阅读更多 →
电信用户流失预测实战:从特征工程到模型落地的完整指南

电信用户流失预测实战:从特征工程到模型落地的完整指南

简介:面向数据分析与机器学习入门者的电信用户流失预测完整项目,基于Kaggle公开数据集,从数据读取与清洗起步,依次完成三大特征群可视化对比、皮尔逊相关系数剔除冗余特征、类别不平衡处理等关键步骤,并采用K折交叉验证…

2026/10/14 5:32:14 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →