python Chapter 3:雨滴/雪花Nw、Dm、u、R、Nt计算
一、Nw


二、Dm


三、u(不用换算)
法一:用 M₃、M₄、M₆ 推导u

法二:用 M2、M3、M4 阶矩推导 μ

四、Nt(不用换算直接算)

五、R_rain


六、R_snow

#!/usr/bin/env python # -*- coding:utf-8 -*- """ @author: Suyue @file: calculate_all_parameters.py @time: 2026/09/07 @desc: 整合计算所有雨滴谱参数:Dm, μ_234, μ_346, Nw, Nt, R_rain, R_snow """ import numpy as np import re import os import csv def read_cleaned_data(cleaned_file): """ 读取清洗后的数据文件 格式:时间戳 + 32行数据 + 空行 返回:时间戳列表 和 数据矩阵列表 注意:读取的矩阵每一行是直径通道(32行),每一列是速度通道(32列) """ timestamps = [] data_matrices = [] current_data = [] current_timestamp = None timestamp_pattern = re.compile(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$') print(f"正在读取文件: {cleaned_file}") with open(cleaned_file, 'r') as f: for line_num, line in enumerate(f): line = line.strip() if timestamp_pattern.match(line): if current_data and len(current_data) == 32 and current_timestamp: data_matrices.append(np.array(current_data, dtype=float)) timestamps.append(current_timestamp) current_timestamp = line current_data = [] elif line and any(c.isdigit() for c in line): try: row_data = list(map(float, line.split())) if len(row_data) == 32: # 每行32列(速度通道) current_data.append(row_data) except: pass elif not line and current_data: if len(current_data) == 32 and current_timestamp: data_matrices.append(np.array(current_data, dtype=float)) timestamps.append(current_timestamp) current_timestamp = None current_data = [] if current_data and len(current_data) == 32 and current_timestamp: data_matrices.append(np.array(current_data, dtype=float)) timestamps.append(current_timestamp) print(f"读取完成: 共{len(timestamps)}个时间戳,每个矩阵形状: {data_matrices[0].shape if data_matrices else '无数据'}") if len(timestamps) != len(data_matrices): print(f"警告: 时间戳数量({len(timestamps)})与数据矩阵数量({len(data_matrices)})不匹配") min_len = min(len(timestamps), len(data_matrices)) timestamps = timestamps[:min_len] data_matrices = data_matrices[:min_len] return timestamps, data_matrices def calculate_all_parameters(data_32x32, diameters_mm, velocities_ms): """ 计算所有雨滴谱参数:Dm, μ_234, μ_346, Nw, Nt, R_rain, R_snow 参数: data_32x32: 32x32雨滴数矩阵 行索引 (i) = 直径通道 (0-31) 列索引 (j) = 速度通道 (0-31) 即 data_32x32[i, j] 表示直径通道i、速度通道j的粒子数 diameters_mm: 32个直径通道的中心直径(mm),对应行索引 i velocities_ms: 32个速度通道的中心速度(m/s),对应列索引 j 返回: Dm_mm, mu_234, mu_346, Nw, Nt, R_rain_mmh, R_snow_mmh """ # ===== 常数设置 ===== A_m2 = 0.0054 # 采样面积 m² delta_t = 60 # 采样时间 s # ===== 初始化累加变量 ===== # 用于Dm计算(保持mm单位) numerator_dm = 0.0 # ΣΣ n_ij * D_i^4 / V_j denominator_dm = 0.0 # ΣΣ n_ij * D_i^3 / V_j # 用于矩计算(先保持mm单位,方便后续换算) sum_nD2_V_mm = 0.0 # ΣΣ n_ij * D_i^2 / V_j (D单位:mm) sum_nD3_V_mm = 0.0 # ΣΣ n_ij * D_i^3 / V_j (D单位:mm) sum_nD4_V_mm = 0.0 # ΣΣ n_ij * D_i^4 / V_j (D单位:mm) sum_nD6_V_mm = 0.0 # ΣΣ n_ij * D_i^6 / V_j (D单位:mm) # 用于Nt计算 sum_n_V = 0.0 # ΣΣ n_ij / V_j # 用于R_rain计算 (D³) sum_D3_n = 0.0 # ΣΣ D_i³ × n_ij # 用于R_snow计算 (D²) sum_D2_n = 0.0 # ΣΣ D_i² × n_ij # ===== 遍历矩阵:行=直径,列=速度 ===== for i in range(32): # i = 直径通道索引(行) D_i_mm = diameters_mm[i] D_i_squared = D_i_mm ** 2 D_i_cubed = D_i_mm ** 3 D_i_fourth = D_i_mm ** 4 D_i_sixth = D_i_mm ** 6 for j in range(32): # j = 速度通道索引(列) V_j = velocities_ms[j] if V_j <= 0: continue n_ij = data_32x32[i, j] # 第i行第j列 = 直径i、速度j的粒子数 if n_ij > 0: # 用于Dm计算(mm单位) numerator_dm += n_ij * D_i_fourth / V_j denominator_dm += n_ij * D_i_cubed / V_j # 用于矩计算(保持mm单位) sum_nD2_V_mm += n_ij * D_i_squared / V_j sum_nD3_V_mm += n_ij * D_i_cubed / V_j sum_nD4_V_mm += n_ij * D_i_fourth / V_j sum_nD6_V_mm += n_ij * D_i_sixth / V_j # 用于Nt计算 sum_n_V += n_ij / V_j # 用于R_rain计算 (D³) sum_D3_n += D_i_cubed * n_ij # 用于R_snow计算 (D²) sum_D2_n += D_i_squared * n_ij # ===== 1. 计算Dm (mm) ===== if denominator_dm > 0: Dm_mm = numerator_dm / denominator_dm else: Dm_mm = np.nan # ===== 2. 计算μ值 ===== # 方法1:用2、3、4阶矩计算μ M2_mm = sum_nD2_V_mm M3_mm = sum_nD3_V_mm M4_mm = sum_nD4_V_mm M6_mm = sum_nD6_V_mm if M2_mm > 0 and M3_mm > 0 and M4_mm > 0: denominator = M3_mm ** 2 - M4_mm * M2_mm if abs(denominator) > 1e-12: mu_234 = (3 * M4_mm * M2_mm - 4 * M3_mm ** 2) / denominator else: mu_234 = np.nan else: mu_234 = np.nan # 方法2:用3、4、6阶矩计算μ if M3_mm > 0 and M4_mm > 0 and M6_mm > 0: G = (M4_mm ** 3) / (M3_mm ** 2 * M6_mm) if abs(1 - G) > 1e-12: mu_346 = (11 * G - 8 + np.sqrt(G * (G + 8))) / (2 * (1 - G)) else: mu_346 = np.nan else: mu_346 = np.nan # ===== 3. 计算Nw ===== # 单位换算:D(mm) -> D(m): 乘以 1e-3 sum_nD3_V_SI = sum_nD3_V_mm * 1e-9 # mm³ -> m³ sum_nD4_V_SI = sum_nD4_V_mm * 1e-12 # mm⁴ -> m⁴ M3_SI = sum_nD3_V_SI / (A_m2 * delta_t) # 单位: m³/(m²·s) = m/s M4_SI = sum_nD4_V_SI / (A_m2 * delta_t) # 单位: m⁴/(m²·s) = m²/s if M3_SI > 0 and M4_SI > 0: N0_star_SI = (256.0 / 6.0) * (M3_SI ** 5) / (M4_SI ** 4) # 国际单位: m⁻⁴ Nw = N0_star_SI * 1e-3 # 转换为 mm⁻¹·m⁻³ else: Nw = np.nan # ===== 4. 计算Nt (总浓度) ===== Nt = sum_n_V / (A_m2 * delta_t) # 单位: m⁻³ # ===== 5. 计算R_rain (雨强) ===== constant_rain = (6 * np.pi * 1e-4) / (A_m2 * delta_t) R_rain_mmh = constant_rain * sum_D3_n # ===== 6. 计算R_snow (雪的雨强) ===== constant_snow = (1.02 * 1e-4 * np.pi) / (A_m2 * delta_t) R_snow_mmh = constant_snow * sum_D2_n return Dm_mm, mu_234, mu_346, Nw, Nt, R_rain_mmh, R_snow_mmh def main(): # 配置文件路径 input_file = 'D:/lianxi/50934-20210426200700-20210426212359-0.txt' output_csv = 'D:/lianxi/All_Parameters.csv' # 直径通道(行索引 i = 0-31) diameters_mm = np.array([ 0.062, 0.187, 0.312, 0.437, 0.562, 0.687, 0.812, 0.937, 1.064, 1.193, 1.388, 1.651, 1.918, 2.188, 2.463, 2.882, 3.457, 4.050, 4.665, 5.303, 6.194, 7.321, 8.447, 9.573, 10.699, 12.389, 14.641, 16.894, 19.146, 21.399, 24.214, 27.593 ]) # 速度通道(列索引 j = 0-31) velocities_ms = np.array([ 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95, 1.1, 1.3, 1.5, 1.7, 1.9, 2.2, 2.6, 3, 3.4, 3.8, 4.4, 5.2, 6, 6.8, 7.6, 8.8, 10.4, 12, 13.6, 15.2, 17.6, 20.8 ]) print(f"直径通道数: {len(diameters_mm)} (行)") print(f"速度通道数: {len(velocities_ms)} (列)") if not os.path.exists(input_file): print(f"错误: 输入文件不存在: {input_file}") return print("=" * 60) print("雨滴谱参数综合计算程序") print("=" * 60) print(f"输入文件: {input_file}") print(f"输出CSV: {output_csv}") print("数据矩阵结构: 行=直径通道(32行), 列=速度通道(32列)") print("=" * 60) # 读取数据 timestamps, data_matrices = read_cleaned_data(input_file) if not timestamps: print("错误: 没有读取到有效数据") return # 计算所有参数 print(f"\n开始计算所有参数,共 {len(timestamps)} 个时间戳...") all_results = [] for idx, (timestamp, data_matrix) in enumerate(zip(timestamps, data_matrices)): if idx % 200 == 0: print(f" 处理到第 {idx + 1}/{len(timestamps)} 个时间戳") Dm_mm, mu_234, mu_346, Nw, Nt, R_rain_mmh, R_snow_mmh = calculate_all_parameters( data_matrix, diameters_mm, velocities_ms ) all_results.append({ 'timestamp': timestamp, 'Dm': Dm_mm, 'mu_234': mu_234, 'mu_346': mu_346, 'Nw': Nw, 'Nt': Nt, 'R_rain': R_rain_mmh, 'R_snow': R_snow_mmh }) print(f"计算完成") # 输出CSV print(f"\n正在保存结果到CSV: {output_csv}") fieldnames = ['time', 'Dm', 'mu_234', 'mu_346', 'Nw', 'Nt', 'R_rain', 'R_snow'] with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for result in all_results: row = { 'time': result['timestamp'], 'Dm': f"{result['Dm']:.6f}" if not np.isnan(result['Dm']) else 'NaN', 'mu_234': f"{result['mu_234']:.6f}" if not np.isnan(result['mu_234']) else 'NaN', 'mu_346': f"{result['mu_346']:.6f}" if not np.isnan(result['mu_346']) else 'NaN', 'Nw': f"{result['Nw']:.6e}" if not np.isnan(result['Nw']) else 'NaN', 'Nt': f"{result['Nt']:.2f}", 'R_rain': f"{result['R_rain']:.6f}", 'R_snow': f"{result['R_snow']:.6f}" } writer.writerow(row) print(f"CSV文件已保存: {output_csv}") # 预览 print("\n" + "=" * 60) print("CSV文件内容预览 (前5行):") print("=" * 60) with open(output_csv, 'r', encoding='utf-8') as f: for i, line in enumerate(f): if i < 6: print(line.strip()) else: break # 统计信息 print("\n" + "=" * 60) print("统计信息:") print(f" 时间点数量: {len(all_results)}") # 提取各参数值(排除NaN) Dm_values = [r['Dm'] for r in all_results if not np.isnan(r['Dm'])] mu_234_values = [r['mu_234'] for r in all_results if not np.isnan(r['mu_234'])] mu_346_values = [r['mu_346'] for r in all_results if not np.isnan(r['mu_346'])] Nw_values = [r['Nw'] for r in all_results if not np.isnan(r['Nw'])] Nt_values = [r['Nt'] for r in all_results] R_rain_values = [r['R_rain'] for r in all_results] R_snow_values = [r['R_snow'] for r in all_results] if Dm_values: print(f" Dm 范围: {min(Dm_values):.2f} - {max(Dm_values):.2f} mm") print(f" Dm 平均: {np.mean(Dm_values):.2f} mm") if mu_234_values: print(f" μ_234 范围: {min(mu_234_values):.2f} - {max(mu_234_values):.2f}") print(f" μ_234 平均: {np.mean(mu_234_values):.2f}") if mu_346_values: print(f" μ_346 范围: {min(mu_346_values):.2f} - {max(mu_346_values):.2f}") print(f" μ_346 平均: {np.mean(mu_346_values):.2f}") if Nw_values: print(f" Nw 范围: {min(Nw_values):.2e} - {max(Nw_values):.2e} mm⁻¹·m⁻³") print(f" Nw 平均: {np.mean(Nw_values):.2e} mm⁻¹·m⁻³") print(f" Nt 范围: {min(Nt_values):.2f} - {max(Nt_values):.2f} m⁻³") print(f" Nt 平均: {np.mean(Nt_values):.2f} m⁻³") print(f" R_rain 范围: {min(R_rain_values):.2f} - {max(R_rain_values):.2f} mm/h") print(f" R_rain 平均: {np.mean(R_rain_values):.2f} mm/h") print(f" R_rain 总量: {np.sum(R_rain_values) / 60:.2f} mm") print(f" R_snow 范围: {min(R_snow_values):.2f} - {max(R_snow_values):.2f} mm/h") print(f" R_snow 平均: {np.mean(R_snow_values):.2f} mm/h") print(f" R_snow 总量: {np.sum(R_snow_values) / 60:.2f} mm") print("=" * 60) if __name__ == "__main__": main()

