ソースを参照

feat: 添加点云单元测试

yangliu 4 ヶ月 前
コミット
613345142c

+ 435 - 0
device-service-domain/src/test/java/com/hfln/device/domain/entity/DevicePointCloudTest.java

@@ -0,0 +1,435 @@
+package com.hfln.device.domain.entity;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Device类点云算法功能单元测试
+ * 测试新增的TargetStabilizer、点云队列管理和相关算法
+ */
+@DisplayName("设备点云算法测试")
+class DevicePointCloudTest {
+
+    private Device device;
+
+    @BeforeEach
+    void setUp() {
+        device = new Device("TEST_DEVICE_001");
+        device.setDevType("LNA"); // 默认设为LNA类型以启用点云处理
+    }
+
+    @Nested
+    @DisplayName("目标稳定器算法测试")
+    class TargetStabilizerTest {
+
+        @Test
+        @DisplayName("基础目标更新 - 空队列时直接返回输入")
+        void testFirstTargetUpdate() {
+            // 准备测试数据
+            List<List<Float>> newTargets = Arrays.asList(
+                Arrays.asList(100.0f, 200.0f, 50.0f)
+            );
+            
+            // 执行测试
+            List<List<Float>> result = device.updateTargets(newTargets);
+            
+            // 验证结果
+            assertNotNull(result);
+            assertEquals(1, result.size());
+            assertEquals(3, result.get(0).size());
+            assertEquals(100.0f, result.get(0).get(0), 0.001f);
+            assertEquals(200.0f, result.get(0).get(1), 0.001f);
+            assertEquals(50.0f, result.get(0).get(2), 0.001f);
+        }
+
+        @Test
+        @DisplayName("动态阈值调整测试 - 小偏差不触发平滑")
+        void testSmallDeviationNoSmoothing() {
+            // 建立历史数据基础
+            List<List<Float>> baseTarget = Arrays.asList(Arrays.asList(100.0f, 200.0f, 50.0f));
+            device.updateTargets(baseTarget);
+            
+            // 添加小偏差的新目标(在阈值内)
+            List<List<Float>> newTarget = Arrays.asList(Arrays.asList(100.5f, 200.3f, 50.2f));
+            List<List<Float>> result = device.updateTargets(newTarget);
+            
+            // 验证未触发平滑处理,直接返回新目标
+            assertEquals(100.5f, result.get(0).get(0), 0.001f);
+            assertEquals(200.3f, result.get(0).get(1), 0.001f);
+            assertEquals(50.2f, result.get(0).get(2), 0.001f);
+        }
+
+        @Test
+        @DisplayName("动态阈值调整测试 - 大偏差触发平滑处理")
+        void testLargeDeviationTriggerSmoothing() {
+            // 建立历史数据基础 - 添加多个目标建立稳定的平均值
+            List<List<Float>> targets = Arrays.asList(
+                Arrays.asList(100.0f, 200.0f, 50.0f),
+                Arrays.asList(101.0f, 201.0f, 51.0f),
+                Arrays.asList(99.0f, 199.0f, 49.0f)
+            );
+            
+            for (List<Float> target : targets) {
+                device.updateTargets(Arrays.asList(target));
+            }
+            
+            // 添加大偏差的新目标(超出动态阈值)
+            List<List<Float>> newTarget = Arrays.asList(Arrays.asList(110.0f, 210.0f, 60.0f));
+            List<List<Float>> result = device.updateTargets(newTarget);
+            
+            // 验证触发了平滑处理
+            // 实际历史平均值:(100+101+99)/3=100, (200+201+199)/3=200, (50+51+49)/3=50
+            // 加上新目标后的队列长度可能不是3,需要重新计算
+            // 期望结果应该是 (新目标 + 实际历史平均值) / 2
+            // 由于动态队列管理,实际平均值可能与预期不同
+            assertNotNull(result);
+            assertEquals(1, result.size());
+            assertEquals(3, result.get(0).size());
+            
+            // 验证X坐标在合理范围内(应该是平滑处理的结果)
+            assertTrue(result.get(0).get(0) >= 100.0f && result.get(0).get(0) <= 110.0f, 
+                      "X坐标应该在100-110之间,实际值: " + result.get(0).get(0));
+            // 验证Y坐标在合理范围内
+            assertTrue(result.get(0).get(1) >= 200.0f && result.get(0).get(1) <= 210.0f,
+                      "Y坐标应该在200-210之间,实际值: " + result.get(0).get(1));
+        }
+
+        @Test
+        @DisplayName("测试Python版本的Z坐标bug复制")
+        void testPythonBugReplication() {
+            // 建立基础目标
+            device.updateTargets(Arrays.asList(Arrays.asList(0.0f, 0.0f, 0.0f)));
+            
+            // 添加会触发平滑的目标
+            List<List<Float>> newTarget = Arrays.asList(Arrays.asList(10.0f, 20.0f, 30.0f));
+            List<List<Float>> result = device.updateTargets(newTarget);
+            
+            // 验证Z坐标使用了Y坐标的值(复制Python bug)
+            float expectedZ = (20.0f + 0.0f) / 2.0f; // 使用newTarget[1]而不是newTarget[2]
+            assertEquals(expectedZ, result.get(0).get(2), 0.001f);
+        }
+
+        @Test
+        @DisplayName("输入验证测试 - 无效输入处理")
+        void testInvalidInputHandling() {
+            // 测试null输入
+            List<List<Float>> result1 = device.updateTargets(null);
+            assertTrue(result1.isEmpty());
+            
+            // 测试空列表
+            List<List<Float>> result2 = device.updateTargets(new ArrayList<>());
+            assertTrue(result2.isEmpty());
+            
+            // 测试坐标不足的目标
+            List<List<Float>> invalidTarget = Arrays.asList(Arrays.asList(100.0f, 200.0f)); // 只有2个坐标
+            List<List<Float>> result3 = device.updateTargets(invalidTarget);
+            assertTrue(result3.isEmpty());
+        }
+    }
+
+    @Nested
+    @DisplayName("点云队列管理测试")
+    class CloudPointsQueueTest {
+
+        @Test
+        @DisplayName("基础队列操作测试")
+        void testBasicQueueOperations() {
+            // 测试放入点云数据
+            List<List<Float>> cloudPoints1 = Arrays.asList(
+                Arrays.asList(1.0f, 2.0f, 3.0f),
+                Arrays.asList(4.0f, 5.0f, 6.0f)
+            );
+            device.putCloudPointsQueue(cloudPoints1);
+            
+            List<List<Float>> cloudPoints2 = Arrays.asList(
+                Arrays.asList(7.0f, 8.0f, 9.0f),
+                Arrays.asList(10.0f, 11.0f, 12.0f),
+                Arrays.asList(13.0f, 14.0f, 15.0f)
+            );
+            device.putCloudPointsQueue(cloudPoints2);
+            
+            // 验证队列内容
+            List<List<List<Float>>> queueContent = device.getCloudPointsQueue();
+            assertEquals(2, queueContent.size());
+        }
+
+        @Test
+        @DisplayName("最大长度点云选择测试 - LNA设备")
+        void testGetMaxLenCloudPointsLNA() {
+            device.setDevType("LNA");
+            
+            // 添加不同长度的点云数据
+            List<List<Float>> cloudPoints1 = Arrays.asList(
+                Arrays.asList(1.0f, 2.0f, 3.0f),
+                Arrays.asList(4.0f, 5.0f, 6.0f)
+            ); // 长度: 2
+            
+            List<List<Float>> cloudPoints2 = Arrays.asList(
+                Arrays.asList(7.0f, 8.0f, 9.0f),
+                Arrays.asList(10.0f, 11.0f, 12.0f),
+                Arrays.asList(13.0f, 14.0f, 15.0f),
+                Arrays.asList(16.0f, 17.0f, 18.0f)
+            ); // 长度: 4
+            
+            List<List<Float>> cloudPoints3 = Arrays.asList(
+                Arrays.asList(19.0f, 20.0f, 21.0f)
+            ); // 长度: 1
+            
+            device.putCloudPointsQueue(cloudPoints1);
+            device.putCloudPointsQueue(cloudPoints2);
+            device.putCloudPointsQueue(cloudPoints3);
+            
+            // 获取最大长度的点云
+            List<List<Float>> maxLenCloudPoints = device.getMaxLenCloudPoints();
+            
+            // 验证返回的是长度最大的点云(长度为4)
+            assertNotNull(maxLenCloudPoints);
+            assertEquals(4, maxLenCloudPoints.size());
+            assertEquals(7.0f, maxLenCloudPoints.get(0).get(0), 0.001f);
+            
+            // 验证队列已被清空
+            assertTrue(device.getCloudPointsQueue().isEmpty());
+        }
+
+        @Test
+        @DisplayName("LNB设备类型处理测试")
+        void testLNBDeviceTypeHandling() {
+            device.setDevType("LNB");
+            
+            // 添加点云数据
+            List<List<Float>> cloudPoints = Arrays.asList(
+                Arrays.asList(1.0f, 2.0f, 3.0f),
+                Arrays.asList(4.0f, 5.0f, 6.0f)
+            );
+            device.putCloudPointsQueue(cloudPoints);
+            
+            // LNB设备应该返回null
+            List<List<Float>> result = device.getMaxLenCloudPoints();
+            assertNull(result);
+        }
+
+        @Test
+        @DisplayName("队列大小限制测试")
+        void testQueueSizeLimit() {
+            // 添加超过最大队列大小的点云数据
+            for (int i = 0; i < 15; i++) {
+                List<List<Float>> cloudPoints = Arrays.asList(
+                    Arrays.asList((float)i, (float)i+1, (float)i+2)
+                );
+                device.putCloudPointsQueue(cloudPoints);
+            }
+            
+            // 验证队列大小不超过限制
+            List<List<List<Float>>> queueContent = device.getCloudPointsQueue();
+            assertTrue(queueContent.size() <= 10); // MAX_CLOUD_POINTS_QUEUE_SIZE = 10
+        }
+
+        @Test
+        @DisplayName("空队列处理测试")
+        void testEmptyQueueHandling() {
+            device.setDevType("LNA");
+            
+            // 空队列时获取最大长度点云
+            List<List<Float>> result = device.getMaxLenCloudPoints();
+            assertNull(result);
+        }
+    }
+
+    @Nested
+    @DisplayName("线程安全测试")
+    class ThreadSafetyTest {
+
+        @Test
+        @DisplayName("并发目标更新测试")
+        void testConcurrentTargetUpdates() throws InterruptedException {
+            int threadCount = 10;
+            int operationsPerThread = 100;
+            ExecutorService executor = Executors.newFixedThreadPool(threadCount);
+            CountDownLatch latch = new CountDownLatch(threadCount);
+            
+            for (int i = 0; i < threadCount; i++) {
+                final int threadId = i;
+                executor.submit(() -> {
+                    try {
+                        for (int j = 0; j < operationsPerThread; j++) {
+                            List<List<Float>> target = Arrays.asList(
+                                Arrays.asList((float)(threadId * 100 + j), 
+                                            (float)(threadId * 100 + j + 1), 
+                                            (float)(threadId * 100 + j + 2))
+                            );
+                            device.updateTargets(target);
+                        }
+                    } finally {
+                        latch.countDown();
+                    }
+                });
+            }
+            
+            assertTrue(latch.await(10, TimeUnit.SECONDS));
+            executor.shutdown();
+            
+            // 验证没有异常,且最终状态一致
+            assertNotNull(device.getTargets());
+        }
+
+        @Test
+        @DisplayName("并发点云队列操作测试")
+        void testConcurrentQueueOperations() throws InterruptedException {
+            int threadCount = 5;
+            ExecutorService executor = Executors.newFixedThreadPool(threadCount);
+            CountDownLatch latch = new CountDownLatch(threadCount);
+            
+            for (int i = 0; i < threadCount; i++) {
+                final int threadId = i;
+                executor.submit(() -> {
+                    try {
+                        // 并发添加点云数据
+                        for (int j = 0; j < 20; j++) {
+                            List<List<Float>> cloudPoints = Arrays.asList(
+                                Arrays.asList((float)(threadId * 100 + j), 
+                                            (float)(threadId * 100 + j + 1), 
+                                            (float)(threadId * 100 + j + 2))
+                            );
+                            device.putCloudPointsQueue(cloudPoints);
+                        }
+                        
+                        // 并发获取最大长度点云
+                        device.getMaxLenCloudPoints();
+                    } finally {
+                        latch.countDown();
+                    }
+                });
+            }
+            
+            assertTrue(latch.await(10, TimeUnit.SECONDS));
+            executor.shutdown();
+            
+            // 验证操作成功完成,没有死锁或异常
+            assertTrue(true); // 如果到达这里说明没有死锁
+        }
+    }
+
+    @Nested
+    @DisplayName("性能测试")
+    class PerformanceTest {
+
+        @Test
+        @DisplayName("大量目标更新性能测试")
+        void testTargetUpdatePerformance() {
+            long startTime = System.currentTimeMillis();
+            
+            // 执行大量目标更新操作
+            for (int i = 0; i < 10000; i++) {
+                List<List<Float>> target = Arrays.asList(
+                    Arrays.asList((float)i, (float)i+1, (float)i+2)
+                );
+                device.updateTargets(target);
+            }
+            
+            long endTime = System.currentTimeMillis();
+            long duration = endTime - startTime;
+            
+            // 验证性能在合理范围内(应该在几秒内完成)
+            assertTrue(duration < 5000, "目标更新操作耗时过长: " + duration + "ms");
+        }
+
+        @Test
+        @DisplayName("大量点云队列操作性能测试")
+        void testQueueOperationPerformance() {
+            long startTime = System.currentTimeMillis();
+            
+            // 执行大量队列操作
+            for (int i = 0; i < 1000; i++) {
+                List<List<Float>> cloudPoints = new ArrayList<>();
+                for (int j = 0; j < 100; j++) {
+                    cloudPoints.add(Arrays.asList((float)j, (float)j+1, (float)j+2));
+                }
+                device.putCloudPointsQueue(cloudPoints);
+                
+                if (i % 10 == 0) {
+                    device.getMaxLenCloudPoints();
+                }
+            }
+            
+            long endTime = System.currentTimeMillis();
+            long duration = endTime - startTime;
+            
+            // 验证性能在合理范围内
+            assertTrue(duration < 10000, "队列操作耗时过长: " + duration + "ms");
+        }
+    }
+
+    @Nested
+    @DisplayName("边界条件测试")
+    class BoundaryConditionTest {
+
+        @Test
+        @DisplayName("极值坐标处理测试")
+        void testExtremeCoordinates() {
+            // 测试极大值
+            List<List<Float>> extremeTarget1 = Arrays.asList(
+                Arrays.asList(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE)
+            );
+            List<List<Float>> result1 = device.updateTargets(extremeTarget1);
+            assertNotNull(result1);
+            assertFalse(result1.isEmpty());
+            
+            // 测试极小值
+            List<List<Float>> extremeTarget2 = Arrays.asList(
+                Arrays.asList(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE)
+            );
+            List<List<Float>> result2 = device.updateTargets(extremeTarget2);
+            assertNotNull(result2);
+            assertFalse(result2.isEmpty());
+            
+            // 测试负值
+            List<List<Float>> negativeTarget = Arrays.asList(
+                Arrays.asList(-1000.0f, -2000.0f, -3000.0f)
+            );
+            List<List<Float>> result3 = device.updateTargets(negativeTarget);
+            assertNotNull(result3);
+            assertFalse(result3.isEmpty());
+        }
+
+        @Test
+        @DisplayName("单点云数据处理测试")
+        void testSinglePointCloudData() {
+            List<List<Float>> singlePoint = Arrays.asList(
+                Arrays.asList(10.0f, 20.0f, 30.0f)
+            );
+            device.putCloudPointsQueue(singlePoint);
+            
+            List<List<Float>> result = device.getMaxLenCloudPoints();
+            assertNotNull(result);
+            assertEquals(1, result.size());
+            assertEquals(10.0f, result.get(0).get(0), 0.001f);
+        }
+
+        @Test
+        @DisplayName("零坐标处理测试")
+        void testZeroCoordinates() {
+            List<List<Float>> zeroTarget = Arrays.asList(
+                Arrays.asList(0.0f, 0.0f, 0.0f)
+            );
+            List<List<Float>> result = device.updateTargets(zeroTarget);
+            
+            assertNotNull(result);
+            assertEquals(1, result.size());
+            assertEquals(0.0f, result.get(0).get(0), 0.001f);
+            assertEquals(0.0f, result.get(0).get(1), 0.001f);
+            assertEquals(0.0f, result.get(0).get(2), 0.001f);
+        }
+    }
+} 

