before new database
This commit is contained in:
105
Tests/04_DSP/Equalizer/FFE_plain_test.m
Normal file
105
Tests/04_DSP/Equalizer/FFE_plain_test.m
Normal file
@@ -0,0 +1,105 @@
|
||||
classdef FFE_plain_test < IMDDTestCase
|
||||
methods (Test, TestTags = {'unit', 'fast', 'dsp', 'ffe'})
|
||||
function constructorKeepsPlainDefaults(testCase)
|
||||
ffe = FFE_plain();
|
||||
|
||||
testCase.verifyEqual(ffe.sps, 2);
|
||||
testCase.verifyEqual(ffe.order, 15);
|
||||
testCase.verifyEqual(ffe.len_tr, 4096);
|
||||
testCase.verifyEqual(ffe.mu_tr, 0);
|
||||
testCase.verifyEqual(ffe.epochs_tr, 5);
|
||||
testCase.verifyEqual(ffe.adaption_technique, adaption_method.lms);
|
||||
testCase.verifyEqual(ffe.dd_mode, 1);
|
||||
testCase.verifyEqual(ffe.mu_dd, 1e-5);
|
||||
testCase.verifyEqual(ffe.epochs_dd, 5);
|
||||
testCase.verifyEqual(ffe.dd_len_fraction, 1);
|
||||
testCase.verifyFalse(ffe.decide);
|
||||
testCase.verifyEqual(ffe.e, zeros(ffe.order,1));
|
||||
testCase.verifyFalse(isprop(ffe,"dc_tracking_mu"));
|
||||
testCase.verifyFalse(isprop(ffe,"dc_avg_bufferlength_a1"));
|
||||
testCase.verifyFalse(isprop(ffe,"dc_level_avg_bufferlength_a2"));
|
||||
end
|
||||
|
||||
function plainMatchesFullCoreForLms(testCase)
|
||||
result = runCoreParity(adaption_method.lms,0.02,0.01);
|
||||
|
||||
verifyCoreParity(testCase,result);
|
||||
end
|
||||
|
||||
function plainMatchesFullCoreForNlms(testCase)
|
||||
result = runCoreParity(adaption_method.nlms,0.08,0.03);
|
||||
|
||||
verifyCoreParity(testCase,result);
|
||||
end
|
||||
|
||||
function plainMatchesFullCoreForRls(testCase)
|
||||
result = runCoreParity(adaption_method.rls,0.995,0.998);
|
||||
|
||||
verifyCoreParity(testCase,result);
|
||||
end
|
||||
|
||||
function optimizationSignalsUsesShortenedAlignedPrefix(testCase)
|
||||
ffe = FFE_plain( ...
|
||||
"sps", 2, ...
|
||||
"len_tr", 16, ...
|
||||
"mu_optimization_len", 22);
|
||||
x = (1:100).';
|
||||
d = (1:50).';
|
||||
|
||||
[x_opt,d_opt,N_opt] = ffe.optimizationSignals(x,d);
|
||||
|
||||
testCase.verifyEqual(N_opt, 22);
|
||||
testCase.verifyEqual(x_opt, x(1:22));
|
||||
testCase.verifyEqual(d_opt, d(1:11));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function result = runCoreParity(adaption,mu_tr,mu_dd)
|
||||
x = [ ...
|
||||
-2.2; -0.9; 0.8; 2.1; ...
|
||||
-2.0; -1.1; 1.1; 2.2; ...
|
||||
-2.1; -0.8; 0.9; 2.0; ...
|
||||
-2.3; -1.0; 1.0; 2.3];
|
||||
d = [ ...
|
||||
-3; -1; 1; 3; ...
|
||||
-3; -1; 1; 3; ...
|
||||
-3; -1; 1; 3; ...
|
||||
-3; -1; 1; 3];
|
||||
settings = { ...
|
||||
"sps", 1, ...
|
||||
"order", 3, ...
|
||||
"len_tr", numel(x), ...
|
||||
"epochs_tr", 2, ...
|
||||
"mu_tr", mu_tr, ...
|
||||
"dd_mode", 1, ...
|
||||
"epochs_dd", 2, ...
|
||||
"mu_dd", mu_dd, ...
|
||||
"adaption_technique", adaption};
|
||||
|
||||
plain = FFE_plain(settings{:});
|
||||
full = FFE(settings{:});
|
||||
plain.constellation = unique(d);
|
||||
full.constellation = unique(d);
|
||||
plain.P = (1/0.05) * eye(plain.order);
|
||||
full.P = (1/0.05) * eye(full.order);
|
||||
|
||||
plain.equalize(x,d,plain.mu_tr,plain.epochs_tr,plain.len_tr,true,false);
|
||||
full.equalize(x,d,full.mu_tr,full.epochs_tr,full.len_tr,true,false);
|
||||
plain.e_tr = plain.e;
|
||||
full.e_tr = full.e;
|
||||
|
||||
[result.y_plain,result.dhat_plain] = plain.equalize(x,d,plain.mu_dd,plain.epochs_dd,numel(x),false,false);
|
||||
[result.y_full,result.dhat_full] = full.equalize(x,d,full.mu_dd,full.epochs_dd,numel(x),false,false);
|
||||
result.e_plain = plain.e;
|
||||
result.e_full = full.e;
|
||||
result.e_tr_plain = plain.e_tr;
|
||||
result.e_tr_full = full.e_tr;
|
||||
end
|
||||
|
||||
function verifyCoreParity(testCase,result)
|
||||
testCase.verifyEqual(result.y_plain,result.y_full,"AbsTol",1e-12);
|
||||
testCase.verifyEqual(result.dhat_plain,result.dhat_full,"AbsTol",1e-12);
|
||||
testCase.verifyEqual(result.e_plain,result.e_full,"AbsTol",1e-12);
|
||||
testCase.verifyEqual(result.e_tr_plain,result.e_tr_full,"AbsTol",1e-12);
|
||||
end
|
||||
@@ -22,6 +22,7 @@ classdef FFE_test < IMDDTestCase
|
||||
testCase.verifyEqual(ffe.dc_level_avg_bufferlength_a2, 0);
|
||||
testCase.verifyEqual(ffe.dc_level_update_blocklength_a2, 0);
|
||||
testCase.verifyEqual(ffe.dc_smoothing_a2, 0);
|
||||
testCase.verifyEqual(ffe.dc_level_decision_mode_a2, "residual");
|
||||
testCase.verifyEqual(ffe.dc_level_weights_a2, 0);
|
||||
testCase.verifyEqual(ffe.dc_tracking_buffer_len, 1);
|
||||
testCase.verifyEqual(ffe.ffe_update_buffer_len, 1);
|
||||
@@ -174,6 +175,64 @@ classdef FFE_test < IMDDTestCase
|
||||
testCase.verifyEqual(ffe.e_dc, 0.36, "AbsTol", 1e-12);
|
||||
end
|
||||
|
||||
function ffeDcTrackingClassMatchesFullUnbufferedPath(testCase)
|
||||
x = zeros(4, 1);
|
||||
d = ones(4, 1);
|
||||
settings = { ...
|
||||
"sps", 1, ...
|
||||
"order", 1, ...
|
||||
"dc_tracking_mu", 0.1, ...
|
||||
"dc_tracking_buffer_len", 1, ...
|
||||
"save_debug", true, ...
|
||||
"dd_mode", 0, ...
|
||||
"adaption_technique", adaption_method.lms};
|
||||
|
||||
full = FFE(settings{:});
|
||||
tracking = FFE_DCTracking(settings{:});
|
||||
full.constellation = unique(d);
|
||||
tracking.constellation = unique(d);
|
||||
|
||||
[y_full,d_hat_full] = full.equalize(x, d, 0, 1, numel(x), true, false);
|
||||
[y_tracking,d_hat_tracking] = tracking.equalize(x, d, 0, 1, numel(x), true, false);
|
||||
|
||||
testCase.verifyEqual(y_tracking, y_full, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(d_hat_tracking, d_hat_full, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(tracking.e_dc, full.e_dc, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(tracking.debug_struct.dc_tracking_est, ...
|
||||
full.debug_struct.dc_tracking_est, "AbsTol", 1e-12);
|
||||
end
|
||||
|
||||
function ffeDcTrackingClassMatchesFullBufferedPersistencePath(testCase)
|
||||
x = zeros(4, 1);
|
||||
d = ones(4, 1);
|
||||
settings = { ...
|
||||
"sps", 1, ...
|
||||
"order", 1, ...
|
||||
"dc_tracking_mu", 0.1, ...
|
||||
"dc_tracking_adaptive_enabled", true, ...
|
||||
"dc_tracking_persistence_gain", 1, ...
|
||||
"dc_tracking_buffer_len", 2, ...
|
||||
"save_debug", true, ...
|
||||
"dd_mode", 0, ...
|
||||
"adaption_technique", adaption_method.lms};
|
||||
|
||||
full = FFE(settings{:});
|
||||
tracking = FFE_DCTracking(settings{:});
|
||||
full.constellation = unique(d);
|
||||
tracking.constellation = unique(d);
|
||||
|
||||
[y_full,d_hat_full] = full.equalize(x, d, 0, 1, numel(x), true, false);
|
||||
[y_tracking,d_hat_tracking] = tracking.equalize(x, d, 0, 1, numel(x), true, false);
|
||||
|
||||
testCase.verifyEqual(y_tracking, y_full, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(d_hat_tracking, d_hat_full, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(tracking.e_dc, full.e_dc, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(tracking.debug_struct.dc_tracking_mu_eff, ...
|
||||
full.debug_struct.dc_tracking_mu_eff, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(tracking.debug_struct.dc_tracking_est, ...
|
||||
full.debug_struct.dc_tracking_est, "AbsTol", 1e-12);
|
||||
end
|
||||
|
||||
function ffeBufferDelaysTapUpdateUntilBlockBoundary(testCase)
|
||||
x = ones(4, 1);
|
||||
d = ones(4, 1);
|
||||
@@ -349,6 +408,118 @@ classdef FFE_test < IMDDTestCase
|
||||
testCase.verifyEqual(y, [1; 3; 1; 3.5], "AbsTol", 1e-12);
|
||||
end
|
||||
|
||||
function dcLevelAvgA2TrackedLevelsUseAdaptiveDecision(testCase)
|
||||
x = [0.5; 2.5; 0.5; 2.5; 1.3];
|
||||
d = [0; 2; 0; 2; 0];
|
||||
|
||||
ffe = FFE( ...
|
||||
"sps", 1, ...
|
||||
"order", 1, ...
|
||||
"dc_level_avg_bufferlength_a2", 2, ...
|
||||
"dc_level_update_blocklength_a2", 1, ...
|
||||
"dc_level_decision_mode_a2", "tracked_levels", ...
|
||||
"dc_level_weights_a2", 1, ...
|
||||
"save_debug", true, ...
|
||||
"dd_mode", 0, ...
|
||||
"adaption_technique", adaption_method.lms);
|
||||
ffe.e = 1;
|
||||
ffe.constellation = [0; 2];
|
||||
|
||||
[y,d_hat] = ffe.equalize(x, d, 0, 1, numel(x), false, false);
|
||||
|
||||
testCase.verifyEqual(y, x, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(d_hat, d, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual( ...
|
||||
ffe.debug_struct.dc_level_decision_level, ...
|
||||
[0, 2, 0.25, 2.25, 0.5], ...
|
||||
"AbsTol", 1e-12);
|
||||
end
|
||||
|
||||
function ffeA2ResidualClassSubtractsScalarWeightedResidual(testCase)
|
||||
x = (1:4).';
|
||||
d = zeros(4, 1);
|
||||
|
||||
ffe = FFE_A2Residual( ...
|
||||
"sps", 1, ...
|
||||
"order", 1, ...
|
||||
"dc_level_avg_bufferlength_a2", 2, ...
|
||||
"dc_level_weights_a2", 1, ...
|
||||
"save_debug", true, ...
|
||||
"dd_mode", 0, ...
|
||||
"adaption_technique", adaption_method.lms);
|
||||
ffe.e = 1;
|
||||
ffe.constellation = 0;
|
||||
|
||||
[y,~] = ffe.equalize(x, d, 0, 1, numel(x), true, false);
|
||||
|
||||
testCase.verifyEqual(y, [1; 2; 1.5; 2.5], "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(ffe.debug_struct.dc_level_mpi_est, [0, 0, 1.5, 1.5], "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(ffe.debug_struct.dc_level_weight, [0, 0, 1, 1], "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(ffe.debug_struct.dc_level_valid_count, [0, 0, 2, 2]);
|
||||
end
|
||||
|
||||
function ffeA2ResidualClassMatchesFullResidualPath(testCase)
|
||||
x = [1; 3; 1; 4; 2; 5];
|
||||
d = [0; 2; 0; 2; 0; 2];
|
||||
settings = { ...
|
||||
"sps", 1, ...
|
||||
"order", 1, ...
|
||||
"dc_level_avg_bufferlength_a2", 2, ...
|
||||
"dc_level_update_blocklength_a2", 1, ...
|
||||
"dc_level_weights_a2", [0.25, 0.75], ...
|
||||
"save_debug", true, ...
|
||||
"dd_mode", 0, ...
|
||||
"adaption_technique", adaption_method.lms};
|
||||
|
||||
full = FFE(settings{:});
|
||||
residual = FFE_A2Residual(settings{:});
|
||||
full.e = 1;
|
||||
residual.e = 1;
|
||||
full.constellation = [0; 2];
|
||||
residual.constellation = [0; 2];
|
||||
|
||||
[y_full,d_hat_full] = full.equalize(x, d, 0, 1, numel(x), true, false);
|
||||
[y_residual,d_hat_residual] = residual.equalize(x, d, 0, 1, numel(x), true, false);
|
||||
|
||||
testCase.verifyEqual(y_residual, y_full, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(d_hat_residual, d_hat_full, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(residual.debug_struct.dc_level_mpi_est, ...
|
||||
full.debug_struct.dc_level_mpi_est, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(residual.debug_struct.dc_level_weight, ...
|
||||
full.debug_struct.dc_level_weight, "AbsTol", 1e-12);
|
||||
end
|
||||
|
||||
function dcLevelAvgA2RejectsUnknownDecisionMode(testCase)
|
||||
testCase.verifyError(@() FFE("dc_level_decision_mode_a2", "unknown"), ...
|
||||
"FFE:InvalidA2DecisionMode");
|
||||
end
|
||||
|
||||
function ffeA2TrackedLevelsClassUsesAdaptiveDecision(testCase)
|
||||
x = [0.5; 2.5; 0.5; 2.5; 1.3];
|
||||
d = [0; 2; 0; 2; 0];
|
||||
|
||||
ffe = FFE_A2TrackedLevels( ...
|
||||
"sps", 1, ...
|
||||
"order", 1, ...
|
||||
"dc_level_avg_bufferlength_a2", 2, ...
|
||||
"dc_level_update_blocklength_a2", 1, ...
|
||||
"dc_level_weights_a2", 1, ...
|
||||
"save_debug", true, ...
|
||||
"dd_mode", 0, ...
|
||||
"adaption_technique", adaption_method.lms);
|
||||
ffe.e = 1;
|
||||
ffe.constellation = [0; 2];
|
||||
|
||||
[y,d_hat] = ffe.equalize(x, d, 0, 1, numel(x), false, false);
|
||||
|
||||
testCase.verifyEqual(y, x, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual(d_hat, d, "AbsTol", 1e-12);
|
||||
testCase.verifyEqual( ...
|
||||
ffe.debug_struct.dc_level_decision_level, ...
|
||||
[0, 2, 0.25, 2.25, 0.5], ...
|
||||
"AbsTol", 1e-12);
|
||||
end
|
||||
|
||||
function dcLevelAvgA2WarnsWhenCombinedWithDcTracking(testCase)
|
||||
testCase.verifyWarning(@() FFE( ...
|
||||
"dc_level_avg_bufferlength_a2", 2, ...
|
||||
|
||||
Reference in New Issue
Block a user