批量处理数据代码
#!/usr/bin/env python # -*- coding:utf-8 -*- """ @author: Suyue @file: batch_calculate_parameters.py @time: 2026/09/09 @desc: 批量计算雨滴谱参数:Dm, μ_234, μ_346, Nw, Nt, R_rain, R_snow """ import numpy as np import re import os import glob import csv # ==================== 常量定义 ==================== DIAMETERS_MM = np.array([ 0.062, 0.187, 0.312, 0.437, 0.562, 0.687, 0.812, 0.937, 1.064, 1.193, 1.388, 1.651, 1.918, 2.188, 2.463, 2.882, 3.457, 4.050, 4.665, 5.303, 6.194, 7.321, 8.447, 9.573, 10.699, 12.389, 14.641, 16.894, 19.146, 21.399, 24.214, 27.593 ]) VELOCITIES_MS = np.array([ 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95, 1.1, 1.3, 1.5, 1.7, 1.9, 2.2, 2.6, 3, 3.4, 3.8, 4.4, 5.2, 6, 6.8, 7.6, 8.8, 10.4, 12, 13.6, 15.2, 17.6, 20.8 ]) A_M2 = 0.0054 DELTA_T = 60 # ==================== 参数计算函数 ==================== def calculate_parameters(data_32x32): """计算所有雨滴谱参数""" numerator_dm = 0.0 denominator_dm = 0.0 sum_nD2_V = 0.0 sum_nD3_V = 0.0 sum_nD4_V = 0.0 sum_nD6_V = 0.0 sum_n_V = 0.0 sum_D3_n = 0.0 sum_D2_n = 0.0 for i in range(32): D = DIAMETERS_MM[i] D2 = D ** 2 D3 = D ** 3 D4 = D ** 4 D6 = D ** 6 for j in range(32): V = VELOCITIES_MS[j] if V <= 0: continue n = data_32x32[i, j] if n > 0: numerator_dm += n * D4 / V denominator_dm += n * D3 / V sum_nD2_V += n * D2 / V sum_nD3_V += n * D3 / V sum_nD4_V += n * D4 / V sum_nD6_V += n * D6 / V sum_n_V += n / V sum_D3_n += D3 * n sum_D2_n += D2 * n # Dm Dm = numerator_dm / denominator_dm if denominator_dm > 0 else np.nan # μ_234 M2, M3, M4, M6 = sum_nD2_V, sum_nD3_V, sum_nD4_V, sum_nD6_V if M2 > 0 and M3 > 0 and M4 > 0: denom = M3 ** 2 - M4 * M2 mu_234 = (3 * M4 * M2 - 4 * M3 ** 2) / denom if abs(denom) > 1e-12 else np.nan else: mu_234 = np.nan # μ_346 if M3 > 0 and M4 > 0 and M6 > 0: G = (M4 ** 3) / (M3 ** 2 * M6) if abs(1 - G) > 1e-12: mu_346 = (11 * G - 8 + np.sqrt(G * (G + 8))) / (2 * (1 - G)) else: mu_346 = np.nan else: mu_346 = np.nan # Nw M3_SI = sum_nD3_V * 1e-9 / (A_M2 * DELTA_T) M4_SI = sum_nD4_V * 1e-12 / (A_M2 * DELTA_T) if M3_SI > 0 and M4_SI > 0: Nw = (256.0 / 6.0) * (M3_SI ** 5) / (M4_SI ** 4) * 1e-3 else: Nw = np.nan # Nt Nt = sum_n_V / (A_M2 * DELTA_T) # R_rain R_rain = (6 * np.pi * 1e-4) / (A_M2 * DELTA_T) * sum_D3_n # R_snow R_snow = (1.02 * 1e-4 * np.pi) / (A_M2 * DELTA_T) * sum_D2_n return { 'Dm': Dm, 'mu_234': mu_234, 'mu_346': mu_346, 'Nw': Nw, 'Nt': Nt, 'R_rain': R_rain, 'R_snow': R_snow } # ==================== 文件读取函数 ==================== def read_data_file(input_file): """读取数据文件,返回时间戳列表和数据矩阵列表""" timestamps = [] data_matrices = [] current_data = [] current_timestamp = None timestamp_pattern = re.compile(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$') with open(input_file, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if timestamp_pattern.match(line): if current_data and len(current_data) == 32 and current_timestamp: data_matrices.append(np.array(current_data, dtype=float)) timestamps.append(current_timestamp) current_timestamp = line current_data = [] elif line and any(c.isdigit() for c in line): try: row_data = list(map(float, line.split())) if len(row_data) == 32: current_data.append(row_data) except: pass elif not line and current_data: if len(current_data) == 32 and current_timestamp: data_matrices.append(np.array(current_data, dtype=float)) timestamps.append(current_timestamp) current_timestamp = None current_data = [] # 处理最后一个分钟 if current_data and len(current_data) == 32 and current_timestamp: data_matrices.append(np.array(current_data, dtype=float)) timestamps.append(current_timestamp) return timestamps, data_matrices # ==================== 批量处理函数 ==================== def batch_process(input_dir, output_dir): """批量处理目录下所有txt文件""" # 创建输出目录 if not os.path.exists(output_dir): os.makedirs(output_dir) # 查找所有txt文件 txt_files = glob.glob(os.path.join(input_dir, "*.txt")) if not txt_files: print(f"在 {input_dir} 中没有找到txt文件") return print(f"\n找到 {len(txt_files)} 个数据文件") print("=" * 60) total_files = 0 total_minutes = 0 for idx, input_file in enumerate(txt_files, 1): base_name = os.path.basename(input_file) name_without_ext = os.path.splitext(base_name)[0] output_csv = os.path.join(output_dir, f"{name_without_ext}_parameters.csv") # print(f"\n[{idx}/{len(txt_files)}] 处理: {base_name}") try: # 读取数据 timestamps, data_matrices = read_data_file(input_file) if not timestamps: # print(f" 警告: 没有读取到有效数据,跳过") continue # print(f" 读取到 {len(timestamps)} 个时间戳") # 计算所有参数 all_results = [] for timestamp, data_matrix in zip(timestamps, data_matrices): if data_matrix.shape != (32, 32): continue results = calculate_parameters(data_matrix) all_results.append({ 'timestamp': timestamp, **results }) # 保存CSV fieldnames = ['time', 'Dm', 'mu_234', 'mu_346', 'Nw', 'Nt', 'R_rain', 'R_snow'] with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for result in all_results: row = { 'time': result['timestamp'], 'Dm': f"{result['Dm']:.6f}" if not np.isnan(result['Dm']) else 'NaN', 'mu_234': f"{result['mu_234']:.6f}" if not np.isnan(result['mu_234']) else 'NaN', 'mu_346': f"{result['mu_346']:.6f}" if not np.isnan(result['mu_346']) else 'NaN', 'Nw': f"{result['Nw']:.6e}" if not np.isnan(result['Nw']) else 'NaN', 'Nt': f"{result['Nt']:.2f}", 'R_rain': f"{result['R_rain']:.6f}", 'R_snow': f"{result['R_snow']:.6f}" } writer.writerow(row) total_files += 1 total_minutes += len(timestamps) # print(f" 输出: {os.path.basename(output_csv)}") except Exception as e: print(f" 错误: {e}") # 打印汇总 print("\n" + "=" * 60) print("批量计算完成!") print("=" * 60) print(f"处理文件数: {total_files}") print(f"总共处理分钟数: {total_minutes}") print(f"输出目录: {output_dir}") print("=" * 60) # ==================== 主函数 ==================== if __name__ == "__main__": # ==================== 配置路径 ==================== input_dir = 'D:/lianxi/cleaned/' # 数据文件所在目录 output_dir = 'D:/lianxi/parameters/' # 参数CSV输出目录 print("=" * 60) print("雨滴谱参数批量计算程序") print("=" * 60) print("计算参数:") print(" - Dm: 质量加权平均直径 (mm)") print(" - μ_234: 从2、3、4阶矩计算的谱形状参数") print(" - μ_346: 从3、4、6阶矩计算的谱形状参数") print(" - Nw: 归一化截距参数 (mm⁻¹·m⁻³)") print(" - Nt: 总粒子数浓度 (m⁻³)") print(" - R_rain: 雨强 (mm/h)") print(" - R_snow: 雪强 (mm/h)") print("=" * 60) print(f"输入目录: {input_dir}") print(f"输出目录: {output_dir}") print("=" * 60) try: batch_process(input_dir, output_dir) except Exception as e: print(f"处理过程中出现错误: {e}") import traceback traceback.print_exc()

浙公网安备 33010602011771号