开机、插卡、等信号栏亮起来,终端在后台干的第一件正事就是小区搜索。我做过几年终端侧物理层和协议栈的活,被问得最多的不是调度、不是HARQ重传,而是“为什么这块模块在这个频点上死活驻留不上”。追根溯源,八成卡在小区搜索这一段:PSS没对上、SSS解出歧义、PCI算错、PBCH盲检失败,或者SIB1根本读不下来。小区搜索是LTE接入流程的第一道门,走不过去,后面的一切都免谈。
这篇东西我按实际调试的顺序来写:先讲清楚这一步到底要找什么,再拆PSS/SSS的序列构造和检测方法,然后是PBCH和MIB的盲检,最后落到SIB1读取和小区选择的S准则。中间会插一段用离线IQ数据实跑的例子,以及我在真实项目里踩过的坑。刚入行的读者可以把它当成一张流程地图,做过一轮的读者建议重点看参数细节、盲检组合和排查表。
1. 小区搜索到底在找什么:目标拆解与流程地图
1.1 终端开机后必须拿到的五样东西
小区搜索不是单一动作,而是一串有严格先后依赖的任务。终端在不知道任何先验信息的前提下,要逐一把下面这些“未知量”变成“已知量”:时间同步(10ms无线帧边界、5ms半帧、子帧边界)、频率同步(载波频偏,晶振初始误差加上温漂,几个ppm很常见)、小区物理标识PCI(取值范围0到503)、下行系统带宽、以及最基础的广播信息(MIB和SIB1)。这五样东西的获取顺序不能乱:不知道帧定时就不知道参考信号的位置,不知道PCI就没法生成PBCH的加扰序列,不知道带宽就没法确定PDCCH的控制信道资源,不知道SIB1就不知道这个小区到底能不能驻留。
我习惯把这一串依赖画成一条“解锁链”:频偏校正→PSS(时隙级同步加N_ID(2))→SSS(帧级同步加N_ID(1))→PCI→CRS(信道估计与RSRP测量)→PBCH(MIB)→PDCCH(SIB1调度)→SIB1。链条上任何一环掉链子,后面的全部停摆。这也是为什么排查驻留失败必须从最上游开始,不能一上来就怀疑协议栈高层——我在项目里见过太多次,高层同事对着RRC日志分析半天,最后发现是PSS相关峰门限设得太高,物理层压根没上报过这个小区。
1.2 盲扫与带先验信息搜索,两条完全不同的路径
规范里其实区分了两类小区搜索。一类叫初始小区搜索(initial cell search),终端不知道任何频点信息,需要在支持的频段上按信道栅格逐个频点尝试,每个频点还要尝试所有可能的中心频偏。另一类叫基于已存信息的小区搜索(stored information cell search),终端之前驻留过或者从别的系统继承了频点、甚至PCI列表,可以直接跳到指定频点做定向搜索。这两条路径的复杂度差着一个数量级。
盲扫的代价主要来自“三维搜索空间”:频点维度(一个Band可能有几十上百个栅格点)、时间维度(每个频点要在一个5ms窗口内滑动相关)、序列维度(PSS有3个根索引)。如果采样率是30.72MHz,一个5ms窗口就是153600个采样点,哪怕做了降采样,计算量依然可观。实际产品里通常会把IQ降到1.92MHz先做粗同步——PSS和SSS只占中心1.08MHz,降采样后信息完全够用,运算量却降到原来的1/256。这个取舍非常划算,也是我最推荐新手在离线仿真时采用的策略。
带先验信息的搜索就轻松多了:频点已知、带宽大概率已知、甚至可以只在PCI候选列表里做SSS盲检。很多物联网模组为了省电和省时间,会在出厂或者上一次驻留时把频点信息写进非易失存储,开机直接定向搜,搜网时间能从十几秒压到一两秒。这个设计思路值得借鉴:能记住的就别重算。
1.3 为什么把PSS放在第一步:低复杂度与高鲁棒性的权衡
有人会问,既然最终要解PBCH,为什么不直接盲检PBCH?答案在于复杂度。PBCH的盲检依赖PCI(加扰序列初始化)、依赖帧定时(确定40ms窗口内的冗余版本位置),还要盲猜天线端口数。如果连PCI和定时都不知道,盲检的组合数会爆炸。
而PSS的设计恰好解决了这个问题。它只用三个序列,周期5ms,在频域上只占中心62个子载波,时域上是一个符号长度的固定波形。终端可以用一套匹配滤波器,在时域上滑动相关,一次性同时得到“有没有小区”“时隙边界在哪”“N_ID(2)是几”三个信息。这是一种典型的用结构化信号换取搜索效率的设计:序列越少、周期越短、占带宽越窄,盲检成本越低。
代价是信息量少——PSS只给出了3种可能,剩下168种(336个N_ID(1)分成两半用于半帧区分)要靠SSS补齐。这个“粗同步用简单序列、精同步用复杂序列”的分层思路,后来在很多系统里都被沿用,理解了这一层,再看后面的PBCH盲检就不会觉得突兀了。
2. PSS与SSS:把时间和小区身份从噪声里抠出来
2.1 PSS的序列构造与三个根索引的物理含义
PSS在频域上是一条长度为63的Zadoff-Chu序列,三个根索引分别是25、29、34,对应N_ID(2)取0、1、2。ZC序列的好处是恒包络(时域上幅度恒定,对功放友好)和理想周期自相关(除了零位移,自相关值恒为零),这两个性质让它在低信噪比下的相关检测性能非常稳。频域上它占据中心6个资源块的中间62个子载波,正中间那个子载波(直流分量)被打孔不用,避免直流偏移干扰。
时域位置上,在常规CP的FDD配置下,PSS位于时隙0和时隙10的最后一个OFDM符号。因为一个无线帧10ms里有两个时隙包含PSS(时隙0和时隙10,间隔5ms),所以PSS的重复周期是5ms。这就带来一个天然的模糊:终端检测到一个PSS后,只知道“现在是某个5ms边界”,但不知道这是帧头(子帧0)还是帧中间(子帧5)。
生成PSS的代码很短,但映射细节容易出错:
import numpy as np def gen_pss_freq(nid2): u = [25, 29, 34][nid2] n = np.arange(63) return np.exp(-1j * np.pi * u * n * (n + 1) / 63) def pss_time_domain(nid2, fft_size=128): d = gen_pss_freq(nid2) X = np.zeros(fft_size, dtype=complex) # d(n) 映射到子载波 n-31,n=31 是直流,打孔 X[1:32] = d[32:63] # 正频率侧,子载波 1..31 X[fft_size-31:] = d[0:31] # 负频率侧,子载波 -31..-1 return np.fft.ifft(X) * np.sqrt(fft_size)这段代码在1.92MHz采样率下(对应128点FFT,子载波间隔15kHz)是准确的。如果你的采样率是30.72MHz,FFT点数变成2048,映射的索引要相应放大,但“中间打孔、两侧对称”的原则不变。我见过有人把DC也填上值,结果相关峰分裂成两个,误以为是多径,查了一整天才发现问题。
2.2 SSS的336个假设与半帧定时的消歧
SSS负责给出N_ID(1),取值范围0到335。它在频域上同样是62个长度,但不是单一ZC序列,而是由两组长度为31的m序列交织构成,偶数子载波放一组、奇数子载波放另一组,再用扰码序列做区分。这种交织结构让SSS在频域上呈现“梳状”特征,对频率选择性衰落有一定的抵抗能力。
关键在于,子帧0和子帧5上的SSS序列是不同的。具体做法是通过两组序列的循环移位组合来区分,使得同一个N_ID(1)在帧头和帧中呈现不同的码字。终端在检测到PSS之后,本来有5ms的定时模糊,只要在候选位置分别尝试“这是子帧0”和“这是子帧5”两种假设,看哪种假设的相关值更高,就能同时解出N_ID(1)和10ms帧边界。这个设计非常巧妙:用一次序列检测同时解决两个未知量。
从工程角度看,SSS的检测复杂度比PSS高一个量级。PSS只需要3个假设,SSS在定时已知的前提下有336个假设(如果半帧模糊未解,则是672个)。常见的优化是先做相干合并:因为PSS和SSS在同一个时隙内,两者之间的信道可以认为是准静态的,用PSS估计出的信道对SSS做均衡,再算相关,信噪比能提升2到3个dB。在弱覆盖场景(比如RSRP在-120dBm附近)这一点提升往往就是能不能搜到的分界线。
我自己调试时踩过一个坑:SSS的频域解调必须基于正确的CP长度假设。常规CP和扩展CP下,SSS所在的符号位置不同,如果用错了CP类型,相关峰会明显偏低但不为零,容易被误判成“小区存在但信号弱”。所以离线工具里一定要把CP类型做成可配置参数,扫频时两种都试一遍。
2.3 PCI合成、频偏估计与相关峰检测的实操细节
拿到N_ID(1)和N_ID(2)之后,PCI的计算只有一行:PCI = 3 × N_ID(1) + N_ID(2)。这个公式看着简单,但实际项目里因为N_ID(1)解错导致PCI错、进而导致PBCH永远解不出来的案例非常多。判断N_ID(1)是否解对有一个土办法:用解出的PCI生成CRS序列,跟接收信号做相关,如果PCI正确,CRS相关峰应当明显高于错误PCI的情况。这个交叉校验花不了多少算力,但能挡掉大量低级错误。
频偏估计通常分两步走。粗估计用PSS本身:把相邻两个5ms的PSS相关峰做相位差,相位差除以时间间隔就得到小数倍频偏的估计值。5ms对应200Hz的频率分辨率,对晶振初始误差(通常±5ppm,2GHz载波下就是±10kHz)来说足够覆盖。精估计则用CP自相关:CP是OFDM符号末尾的复制,把CP和对应位置的样点做相关,相位差除以CP长度对应的时长,精度能到几十Hz。这两步做完,残余频偏应该控制在子载波间隔的百分之几以内,否则后面的PBCH解调会因为相位旋转而失败。
相关峰检测的门限设置是个经验活。理论上可以用恒虚警率准则,但实际信道的噪声不是白的,邻区干扰、突发脉冲都会抬高底噪。我的习惯是:先计算整个搜索窗口内相关值的均值μ和标准差σ,门限取μ + kσ,k在6到8之间调整。同时加一条“峰值必须超过次高峰一定比例”的规则(比如1.3倍),防止多径造成的双峰被误判成两个小区。这套规则在密集城区和郊区都验证过,误检率可以压得很低。当然,如果要做邻区测量,就不能只取最高峰,得把所有超过门限的峰都记下来,按PCI去重。
3. PBCH与MIB:从“知道自己在哪”到“知道带宽是多少”
3.1 时频位置与那72个子载波的怪癖
PBCH的位置很有特点:它位于子帧0的第二个时隙,占据前4个OFDM符号,频域上是中心72个子载波(6个资源块)。注意这里是72而不是62——两侧各有5个子载波是保留的,不承载PBCH数据。这个设计当初是为了兼容不同带宽下的统一实现,终端不管小区带宽是1.4MHz还是20MHz,都只需要处理中心6个RB,实现复杂度大大降低。
PBCH的传输周期是40ms,但每10ms就会发送一次,四次发送分别对应四个不同的冗余版本。终端在不知道帧号低两位的情况下,理论上要尝试四种相位假设,把接收到的PBCH软信息按不同对齐方式合并,看哪种假设下CRC校验通过。实际实现中,因为PBCH的编码是咬尾卷积码加速率匹配,四种冗余版本合并后的增益能到5dB以上,所以即使单次接收质量一般,合并后往往也能解出来。
这里有个容易忽略的细节:PBCH的加扰序列初始化用到了小区ID和传输所在的时隙号、符号号。也就是说,必须先有正确的PCI才能正确解扰。这解释了为什么PCI解错会导致PBCH彻底解不出来,而不是“解得质量差一点”。
3.2 MIB的24个比特,每一位都有用
MIB的信息量很小,24个比特,但它决定了终端能不能继续往下走。逐位拆开看:
| 字段 | 比特数 | 取值范围与含义 |
|---|---|---|
| dl-Bandwidth | 3 | 0到5,分别对应6、15、25、50、75、100个资源块 |
| phich-Config | 3 | PHICH的持续时间(1或3个符号)和资源组比例(1/6、1/2、1、2) |
| systemFrameNumber | 8 | 系统帧号的高8位,低2位由PBCH的4次冗余定时推得 |
| spare | 10 | 预留位,终端必须忽略 |
带宽字段是最关键的。它告诉终端这个小区的下行带宽到底是1.4MHz还是20MHz,直接影响后续PDCCH的盲检范围、CRS的分布、以及测量带宽。如果带宽解错,后面的所有解调都会在错误的资源网格上进行,表现出的现象就是“PDCCH永远盲检不到DCI”。
PHICH配置同样重要,但很多新手会忽略它。PHICH承载上行HARQ的ACK/NACK,如果配置解析错误,终端可能在随机接入阶段就失败——因为Msg3的HARQ反馈对不上。我在一个项目里遇到过“随机接入成功率只有60%”的问题,最后定位到是PHICH的组比例参数解析有一个bit的偏移,改过来之后成功率立刻上到99%以上。这种问题在实验室里很难复现,因为实验室通常只有一个小区、干扰干净。
3.3 天线端口盲检与CRC掩码的组合博弈
MIB的16位CRC上面还叠了一层“掩码”,用来隐含指示基站的天线端口数。具体做法是用不同的比特图样对CRC做异或,终端用四种候选掩码分别尝试,哪种能通过CRC校验,就说明对应哪种天线配置(1天线、2天线、4天线)。这个设计把“天线端口数”这个额外信息塞进了CRC里,不占用宝贵的MIB比特。
盲检的组合数是“4种冗余相位 × 4种天线掩码 = 16种”,每种都要跑一遍解速率匹配、维特比译码和CRC校验。看起来很吓人,但实际实现里可以把解速率匹配之后的数据缓存起来,只改变合并相位和CRC掩码,计算量可以接受。优化技巧是先做CRC软判决预筛:对每个组合快速算一个CRC的软度量,只对度量最高的两三个组合做完整译码。
还有一个隐含信息值得提:PBCH的参考信号(也就是CRS)在解调时需要知道天线端口数才能正确做信道估计。这就形成了一个鸡生蛋的问题——解PBCH需要知道天线数,天线数又藏在PBCH里。实际做法是先假设单天线做一次信道估计和解调,如果CRC过不了,再假设双天线、四天线重来。这个顺序也有讲究:按1、2、4的顺序试,因为大部分宏站配置是2天线或者4天线,但单天线假设下的信道估计最鲁棒,误判成本最低。
4. SIB1读取与小区选择:从“能解调”到“能驻留”
4.1 SI-RNTI与公共搜索空间的PDCCH盲检
MIB解出来之后,终端知道了带宽和PHICH配置,下一步是去PDCCH上找调度SIB1的DCI。SIB1的调度信息用系统信息无线网络临时标识(SI-RNTI,固定值0xFFFF)加扰,终端在公共搜索空间里盲检可能的聚合等级和候选位置。
公共搜索空间的候选位置是规范固定的,聚合等级支持4和8,每种聚合等级有固定的候选数。终端要做的是:对每个候选位置,用SI-RNTI解PDCCH的CRC,通过的那一个就是调度SIB1的DCI。这里用到的DCI格式通常是1C(带宽大于1.4MHz时)或者1A,两者的资源分配字段结构不同,终端要按带宽选择尝试的格式。
这一步的失败率在实际网络中并不低,原因往往是PDCCH的信道估计质量不够。公共搜索空间没有UE专属的波束赋形增益,只能依赖CRS做信道估计。在小区边缘或者强干扰下,PDCCH的误检率会明显上升。工程上的应对办法是多次尝试:SIB1的调度周期是80ms,在这80ms内同一个DCI会重复发送多次,终端可以累积多次软信息再判决,这跟PBCH的冗余合并是同一个思路。
4.2 SIB1里真正决定命运的那几个参数
SIB1的内容比MIB丰富得多,但真正影响“能不能驻留”的就是那么几个。PLMN列表决定这个小区是不是你签约网络的,如果列表里没有匹配的PLMN,直接判为不可用。cellBarred字段如果是“禁止”,说明这个小区不接纳普通终端(可能是专网或者故障状态),也要放弃。trackingAreaCode用于位置更新,不匹配时会触发TAU流程。freqBandIndicator告诉终端这是哪个频段,用于后续的测量配置和切换判决。
真正参与驻留判决的是q-RxLevMin(最小接收电平)和可选的q-QualMin(最小接收质量)。这两个参数是运营商在网络规划时设定的,不同场景差异很大:市区宏站可能设到-120dBm,深度覆盖场景可能放宽到-124dBm甚至更低。这两个值在SIB1里的编码步长是2dB,所以实际值一定是偶数,如果你算出来的最小接收电平是奇数,那一定是解析错了。
还有一个经常被忽略的字段是si-WindowLength和schedulingInfoList,它们决定了其他SIB(比如SIB2的上行配置)什么时候、在哪个窗口发送。如果这些解析错误,终端可能在读完SIB1之后卡在“等SIB2”的状态,表现出来的现象是“驻留成功但无法发起业务”。
4.3 S准则的逐项计算与门限取值经验
小区选择的判决依据是S准则,核心公式是:
Srxlev = Qrxlevmeas − (Qrxlevmin + Qrxlevminoffset) − Pcompensation
其中Qrxlevmeas就是测到的RSRP,Qrxlevmin来自SIB1,Qrxlevminoffset用于周期性搜索时给已驻留小区一点“优待”(通常为0或者正值,让终端不那么容易换小区),Pcompensation是功率补偿项,等于最大发射功率减去终端功率等级,如果是负值就取0。
如果网络配置了基于质量的判决,还要算:
Squal = Qqualmeas − (Qqualmin + Qqualminoffset)
两项都大于等于0才算满足S准则。RSRP的测量本身有讲究:它是在CRS所在的资源粒子上测的参考信号功率,测量带宽可以是整个系统带宽,也可以配置成部分带宽。窄带测量抗干扰更好但代表性差,宽带测量更准确但容易被邻区干扰污染。实际网络里通常配置成系统带宽,因为LTE的CRS是全程发送的,测量样本足够多。
| 参数 | 典型取值 | 单位与步长 | 说明 |
|---|---|---|---|
| q-RxLevMin | -60 到 -70(编码值) | 2dB,实际-120到-140dBm | 决定覆盖边界 |
| q-QualMin | -18 到 -20 | 1dB | 只有配了质量判决才用 |
| q-RxLevMinOffset | 0 到 8 | 2dB | 周期性搜索时的偏置 |
| Pcompensation | 0 或正值 | dB | 多数终端为0 |
我在实测中总结出一条经验:当测到的RSRP比q-RxLevMin高出不到3dB时,驻留往往不稳定,因为信道快衰落会让瞬时值反复跌破门限,导致终端在“驻留—重选—再驻留”之间来回震荡,功耗飙升。这种情况下更好的策略是继续搜索其他小区,而不是勉强驻留。很多模组的搜网策略里会加一个“迟滞量”,就是这个道理。
5. 拿一段IQ数据把流程跑通:离线仿真实操
5.1 数据准备与采样率选择的取舍
想真正理解小区搜索,最好的办法是自己拿一段IQ数据跑一遍。数据来源可以是软件无线电设备采集的空口信号,也可以是仿真生成的基带信号。采集时注意两点:采样率至少要覆盖中心1.08MHz的同步信号,建议直接用1.92MHz的整数倍;采集时长至少100ms,因为PBCH的完整周期是40ms,要保证能覆盖至少两次完整的PBCH传输,才能做冗余合并。
我一般用1.92MHz采样率,理由很实在:这个采样率对应128点FFT,子载波间隔正好15kHz,PSS、SSS、PBCH都在这个带宽内,处理起来干净利落,不用做复杂的重采样。如果原始数据是30.72MHz,先做低通滤波再抽取16倍,注意滤波器要有足够的阻带衰减,否则抽取会引入混叠,把邻道的干扰折到带内来,让相关峰变得很脏。
预处理还有一步经常被跳过:直流分量去除。软件无线电设备的前端本振泄漏会在零频处产生一个很强的直流分量,这个分量在时域上表现为一个常数偏置,做相关时会抬高整个底噪。简单的做法是先减去均值,或者用高通滤波把零频附近几十kHz挖掉。这个操作对PSS检测的影响很大,我见过不少新手因为没做这一步,误以为信号质量太差。
5.2 PSS粗同步的代码实现与门限设定
有了干净的IQ数据,PSS检测可以写成下面这样:
def pss_search(rx, fs=1.92e6, th_ratio=1.3): N = 128 # 1.92MHz 对应 FFT 长度 win = int(5e-3 * fs) # 5ms 搜索窗口 results = [] for nid2 in range(3): local = pss_time_domain(nid2, N) # 只用后半段做相关,避开 CP 影响 seg = rx[:win] corr = np.abs(np.correlate(seg, local, mode='valid')) # 归一化,消除信号强度影响 energy = np.sqrt(np.convolve(np.abs(seg)**2, np.ones(N), mode='valid')) norm = corr / (energy + 1e-12) peak = np.argmax(norm) results.append((nid2, peak, norm[peak])) # 取最强的一个,同时检查是否显著高于次强 results.sort(key=lambda x: -x[2]) best, second = results[0], results[1] if best[2] > th_ratio * second[2]: return best return None # 判决为无小区这段代码有几个值得说明的地方。第一,相关用的本地序列只取有用符号长度,不包含CP,避免CP引入的伪峰。第二,归一化用滑动能量而不是固定常数,这样信号强弱变化时门限依然有效。第三,最后那句“显著高于次强”的判断非常关键——如果三个N_ID(2)的相关值都差不多,那多半是噪声,不该报小区。
检测到PSS之后,把它给出的位置作为5ms边界,然后在这个边界前后各开一个符号长度的窗口,在这个小范围里做SSS的336个假设搜索。因为定时已经大致确定,搜索范围小、计算量可控。SSS解出之后,用“子帧0假设”和“子帧5假设”分别计算相关能量,能量大的那个决定10ms帧边界,同时交叉验证N_ID(1)。
5.3 从PCI到PBCH再到SIB1的落地步骤
PCI确定之后,后面的流程就可以按部就班走:
第一步,用PCI生成CRS序列,在PBCH所在的资源块上做信道估计,得到每个资源粒子的信道响应。这一步的精度直接决定PBCH能不能解出来,所以要用二维维纳滤波或者至少做频域和时域的平滑。
第二步,对PBCH的四个OFDM符号做均衡、解预编码(这里要盲猜天线数)、解层映射、解调,得到软比特。注意PBCH用的是发射分集,天线数不同,解预编码的方式完全不同,这就是为什么天线数必须盲检。
第三步,解扰(用PCI和时隙号初始化)、解速率匹配、维特比译码、CRC校验。CRC通过就拿到了24比特MIB,把冗余相位、天线掩码、SFN低两位一起确定下来。
第四步,用MIB给出的带宽重新配置资源网格,去公共搜索空间盲检SI-RNTI加扰的DCI,拿到SIB1的时频资源位置,解PDSCH,最后解析RRC消息。
这四步串起来,一段完整的离线仿真大概两三百行代码。跑通之后你会对“为什么每一步都要依赖前一步”有非常直观的体会。我当初第一次跑通,最兴奋的不是看到MIB,而是发现当故意把PCI改错一位时,PBCH的CRC通过率立刻掉到零——这种“因果关系被验证”的感觉,比看十遍文档都管用。
6. 踩坑实录:文档里不会写的失败模式
6.1 相关峰虚警与频偏拖累,两个最常见的“假故障”
场景一:扫频时报告发现了小区,但PBCH怎么都解不出来。这种情况九成是PSS虚警——某个干扰信号恰好和某个根索引的PSS有较高的相关值。判断方法很直接:看相关峰的宽度和形状,真实PSS的相关峰应该接近理想三角波,主瓣窄、旁瓣低;干扰造成的虚峰通常又宽又毛糙。另一个判据是看三个根索引的相关值分布,真实小区的三个值会有一个明显突出,虚警往往三个都差不多。
场景二:PSS能稳定检测到,SSS却时好时坏。这通常是频偏没补干净。ZC序列对频偏比较宽容,几个kHz的残余频偏不会让PSS相关峰明显下降,但SSS用的是m序列交织结构,对频偏敏感得多。我的处理办法是在SSS检测前先用PSS做一次频偏粗估和补偿,补偿后再做SSS相关。实测下来,残余频偏从5kHz降到500Hz以内,SSS的检测成功率能从70%提升到接近100%。
还有一个隐蔽的坑是采样时钟偏差。收发两端的晶振不可能完全一致,几个ppm的采样偏差在100ms的累积下会造成明显的定时漂移。表现在PBCH上就是“前半段能解,后半段解不出”。解决办法是在解PBCH之前用CRS做一次定时精跟踪,或者干脆缩短单次处理的窗口长度。
6.2 常见问题速查表
| 现象 | 最可能的原因 | 排查顺序 |
|---|---|---|
| 完全搜不到小区 | 频点错误、增益太低、IQ数据饱和 | 先看时域波形幅度分布,再看频谱有没有明显信号 |
| 搜到小区但PCI一直变 | PSS虚警、多径导致峰分裂 | 看相关峰形状,加峰值比例判决 |
| PCI稳定但PBCH CRC全失败 | PCI解错、CP类型错、频偏未补偿 | 用CRS交叉验证PCI,试两种CP |
| PBCH偶尔能解,MIB字段异常 | 冗余版本相位判断错误 | 检查四次合并的对齐方式 |
| MIB正常但找不到SIB1 | 带宽配置错、PDCCH聚合等级范围设错 | 核对MIB带宽字段,扩大盲检范围 |
| SIB1解出但驻留失败 | PLMN不匹配、cellBarred、S准则不满足 | 逐字段打印SIB1内容,算Srxlev |
| 驻留后频繁重选 | 门限余量太小、邻区干扰 | 看RSRP波动范围,调迟滞参数 |
这张表是我这些年遇到问题后一条条攒下来的,很多条目对应的都是“文档里写得清清楚楚、但实际就是会错”的地方。比如CP类型,规范里明明说了常规CP是默认配置,但某些专网设备就是配了扩展CP,你的工具如果写死了常规CP,就会一直搜不到。
6.3 几条我认为最值钱的实操习惯
第一,永远从物理层最上游开始排查。RRC日志里显示“无合适小区”,不代表问题在RRC。先确认物理层有没有上报过这个PCI的测量结果,如果没有,往下查到PSS;如果有但测量值异常,查到CRS;如果测量正常但驻留失败,才轮到SIB1和S准则。这个顺序能省掉大量无效分析。
第二,把每一个中间结果都打日志。PCI、频偏估计值、相关峰信噪比、MIB的每个字段、SIB1的关键参数,全部落盘。我在排查一个偶发问题时就靠这个救命:日志显示失败的那几次,频偏估计值都比正常情况大了3kHz,顺着这条线查到是温度变化导致晶振漂移,补偿算法没跟上。
第三,用错误注入验证代码的鲁棒性。故意把PCI改错、把频偏调大、把信噪比压低,看流程在什么条件下崩溃。这比在正常条件下跑通更能暴露问题,也更能建立你对每个参数物理意义的直觉。
第四,不要迷信单一门限。小区搜索里几乎所有的判决都是统计判决,任何单一门限都会在某个场景下失效。多设几个互相校验的条件(相关峰高度、峰宽、次峰比例、CRS交叉验证),比反复调一个门限有效得多。
最后分享一个我自己的体会:小区搜索这段流程,规范文档读三遍不如自己用一段带噪的IQ数据跑一遍。跑通之后你会发现,那些原本抽象的“盲检”“合并”“交叉验证”,全都是为了让终端在什么都不知道的情况下,一步步把不确定性剥掉。这个过程的设计思路,比任何单个参数都值得琢磨。