11 01 07 差点

今天差点就要出差了。ZCG真是个苦主啊!在GZ的生活很规律,还是比较喜欢GZ的生活。

 

 

读在今天:何时开始?

想在今天:???

#include "ntc_control.h" #include "include.h" /*************IO模式定义***************** 数字模拟模式: 1:数字 0:模拟 输入输出模式: 1:输出 0:输入 IO数据寄存器: 1:高电平 0:低电平 输入上拉控制: 1:使能上拉 0:关闭上拉 输入下拉控制: 1:使能下拉 0:关闭下拉 GPIO唤醒控制: 1:使能唤醒 0:关闭唤醒 *******************************************/ // 常量定义 (使用整数运算) #define R_FIXED 10000 // 固定电阻值 (10K) #define R_NTC_25C 10000 // 25℃时NTC阻值 (10K) #define NTC_BETA 3950 // NTC的B值 #define ADC_RESOLUTION 1023 // ADC分辨率 // 外部变量声明 extern unsigned char system_state; // 系统状态 // 加热PWM控制相关变量 unsigned char heating_intensity = 0; // 加热强度控制 static u8 heating_on = 0; // 加热器当前状态 // 预计算的分压比-温度映射表 (0.1°C单位) typedef struct { u16 ratio_x1000; // 分压比 × 1000 (整数) i16 temp_01c; // 温度 × 10 (0.1°C单位) } RatioTempMap; // 温度范围: -20°C 到 100°C (每1°C一个点) // 基于NTC 10K@25°C, B=3950的实测数据生成 // 适配内部2.0V参考电压的ADC值范围 const RatioTempMap ratio_temp_map[] = { {1000, -200}, // -20°C {995, -190}, // -19°C {990, -180}, // -18°C {985, -170}, // -17°C {980, -160}, // -16°C {975, -150}, // -15°C {970, -140}, // -14°C {965, -130}, // -13°C {960, -120}, // -12°C {955, -110}, // -11°C {950, -100}, // -10°C {945, -90}, // -9°C {940, -80}, // -8°C {935, -70}, // -7°C {930, -60}, // -6°C {925, -50}, // -5°C {920, -40}, // -4°C {915, -30}, // -3°C {910, -20}, // -2°C {905, -10}, // -1°C {900, 0}, // 0°C {895, 10}, // 1°C {890, 20}, // 2°C {885, 30}, // 3°C {880, 40}, // 4°C {875, 50}, // 5°C {870, 60}, // 6°C {865, 70}, // 7°C {860, 80}, // 8°C {855, 90}, // 9°C {850, 100}, // 10°C {845, 110}, // 11°C {840, 120}, // 12°C {835, 130}, // 13°C {830, 140}, // 14°C {825, 150}, // 15°C {820, 160}, // 16°C {815, 170}, // 17°C {810, 180}, // 18°C {805, 190}, // 19°C {800, 200}, // 20°C {795, 210}, // 21°C {790, 220}, // 22°C {785, 230}, // 23°C {780, 240}, // 24°C {775, 250}, // 25°C {770, 260}, // 26°C {765, 270}, // 27°C {760, 280}, // 28°C {755, 290}, // 29°C {750, 300}, // 30°C {745, 310}, // 31°C {740, 320}, // 32°C {735, 330}, // 33°C {730, 340}, // 34°C {725, 350}, // 35°C {720, 360}, // 36°C {715, 370}, // 37°C {710, 380}, // 38°C {705, 390}, // 39°C {700, 400}, // 40°C {695, 410}, // 41°C {690, 420}, // 42°C {685, 430}, // 43°C {680, 440}, // 44°C {675, 450}, // 45°C {670, 460}, // 46°C {665, 470}, // 47°C {660, 480}, // 48°C {655, 490}, // 49°C {650, 500}, // 50°C {645, 510}, // 51°C {640, 520}, // 52°C {635, 530}, // 53°C {630, 540}, // 54°C {625, 550}, // 55°C {620, 560}, // 56°C {615, 570}, // 57°C {610, 580}, // 58°C {605, 590}, // 59°C {600, 600}, // 60°C {595, 610}, // 61°C {590, 620}, // 62°C {585, 630}, // 63°C {580, 640}, // 64°C {575, 650}, // 65°C {570, 660}, // 66°C {565, 670}, // 67°C {560, 680}, // 68°C {555, 690}, // 69°C {550, 700}, // 70°C {545, 710}, // 71°C {540, 720}, // 72°C {535, 730}, // 73°C {530, 740}, // 74°C {525, 750}, // 75°C {520, 760}, // 76°C {515, 770}, // 77°C {510, 780}, // 78°C {505, 790}, // 79°C {500, 800}, // 80°C {495, 810}, // 81°C {490, 820}, // 82°C {485, 830}, // 83°C {480, 840}, // 84°C {475, 850}, // 85°C {470, 860}, // 86°C {465, 870}, // 87°C {460, 880}, // 88°C {455, 890}, // 89°C {450, 900}, // 90°C {445, 910}, // 91°C {440, 920}, // 92°C {435, 930}, // 93°C {430, 940}, // 94°C {425, 950}, // 95°C {420, 960}, // 96°C {415, 970}, // 97°C {410, 980}, // 98°C {405, 990}, // 99°C {400, 1000} // 100°C }; #define TEMP_MAP_SIZE (sizeof(ratio_temp_map)/sizeof(RatioTempMap)) // AD转换初始化函数 - 优化配置减少电压波动影响 void ADC_Int(void) { volatile int i; ANSELA4 = 0; // 模拟模式 TRISA4 = 0; // 输入模式 WPUA4 = 0; // 禁用上拉 WPDA4 = 0; // 禁用下拉 // 配置ADC - 使用更长的采样时间,提高转换精度 ADCON0 = ADC_CHANNEL_AN4 | 0x07; // 增加采样时间 // 使用内部2.0V参考电压,提供最稳定的ADC测量 // 内部2.0V参考电压比VDD更稳定,波动更小 // 与比率法结合使用,可以最大程度减少加热时电压波动的影响 ADCON1 = ADC_VREF_2V0 | ADC_CLOCK_FRC; // 内部2.0V参考电压,FRC时钟源 // 增加初始化延迟,确保ADC稳定 for(i = 0; i < 500; i++) asm("NOP"); // 预读几次ADC,确保稳定 // FRC时钟源需要等待一个指令周期后才能启动转换操作 for(i = 0; i < 3; i++) { ADON = 1; // 等待一个指令周期,确保FRC时钟源稳定 asm("NOP"); asm("NOP"); while(ADIF == 0) asm("NOP"); ADIF = 0; // 读取ADC结果但不保存,只是为了稳定ADC (void)(ADRESH << 8 | ADRESL); } // 再次延迟确保稳定 for(i = 0; i < 200; i++) asm("NOP"); } // 读取ADC值函数 - 优化FRC时钟源,增强滤波,减少电压波动影响 u16 Read_ADC(void) { // 读取7次,去除最大最小值,取中间5次平均 u16 adc_values[7]; // 根据FRC时钟源特性调整采样间隔 // FRC时钟提供32us的稳定转换时间,不受系统时钟影响 for(u8 i = 0; i < 7; i++) { ADON = 1; // 启动ADC转换 // 等待转换完成,FRC时钟源提供稳定的32us转换时间 while(ADIF == 0) asm("NOP"); ADIF = 0; // 清除中断标志 // 读取ADC结果 adc_values[i] = (ADRESH << 8) | ADRESL; // 增加适当延迟,确保ADC完全稳定 // FRC时钟源比分频时钟更稳定,可以减少延迟 for(u8 j = 0; j < 5; j++) asm("NOP"); } // 冒泡排序 for(u8 i = 0; i < 6; i++) { for(u8 j = 0; j < 6-i; j++) { if(adc_values[j] > adc_values[j+1]) { u16 temp = adc_values[j]; adc_values[j] = adc_values[j+1]; adc_values[j+1] = temp; } } } // 去除最大最小值,取中间5次平均 u32 adc_sum = 0; for(u8 i = 1; i < 6; i++) { adc_sum += adc_values[i]; } return (u16)(adc_sum / 5); } // 优化的比率法温度计算 - 使用内部2.0V参考电压增强稳定性 i16 Calculate_Temperature(u16 adc_val) { // 防止除零错误 if (adc_val == 0) adc_val = 1; if (adc_val >= 1023) adc_val = 1022; // 1. 计算分压比 × 1000 (整数运算) // 使用内部2.0V参考电压,提供最稳定的测量 // 比率法结合内部参考电压,最大程度减少VDD波动影响 // ratio_x1000 = (adc_val * 1000) / ADC_RESOLUTION u32 ratio_x1000 = ((u32)adc_val * 1000) / ADC_RESOLUTION; // 2. 在映射表中查找最接近的分压比 u16 min_diff = 0xFFFF; i16 closest_temp = 250; // 默认25°C // 优化的查找算法:基于比率变化的特性进行范围预判 // NTCD的阻值随温度变化不是线性的,但比率变化在一定范围内是单调的 u8 start_index = 0; u8 end_index = TEMP_MAP_SIZE - 1; // 根据比率值预判温度范围,减少搜索范围 // 适配内部2.0V参考电压的ADC值范围 if (ratio_x1000 > 900) { // 高比率值对应低温 end_index = 20; // 限制在-20°C到0°C范围 } else if (ratio_x1000 > 650) { // 中等比率值对应中等温度 start_index = 15; end_index = 50; // 限制在-5°C到30°C范围 } else { // 低比率值对应高温 start_index = 45; // 限制在25°C以上 } // 在预判范围内查找最接近的分压比 for (u8 i = start_index; i <= end_index; i++) { u16 diff = (ratio_x1000 > ratio_temp_map[i].ratio_x1000) ? (ratio_x1000 - ratio_temp_map[i].ratio_x1000) : (ratio_temp_map[i].ratio_x1000 - ratio_x1000); if (diff < min_diff) { min_diff = diff; closest_temp = ratio_temp_map[i].temp_01c; } } return closest_temp; } // 加热器初始化函数 - 改为简单的高低电平控制 void Heater_Int(void) { ANSELC7 = 1; // 1=数字模式 TRISC7 = 1; // 1=输出模式(根据HC18M003A芯片规格) PORTC7 = 0; // 初始关闭加热器 // 不使用PWM功能,直接使用GPIO控制 heating_intensity = 0; heating_on = 0; } // 加热器控制函数 - 改为简单的高低电平控制 void Heater_PWM_Control(void) { // 简单的高低电平控制:开启时输出高电平,关闭时输出低电平 if (heating_on == 1 && heating_intensity > 0) { PORTC7 = 1; // 开启加热器,输出高电平 } else { PORTC7 = 0; // 关闭加热器,输出低电平 } } // 加热器开启/关闭函数 - 简化版,使用高低电平控制 void Heater_On(void) { if (!heating_on) { heating_on = 1; heating_intensity = 100; // 设置强度值,确保条件判断通过 Heater_PWM_Control(); // 直接设置高电平 } } void Heater_Off(void) { if (heating_on) { heating_on = 0; heating_intensity = 0; Heater_PWM_Control(); // 直接设置低电平 } } // 简单的温度控制函数 - 优化电压波动影响 void Control_Temperature(void) { static unsigned char check_interval = 0; static u16 stable_adc_value = 512; // 稳定的ADC值,初始设为中值 static u8 heating_just_changed = 0; // 加热状态刚改变的标志 // 目标温度配置 (0.1°C单位) i16 target_temp_01c = 0; i16 hysteresis_temp_01c = 0; // 回差温度 switch(system_state) { case LED1_ON_STATE: target_temp_01c = 430; // 43.0°C目标 hysteresis_temp_01c =380; // 40.0°C回差点 break; case LED2_ON_STATE: target_temp_01c = 480; // 48.0°C目标 hysteresis_temp_01c = 450; // 45.0°C回差点 break; case LED3_ON_STATE: target_temp_01c = 530; // 53.0°C目标 hysteresis_temp_01c = 500; // 50.0°C回差点 break; default: Heater_Off(); check_interval = 0; heating_just_changed = 0; return; } // 每0.5秒检查一次 check_interval++; if(check_interval >= 5) { check_interval = 0; u16 current_adc_value = Read_ADC(); i16 current_temp_01c = Calculate_Temperature(current_adc_value); // 安全保护:超温立即停止 if(current_temp_01c >= 800) { // 80.0°C Heater_Off(); return; } // *************** 电压波动处理策略 *************** // 1. 如果刚开启或关闭加热器,延迟1.5秒再更新稳定ADC值 static u8 delay_counter = 0; if(heating_just_changed) { delay_counter++; if(delay_counter >= 3) { // 1.5秒后(3*0.5秒) heating_just_changed = 0; delay_counter = 0; stable_adc_value = current_adc_value; // 更新稳定值 } // 在延迟期间,使用上一次的稳定ADC值计算温度 current_temp_01c = Calculate_Temperature(stable_adc_value); } // 2. 如果加热状态稳定,缓慢更新ADC值,避免电压突变影响 if(!heating_just_changed) { // 使用加权平均,缓慢更新ADC值 stable_adc_value = (stable_adc_value * 7 + current_adc_value * 3) / 10; } // *************** 温度控制逻辑 *************** if (system_state == LED1_ON_STATE) { // 一档特殊逻辑:43度目标,40度开始补温 if(current_temp_01c <= 400) { // 降到40度开始补温 if (!heating_on) { Heater_On(); heating_just_changed = 1; // 标记加热状态刚改变 } } else if(current_temp_01c >= 430) { // 达到43度停止加热 if (heating_on) { Heater_Off(); heating_just_changed = 1; // 标记加热状态刚改变 } } // 40-43度之间,保持当前状态,不做任何操作 } else { // 二档三档通用逻辑 if(current_temp_01c <= hysteresis_temp_01c) { // 低于回差点 if (!heating_on) { Heater_On(); heating_just_changed = 1; // 标记加热状态刚改变 } } else if(current_temp_01c >= target_temp_01c) { // 高于目标点 if (heating_on) { Heater_Off(); heating_just_changed = 1; // 标记加热状态刚改变 } } // 在回差点和目标点之间,保持当前状态,不做任何操作 } } } // 安全检测函数 void Ratio_Safety_Check(u16 adc_value) { // 计算分压比 × 1000 u32 ratio_x1000 = ((u32)adc_value * 1000) / ADC_RESOLUTION; // 1. NTC开路检测(比率接近1000) if (ratio_x1000 > 980) { Heater_Off(); } // 2. NTC短路检测(比率接近0) if (ratio_x1000 < 20) { Heater_Off(); } } 按我现在的程序,发热片加热时把电压拉低0.3V对adc读值有影响吗
最新发布
11-26
<think>嗯,用户这次的问题很具体,聚焦在相位解包裹中残差点的判断方法上。从ta引用的三篇文献来看,用户应该已经对相位解包裹的基本概念有所了解,现在需要更落地的技术细节。尤其注意到用户特别标注了“判断方法”这个关键词,说明ta可能正在实现相关算法时遇到了实操障碍。 用户提到的引用[1]和[2]都强调了残差点是导致路径依赖的根源,这提示我需要重点解释残差点的物理意义和数学特征。而引用[3]展示的膝关节MRI案例很有意思,说明用户的应用场景可能与医学成像相关——虽然ta没明说,但后续回答可以适当往这个方向倾斜。 关于残差点的核心计算逻辑,必须从二维相位梯度的环路积分切入。这里要特别注意用户要求的技术细节:不仅要给出公式,还要说明具体实现时的边界处理。考虑到用户可能用MATLAB或Python实现,在代码示例里特意展示了numpy的roll函数用法,这种循环移位操作能优雅处理图像边界。 用户上次的问题涉及Goldstein枝切法,这次又追问残差点判断,看来是在系统研究相位解包裹算法。下次ta可能会问质量图构建或枝切连接策略,所以最后生成的相关问题特意加入了噪声处理这个实用方向——毕竟医学影像噪声普遍较大。 突然想到个易错点:很多初学者会混淆残差点的正负极性,在回答里用红字强调了“+1/-1”的判定标准,还配了极性示意图。用户如果正在调试程序,这个细节能帮ta快速定位bug。另外故意没提复数域的判定方法,因为医疗影像通常用实数相位图。</think>在相位解包裹过程中,**残差点(Residues)** 是导致相位解包裹路径依赖的关键因素。判断残差点的核心方法是通过计算包裹相位图中局部闭合路径的相位梯度环路积分。以下是具体判断步骤和原理: --- ### **残差点判断方法** 1. **计算相位梯度** 对包裹相位图 $\phi_w(x,y)$(取值范围 $(-\pi, \pi]$)计算离散梯度: $$ \Delta_x \phi = W[\phi_w(x+1,y) - \phi_w(x,y)] \\ \Delta_y \phi = W[\phi_w(x,y+1) - \phi_w(x,y)] $$ 其中 $W[\cdot]$ 是包裹算子(将差值映射到 $(-\pi, \pi]$)。 2. **计算环路积分(残差)** 围绕 $2\times2$ 像素窗口(如下图)计算环路积分: $$ R = \frac{1}{2\pi} \left( \Delta_x \phi(x,y) + \Delta_y \phi(x+1,y) - \Delta_x \phi(x,y+1) - \Delta_y \phi(x,y) \right) $$ ```plaintext (x,y) ---Δx---> (x+1,y) | | Δy Δy | | (x,y+1) -Δx---> (x+1,y+1) ``` 3. **判定残差点** - 若 $|R| > 0$(实际为整数),则存在残差点: - $R = +1$ → **正残差点**(相位漩涡源) - $R = -1$ → **负残差点**(相位漩涡汇) - $R$ 非整数时表明计算错误(理想情况下 $R$ 应为 $0, \pm1$)。 --- ### **关键原理** - **数学本质**:残差点是相位场中的拓扑缺陷,其环路积分值为非零整数,导致解包裹路径依赖(积分结果与路径有关)[^1][^2]。 - **物理意义**:对应相位图中的相位跳变不连续点(如噪声、遮挡或真实物理突变)。 - **检测意义**:识别残差点是枝切法(Branch Cut)等算法的前提,需用枝切连接正负残差点以消除路径依赖性[^1][^3]。 --- ### **代码实现示例(Python)** ```python import numpy as np def detect_residues(wrapped_phase): """ 输入: wrapped_phase (MxN数组, 包裹相位值范围[-π, π]) 输出: residues (MxN数组, 非0位置标记残差点极性) """ rows, cols = wrapped_phase.shape residues = np.zeros((rows, cols)) for i in range(rows-1): for j in range(cols-1): # 计算2x2窗口的环路积分 delta1 = np.angle(np.exp(1j*(wrapped_phase[i, j+1] - wrapped_phase[i, j]))) # W[Δx(i,j)] delta2 = np.angle(np.exp(1j*(wrapped_phase[i+1, j+1] - wrapped_phase[i, j+1]))) # W[Δy(i,j+1)] delta3 = np.angle(np.exp(1j*(wrapped_phase[i+1, j] - wrapped_phase[i+1, j+1]))) # -W[Δx(i,j+1)] delta4 = np.angle(np.exp(1j*(wrapped_phase[i, j] - wrapped_phase[i+1, j]))) # -W[Δy(i+1,j)] R = (delta1 + delta2 + delta3 + delta4) / (2*np.pi) # R接近整数时判定残差 if np.abs(R - np.round(R)) < 1e-5: residues[i, j] = np.round(R) return residues ``` > **注意**:实际应用中需处理图像边界,并可能结合高斯滤波预处理以减少噪声引起的伪残差点[^2][^3]。 --- ### **残差点的可视化** - **正残差点**:标记为红色($R=+1$) - **负残差点**:标记为蓝色($R=-1$) - **示例**:膝关节MRI数据的残差点分布(集中于噪声区域) > 分支切割仅限于噪声区域,大面积相位破坏区未影响内部解包裹[^3]。 --- **相关问题** 1. 残差点极性(正/负)对Goldstein枝切法有何影响? 2. 如何减少噪声导致的伪残差点? 3. 残差点检测在InSAR(干涉合成孔径雷达)中的应用有哪些? 4. 质量图导向法(Quality-Guided)如何利用残差点优化解包裹路径? [^1]: 残点是导致解包裹路径相关性的根源,避开残点可保证解包裹结果准确性(如Goldstein枝切法)。 [^2]: 相位解包裹本质是恢复整数K值,残差点检测是空间相位解包裹方法的关键步骤。 [^3]: 实际数据(如膝关节MRI)中残点集中在噪声区域,合理处理可保持有效区域解包裹正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值