[学习] GNSS信号跟踪环路原理、设计与仿真(仿真代码)
GNSS信号跟踪环路原理、设计与仿真
文章目录
- GNSS信号跟踪环路原理、设计与仿真
- 一、GNSS信号跟踪环路概述
- 二、跟踪环路基本原理
- 1. 信号跟踪的概念与目标
- 2. 锁相环(PLL)原理
- 3. 锁频环(FLL)原理
- 4. 延迟锁定环(DLL)原理
- 5. 三环联合跟踪结构
- 三、跟踪环路关键参数设计
- 四、跟踪环路性能分析
- 五、环路仿真示例
- 代码功能说明
- 关键可视化结果
- 运行说明
- 参数调整建议
- 附录:关键公式
一、GNSS信号跟踪环路概述
- GNSS信号接收的基本流程
完整的GNSS信号接收处理包括以下关键步骤:天线接收射频信号→低噪声放大→下变频至中频→AD采样→捕获阶段(粗略估计卫星信号的多普勒频移和码相位)→跟踪阶段(精确同步并持续跟踪信号)。以GPS L1 C/A码为例,接收信号先经过1575.42MHz的射频前端处理,再通过数字相关器实现伪码剥离和载波剥离。
流程如下图所示:
-
跟踪环路的定义与功能
跟踪环路是由载波跟踪环(如PLL或FLL)和码跟踪环(DLL)组成的闭环控制系统。其核心功能包括:- 实时补偿动态用户导致的载波多普勒变化(如车载接收机运动时可能产生±5kHz的频偏)
- 精确对齐本地伪随机码与接收信号的码相位(C/A码要求对齐误差小于1/4码片,约73米)
- 解调导航电文数据(50bps的导航比特流)
典型结构包含鉴相器、环路滤波器和数控振荡器(NCO)三个模块。
-
跟踪环路在GNSS接收机中的重要性
跟踪性能直接决定定位精度和可用性:
• 动态场景下(如无人机应用),环路带宽设计需在跟踪灵敏度(窄带宽)与动态应力容限(宽带宽)间折衷
• 城市峡谷环境中,多径效应可能导致传统DLL出现米级误差,此时需采用窄相关器或多径抑制技术
• 高精度接收机(如RTK)要求载波相位跟踪精度达毫米级,需结合卡尔曼滤波等先进算法
二、跟踪环路基本原理
1. 信号跟踪的概念与目标
信号跟踪是指接收机持续锁定并跟随卫星信号的过程,主要实现两个目标:
- 动态适应:在用户移动过程中保持对信号频率和相位变化的跟踪(如车载导航时速达200km/h时产生的多普勒频移)
- 抗干扰:在噪声和干扰环境下维持稳定跟踪(如城市峡谷中信号衰减达20dB时仍能工作)
2. 锁相环(PLL)原理
PLL通过相位鉴别实现精确跟踪:
- 核心组件:鉴相器(比较输入信号与本地振荡器相位差)、环路滤波器(如二阶滤波器去除高频噪声)、压控振荡器(调整频率)
- 典型参数:捕获范围±5Hz,跟踪精度±0.25Hz
- 应用场景:高精度测距、载波相位测量(RTK定位中要求相位误差<1°)
3. 锁频环(FLL)原理
FLL通过频率鉴别实现快速跟踪:
- 工作方式:比较相邻两个积分周期的相位差(典型积分时间1-10ms)
- 性能特点:捕获范围可达±500Hz,但精度较PLL低约1Hz
- 典型应用:高动态场景初始化(如导弹发射初期的信号捕获)
4. 延迟锁定环(DLL)原理
DLL专用于码跟踪:
- 实现方式:采用早-迟相关器结构(间隔通常为1/2码片)
- 关键指标:码环带宽0.5-2Hz,跟踪门限约20dB-Hz
- 特殊结构:双阻尼设计(高速时用宽带宽,静态时切窄带宽)
5. 三环联合跟踪结构
多环路协同工作模式:
- FLL辅助PLL:FLL先捕获信号(±1kHz范围),PLL随后精细锁定(切换阈值通常设为FLL频率误差<5Hz)
- PLL辅助DLL:载波环提供动态应力信息给码环(如PLL测得的加速度用于DLL预测)
三、跟踪环路关键参数设计
-
环路带宽的选择与优化
- 环路带宽直接影响跟踪环路的动态性能和抗噪声能力
- 窄带宽:噪声抑制好但动态响应慢(典型值1-10Hz)
- 宽带宽:动态性能好但噪声抑制差(典型值10-100Hz)
- 优化方法:
- 根据动态场景需求调整(如车载应用需要10-20Hz)
- 采用自适应带宽算法(如基于载噪比的自适应调整)
-
积分时间的设计
- 积分时间决定环路对信号积累的时长
- 短积分时间(1ms):适用于高动态场景
- 长积分时间(20ms):适用于弱信号环境
- 设计要点:
- 需与数据位边界对齐(GPS的20ms数据位)
- 平衡捕获灵敏度和动态性能的矛盾
-
鉴别器类型与性能比较
-
载波环鉴别器
- ATAN2鉴别器:
- 提供线性输出范围(-π/2~π/2)
- 适用于高动态环境
- 计算复杂度较高
- Costas鉴别器:
- 抗180度相位翻转
- 适用于BPSK调制信号
- 输出非线性(sin(2Δφ))
- ATAN2鉴别器:
-
码环鉴别器
- 非相干早迟门:
- 典型间隔1/2码片
- 抗多径性能较好
- 需要额外的载波剥离
- 相干点积:
- 更高精度
- 但需要精确的载波跟踪
- 适用于高精度应用
- 非相干早迟门:
-
-
环路滤波器的设计与实现
- 二阶环路滤波器:
- 典型结构:比例积分(PI)滤波器
- 参数计算:
K1 = 4B_LT/(4+4ξ^2)
K2 = 4B_L2T/(4+4ξ2)
(B_L为噪声带宽,ξ为阻尼系数,T为积分时间)
- 三阶环路滤波器:
- 适用于超高动态场景
- 增加加速度误差补偿
- 实现方式:
- 数字实现:定点/浮点运算选择
- 考虑量化噪声影响
- 典型更新率1ms-20ms
- 二阶环路滤波器:
四、跟踪环路性能分析
-
跟踪灵敏度的定义与影响因素
- 跟踪灵敏度是指接收机能够稳定跟踪卫星信号的最低信号强度(通常用dB-Hz表示)
- 主要影响因素:
- 环路带宽:带宽越窄灵敏度越高,但动态性能越差(典型值0.5-5Hz)
- 积分时间:延长积分时间可提高灵敏度(如从1ms增至20ms)
- 前端噪声系数:接收机前端噪声直接影响灵敏度
- 信号调制方式:BPSK比BOC调制更易跟踪
- 载噪比(C/N0):跟踪门限通常为20-25dB-Hz
-
动态性能与噪声性能的权衡
- 动态性能指标:最大可跟踪加速度(0.5g)、加加速度(1g/s)
- 噪声性能指标:伪距测量误差(0.1-1m)、载波相位噪声(1-5mm)
- 设计权衡:
- 宽带环路(如10Hz)适合高动态环境但噪声大
- 窄带环路(如1Hz)适合静态应用但动态受限
- 自适应带宽技术可根据场景自动调整
-
多径效应的影响与缓解方法
- 多径效应会导致:
- 伪距测量偏差(最大可达半波长)
- 载波相位周跳
- 跟踪环路失锁
- 缓解技术:
- 窄相关间隔技术(如Strobe相关器)
- 多径估计消除算法(MEDLL)
- 天线抗多径设计(扼流圈天线)
- 信号选择(L5比L1抗多径能力强30%)
- 多径效应会导致:
-
抗干扰能力分析
- 干扰类型:
- 宽带噪声干扰(最常见)
- 单频干扰(容易滤除)
- 脉冲干扰(影响最大)
- 欺骗干扰(最难防范)
- 防护措施:
- 空域滤波:自适应调零天线
- 时域滤波:脉冲干扰消除
- 频域滤波:FFT窄带抑制
- 信号处理:增强相关器设计
- 典型指标:
- 窄带干扰抑制比>30dB
- 宽带干扰抑制比>20dB
- 欺骗信号识别时间<1s
- 干扰类型:
五、环路仿真示例
以下是一个完整的Python仿真代码,实现了GPS L1 C/A码信号跟踪过程(PRN 1)。代码包含信号生成、跟踪环实现和可视化分析。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from scipy.signal import correlate# ==============================
# 参数设置
# ==============================
fs = 6.144e6 # 采样率 (6.144 MHz)
f_IF = 4.308e6 # 中频频率 (4.308 MHz)
code_rate = 1.023e6 # C/A码速率 (1.023 MHz)
code_length = 1023 # C/A码长度
ts = 1/fs # 采样间隔
t_coherent = 1e-3 # 相干积分时间 (1ms)
samples_per_ms = int(fs * t_coherent) # 每毫秒采样点数
doppler_true = 4200 # 真实多普勒频移 (Hz)
code_delay_true = 175.3 # 真实码延迟 (采样点)
SNR_dB = -20 # 信噪比 (dB)# 跟踪环参数
dll_damping = 0.7 # DLL阻尼系数
dll_bandwidth = 2.0 # DLL带宽 (Hz)
dll_noise_bandwidth = dll_bandwidth * 8/(4*dll_damping + 1/dll_damping) # 噪声带宽
dll_gain = 4 * dll_noise_bandwidth * t_coherent # DLL增益costas_damping = 0.707 # Costas环阻尼系数
costas_bandwidth = 15.0 # Costas环带宽 (Hz)
costas_noise_bandwidth = costas_bandwidth * 4 * costas_damping / (4*costas_damping**2 + 1) # 噪声带宽
costas_gain = 4 * costas_noise_bandwidth * t_coherent # Costas环增益# ==============================
# 辅助函数
# ==============================
def generate_ca_code(prn, code_length=1023):"""生成PRN 1的C/A码"""# PRN 1的Gold码生成多项式g1 = np.ones(10, dtype=int)g2 = np.ones(10, dtype=int)ca_code = np.zeros(code_length, dtype=int)for i in range(code_length):ca_code[i] = g1[9] ^ g2[9] # PRN 1的特殊抽头配置# 更新G1寄存器g1_new = g1[2] ^ g1[9]g1[1:] = g1[:-1]g1[0] = g1_new# 更新G2寄存器 (PRN 1的特殊抽头: 2和6)g2_new = g2[1] ^ g2[2] ^ g2[5] ^ g2[7] ^ g2[8] ^ g2[9]g2[1:] = g2[:-1]g2[0] = g2_newreturn 1 - 2*ca_code # 转换为±1def generate_nav_data(bit_rate=50, duration=0.3):"""生成50Hz导航电文数据"""num_bits = int(bit_rate * duration)return 1 - 2*np.random.randint(0, 2, num_bits) # 随机生成±1def add_doppler(signal, f_doppler, fs, phase=0):"""添加多普勒频移"""t = np.arange(len(signal)) / fsreturn signal * np.exp(1j * 2 * np.pi * f_doppler * t + 1j * phase)def add_noise(signal, snr_dB):"""添加高斯白噪声"""signal_power = np.mean(np.abs(signal)**2)noise_power = signal_power / (10**(snr_dB/10))noise = np.sqrt(noise_power/2) * (np.random.randn(len(signal)) + 1j*np.random.randn(len(signal)))return signal + noise# ==============================
# 信号生成
# ==============================
# 生成C/A码
ca_code = generate_ca_code(1)# 生成导航电文 (300ms)
nav_data = generate_nav_data(50, 0.3)# 创建完整基带信号
t_total = 0.3 # 300ms
num_samples = int(fs * t_total)
signal = np.zeros(num_samples, dtype=complex)# 扩展C/A码以匹配信号长度
ca_code_full = np.tile(ca_code, int(np.ceil(num_samples / len(ca_code))))[:num_samples]# 添加导航电文
for i in range(len(nav_data)):start_idx = i * samples_per_ms * 20 # 每比特20msend_idx = (i+1) * samples_per_ms * 20if end_idx > num_samples:end_idx = num_samplessignal[start_idx:end_idx] = nav_data[i] * ca_code_full[start_idx:end_idx]# 添加载波和多普勒
signal = add_doppler(signal, f_IF + doppler_true, fs, phase=np.pi/4)# 添加码延迟
signal = np.roll(signal, int(code_delay_true))# 添加噪声
signal = add_noise(signal, SNR_dB)# ==============================
# 跟踪环实现
# ==============================
class TrackingLoop:def __init__(self, fs, f_IF, code_length, samples_per_ms, dll_gain, costas_gain, dll_spacing=0.5):self.fs = fsself.f_IF = f_IFself.code_length = code_lengthself.samples_per_ms = samples_per_msself.dll_gain = dll_gainself.costas_gain = costas_gainself.dll_spacing = dll_spacing # 超前滞后码间距 (码片)# 状态变量初始化self.carrier_phase = 0.0self.carrier_freq = f_IF + 4000 # 初始多普勒估计 (带误差)self.code_phase = 170.0 # 初始码相位估计 (带误差)self.code_freq = code_rate # 码频率# 积分器状态self.I_E = 0.0self.Q_E = 0.0self.I_P = 0.0self.Q_P = 0.0self.I_L = 0.0self.Q_L = 0.0# 历史记录self.phase_error_history = []self.freq_error_history = []self.code_error_history = []self.corr_history = []def update(self, signal_chunk, ca_code):"""处理1ms的信号块"""# 生成本地载波t = np.arange(len(signal_chunk)) / self.fslocal_carrier = np.exp(-1j * (2 * np.pi * self.carrier_freq * t + self.carrier_phase))# 载波剥离baseband = signal_chunk * local_carrier# 生成本地C/A码 (三个版本)# 计算码相位偏移 (以采样点为单位)spacing_samples = self.dll_spacing * (self.fs / code_rate)# 即时码idx_p = np.arange(len(signal_chunk)) + self.code_phaseca_p = ca_code[np.mod(np.floor(idx_p).astype(int), self.code_length)]# 超前码 (提前spacing_samples)idx_e = idx_p - spacing_samplesca_e = ca_code[np.mod(np.floor(idx_e).astype(int), self.code_length)]# 滞后码 (延后spacing_samples)idx_l = idx_p + spacing_samplesca_l = ca_code[np.mod(np.floor(idx_l).astype(int), self.code_length)]# 相关积分 (1ms相干积分)self.I_E = np.sum(np.real(baseband) * ca_e)self.Q_E = np.sum(np.imag(baseband) * ca_e)self.I_P = np.sum(np.real(baseband) * ca_p)self.Q_P = np.sum(np.imag(baseband) * ca_p)self.I_L = np.sum(np.real(baseband) * ca_l)self.Q_L = np.sum(np.imag(baseband) * ca_l)# Costas环鉴相器 (相位误差检测)phase_error = np.arctan2(self.Q_P, self.I_P)# DLL鉴相器 (非相干超前减滞后)E = np.sqrt(self.I_E**2 + self.Q_E**2)L = np.sqrt(self.I_L**2 + self.Q_L**2)code_error = (E - L) / (2 * (E + L)) # 归一化误差# 更新载波环self.carrier_freq += self.costas_gain * phase_errorself.carrier_phase += phase_error# 更新码环self.code_phase += self.dll_gain * code_error# 记录历史self.phase_error_history.append(np.degrees(phase_error))self.freq_error_history.append(self.carrier_freq - (f_IF + doppler_true))self.code_error_history.append((self.code_phase - code_delay_true) * (code_rate/fs))self.corr_history.append((self.I_P, self.Q_P, self.I_E, self.Q_E, self.I_L, self.Q_L))# 相位归零处理if self.carrier_phase > 2*np.pi:self.carrier_phase -= 2*np.pielif self.carrier_phase < -2*np.pi:self.carrier_phase += 2*np.pireturn phase_error, code_error# ==============================
# 仿真运行
# ==============================
# 初始化跟踪环
tracker = TrackingLoop(fs, f_IF, code_length, samples_per_ms, dll_gain, costas_gain, dll_spacing=0.5)# 运行跟踪过程 (300ms)
num_chunks = int(t_total / t_coherent)
for i in range(num_chunks):start_idx = i * samples_per_msend_idx = (i+1) * samples_per_mssignal_chunk = signal[start_idx:end_idx]# 更新跟踪环phase_error, code_error = tracker.update(signal_chunk, ca_code)# 打印前10次更新if i < 10:print(f"Chunk {i+1}: Phase Error={np.degrees(phase_error):.2f}°, "f"Code Error={code_error:.4f} chips")# ==============================
# 结果可视化
# ==============================
plt.figure(figsize=(15, 15))
gs = GridSpec(4, 2, figure=plt.gcf())# 1. 载波相位误差
ax1 = plt.subplot(gs[0, 0])
ax1.plot(tracker.phase_error_history)
ax1.set_title('载波相位误差 (度)')
ax1.set_xlabel('时间 (ms)')
ax1.set_ylabel('相位误差 (°)')
ax1.grid(True)
ax1.axhline(15, color='r', linestyle='--', alpha=0.7, label='收敛阈值')
ax1.axhline(-15, color='r', linestyle='--', alpha=0.7)
ax1.legend()# 2. 多普勒频率误差
ax2 = plt.subplot(gs[0, 1])
ax2.plot(np.array(tracker.freq_error_history) / 1000)
ax2.set_title('多普勒频率误差')
ax2.set_xlabel('时间 (ms)')
ax2.set_ylabel('频率误差 (kHz)')
ax2.grid(True)
ax2.axhline(0, color='r', linestyle='--', alpha=0.7)# 3. 码相位误差
ax3 = plt.subplot(gs[1, 0])
ax3.plot(tracker.code_error_history)
ax3.set_title('码相位误差')
ax3.set_xlabel('时间 (ms)')
ax3.set_ylabel('码片误差')
ax3.grid(True)
ax3.axhline(0.1, color='r', linestyle='--', alpha=0.7, label='收敛阈值')
ax3.axhline(-0.1, color='r', linestyle='--', alpha=0.7)
ax3.legend()# 4. 相关器输出 (IQ平面)
corr_data = np.array(tracker.corr_history)
ax4 = plt.subplot(gs[1, 1])
ax4.scatter(corr_data[:50, 0], corr_data[:50, 1], c='b', marker='o', label='前50ms')
ax4.scatter(corr_data[50:, 0], corr_data[50:, 1], c='r', marker='x', label='后250ms')
ax4.set_title('即时支路相关器输出 (IQ平面)')
ax4.set_xlabel('I 分量')
ax4.set_ylabel('Q 分量')
ax4.grid(True)
ax4.legend()
ax4.axis('equal')# 5. 相关器输出幅度
E_mag = np.sqrt(corr_data[:, 2]**2 + corr_data[:, 3]**2)
P_mag = np.sqrt(corr_data[:, 0]**2 + corr_data[:, 1]**2)
L_mag = np.sqrt(corr_data[:, 4]**2 + corr_data[:, 5]**2)ax5 = plt.subplot(gs[2, :])
ax5.plot(E_mag, label='超前支路')
ax5.plot(P_mag, label='即时支路')
ax5.plot(L_mag, label='滞后支路')
ax5.set_title('相关器输出幅度')
ax5.set_xlabel('时间 (ms)')
ax5.set_ylabel('相关幅度')
ax5.grid(True)
ax5.legend()# 6. 导航电文解调
# 每20ms取一次符号 (1个导航比特)
nav_bits = []
for i in range(0, num_chunks, 20):if i+20 > num_chunks:break# 取20ms的I路积分值I_sum = np.sum(corr_data[i:i+20, 0])nav_bits.append(1 if I_sum > 0 else -1)# 原始导航电文
true_nav = nav_data[:len(nav_bits)]ax6 = plt.subplot(gs[3, :])
ax6.step(np.arange(len(nav_bits)), nav_bits, 'b-', where='post', label='解调电文')
ax6.step(np.arange(len(true_nav)), true_nav, 'r--', where='post', label='真实电文')
ax6.set_title('导航电文解调结果')
ax6.set_xlabel('比特序号')
ax6.set_ylabel('比特值')
ax6.set_yticks([-1, 1])
ax6.set_yticklabels(['-1 (0)', '1 (1)'])
ax6.grid(True)
ax6.legend()plt.tight_layout()
plt.savefig('gps_tracking_results.png', dpi=300)
plt.show()# 收敛性能分析
last_100 = slice(-100, None)
phase_stable = np.max(np.abs(tracker.phase_error_history[last_100])) < 15
freq_stable = np.abs(np.mean(tracker.freq_error_history[last_100])) < 10
code_stable = np.max(np.abs(tracker.code_error_history[last_100])) < 0.1print("\n跟踪性能分析:")
print(f"载波相位稳定: {'是' if phase_stable else '否'} (最大误差: {np.max(np.abs(tracker.phase_error_history[last_100])):.2f}°)")
print(f"多普勒频率稳定: {'是' if freq_stable else '否'} (平均误差: {np.mean(tracker.freq_error_history[last_100]):.2f} Hz)")
print(f"码相位稳定: {'是' if code_stable else '否'} (最大误差: {np.max(np.abs(tracker.code_error_history[last_100])):.4f} 码片)")
print(f"导航电文正确率: {np.mean(np.array(nav_bits) == true_nav)*100:.2f}%")
代码功能说明
-
信号生成模块:
- 生成PRN 1的C/A码(使用Gold码生成算法)
- 创建50Hz导航电文(随机比特序列)
- 构建包含载波、多普勒和噪声的中频信号
-
跟踪环实现:
- Costas环(载波跟踪):使用arctan鉴相器和二阶环路滤波器
- 延迟锁定环(码跟踪):使用非相干超前-滞后鉴别器
- 实时更新载波频率、相位和码相位
-
可视化分析:
- 载波相位误差收敛过程
- 多普勒频率跟踪性能
- 码相位误差变化
- 相关器输出(IQ平面和幅度)
- 导航电文解调结果对比
关键可视化结果
-
载波相位误差:
- 显示载波环从初始误差收敛到稳定状态(<15°)的过程
- 红色虚线表示收敛阈值
-
多普勒跟踪:
- 展示频率误差从初始4000Hz偏差收敛到接近0Hz的过程
-
码相位误差:
- 显示码环收敛到±0.1码片精度的过程
-
相关器输出:
- IQ平面:展示相关点从发散到聚集的过程
- 幅度图:显示超前、即时、滞后三路相关器输出
-
导航电文解调:
- 对比解调出的导航电文与原始电文
- 计算解调正确率
运行说明
-
代码需要安装Python科学计算库:
pip install numpy matplotlib scipy
-
运行后将生成6个子图,展示跟踪过程的关键性能指标
-
程序输出跟踪性能分析,包括:
- 载波相位稳定状态
- 多普勒频率跟踪精度
- 码相位跟踪精度
- 导航电文解调正确率
参数调整建议
- 信号强度:修改
SNR_dB
参数(典型范围-20dB至-30dB) - 动态特性:调整
doppler_true
模拟不同动态场景 - 环路带宽:
costas_bandwidth
:影响载波环响应速度(典型值10-25Hz)dll_bandwidth
:影响码环响应速度(典型值1-5Hz)
- 初始误差:在
TrackingLoop
初始化中调整初始频率和相位误差
此代码完整展示了GPS信号跟踪的全过程,通过可视化结果可清晰观察环路收敛特性和跟踪性能。
附录:关键公式
载波环鉴别器输出(ATAN2型):
θ e = arctan ( Q I ) \theta_e = \arctan\left(\frac{Q}{I}\right) θe=arctan(IQ)
DLL早迟门非相干鉴别器:
E = I E 2 + Q E 2 , L = I L 2 + Q L 2 E = \sqrt{I_E^2 + Q_E^2}, \quad L = \sqrt{I_L^2 + Q_L^2} E=IE2+QE2,L=IL2+QL2
ϵ = E − L E + L \epsilon = \frac{E - L}{E + L} ϵ=E+LE−L
研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)
相关文章:
[学习] GNSS信号跟踪环路原理、设计与仿真(仿真代码)
GNSS信号跟踪环路原理、设计与仿真 文章目录 GNSS信号跟踪环路原理、设计与仿真一、GNSS信号跟踪环路概述二、跟踪环路基本原理1. 信号跟踪的概念与目标2. 锁相环(PLL)原理3. 锁频环(FLL)原理4. 延迟锁定环(DLL&#x…...
Python实例题:Python计算微积分
目录 Python实例题 题目 代码实现 实现原理 符号计算: 数值计算: 可视化功能: 关键代码解析 1. 导数计算 2. 积分计算 3. 微分方程求解 4. 函数图像绘制 使用说明 安装依赖: 基本用法: 示例输出&#…...
如何判断指针是否需要释放?
在 C 中判断一个指针是否需要释放可以考虑以下几个方面: 一、确定指针的来源 1. 动态分配的内存: 如果指针是通过new、new[]、malloc、calloc等动态内存分配函数获取的,那么在不再需要该内存时,必须手动释放。 例如:…...
Spark 之 AQE
个人其他链接 AQE 执行顺序https://blog.csdn.net/zhixingheyi_tian/article/details/125112793 AQE 产生 AQE 的 循环触发点 src/main/scala/org/apache/spark/sql/execution/adaptive/AdaptiveSparkPlanExec.scala override def doExecute(): RDD[InternalRow] = {withFin…...
随访系统安装的记录
安装PG17.5 安装https://www.cnblogs.com/nulixuexipython/p/18040243 1、遇到navicat链接不了PG https://blog.csdn.net/sarsscofy/article/details/84985933 2、查看有无安装mysqlhttps://blog.51cto.com/u_16175430/7261412 3、 方案一:oracle不开日志 data…...
NLP学习路线图(二十四):门控循环单元(GRU)
一、背景:RNN的困境与门控机制的曙光 RNN的基本原理: RNN的核心思想是引入循环连接,使网络具有“记忆”功能。 在时刻 t,RNN接收当前输入 x_t 和前一个时刻的隐藏状态 h_{t-1}。 通过一个共享的权重参数(W, U, b)计算当前时刻的隐藏状态 h_t: h_t = tanh(W * x_t + U * …...
Doris查询Hive数据:实现高效跨数据源分析的实践指南
#### 1. Doris与Hive的集成背景 在大数据生态中,Hive作为基于Hadoop的数据仓库工具,广泛用于海量数据的批处理分析。而Apache Doris(原百度 Palo)是一种高性能、实时分析的MPP(大规模并行处理)数据库&…...
vsCode使用本地低版本node启动配置文件
npm run dev的配置文件 {"configurations": [{"type": "node-terminal","name": "项目运行: dev","request": "launch",//重点在这里 这行注释到时候删掉"command": "E:\\node-v14.21.…...
在Ubuntu上使用 dd 工具制作U盘启动盘
在Ubuntu上使用 dd 工具制作U盘启动盘 在Linux系统中,dd 是一个功能强大且原生支持的命令行工具,常用于复制文件和转换数据。它也可以用来将ISO镜像写入U盘,从而创建一个可启动的操作系统安装盘。虽然图形化工具(如 Startup Disk…...
el-table表格增加序号列index vue2和vue3的写法
<el-table><!--每页从1开始的序号--><el-table-column label"序号" width"60" align"center" type"index" /><!--一直递增的序号 vue2写法--><el-table-column label"序号" width"60"…...
【学习记录】如何使用 Python 提取 PDF 文件中的内容
如何使用 Python 提取 PDF 文件中的内容 在文档自动化处理、数据提取和信息分析等任务中,从 PDF 文件中提取文本是一项常见需求。PDF 文件通常分为两种类型:基于文本的 PDF 和 包含扫描图像的 PDF。 本文将介绍如何使用 Python 分别提取这两种类型的 P…...

Spark 之 DataFrame 开发
foreachPartition val data = spark.sparkContext.parallelize(1 to 100)// 使用 foreachPartition 批量处理分区 data.foreachPartition {partitionIterator =...

嵌入式学习笔记 - freeRTOS xTaskResumeAll( )函数解析
第一部分 移除挂起等待列表中的任务 while( listLIST_IS_EMPTY( &xPendingReadyList ) pdFALSE )//循环寻找直到为空,把全部任务扫描一遍 { pxTCB ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingR…...

机器学习KNN算法全解析:从原理到实战
大家好!今天我们来聊聊机器学习中的"懒人算法"——KNN(K-Nearest Neighbors,K近邻)算法。这个算法就像个"墙头草",它不学习模型参数,而是直接根据邻居的"投票"来做决策&…...

【QT】自定义QWidget标题栏,可拖拽(拖拽时窗体变为normal大小),可最小/大化、关闭(图文详情)
目录 0.背景 1.详细实现 思路简介 .h文件 .cpp文件 0.背景 Qt Linux;项目遇到问题,解决后特此记录 项目需要,个性化的标题栏(是个widget),在传统的三个按钮(最大化、最小化、关闭…...

FPGA定点和浮点数学运算-实例对比
在创建 RTL 示例时,经常使用 VHDL 2008 附带的 VHDL 包。它提供了出色的功能,可以高效地处理定点数,当然,它们也是可综合的。该包的一些优点包括: 有符号和无符号(后缀和后缀)定点向量。轻松将定…...
MySQL Binlog 数据恢复全指南
MySQL Binlog 数据恢复全指南 一、Binlog 核心概念 1. 什么是 Binlog? Binlog(二进制日志)是 MySQL 记录所有修改数据的 SQL 语句的日志文件,采用二进制格式存储。它是 MySQL 最重要的日志之一,具有三大核心功能&am…...
python版若依框架开发:后端开发规范
python版若依框架开发 从0起步,扬帆起航。 python版若依部署代码生成指南,迅速落地CURD!项目结构解析前端开发规范后端开发规范文章目录 python版若依框架开发1.启动命令2.配置⽂件3.上传配置1.启动命令 本项⽬⾃定义了两个启动命令 pyhton app.py --env=devpython app.p…...

Linux编程:2、进程基础知识
一、进程基本概念 1、进程与程序的区别 程序:静态的可执行文件(如电脑中的vs2022安装程序)。进程:程序的动态执行过程(如启动后的vs2022实例),是操作系统分配资源的单位(如 CPU 时…...
时序数据库IoTDB与EdgeX Foundry集成适配服务介绍
一、背景介绍 EdgeX Foundry:由Linux基金会运维的开放源码边缘计算软件框架,自2017年开源后广泛应用于全球各行业场景。VMware自2018年起在中国社区推广EdgeX技术,拓展生态,并持续贡献代码。IoTDB:由Apache基…...
Android第十二次面试-多线程和字符串算法总结
多线程的创建与常见使用方法 一、多线程创建方式 1. 继承Thread类 class MyThread extends Thread {Overridepublic void run() {// 线程执行逻辑System.out.println(Thread.currentThread().getName() " is running");} }// 使用 MyThread thread new …...
ES6——数组扩展之Set数组
在ES6(ECMAScript 2015)中,JavaScript的Set对象提供了一种存储任何值唯一性的方式,类似于数组但又不需要索引访问。这对于需要确保元素唯一性的场景非常有用。Set对象本身并不直接提供数组那样的方法来操作数据(例如ma…...

Cursor Rules 使用
前言 最近在使用 Cursor 进行编程辅助时,发现 AI 生成的代码风格和当前的代码风格大相径庭。而且有时它会输出很奇怪的代码,总是不符合预期。 遂引出本篇,介绍一下 Rules ,它就可以做一些规范约束之类的事情。 什么是 Cursor R…...

服务器数据恢复—服务器raid5阵列崩溃如何恢复数据?
服务器数据恢复环境&故障: 某品牌型号为X3850服务器上有一组由14块数据盘和1块热备盘组建的raid5磁盘阵列。 服务器在正常使用过程中突然崩溃,管理员查看raid5阵列故障情况的时发现磁盘阵列中有2块硬盘掉线,但是热备盘没有启用。 服务器数…...

Go语言堆内存管理
Go堆内存管理 1. Go内存模型层级结构 Golang内存管理模型与TCMalloc的设计极其相似。基本轮廓和概念也几乎相同,只是一些规则和流程存在差异。 2. Go内存管理的基本概念 Go内存管理的许多概念在TCMalloc中已经有了,含义是相同的,只是名字有…...

【DAY41】简单CNN
内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点: 数据增强卷积神经网络定义的写法batch归一化:调整一个批次的分布,常用与图像数据特征图:只有卷积操作输出的才叫特征图调度器:直接修改基础学习率 卷积操作常…...
Rust 学习笔记:使用自定义命令扩展 Cargo
Rust 学习笔记:使用自定义命令扩展 Cargo Rust 学习笔记:使用自定义命令扩展 Cargo Rust 学习笔记:使用自定义命令扩展 Cargo Cargo 支持通过 $PATH 中的 cargo-something 形式的二进制文件拓展子命令,而无需修改 Cargo 本身。 …...
LeetCode 08.06 面试题 汉诺塔 (Java)
经典递归解决汉诺塔问题:清晰的三步移动策略 问题描述 在汉诺塔问题中,有 3 根柱子和 N 个大小不同的盘子,盘子初始按升序堆叠在第一根柱子上(最小的在顶部)。目标是将所有盘子移动到第三根柱子上,并满足…...

使用MinIO搭建自己的分布式文件存储
目录 引言: 一.什么是 MinIO ? 二.MinIO 的安装与部署: 三.Spring Cloud 集成 MinIO: 1.前提准备: (1)安装依赖: (2)配置MinIO连接: &…...
单元测试与QTestLib框架使用
一.单元测试的意义 在软件开发中,单元测试是指对软件中最小可测试单元(通常是函数、类的方法)进行隔离的、可重复的验证。进行单元测试具有以下重要意义: 1.提升代码质量与可靠性: 早期错误检测: 在开发…...