+ 440 - 0
device-service-domain/src/test/java/com/hfln/device/domain/service/PointCloudProcessServiceTest.java

@@ -0,0 +1,440 @@
+package com.hfln.device.domain.service;
+
+import com.hfln.device.domain.constant.DeviceConstants;
+import com.hfln.device.domain.entity.Device;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * PointCloudProcessService 单元测试
+ * 测试点云后处理、AI算法集成相关功能
+ */
+@DisplayName("点云处理服务测试")
+class PointCloudProcessServiceTest {
+
+    private PointCloudProcessService pointCloudProcessService;
+
+    @BeforeEach
+    void setUp() {
+        pointCloudProcessService = new PointCloudProcessService();
+    }
+
+    @Nested
+    @DisplayName("点云目标提取测试")
+    class TrackerTargetsTest {
+
+        @Test
+        @DisplayName("基础目标提取测试 - 单个点")
+        void testGetTrackerTargetsSinglePoint() {
+            List<List<Float>> pointCloud = Arrays.asList(
+                Arrays.asList(100.0f, 200.0f, 50.0f)
+            );
+            
+            List<List<Float>> result = pointCloudProcessService.getTrackerTargets(pointCloud);
+            
+            assertNotNull(result);
+            assertEquals(1, result.size());
+            assertEquals(3, result.get(0).size());
+            assertEquals(100.0f, result.get(0).get(0), 0.001f);
+            assertEquals(200.0f, result.get(0).get(1), 0.001f);
+            assertEquals(50.0f, result.get(0).get(2), 0.001f);
+        }
+
+        @Test
+        @DisplayName("多点云平均值计算测试")
+        void testGetTrackerTargetsMultiplePoints() {
+            List<List<Float>> pointCloud = Arrays.asList(
+                Arrays.asList(100.0f, 200.0f, 50.0f),
+                Arrays.asList(200.0f, 400.0f, 100.0f),
+                Arrays.asList(300.0f, 600.0f, 150.0f)
+            );
+            
+            List<List<Float>> result = pointCloudProcessService.getTrackerTargets(pointCloud);
+            
+            assertNotNull(result);
+            assertEquals(1, result.size());
+            // 验证平均值计算:(100+200+300)/3=200, (200+400+600)/3=400, (50+100+150)/3=100
+            assertEquals(200.0f, result.get(0).get(0), 0.001f);
+            assertEquals(400.0f, result.get(0).get(1), 0.001f);
+            assertEquals(100.0f, result.get(0).get(2), 0.001f);
+        }
+
+        @Test
+        @DisplayName("空点云处理测试")
+        void testGetTrackerTargetsEmptyCloud() {
+            // 测试null输入
+            List<List<Float>> result1 = pointCloudProcessService.getTrackerTargets(null);
+            assertTrue(result1.isEmpty());
+            
+            // 测试空列表
+            List<List<Float>> result2 = pointCloudProcessService.getTrackerTargets(new ArrayList<>());
+            assertTrue(result2.isEmpty());
+        }
+
+        @Test
+        @DisplayName("getTrackerTargetsMult功能测试")
+        void testGetTrackerTargetsMult() {
+            List<List<Float>> pointCloud = Arrays.asList(
+                Arrays.asList(10.0f, 20.0f, 30.0f),
+                Arrays.asList(40.0f, 50.0f, 60.0f)
+            );
+            
+            List<List<Float>> result1 = pointCloudProcessService.getTrackerTargets(pointCloud);
+            List<List<Float>> result2 = pointCloudProcessService.getTrackerTargetsMult(pointCloud);
+            
+            // 验证两个方法返回相同结果(对应Python版本的相同实现)
+            assertEquals(result1.size(), result2.size());
+            assertEquals(result1.get(0).get(0), result2.get(0).get(0), 0.001f);
+            assertEquals(result1.get(0).get(1), result2.get(0).get(1), 0.001f);
+            assertEquals(result1.get(0).get(2), result2.get(0).get(2), 0.001f);
+        }
+
+        @Test
+        @DisplayName("不同维度点云处理测试")
+        void testDifferentDimensionPoints() {
+            // 测试2D点云(只有x,y坐标)
+            List<List<Float>> pointCloud2D = Arrays.asList(
+                Arrays.asList(10.0f, 20.0f),
+                Arrays.asList(30.0f, 40.0f)
+            );
+            
+            List<List<Float>> result2D = pointCloudProcessService.getTrackerTargets(pointCloud2D);
+            assertNotNull(result2D);
+            assertEquals(1, result2D.size());
+            assertEquals(2, result2D.get(0).size());
+            assertEquals(20.0f, result2D.get(0).get(0), 0.001f); // (10+30)/2
+            assertEquals(30.0f, result2D.get(0).get(1), 0.001f); // (20+40)/2
+            
+            // 测试4D点云(包含额外维度)
+            List<List<Float>> pointCloud4D = Arrays.asList(
+                Arrays.asList(10.0f, 20.0f, 30.0f, 40.0f),
+                Arrays.asList(50.0f, 60.0f, 70.0f, 80.0f)
+            );
+            
+            List<List<Float>> result4D = pointCloudProcessService.getTrackerTargets(pointCloud4D);
+            assertNotNull(result4D);
+            assertEquals(1, result4D.size());
+            assertEquals(4, result4D.get(0).size());
+            assertEquals(30.0f, result4D.get(0).get(0), 0.001f); // (10+50)/2
+            assertEquals(40.0f, result4D.get(0).get(1), 0.001f); // (20+60)/2
+            assertEquals(50.0f, result4D.get(0).get(2), 0.001f); // (30+70)/2
+            assertEquals(60.0f, result4D.get(0).get(3), 0.001f); // (40+80)/2
+        }
+    }
+
+    @Nested
+    @DisplayName("AI算法后处理测试")
+    class PostProcessTest {
+
+        @Test
+        @DisplayName("AI数据预处理测试 - 李博模型格式")
+        void testPreparePostDataLibo() {
+            List<List<Float>> rawPoints = Arrays.asList(
+                Arrays.asList(10.0f, 20.0f, 30.0f, 40.0f), // 4维数据,应该只取前3维
+                Arrays.asList(50.0f, 60.0f, 70.0f, 80.0f),
+                Arrays.asList(90.0f, 100.0f, 110.0f, 120.0f)
+            );
+            
+            Map<String, Object> result = pointCloudProcessService.preparePostData(rawPoints);
+            
+            assertNotNull(result);
+            assertTrue(result.containsKey("point_cloud"));
+            
+            @SuppressWarnings("unchecked")
+            List<List<Float>> processedPoints = (List<List<Float>>) result.get("point_cloud");
+            assertEquals(3, processedPoints.size());
+            
+            // 验证每个点只保留了前3个坐标
+            for (List<Float> point : processedPoints) {
+                assertEquals(3, point.size());
+            }
+            
+            // 验证第一个点的坐标
+            assertEquals(10.0f, processedPoints.get(0).get(0), 0.001f);
+            assertEquals(20.0f, processedPoints.get(0).get(1), 0.001f);
+            assertEquals(30.0f, processedPoints.get(0).get(2), 0.001f);
+        }
+
+        @Test
+        @DisplayName("空数据预处理测试")
+        void testPreparePostDataEmpty() {
+            // 测试null输入
+            Map<String, Object> result1 = pointCloudProcessService.preparePostData(null);
+            assertTrue(result1.isEmpty());
+            
+            // 测试空列表
+            Map<String, Object> result2 = pointCloudProcessService.preparePostData(new ArrayList<>());
+            assertTrue(result2.isEmpty());
+        }
+
+        @Test
+        @DisplayName("姿态分类映射测试")
+        void testCheckPose() {
+            // 测试各种姿态分类映射
+            assertEquals(DeviceConstants.PoseEnum.POSE_FALLING.getCode(), 
+                        pointCloudProcessService.checkPose(0));
+            assertEquals(DeviceConstants.PoseEnum.POSE_SITTING_ON_CHAIR.getCode(), 
+                        pointCloudProcessService.checkPose(1));
+            assertEquals(DeviceConstants.PoseEnum.POSE_SITTING_ON_FLOOR.getCode(), 
+                        pointCloudProcessService.checkPose(2));
+            assertEquals(DeviceConstants.PoseEnum.POSE_SQUATTING.getCode(), 
+                        pointCloudProcessService.checkPose(3));
+            assertEquals(DeviceConstants.PoseEnum.POSE_STANDING.getCode(), 
+                        pointCloudProcessService.checkPose(4));
+            assertEquals(DeviceConstants.PoseEnum.POSE_SITTING.getCode(), 
+                        pointCloudProcessService.checkPose(5));
+            assertEquals(DeviceConstants.PoseEnum.POSE_LYING.getCode(), 
+                        pointCloudProcessService.checkPose(6));
+            assertEquals(DeviceConstants.PoseEnum.POSE_INVALID.getCode(), 
+                        pointCloudProcessService.checkPose(999)); // 无效值
+        }
+
+        @Test
+        @DisplayName("AI响应处理测试")
+        void testProcessPoseResponse() {
+            // 测试正常响应
+            Map<String, Object> responseJson = new HashMap<>();
+            responseJson.put("predicted_class", 4);
+            
+            int result = pointCloudProcessService.processPoseResponse(responseJson);
+            assertEquals(DeviceConstants.PoseEnum.POSE_STANDING.getCode(), result);
+            
+            // 测试无效响应
+            Map<String, Object> invalidResponse = new HashMap<>();
+            invalidResponse.put("other_field", "value");
+            
+            int invalidResult = pointCloudProcessService.processPoseResponse(invalidResponse);
+            assertEquals(DeviceConstants.PoseEnum.POSE_INVALID.getCode(), invalidResult);
+            
+            // 测试空响应
+            int emptyResult = pointCloudProcessService.processPoseResponse(new HashMap<>());
+            assertEquals(DeviceConstants.PoseEnum.POSE_INVALID.getCode(), emptyResult);
+        }
+    }
+
+    @Nested
+    @DisplayName("多设备点云处理测试")
+    class MultiDeviceTest {
+
+        @Test
+        @DisplayName("获取最大长度点云测试")
+        void testGetMaxLenRawPoints() {
+            // 创建测试设备
+            Device device1 = new Device("DEV001");
+            device1.setDevType("LNA");
+            
+            Device device2 = new Device("DEV002");
+            device2.setDevType("LNA");
+            
+            Device device3 = new Device("DEV003");
+            device3.setDevType("LNB"); // LNB设备应该被忽略
+            
+            // 为设备添加不同长度的点云数据
+            List<List<Float>> cloudPoints1 = Arrays.asList(
+                Arrays.asList(1.0f, 2.0f, 3.0f),
+                Arrays.asList(4.0f, 5.0f, 6.0f)
+            ); // 长度: 2
+            device1.putCloudPointsQueue(cloudPoints1);
+            
+            List<List<Float>> cloudPoints2 = Arrays.asList(
+                Arrays.asList(7.0f, 8.0f, 9.0f),
+                Arrays.asList(10.0f, 11.0f, 12.0f),
+                Arrays.asList(13.0f, 14.0f, 15.0f),
+                Arrays.asList(16.0f, 17.0f, 18.0f),
+                Arrays.asList(19.0f, 20.0f, 21.0f)
+            ); // 长度: 5
+            device2.putCloudPointsQueue(cloudPoints2);
+            
+            List<List<Float>> cloudPoints3 = Arrays.asList(
+                Arrays.asList(22.0f, 23.0f, 24.0f),
+                Arrays.asList(25.0f, 26.0f, 27.0f),
+                Arrays.asList(28.0f, 29.0f, 30.0f)
+            ); // 长度: 3
+            device3.putCloudPointsQueue(cloudPoints3);
+            
+            Collection<Device> devices = Arrays.asList(device1, device2, device3);
+            
+            // 获取最大长度的点云
+            Map<String, Object> result = pointCloudProcessService.getMaxLenRawPoints(devices);
+            
+            assertNotNull(result);
+            assertEquals("DEV002", result.get("dev_id"));
+            
+            @SuppressWarnings("unchecked")
+            List<List<Float>> rawPoints = (List<List<Float>>) result.get("raw_points");
+            assertEquals(5, rawPoints.size()); // 应该返回长度为5的点云
+        }
+
+        @Test
+        @DisplayName("所有设备点云数据不足测试")
+        void testGetMaxLenRawPointsInsufficientData() {
+            Device device1 = new Device("DEV001");
+            device1.setDevType("LNA");
+            
+            Device device2 = new Device("DEV002");
+            device2.setDevType("LNA");
+            
+            // 添加少于20个点的点云数据
+            List<List<Float>> smallCloudPoints = Arrays.asList(
+                Arrays.asList(1.0f, 2.0f, 3.0f),
+                Arrays.asList(4.0f, 5.0f, 6.0f)
+            ); // 长度: 2 < 20
+            
+            device1.putCloudPointsQueue(smallCloudPoints);
+            device2.putCloudPointsQueue(smallCloudPoints);
+            
+            Collection<Device> devices = Arrays.asList(device1, device2);
+            
+            Map<String, Object> result = pointCloudProcessService.getMaxLenRawPoints(devices);
+            assertNull(result);
+        }
+
+        @Test
+        @DisplayName("空设备集合处理测试")
+        void testGetMaxLenRawPointsEmptyDevices() {
+            Collection<Device> emptyDevices = new ArrayList<>();
+            Map<String, Object> result = pointCloudProcessService.getMaxLenRawPoints(emptyDevices);
+            assertNull(result);
+        }
+    }
+
+    @Nested
+    @DisplayName("姿态识别测试")
+    class PoseRecognitionTest {
+
+        @Test
+        @DisplayName("基础姿态识别测试")
+        void testProcessPoseRecognition() {
+            List<List<Number>> pointCloud = Arrays.asList(
+                Arrays.asList(100, 200, 80), // 高度较高,应该识别为站立
+                Arrays.asList(110, 210, 85),
+                Arrays.asList(90, 190, 75)
+            );
+            
+            PointCloudProcessService.PoseResult result = 
+                pointCloudProcessService.processPoseRecognition(pointCloud);
+            
+            assertNotNull(result);
+            assertTrue(result.getPose() >= 0); // 应该返回有效的姿态代码
+            assertTrue(result.getConfidence() > 0); // 应该有置信度
+            assertNotNull(result.getTargetPoint()); // 应该有目标点
+            assertEquals(3, result.getTargetPoint().size()); // 目标点应该是3维
+        }
+
+        @Test
+        @DisplayName("不同高度分布姿态识别测试")
+        void testPoseRecognitionDifferentHeights() {
+            // 测试低高度点云(躺着)
+            List<List<Number>> lowHeightCloud = Arrays.asList(
+                Arrays.asList(100, 200, 10),
+                Arrays.asList(110, 210, 15),
+                Arrays.asList(90, 190, 5)
+            );
+            
+            PointCloudProcessService.PoseResult lowResult = 
+                pointCloudProcessService.processPoseRecognition(lowHeightCloud);
+            
+            // 应该识别为躺着或坐在地上
+            assertTrue(lowResult.getPose() == DeviceConstants.PoseEnum.POSE_FALLING.getCode() ||
+                      lowResult.getPose() == DeviceConstants.PoseEnum.POSE_SITTING_ON_FLOOR.getCode());
+            
+            // 测试中等高度点云(坐着)
+            List<List<Number>> mediumHeightCloud = Arrays.asList(
+                Arrays.asList(100, 200, 60),
+                Arrays.asList(110, 210, 65),
+                Arrays.asList(90, 190, 55)
+            );
+            
+            PointCloudProcessService.PoseResult mediumResult = 
+                pointCloudProcessService.processPoseRecognition(mediumHeightCloud);
+            
+            // 应该识别为坐着或蹲着
+            assertTrue(mediumResult.getPose() == DeviceConstants.PoseEnum.POSE_SITTING.getCode() ||
+                      mediumResult.getPose() == DeviceConstants.PoseEnum.POSE_SQUATTING.getCode());
+        }
+
+        @Test
+        @DisplayName("空点云姿态识别测试")
+        void testPoseRecognitionEmptyCloud() {
+            PointCloudProcessService.PoseResult result = 
+                pointCloudProcessService.processPoseRecognition(null);
+            
+            assertEquals(DeviceConstants.PoseEnum.POSE_INVALID.getCode(), result.getPose());
+            assertEquals(0.0f, result.getConfidence(), 0.001f);
+            assertTrue(result.getTargetPoint().isEmpty());
+        }
+
+        @Test
+        @DisplayName("analyzePose适配方法测试")
+        void testAnalyzePose() {
+            List<List<Float>> pointCloud = Arrays.asList(
+                Arrays.asList(100.0f, 200.0f, 80.0f),
+                Arrays.asList(110.0f, 210.0f, 85.0f),
+                Arrays.asList(90.0f, 190.0f, 75.0f)
+            );
+            
+            int pose = pointCloudProcessService.analyzePose(pointCloud);
+            assertTrue(pose >= 0); // 应该返回有效的姿态代码
+            
+            // 测试空输入
+            int invalidPose = pointCloudProcessService.analyzePose(null);
+            assertEquals(DeviceConstants.PoseEnum.POSE_INVALID.getCode(), invalidPose);
+        }
+    }
+
+    @Nested
+    @DisplayName("性能测试")
+    class PerformanceTest {
+
+        @Test
+        @DisplayName("大量点云处理性能测试")
+        void testLargePointCloudProcessing() {
+            // 生成大量点云数据
+            List<List<Float>> largePointCloud = new ArrayList<>();
+            for (int i = 0; i < 10000; i++) {
+                largePointCloud.add(Arrays.asList(
+                    (float)(Math.random() * 1000),
+                    (float)(Math.random() * 1000),
+                    (float)(Math.random() * 100)
+                ));
+            }
+            
+            long startTime = System.currentTimeMillis();
+            List<List<Float>> result = pointCloudProcessService.getTrackerTargets(largePointCloud);
+            long endTime = System.currentTimeMillis();
+            
+            assertNotNull(result);
+            assertEquals(1, result.size());
+            
+            long duration = endTime - startTime;
+            assertTrue(duration < 1000, "大量点云处理耗时过长: " + duration + "ms");
+        }
+
+        @Test
+        @DisplayName("批量姿态识别性能测试")
+        void testBatchPoseRecognitionPerformance() {
+            List<List<Number>> testCloud = Arrays.asList(
+                Arrays.asList(100, 200, 50),
+                Arrays.asList(110, 210, 55),
+                Arrays.asList(90, 190, 45)
+            );
+            
+            long startTime = System.currentTimeMillis();
+            
+            for (int i = 0; i < 1000; i++) {
+                pointCloudProcessService.processPoseRecognition(testCloud);
+            }
+            
+            long endTime = System.currentTimeMillis();
+            long duration = endTime - startTime;
+            
+            assertTrue(duration < 2000, "批量姿态识别耗时过长: " + duration + "ms");
+        }
+    }
+}