44namespace MathCore . DSP . Tests . Samples ;
55
66[ TestClass ]
7- public class SampleSI16ExTests
7+ public class SampleSI16PhaseModulationExTests
88{
99 /// <summary>Тест фазовой демодуляции для пустого массива</summary>
1010 [ TestMethod ]
@@ -52,7 +52,7 @@ public void PhaseDemodulation_ConstantSignal_ReturnsNearZeros()
5252 new ( 100 , 0 ) ,
5353 new ( 100 , 0 )
5454 } . AsSpan ( ) ;
55-
55+
5656 const double f0 = 1000.0 ;
5757 const double fd = 48000.0 ;
5858
@@ -62,12 +62,12 @@ public void PhaseDemodulation_ConstantSignal_ReturnsNearZeros()
6262 // Assert
6363 Assert . AreEqual ( 5 , result . Length ) ;
6464 Assert . AreEqual ( 0f , result [ 0 ] ) ; // Первый всегда 0
65-
65+
6666 // Для постоянного сигнала мгновенная частота должна быть близка к нулю
6767 // после вычитания центральной частоты результат должен быть близок к -f0
6868 for ( var i = 1 ; i < result . Length ; i ++ )
6969 {
70- Assert . IsTrue ( Math . Abs ( result [ i ] + f0 ) < 50 ,
70+ Assert . IsTrue ( Math . Abs ( result [ i ] + f0 ) < 50 ,
7171 $ "Sample { i } : expected ~{ - f0 } , got { result [ i ] } ") ;
7272 }
7373 }
@@ -81,16 +81,16 @@ public void PhaseDemodulation_SinusoidalSignal_ReturnsExpectedFrequency()
8181 const double f0 = 1000.0 ; // Центральная частота
8282 const double f_signal = 1500.0 ; // Частота сигнала
8383 const int samples_count = 200 ;
84-
84+
8585 var samples = new SampleSI16 [ samples_count ] ;
8686 var dt = 1.0 / fd ;
87-
87+
8888 for ( var i = 0 ; i < samples_count ; i ++ )
8989 {
9090 var t = i * dt ;
9191 var angle = 2.0 * Math . PI * f_signal * t ;
9292 var amplitude = 100.0 ;
93-
93+
9494 samples [ i ] = new SampleSI16 (
9595 ( sbyte ) ( amplitude * Math . Cos ( angle ) ) ,
9696 ( sbyte ) ( amplitude * Math . Sin ( angle ) )
@@ -103,19 +103,19 @@ public void PhaseDemodulation_SinusoidalSignal_ReturnsExpectedFrequency()
103103 // Assert
104104 Assert . AreEqual ( samples_count , result . Length ) ;
105105 Assert . AreEqual ( 0f , result [ 0 ] ) ; // Первый всегда 0
106-
106+
107107 // Проверяем, что результат близок к ожидаемой частоте (f_signal - f0)
108108 var expected_frequency = f_signal - f0 ;
109109 var tolerance = 100.0 ; // Допуск в Гц
110-
110+
111111 // Проверяем стабильную часть сигнала (пропускаем начальные образцы)
112112 var stable_samples = 0 ;
113113 for ( var i = 20 ; i < result . Length - 20 ; i ++ ) // Пропускаем края для стабилизации
114114 {
115115 if ( Math . Abs ( result [ i ] - expected_frequency ) < tolerance )
116116 stable_samples ++ ;
117117 }
118-
118+
119119 // Проверяем, что большинство образцов дает правильную частоту
120120 var expected_stable_count = ( result . Length - 40 ) * 0.8 ; // 80% образцов должны быть стабильными
121121 Assert . IsTrue ( stable_samples > expected_stable_count ,
@@ -130,7 +130,7 @@ public void PhaseDemodulation_OptimizedPerformance_BetterThanOldVersion()
130130 const int samples_count = 1_000_000 ; // Увеличиваем размер для лучшего измерения
131131 var samples = new SampleSI16 [ samples_count ] ;
132132 var random = new Random ( 42 ) ; // Фиксированное семя для воспроизводимости
133-
133+
134134 for ( var i = 0 ; i < samples_count ; i ++ )
135135 {
136136 samples [ i ] = new SampleSI16 (
@@ -150,17 +150,17 @@ public void PhaseDemodulation_OptimizedPerformance_BetterThanOldVersion()
150150 var result = samples . AsSpan ( ) . PhaseDemodulation ( f0 , fd ) ;
151151 stopwatch . Stop ( ) ;
152152 times . Add ( stopwatch . ElapsedMilliseconds ) ;
153-
153+
154154 // Проверяем корректность результата
155155 Assert . AreEqual ( samples_count , result . Length ) ;
156156 }
157157
158158 var average_time = times . Average ( ) ;
159-
159+
160160 // Assert - должно быть быстрее чем 1000 мс для 1M образцов
161- Assert . IsTrue ( average_time < 1000 ,
161+ Assert . IsTrue ( average_time < 1000 ,
162162 $ "Optimized demodulation took { average_time : F1} ms on average, expected < 1000 ms") ;
163-
163+
164164 Console . WriteLine ( $ "Оптимизированная фазовая демодуляция { samples_count } образцов:") ;
165165 Console . WriteLine ( $ "Среднее время: { average_time : F1} мс") ;
166166 Console . WriteLine ( $ "Производительность: { samples_count / average_time / 1000 : F1} млн. образцов/сек") ;
@@ -173,7 +173,7 @@ public void PhaseDemodulation_PhaseUnwrap_WorksCorrectly()
173173 // Arrange - создаем сигнал с плавно изменяющейся фазой, но с перескоками ±2π
174174 const double fd = 1000.0 ;
175175 const double f0 = 0.0 ; // Нулевая центральная частота для простоты
176-
176+
177177 var samples = new SampleSI16 [ ]
178178 {
179179 new ( 100 , 0 ) , // фаза ≈ 0
@@ -192,11 +192,11 @@ public void PhaseDemodulation_PhaseUnwrap_WorksCorrectly()
192192 // Assert
193193 Assert . AreEqual ( samples . Length , result . Length ) ;
194194 Assert . AreEqual ( 0f , result [ 0 ] ) ; // Первый всегда 0
195-
195+
196196 // Проверяем, что результаты имеют разумные значения без больших скачков
197197 for ( var i = 1 ; i < result . Length ; i ++ )
198198 {
199- Assert . IsTrue ( Math . Abs ( result [ i ] ) < 1000 ,
199+ Assert . IsTrue ( Math . Abs ( result [ i ] ) < 1000 ,
200200 $ "Sample { i } : frequency { result [ i ] } Hz seems too high") ;
201201 }
202202 }
@@ -208,18 +208,18 @@ public void PhaseDemodulation_OptimizedVsNaive_SameAccuracy()
208208 // Arrange - создаем чистый синусоидальный сигнал
209209 const double fd = 48000.0 ;
210210 const double f0 = 1000.0 ;
211- const double f_signal = 1200.0 ;
211+ const double f_signal = 1200.0 ;
212212 const int samples_count = 100 ;
213-
213+
214214 var samples = new SampleSI16 [ samples_count ] ;
215215 var dt = 1.0 / fd ;
216-
216+
217217 for ( var i = 0 ; i < samples_count ; i ++ )
218218 {
219219 var t = i * dt ;
220220 var angle = 2.0 * Math . PI * f_signal * t ;
221221 var amplitude = 120.0 ; // Используем почти максимальную амплитуду
222-
222+
223223 samples [ i ] = new SampleSI16 (
224224 ( sbyte ) ( amplitude * Math . Cos ( angle ) ) ,
225225 ( sbyte ) ( amplitude * Math . Sin ( angle ) )
@@ -232,19 +232,19 @@ public void PhaseDemodulation_OptimizedVsNaive_SameAccuracy()
232232 // Assert - проверяем точность на стабильной части
233233 var expected_frequency = f_signal - f0 ;
234234 var errors = new List < float > ( ) ;
235-
235+
236236 for ( var i = 10 ; i < optimized_result . Length - 10 ; i ++ )
237237 {
238238 var error = ( float ) Math . Abs ( optimized_result [ i ] - expected_frequency ) ;
239239 errors . Add ( error ) ;
240240 }
241-
241+
242242 var average_error = errors . Average ( ) ;
243243 var max_error = errors . Max ( ) ;
244-
244+
245245 Assert . IsTrue ( average_error < 50 , $ "Average error { average_error : F1} Hz too high") ;
246246 Assert . IsTrue ( max_error < 100 , $ "Max error { max_error : F1} Hz too high") ;
247-
247+
248248 Console . WriteLine ( $ "Точность оптимизированного алгоритма:") ;
249249 Console . WriteLine ( $ "Средняя ошибка: { average_error : F1} Гц") ;
250250 Console . WriteLine ( $ "Максимальная ошибка: { max_error : F1} Гц") ;
@@ -283,12 +283,12 @@ public void PhaseModulation_ConstantFrequency_GeneratesCorrectSignal()
283283
284284 // Assert
285285 Assert . AreEqual ( data . Length , result . Length ) ;
286-
286+
287287 // Проверяем, что амплитуда близка к заданной
288288 for ( var i = 0 ; i < result . Length ; i ++ )
289289 {
290290 var sample_amplitude = Math . Sqrt ( result [ i ] . I * result [ i ] . I + result [ i ] . Q * result [ i ] . Q ) ;
291- Assert . IsTrue ( Math . Abs ( sample_amplitude - amplitude ) < 5 ,
291+ Assert . IsTrue ( Math . Abs ( sample_amplitude - amplitude ) < 5 ,
292292 $ "Sample { i } : amplitude { sample_amplitude : F1} too far from expected { amplitude } ") ;
293293 }
294294 }
@@ -298,8 +298,8 @@ public void PhaseModulation_ConstantFrequency_GeneratesCorrectSignal()
298298 public void PhaseModulation_RoundTrip_PreservesData ( )
299299 {
300300 // Arrange - создаем тестовые данные с различными частотами
301- var original_data = new float [ ]
302- {
301+ var original_data = new float [ ]
302+ {
303303 0f , // Без отклонения
304304 100f , // +100 Гц
305305 - 200f , // -200 Гц
@@ -308,21 +308,21 @@ public void PhaseModulation_RoundTrip_PreservesData()
308308 0f , // Возврат к центральной
309309 50f , // Небольшое отклонение
310310 } ;
311-
311+
312312 const double f0 = 2000.0 ;
313313 const double fd = 48000.0 ;
314314 const float amplitude = 120f ;
315315
316316 // Act - модуляция
317317 var modulated = original_data . AsSpan ( ) . PhaseModulation ( f0 , fd , amplitude ) ;
318-
318+
319319 // Демодуляция
320320 var demodulated = modulated . AsSpan ( ) . PhaseDemodulation ( f0 , fd ) ;
321321
322322 // Assert
323323 Assert . AreEqual ( original_data . Length , demodulated . Length ) ;
324324 Assert . AreEqual ( 0f , demodulated [ 0 ] ) ; // Первый отсчёт всегда 0
325-
325+
326326 // Проверяем восстановление данных (пропускаем первый отсчёт и края)
327327 const float tolerance = 50f ; // Допуск в Гц
328328 for ( var i = 2 ; i < demodulated . Length - 1 ; i ++ ) // Пропускаем края из-за переходных процессов
@@ -345,26 +345,26 @@ public void PhaseModulation_WithInitialPhase_MaintainsPhaseContinuity()
345345
346346 // Act - первый блок
347347 var ( samples1 , final_phase1 ) = data1 . AsSpan ( ) . PhaseModulation ( f0 , fd , 0.0 ) ;
348-
348+
349349 // Второй блок с продолжением фазы
350350 var ( samples2 , final_phase2 ) = data2 . AsSpan ( ) . PhaseModulation ( f0 , fd , final_phase1 ) ;
351351
352352 // Assert
353353 Assert . AreEqual ( data1 . Length , samples1 . Length ) ;
354354 Assert . AreEqual ( data2 . Length , samples2 . Length ) ;
355-
355+
356356 // Проверяем непрерывность фазы на стыке блоков
357357 var last_sample = samples1 [ ^ 1 ] ;
358358 var first_sample = samples2 [ 0 ] ;
359-
359+
360360 var last_phase = Math . Atan2 ( last_sample . Q , last_sample . I ) ;
361361 var first_phase = Math . Atan2 ( first_sample . Q , first_sample . I ) ;
362-
362+
363363 // Разность фаз должна быть небольшой (с учётом возможного перескока через ±π)
364364 var phase_diff = Math . Abs ( first_phase - last_phase ) ;
365365 if ( phase_diff > Math . PI ) phase_diff = 2 * Math . PI - phase_diff ;
366-
367- Assert . IsTrue ( phase_diff < 0.5 ,
366+
367+ Assert . IsTrue ( phase_diff < 0.5 ,
368368 $ "Phase discontinuity too large: { phase_diff : F3} rad") ;
369369 }
370370
@@ -376,10 +376,10 @@ public void PhaseModulation_Performance_CompletesQuickly()
376376 const int data_count = 1_000_000 ;
377377 var data = new float [ data_count ] ;
378378 var random = new Random ( 42 ) ;
379-
379+
380380 for ( var i = 0 ; i < data_count ; i ++ )
381381 data [ i ] = ( float ) ( random . NextDouble ( ) * 1000 - 500 ) ; // ±500 Гц
382-
382+
383383 const double f0 = 2400.0 ;
384384 const double fd = 48000.0 ;
385385
@@ -390,9 +390,9 @@ public void PhaseModulation_Performance_CompletesQuickly()
390390
391391 // Assert
392392 Assert . AreEqual ( data_count , result . Length ) ;
393- Assert . IsTrue ( stopwatch . ElapsedMilliseconds < 500 ,
393+ Assert . IsTrue ( stopwatch . ElapsedMilliseconds < 500 ,
394394 $ "Modulation took { stopwatch . ElapsedMilliseconds } ms, expected < 500 ms") ;
395-
395+
396396 Console . WriteLine ( $ "Фазовая модуляция { data_count } образцов заняла { stopwatch . ElapsedMilliseconds } мс") ;
397397 Console . WriteLine ( $ "Производительность: { data_count / ( double ) stopwatch . ElapsedMilliseconds / 1000 : F1} млн. образцов/сек") ;
398398 }
0 commit comments