1. 项目缘起:为什么要复刻F-14的CADC?
如果你对航空电子、老式军用计算机或者FPGA开发感兴趣,那么“F-14雄猫战斗机的中央大气数据计算机”这个名词,很可能曾让你心头一热。CADC,全称Central Air Data Computer,是上世纪六七十年代航空电子领域的一个工程奇迹。它没有使用任何现代意义上的微处理器,却凭借一套精密的模拟计算机和机械计算装置,实时解算着飞行中最关键的参数:空速、马赫数、气压高度、攻角、大气温度,并将这些数据分发给火控、飞控和显示系统。在那个数字计算资源极其匮乏的年代,它用一套极其巧妙的机械-模拟混合设计,达到了令人惊叹的可靠性和实时性。
那么,在今天这个动辄GHz主频、多核SoC和强大FPGA的时代,我们为什么还要回头去复刻这样一个“古董”?这绝不是简单的怀旧。对我而言,这个项目的吸引力在于几个层面:首先是工程美学。CADC的设计是“形式追随功能”的极致体现,其机械凸轮、伺服电机和模拟电路构成的解算逻辑,本身就是一部精密的物理“算法”教科书。理解它,就像在阅读一首用钢铁和铜线写成的诗歌。其次是技术挑战。用完全不同的技术栈(数字逻辑、FPGA)去精确模拟一个模拟-机械系统的行为,这本身就是一个绝佳的跨领域工程实践。你需要深入理解原始系统的物理模型,然后将其“翻译”成时钟驱动的数字逻辑,这其中涉及到的定点数运算、非线性函数拟合(比如用查找表模拟机械凸轮的特性曲线)、闭环控制仿真,都是对数字设计功底的考验。最后是教育意义。通过这个项目,你能亲手触摸到从连续物理世界到离散数字世界的桥梁,理解经典控制理论如何被硬件实现,这对于深化对嵌入式系统、实时系统乃至计算机体系结构的理解,有着无可替代的价值。
所以,这个“Recreating the F14 CADC”项目,目标不是造一个能飞的真家伙,而是用现代的数字硬件描述语言(如VHDL/Verilog),在FPGA上构建一个功能与原始CADC等效的数字仿真核心。它接收模拟的传感器输入(在测试平台中用数字量代替),经过一系列计算,输出与原系统一致的数据。这是一个纯粹的硬件逻辑设计项目,一场与四十年前工程师的隔空对话。
2. 核心架构解析:从机械凸轮到数字逻辑
原始的F-14 CADC是一个混合系统。要复刻它,我们必须先充当“逆向工程师”,拆解它的功能模块和信息流。虽然无法获得详细的军方原理图,但根据公开的文档、专利和爱好者社区的研究,我们可以勾勒出其核心计算链。
2.1 原始CADC的工作流程与核心算法
CADC的核心输入来自飞机上的几个关键传感器:
- 全压和静压:通过皮托管和静压孔获取,用于计算气压高度和指示空速。
- 总温探头:测量气流的总温( stagnation temperature)。
- 攻角传感器:测量机翼相对于气流的夹角。
它的核心输出包括:
- 马赫数(Mach Number)
- 真实空速(True Airspeed)
- 气压高度(Pressure Altitude)
- 大气静温(Static Air Temperature)
- 真实攻角(True Angle of Attack)
其计算的核心是一系列基于流体力学和大气物理的方程,其中很多是非线性的。例如,马赫数与动压(全压-静压)和静压的比值存在复杂的函数关系。在原始CADC中,这些非线性函数是通过精心设计和加工的机械凸轮(Mechanical Cam)来实现的。凸轮的轮廓就是函数的几何表达,一个伺服电机驱动凸轮旋转,探针随着凸轮轮廓移动,将输入量的旋转角度(或线性位移)转换为输出量的位移,完美地实现了模拟计算。
2.2 数字复刻的架构映射
我们的FPGA设计,就是要用数字模块一一替代这些物理部件。整体架构可以规划如下:
[FPGA内部数字CADC架构框图] 外部模拟输入 (在Testbench中用数字量模拟) | v [ADC接口仿真模块] --> [传感器数据校准与滤波] (数字滤波器,替代模拟电路的噪声处理) | v |-----------------------|-----------------------| v v v [气压解算通道] [温度解算通道] [攻角解算通道] | | | v v v [静压/动压处理] [总温/静温转换] [攻角补偿计算] | | | v v v [马赫数计算LUT] <--------[大气模型参数] | | | | v v v [真实空速计算LUT] [静温输出] [真实攻角输出] | | | v v v [气压高度计算LUT] | | | | | v v v |-----------------------|-----------------------| | v [输出格式化与接口模块] | v (SPI, UART, Parallel Bus等)关键模块的数字化实现思路:
非线性函数(替代机械凸轮):这是核心。我们将使用查找表(LUT, Look-Up Table)来实现。具体步骤是:
- 建模:根据公开的空气动力学公式,在MATLAB或Python中高精度计算出输入-输出对应关系,生成数据对。
- 量化与定点化:确定输入输出的数据位宽和定点数格式(例如Q格式)。例如,马赫数范围0-2.0,用16位有符号定点数,Q8.8格式(8位整数,8位小数)可能足够。
- 生成LUT:将计算好的数据对写入FPGA的Block RAM或分布式RAM中。输入值作为地址,输出值作为存储的数据。
- 插值(可选):为了节省存储空间,可以存储较稀疏的表,然后使用线性插值或多项式插值在相邻点之间计算输出,这比直接模拟凸轮的连续平滑性,但精度可控。
伺服环路与积分(替代伺服电机):原始系统中可能包含用于求解某些微分方程或实现积分的伺服环路。在数字域,我们可以用数字积分器(例如累加器)或数字滤波器(如IIR滤波器)来替代。例如,计算气压高度时,需要对静压变化率进行积分,数字实现就是一个在固定时钟周期内对压差进行累加的过程。
传感器接口:在真实世界中,这些是模拟信号。在我们的FPGA测试环境中,我们需要创建一个仿真传感器模块(Testbench中的驱动部分),它按照一定的物理模型(例如飞机爬升、加速的模型)来生成数字化的“传感器读数”,提供给我们的CADC核心。
3. 开发环境与工具链选型
工欲善其事,必先利其器。对于这样一个涉及复杂算法和硬件描述的项目,工具选型直接影响开发效率和最终成果的可靠性。
3.1 FPGA平台选择
我们不需要追求极致的性能或逻辑规模,因为这个CADC核心的计算复杂度以今天的标准来看并不高。选择应侧重于易用性、社区支持和成本。
- Xilinx Artix-7系列(如Basys 3, Arty A7):这是非常理想的选择。它们逻辑资源适中,拥有足够的Block RAM和DSP切片来处理我们的定点乘加和LUT,价格相对低廉,且被Xilinx(现AMD)的Vivado工具链良好支持。Basys 3开发板还自带VGA、USB等接口,便于我们后期实现可视化输出。
- Intel (Altera) Cyclone IV/V系列(如DE10-Lite, DE0-CV):同样是入门到中级的优选。Quartus Prime工具链成熟,逻辑资源足够。DE10-Lite板载ADC和丰富IO,如果未来想接入真实模拟传感器进行半实物仿真,会更有优势。
- Lattice iCE40或ECP5系列:如果你追求极致的成本或低功耗,这是一个有趣的选择。但高端工具链可能不如前两者普及,对于初学者可能会增加门槛。
我的选择与理由:我个人倾向于Xilinx Artix-7平台,具体是Digilent的Arty A7-35T开发板。理由如下:1) Vivado Design Suite功能强大,集成度高,从仿真、综合到布局布线一体完成,对VHDL/Verilog支持都很好。2) Artix-7的架构(如Slice, BRAM, DSP48E1)非常经典,学习资料丰富。3) Arty A7板载了Pmod接口、以太网、USB-UART,扩展性很好,方便未来添加外部显示或通信模块来输出计算结果。
3.2 硬件描述语言(HDL)选择:VHDL vs. SystemVerilog
这是另一个经典之争。结合“相关热搜词”中频繁出现VHDL,以及项目本身的“复古”气质,我推荐使用VHDL。
- VHDL:语法更严格,类型系统更强,类似于Ada语言。它强制工程师更严谨地思考电路结构,对并发行为的描述非常精确。对于CADC这种高度并行、数据流清晰的设计,VHDL的
process、signal和严格的类型转换,能很好地帮助构建一个结构清晰、易于维护的模型。尤其当我们需要精确描述寄存器传输级(RTL)的时序行为时,VHDL的严谨性是个优势。 - SystemVerilog:更侧重于验证,在设计层面语法更灵活、简洁,类似C语言,学习曲线可能更平缓。但对于一个以教育和精准复现为目标的项目,VHDL的“学院派”风格可能更契合。
我的实操心得:如果你之前主要用Verilog/SystemVerilog,尝试VHDL会是一次很好的拓展。你可以用VHDL编写核心算法模块(如LUT、定点点运算单元),确保其行为的确定性和可综合性。而对于复杂的测试平台(Testbench),则可以发挥SystemVerilog在验证方面的优势,利用其随机关束、功能覆盖率等特性进行充分验证。Vivado同时支持两者,可以混合使用。
3.3 关键开发工具与流程
设计输入与仿真:
- Vivado / Quartus Prime:用于主要的RTL编码、综合、实现和比特流生成。它们的内置文本编辑器足够好用。
- 仿真工具:Vivado自带的XSim或QuestaSim等第三方工具。强烈建议在编写任何可综合代码前,先搭建一个完整的测试平台(Testbench)。在这个项目中,Testbench将扮演“虚拟天空”的角色,模拟飞机在各种飞行剖面下的传感器数据变化。
算法建模与验证:
- MATLAB / Python (NumPy, SciPy):这是不可或缺的前期工具。你需要在这里完成所有空气动力学公式的推导、计算,生成LUT的原始数据,并对比数字计算结果与理论值的误差。可以先用浮点数实现一个“黄金参考模型”,然后用它来验证你的定点化VHDL模型输出是否正确。
版本控制:
- Git:必须使用。为项目建立Git仓库,管理VHDL源码、Testbench、约束文件(XDC)、脚本和文档。清晰的提交信息能让你在调试复杂问题时回溯历史。
4. RTL设计与实现:从公式到门电路
这是最具挑战也最有趣的部分。我们将把理论模型转化为实际的硬件描述。这里以“马赫数计算”这个核心通道为例,拆解设计过程。
4.1 数据表示与定点数运算
原始CADC处理的是连续模拟量,我们处理的是离散数字量。第一步是确定数据的“数字格式”。
- 精度分析:根据F-14的飞行包线,确定各物理量的范围。例如,马赫数范围0-2.5,静压范围可能从海平面101325 Pa到高空数千帕。我们需要为每个信号分配合适的位宽。
- 定点数格式(Q格式):浮点数运算在FPGA中消耗资源多、速度慢(除非用硬核或DSP)。对于实时性要求高、范围确定的系统,定点数是更高效的选择。例如,我们定义马赫数为
Q8.8格式(16位有符号),那么数值1.5在硬件中表示为1.5 * 2^8 = 384(十进制)或0x0180(十六进制)。加减法直接进行,乘法则需要结果移位调整。
-- 示例:VHDL中定义定点数类型和乘法操作(简化) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- 必须使用这个库进行数值运算 entity fixed_point_mult is port ( a : in signed(15 downto 0); -- Q8.8 b : in signed(15 downto 0); -- Q8.8 p : out signed(31 downto 0) -- 乘积,需要调整 ); end entity; architecture rtl of fixed_point_mult is signal product_full : signed(31 downto 0); begin product_full <= a * b; -- 结果为 Q16.16 p <= product_full(23 downto 0) & "00000000"; -- 右移8位,取合适的位宽输出,例如Q8.8或Q16.8,这里需要根据实际需求调整 -- 更严谨的做法是定义一个函数来进行定点数乘法 end architecture;注意:定点数运算最易出错的地方是溢出和精度损失。必须在设计初期就做好最坏情况下的位宽分析,并在仿真中刻意测试边界值。
4.2 查找表(LUT)模块的实现
我们用LUT替代机械凸轮。假设我们已经用Python算好了马赫数Mach = f(P_total, P_static)的对应表,并将其存储为ROM。
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity mach_lut is port ( clk : in std_logic; rst : in std_logic; -- 输入:动压比(或经过处理的地址),假设用10位地址寻址1K深度的LUT pressure_ratio_index : in unsigned(9 downto 0); -- 输出:马赫数,Q8.8格式 mach_number : out signed(15 downto 0) ); end entity; architecture rtl of mach_lut is -- 定义ROM类型并初始化数据 type rom_type is array (0 to 1023) of signed(15 downto 0); -- 如何初始化?数据需要预先计算好。 -- 方法1:在VHDL2008中可以用外部文件读取。 -- 方法2(更通用):使用Vivado的COE文件或Quartus的MIF文件,在综合时由工具初始化BRAM。 -- 这里为示例,使用一个函数生成(实际项目应从文件加载) function init_rom return rom_type is variable rom : rom_type; begin for i in rom'range loop -- 这里应填入真实计算出的值,示例为线性填充 rom(i) := to_signed(i * 64, 16); -- 假设转换 end loop; return rom; end function; signal rom : rom_type := init_rom; begin process(clk) begin if rising_edge(clk) then if rst = '1' then mach_number <= (others => '0'); else -- 同步读取,延迟一个时钟周期 mach_number <= rom(to_integer(pressure_ratio_index)); end if; end if; end process; end architecture;在实际工程中,我们不会在代码里硬编码数据,而是使用工具特性。在Vivado中,你可以创建一个单端口ROM IP核,选择“Load Init File”,然后提供一个COE格式的文件,其中就存放着你用Python/Matlab生成好的定点数数据。这样更专业,也便于数据更新。
4.3 时序与流水线设计
CADC是实时系统,我们的FPGA设计也必须满足吞吐率和延迟要求。虽然原始系统是并行的模拟计算,几乎没有“时钟”概念,但我们的数字系统是时钟驱动的。
- 流水线化:将计算链条拆分成多个阶段。例如:传感器数据同步 -> 校准滤波 -> 计算中间变量1 -> LUT查询1 -> 计算中间变量2 -> LUT查询2 -> 输出格式化。每个阶段用一个寄存器组隔开,在同一个时钟沿下,数据像流水一样依次通过各个阶段。
- 好处:提高了系统的吞吐率(每个时钟周期都能输出一个结果),同时允许每个阶段的工作在一个时钟周期内完成,从而可以运行在更高的时钟频率上。
- 代价:引入了固定的计算延迟(Latency),比如从输入到输出需要5个时钟周期。对于闭环控制这可能是个问题,但对于CADC这种开环计算并广播数据的系统,几个微秒的延迟是完全可接受的。
我的踩坑记录:在最初设计时,我曾试图在一个复杂的组合逻辑进程里完成所有计算。这导致综合后路径延迟过长,最大时钟频率(Fmax)很低。后来我将计算拆分成三级流水线,Fmax立刻提升到了100MHz以上。教训是:对于复杂的数字信号处理路径,尽早规划流水线结构,这是提高性能的关键。
5. 仿真验证:构建“虚拟天空”测试平台
硬件设计的生命线是验证。在生成比特流烧录到板子之前,我们必须通过仿真确保逻辑正确。对于CADC项目,Testbench的设计几乎和核心设计一样重要。
5.1 Testbench的架构
我们的Testbench需要模拟一个动态的飞行环境。它可以分为几个部分:
- 飞行剖面生成器:一个用VHDL或SystemVerilog写的模块,按照预设的剧本(如起飞、爬升、巡航、机动、降落)实时生成“真实”的全压、静压、总温等物理量。这些值可以用浮点数计算,然后量化成我们设计所期望的输入格式。
- 被测设计(DUT)实例化:就是我们的CADC核心。
- 黄金参考模型:同样用高级语言(如SystemVerilog的real类型,或通过DPI调用C/Matlab模型)实现的一个浮点数精度模型。它接收同样的“真实”物理量输入,用双精度浮点计算出期望的输出结果。
- 比较器与记分板:将DUT的输出与黄金模型的输出进行比较,允许一定的误差(由定点化精度决定),并报告通过/失败。同时可以记录整个飞行过程中的数据,用于后期绘制波形图分析。
// 一个简化的SystemVerilog Testbench结构示例 module tb_cadc(); logic clk, rst_n; logic [15:0] sim_p_total, sim_p_static; // 模拟传感器输入 logic [15:0] dut_mach; // DUT输出 real gold_mach; // 黄金模型输出 // 时钟生成 initial begin clk = 0; forever #5 clk = ~clk; // 100MHz时钟 end // 复位生成 initial begin rst_n = 0; #100 rst_n = 1; end // 飞行剖面生成器 flight_profile profile_inst ( .clk(clk), .rst_n(rst_n), .p_total(sim_p_total), .p_static(sim_p_static) // ... 其他传感器 ); // 实例化DUT (VHDL模块) cadc_top dut_inst ( .i_clk(clk), .i_rst_n(rst_n), .i_p_total(sim_p_total), .i_p_static(sim_p_static), .o_mach(dut_mach) // ... 其他端口 ); // 黄金参考模型 (可以用SV real类型简单实现) always @(posedge clk) begin if (rst_n) begin // 将定点输入转换为real进行计算 real p_total_real = $itor(sim_p_total) / 256.0; // 假设Q8.8 real p_static_real = $itor(sim_p_static) / 256.0; // 调用计算马赫数的函数(此处省略具体函数) gold_mach = calculate_mach(p_total_real, p_static_real); end end // 比较器 real error; always @(posedge clk) begin if (rst_n) begin error = $itor(dut_mach)/256.0 - gold_mach; if (abs(error) > 0.01) begin // 设定误差阈值,例如0.01马赫 $display("ERROR at time %t: DUT Mach=%f, Gold Mach=%f, Error=%f", $time, $itor(dut_mach)/256.0, gold_mach, error); end end end // 波形记录和测试结束 initial begin $dumpfile("cadc_wave.vcd"); $dumpvars(0, tb_cadc); #1000000 $finish; // 模拟一段时间的飞行 end endmodule5.2 测试用例设计
不能只做“正常飞行”测试。必须设计边界和极端用例:
- 静态测试:输入一组固定的标准大气压值(如海平面),验证输出是否与标准表一致。
- 动态扫频测试:让输入压力、温度等参数在一定范围内匀速变化,观察输出曲线是否平滑,有无跳变(可能由LUT地址突变或定点数溢出引起)。
- 阶跃响应测试:瞬间改变某个输入(如静压模拟快速爬升),观察系统的响应时间和瞬态过程。数字系统应该是立即跳变(取决于流水线延迟),而原始模拟系统可能有惯性延迟,这里我们验证的是数字逻辑的正确性,而非动态特性匹配。
- 故障注入测试:模拟传感器故障,如输入全0、全1或超出量程的值,检查设计是否有合理的处理(如饱和输出或报错标志)。
我的实操心得:仿真初期,我花了大量时间调试Testbench本身。一个常见错误是时序未对齐:黄金模型是零延迟的组合逻辑计算,而DUT有N个时钟周期的流水线延迟。比较时,必须将黄金模型的输出也延迟相应的周期再进行比较。使用SystemVerilog的#delay或队列可以方便地实现这一点。另外,将仿真波形(如VCD文件)导入GTKWave或Vivado仿真器,直观对比DUT和黄金模型的信号曲线,是定位问题最快的方法。
6. 综合、实现与板级调试
当仿真信心十足后,就可以进入硬件实现阶段了。
6.1 约束文件编写
这是将设计映射到实际FPGA引脚和时钟资源的关键一步。一个.xdc(Vivado)或.sdc(Quartus)文件至少包含:
- 时钟约束:定义输入时钟的频率和不确定性。
# Vivado XDC 示例 create_clock -period 10.000 -name sys_clk [get_ports i_clk] set_input_jitter sys_clk 0.150 - I/O约束:如果你有实际的外部输入(如按键、ADC)或输出(如LED、七段数码管、VGA),需要在这里指定引脚编号和I/O标准。
set_property PACKAGE_PIN E3 [get_ports {o_leds[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {o_leds[0]}] - 时序例外:如果有跨时钟域路径,需要设置
set_false_path或set_clock_groups。
对于我们这个项目,如果前期只用Testbench仿真,可能暂时不需要外部I/O约束,但时钟约束是必须的。
6.2 综合与实现报告分析
运行综合和实现(Place & Route)后,工具会生成报告,必须仔细阅读:
- 资源利用率:查看LUT、FF、BRAM、DSP的用量。确保没有超过目标器件的80%,为后续修改留有余地。
- 时序报告:这是重中之重。检查是否满足所有时序约束(建立时间、保持时间)。重点关注WNS(Worst Negative Slack)和WHS。如果WNS为负,说明有路径不满足时序,需要优化。对于我们的设计,可能是某级组合逻辑太长,需要进一步打拍流水。
- 功耗报告:了解设计的静态和动态功耗,虽然对这个项目通常不是问题。
6.3 板级验证与调试
生成比特流并下载到FPGA后,真正的乐趣才开始。由于我们没有真实的飞机传感器,板级验证需要创造性地进行:
- 软核CPU协同:可以在FPGA里实例化一个软核处理器(如Xilinx MicroBlaze或RISC-V),通过AXI总线与我们的CADC模块通信。软核上运行一个简单的C程序,它可以模拟飞行剖面,通过总线将数据写入CADC模块的输入寄存器,并读取结果寄存器,通过串口打印到电脑上。这比纯Testbench更接近真实情况。
- 外部输入模拟:利用开发板上的拨码开关、按钮和ADC(如果板载),可以手动或通过电位器设置简单的输入值,观察输出LED或数码管的显示是否合理。
- ILA(集成逻辑分析仪):这是FPGA调试的神器。Vivado和Quartus都支持将ILA IP核插入到设计中,可以像示波器一样实时抓取内部信号(如计算中间值、状态机状态)并上传到电脑显示。当板子行为与仿真不符时,ILA是定位问题的终极手段。你可以触发在特定条件下(如某个输入超过阈值)捕获数据。
踩坑实录:第一次上板调试:仿真一切正常,但下载到板子后,输出数据全乱。用ILA抓取发现,输入寄存器的值根本没有变化。排查后发现,是Testbench中的复位信号是低有效(rst_n),而我在顶层端口定义时错误地连成了高有效。在仿真中,我的Testbench驱动了正确的复位,但板子上实际的复位按钮连接的是低有效信号,导致设计一直处于复位状态。教训:严格检查顶层端口的极性(高有效/低有效)与物理约束文件、硬件原理图是否一致。最好在代码中使用异步复位、同步释放的标准化复位处理模块。
7. 项目总结与延伸思考
完成一个基本可工作的FPGA版CADC核心,只是这个项目的起点。它为我们打开了一扇门,通向更多有趣的延伸方向:
7.1 性能与精度优化
- 更高精度定点数或浮点:如果资源允许,可以尝试使用单精度浮点数IP核来实现核心计算,对比与定点数方案在精度和资源上的权衡。
- 更智能的LUT压缩:研究使用非线性寻址或插值算法,在保证精度的前提下减少BRAM消耗。
- 多速率处理:不同物理量的更新率可能不同。可以引入时钟使能或更复杂的时钟域,优化功耗和性能。
7.2 系统集成与可视化
- 添加显示接口:用VGA或HDMI IP核,在显示器上实时绘制高度表、空速表、马赫数表等虚拟仪表盘,让输出更直观。
- 添加通信接口:实现UART、SPI或Ethernet,将计算数据发送给上位机(如PC上的飞行模拟软件),实现硬件在环(HIL)仿真。
- 与开源飞控结合:作为一个有趣的设想,可以将这个CADC模块的输出,提供给一个基于FPGA或高性能MCU的开源飞控系统,虽然F-14的飞控律是保密的,但可以尝试实现一些基本的控制逻辑。
7.3 从复现到创新
理解旧技术是为了创造新技术。通过这个项目,你深刻掌握了:
- 复杂系统分解:如何将一个黑盒系统分解为可实现的模块。
- 跨领域建模:如何将物理世界的连续方程转化为离散的数字模型。
- 硬件算法设计:如何用资源、速度和精度这三大要素来权衡和实现一个算法。
- 严谨的验证方法学:从算法参考模型到RTL仿真,再到板级调试的完整链条。
这些技能,正是设计现代高性能数字信号处理系统、自动驾驶感知单元或任何需要将复杂物理模型硬件化的系统的核心能力。复刻F-14 CADC,就像一位程序员通过重写经典的Unix内核来学习操作系统原理一样,是一次极其扎实的“练功”。当你看到自己编写的VHDL代码,在FPGA上忠实地复现出半个世纪前工程师用齿轮和电路实现的精妙计算时,那种跨越时空的技术共鸣感,无疑是这个项目带来的最大奖赏。