/* ********************************************************************************************************* * IAR Development Kits * on the * * Nano130 * * Filename : adc_calculate.c * Version : V1.00 * Programmer(s) : Qian Xianghong ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #include "includes.h" // 介质介电常数 const float e_Src[] = { 1.62, // LNG 1.48, // O2 1.44, // N2 1.52, // AR 1.60, // CO2 1.23, // H2(介电常数暂未知) 1.10, // CNG(介电常数暂未知) 1.41, // He(介电常数暂未知) 1.60, // C2H4(介电常数暂未知) 1.75, // LPG(介电常数暂未知) 2.5, // NH3(介电常数暂未知) 1.5, // PENT(戊烷,介电常数暂未知) 1.5, // POPO(聚醚多元醇,介电常数暂未知) }; // 传感器规格参数 const Sensor_Model Adc_Sensor_Tables[1] = { // 真空电容常数, 非线性段长度, 底座厚度(忽略), 底部非线性段长度 // {0.0802607, 45, 0, 45}, // 圆管电容,k = 2π*e0 / ln(8 / 4), (e0 = 0.008854187817) {0.0667859, 45, 0, 45}, // 圆管电容, 内管外部涂氟0.2mm }; // 储罐理论参数 Bottle_Data Theoretical_Param; // 余弦函数,只处理[0, PI/2]区间 #define my_cos(angle) cos(angle) // 反余弦函数,只处理[0, 1]区间 #define my_acos(c) acos(c) // 正弦函数,只处理[0, PI/2]区间 #define my_sin(angle) sin(angle) // 反正弦函数,只处理[0, 1]区间 #define my_asin(c) asin(c) // 计算椭球体容积 u32 Calculate_Ellipsoid_Space(u16 d) { float r = ((float) d) / 100 / 2; // 半径, 单位mm->dm return (u32) (2 * PI * r * r * r / 3); // 单位L } // 计算圆柱体积 u32 Calculate_Cylinder_Space(u16 d, u16 L) { float r = (float) d / 200; // 转换成分米 float l = (float) L / 100; return (u32)(PI * r * r * l); // 单位L } // 计算球体积 u32 Calculate_Spherical_Space(u16 d) { float r = (float) d / 200; // 转换成分米 return (u32)(4 * PI * r * r * r / 3); // 单位L } // 根据圆柱体内液位高度与半径之比计算体积比 float Calculate_Cylinder_Rate0(float hr) { float b; float vr; u8 reverse = 0; if(hr > 1) // 超过中线,计算顶部容积,再用总容积来减 { hr = 2 - hr; reverse = 1; } b = my_acos(1 - hr); vr = (b - my_cos(PI / 2 - b) * (1 - hr)) / PI; if(!reverse) { return vr; } return 1 - vr; } // 根据圆柱体内液位高度计算体积比 float Calculate_Cylinder_Rate(u16 d, float h) { float hr = ((float) h) / d * 2; // 高度与半径之比 return Calculate_Cylinder_Rate0(hr); } // 根据椭球体内液位高度计算体积比 float Calculate_Ellipsoid_Rate(u16 d, float h) { float hr; float vr; u8 reverse = 0; hr = ((float) h) / d * 2; // 高度与半径之比 if(hr > 1) // 超过中线,计算顶部容积,再用总容积来减 { hr = 2 - hr; reverse = 1; } vr = hr * hr * (3 - hr) / 4; if(!reverse) { return vr; } return 1 - vr; } // 根据液位高度与直径,计算空间(无扣除) // 卧罐 u32 Calculate_Space(u16 d, float h, u32 v) { u32 ve = Calculate_Ellipsoid_Space(d); u32 vc = v - ve; float re = Calculate_Ellipsoid_Rate(d, h); float rc = Calculate_Cylinder_Rate(d, h); return (u32) (ve * re + vc * rc); } // 根据液位高度与直径之比,计算剩余液量(有扣除) // v0: 留底液量 // 卧罐 u32 Calculate_Volume(u16 d, float h, u32 v, u16 v0) { // 计算空间容积 u32 space = Calculate_Space(d, h, v); // 留底 if(space < v0) { return 0; } return space - v0; } // 根据液位高度,计算空间(无扣除) // 立罐 u32 Calculate_Space_Stand(u16 d, u16 L, float H) { float r = (float) d / 200; // 转为dm,体积单位为L float l = (float) L / 100; float h = (float) H / 100; if(h <= r / 2) { // 只有底下椭球部分 return 2 * PI * r * h * h - 4 * PI * h * h * h / 3; } if(h <= r / 2 + l) { // 底下椭球+圆柱部分 h -= r/2; return PI * r * r * r / 3 + PI * r * r * h; } if(h <= r / 2 + l + r / 2) { // 上下椭球+中间圆柱部分 h -= r / 2 + l; return PI * r * r * r / 3 + PI * r * r * l + PI * r * r * h - 4 * PI * h * h * h / 3; } // 高度超过有效范围 return 2 * PI * r * r * r / 3 + PI * r * r * l; } // 根据液位高度,计算剩余液量(有扣除) // v0: 留底液量 // 立罐 u32 Calculate_Volume_Stand(u16 d, u16 L, float H, u16 v0) { // 计算空间容积 u32 space = Calculate_Space_Stand(d, L, H); // 留底 if(space < v0) { return 0; } return space - v0; } // 根据液位高度,计算空间(无扣除) // 球罐 u32 Calculate_Space_Spherical(u16 d, float H) { float r = (float) d / 200; // 转为dm,体积单位为L float h = (float) H / 100; if(h <= r) { // 高度未超过一半 return PI * r * h * h - PI * h * h * h / 3; } if(h <= r + r) { // 高度超过一半 h = r + r - h; return 4 * PI * r * r * r / 3 - PI * r * h * h + PI * h * h * h / 3; } // 高度超过有效范围 return 4 * PI * r * r * r / 3; } // 根据液位高度,计算剩余液量(有扣除) // v0: 留底液量 // 球罐 u32 Calculate_Volume_Spherical(u16 d, float H, u16 v0) { // 计算空间容积 u32 space = Calculate_Space_Spherical(d, H); // 留底 if(space < v0) { return 0; } return space - v0; } // 计算底部不可测部分高度 s16 Calculate_Base_Height(s16 d, s16 base_d, s16 base_len) { float r = ((float) d) / 2 ; float base_r = ((float) base_d) / 2; float b = my_asin(base_r / r); b = my_cos(b); return (s16) (r * (1 - b)) + base_len; } // 计算理论参数 u8 Calculate_Theoretical_Params(u8 bottle_type, u16 d, u16 L, uint8_t chargePct, float density) { u8 vresv_percent = 0;// 留底百分比,固定为0 u16 h0, h1, zero_h; u16 zero_v, v0; Theoretical_Param.LSrc_k = 1000 / 9.8 / density; if(bottle_type == BOTTLE_TYPE_SPHERICAL) Theoretical_Param.v = Calculate_Spherical_Space(d); else Theoretical_Param.v = Calculate_Ellipsoid_Space(d) + Calculate_Cylinder_Space(d, L); // 计算底部不可测高度 Theoretical_Param.nl_len = Calculate_Base_Height(d, Adc_Sensor_Tables[0].base_d, Adc_Sensor_Tables[0].base_len); // 计算留底液量及高度, 最多留一半 if(vresv_percent == 0) { Theoretical_Param.zero_height = 0; Theoretical_Param.v0 = 0; } else { h0 = 0; if(bottle_type == BOTTLE_TYPE_STAND) { h1 = d / 4 + L / 2; // 立罐 } else { h1 = d / 2; // 卧罐、球罐 } v0 = (u16) (Theoretical_Param.v * (vresv_percent * 0.01)); // 目标留底液量 while(1) { zero_h = (h0 + h1) / 2; if(bottle_type == BOTTLE_TYPE_LYING) { zero_v = Calculate_Volume(d, zero_h, Theoretical_Param.v, 0); } else if(bottle_type == BOTTLE_TYPE_STAND) { zero_v = Calculate_Volume_Stand(d, L, zero_h, 0); } else { zero_v = Calculate_Volume_Spherical(d, zero_h, 0); } if(zero_v == v0) { break; } else if(zero_v > v0) { if(zero_h == h0) { break; } h1 = zero_h - 1; } else { if(zero_h == h1) { break; } h0 = zero_h + 1; } } Theoretical_Param.zero_height = zero_h; Theoretical_Param.v0 = zero_v; } // 有效容积 Theoretical_Param.ve = (Theoretical_Param.v - Theoretical_Param.v0) * chargePct / 100; return 1; } // 判断采集数据范围是否合法 // 输入:采集值、校零值、校满值 // 返回:传感器状态字节 u8 ADC_Validate(u32 adc, u32 zero, u32 full) { u32 temp; // 如果是降序,交换最小最大ADC值 if(zero > full) { temp = zero; zero = full; full = temp; } // 低于校准点的1/3,或低于量程范围的1/3,未连接 if(adc < zero / 3 || adc + (full - zero) / 3 < zero) return SENSOR_STATUS_NOCONNECT; // 低于校准点的1/2,或低于量程范围的1/4,下溢出 if(adc < zero / 2 || adc + (full - zero) / 4 < zero) return SENSOR_STATUS_UNDERFLOW; // 高于量程范围的1/4,上溢出 if(adc > full + (full - zero) / 4) return SENSOR_STATUS_OVERFLOW; return SENSOR_STATUS_NORMAL; } // 计算采集数据 // 输入:adc,校准值,量程 // 输出:经计算得到的值 float ADC_Calculate(u32 adc, u32 zero, u32 full, s32 low, s32 high) { if(zero > full) { if(adc <= full) return high; // 量程最大值 if(adc >= zero) return low; // 量程最小值 return low + ((float) (zero - adc)) / (zero - full) * (high - low); } if(adc <= zero) return low; // 量程最小值 if(adc >= full) return high; // 量程最大值 return low + ((float) (adc - zero)) / (full - zero) * (high - low); } // 冒泡排序,用于数量较少的排序法 void sort(u32 numbs[], s8 cnt) { s8 i, j, k; u32 temp; for(i = 0; i < cnt - 1; i++) { // 查找最小值 k = i; temp = numbs[k]; for(j = i + 1; j < cnt; j++) { if(numbs[j] < temp) { k = j; temp = numbs[k]; } } // 交换 if(k != i) { numbs[k] = numbs[i]; numbs[i] = temp; } } } // KPa转换成mmH2O float KPa2mmH2O(float KPa) { return KPa * 101.9716213; } // 差压转换为液位高度 float Diff2Level(float dp, u8 bottle_type, u16 d, u16 L) // 单位KPa、mm { float h = Theoretical_Param.LSrc_k * dp; u16 max_h; // 不能超过罐子高度 if(bottle_type == BOTTLE_TYPE_STAND) { // 立罐最大高度 max_h = L + d / 2; if(h > max_h) h = max_h; } else { // 卧罐、球罐最大高度 if(h > d) h = d; } return h; } // 高度转换为体积 u32 Level2Vol(float h, u8 bottle_type, u16 d, u16 L) // 单位mm、L { u32 v; if(bottle_type == BOTTLE_TYPE_LYING) { // 卧罐 v = Calculate_Volume(d, h, Theoretical_Param.v, Theoretical_Param.v0); } else if(bottle_type == BOTTLE_TYPE_STAND) { // 立罐 v = Calculate_Volume_Stand(d, L, h, Theoretical_Param.v0); } else { // 球罐 v = Calculate_Volume_Spherical(d, h, Theoretical_Param.v0); } if(v > Theoretical_Param.v - Theoretical_Param.v0) v = Theoretical_Param.v - Theoretical_Param.v0; return v; } // 体积转换为质量 u32 Vol2Quantity(float v, float density) // 单位L、kg { return density * v; } // 质量转换为体积 u32 Quantity2Vol(float quantity, float density) // 单位kg、L { u32 v = quantity / density; if(v > Theoretical_Param.v - Theoretical_Param.v0) v = Theoretical_Param.v - Theoretical_Param.v0; return v; }