Skip to content

Commit

Permalink
Update auto filter generation to passband ripple minimize base on sam…
Browse files Browse the repository at this point in the history
…ple rate (analogdevicesinc#37)

* Add enhanced command line function to try all FIR configuration to meet design spec. Some testing was added for this functionality
* Fix analog filter bandwidth auto-generation to use hardware values not full precision.
* Add specific tests for LTE filters
* Add gitlab ci config

Signed-off-by: Travis Collins <[email protected]>
  • Loading branch information
tfcollins authored Apr 22, 2019
1 parent baf2990 commit 924f0cd
Show file tree
Hide file tree
Showing 15 changed files with 166 additions and 5 deletions.
16 changes: 16 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
stages:
- test
- test_hardware
- deploy

# Linux test
test:linux:
tags:
- linux
- matlab
stage: test
script:
- /usr/local/MATLAB/R2018b/bin/matlab -nodisplay -nodesktop -nosplash -r "addpath(genpath('test'));runTests;"
artifacts:
paths:
- test/
14 changes: 11 additions & 3 deletions auto_fast_rates.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [input,savedFilterConfig] = auto_fast_rates(input)
function [input,savedFilterConfig] = auto_fast_rates(input,FIR_config)
%auto_fast_rates Configures halfband filters, PLL clock, and
%converter rates in an optimal configuration based on the
%current 'Rdata' property
Expand All @@ -20,8 +20,12 @@

DR = input.Rdata;

for FIR = [4,2,1]

if nargin == 1
FIR_config = [1,2,4];
end

for FIR = FIR_config

FilterConfig = [...
3,2,2,FIR;...
2,2,2,FIR;...
Expand Down Expand Up @@ -81,6 +85,10 @@
end
end

if savedFilterConfig==0
input = [];
return;
end

% Set HBs based on best config found
PLLDivider = savedPLL;
Expand Down
4 changes: 3 additions & 1 deletion cook_input.m
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@
end

if ~isfield(input, 'RFbw')
[input.RFbw, input.caldiv] = calculate_rfbw(input.PLL_rate, input.caldiv, input.RxTx, false);
[input.RFbw, input.caldiv] = calculate_rfbw(input.PLL_rate, input.caldiv, input.RxTx, true);
% Update wnom to use hardware applicable value
input.wnom = double(input.RFbw);
end

% Assume no dBmin
Expand Down
2 changes: 1 addition & 1 deletion internal_design_filter.m
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@

% nominal frequency can't be zero
if ~input.wnom
input.wnom = (input.PLL_rate/input.caldiv)*(log(2)/(2*pi));
input.wnom = double(calculate_rfbw(input.PLL_rate, input.caldiv, input.RxTx, true));
end

if strcmp(input.RxTx, 'Rx')
Expand Down
56 changes: 56 additions & 0 deletions internal_design_filter_opt_ripple.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
function output = internal_design_filter_opt_ripple(input)

% support a simple data rate input otherwise it must be a structure
if isfloat(input)
input = struct('Rdata', input);
else
error('Input must be the required samplerate only');
end

input = cook_input(input);

% use the internal FIR if unspecified
if ~isfield(input, 'int_FIR')
input.int_FIR = 1;
end

% nominal frequency can't be zero
if ~input.wnom
input.wnom = calculate_rfbw(input.PLL_rate, input.caldiv, input.RxTx, true);
input.wnom = double(input.wnom);
end

FIR = [1,2,4];
outs = [];
ripples = [];
for i = 1:3
% Recalc clocks
[input0, configIndx] = auto_fast_rates(input,FIR(i));
if configIndx == 0
continue;
end
% Update position of wnom since PLL can change
if strcmp(input.RxTx, 'Rx')
input0.wnom = 1.4 * input0.Fstop; % Rx
else
input0.wnom = 1.6 * input0.Fstop; % Tx
end
div = ceil((input0.PLL_rate/input0.wnom)*(log(2)/(2*pi)));
input0.caldiv = min(max(div,1),511);
input0.wnom = double(calculate_rfbw(input0.PLL_rate, input0.caldiv,...
input0.RxTx, true));
% Design filter
out = internal_design_filter(input0);
outs = [outs; out]; %#ok<AGROW>
ripples = [ripples;out.Apass_actual]; %#ok<AGROW>
end

if isempty(ripples)
error('No valid design found');
end

[~,i] = min(ripples);
output = outs(i);


end
42 changes: 42 additions & 0 deletions test/FilterWizardTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
classdef FilterWizardTests < matlab.unittest.TestCase

properties
SampleRates = [0.52083333,0.6:0.1:61.44].*1e6;
LTEModes = {'LTE5','LTE10','LTE15','LTE20'};
MaxRippleDB = 1;
end

methods(TestClassSetup)
end

methods (Static)
end

methods (Test)

function testAutoGenerationRipple(testCase)
import matlab.unittest.constraints.IsLessThanOrEqualTo
sr = testCase.SampleRates;
limit = testCase.MaxRippleDB;
% Test ripple of generated filters
parfor r = 1:length(sr)
out = internal_design_filter_opt_ripple(sr(r));
verifyThat(testCase, out.Apass_actual, IsLessThanOrEqualTo(limit), ...
sprintf('Generated filter for rate %d with ripple %f (Limit %f)',...
sr(r),out.Apass_actual,limit))
end
end

function testLTEFilterGeneration(testCase)
import matlab.unittest.constraints.IsEqualTo
% Verify LTE filters are created correctly
for m = testCase.LTEModes
i = load([m{:},'_input.mat']);
o = load([m{:},'_output.mat']);
output = internal_design_filter(i.input);
testCase.verifyThat(output,IsEqualTo(o.output));
end
end

end
end
Binary file added test/LTE10_input.mat
Binary file not shown.
Binary file added test/LTE10_output.mat
Binary file not shown.
Binary file added test/LTE15_input.mat
Binary file not shown.
Binary file added test/LTE15_output.mat
Binary file not shown.
Binary file added test/LTE20_input.mat
Binary file not shown.
Binary file added test/LTE20_output.mat
Binary file not shown.
Binary file added test/LTE5_input.mat
Binary file not shown.
Binary file added test/LTE5_output.mat
Binary file not shown.
37 changes: 37 additions & 0 deletions test/runTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import matlab.unittest.TestRunner;
import matlab.unittest.TestSuite;
import matlab.unittest.plugins.TestReportPlugin;
import matlab.unittest.plugins.XMLPlugin
import matlab.unittest.plugins.ToUniqueFile;
import matlab.unittest.plugins.TAPPlugin;
import matlab.unittest.plugins.DiagnosticsValidationPlugin

try
suite = testsuite({'FilterWizardTests'});
runner = matlab.unittest.TestRunner.withTextOutput('OutputDetail',1);
runner.addPlugin(DiagnosticsValidationPlugin)

xmlFile = 'FilterWizardTestResults.xml';
plugin = XMLPlugin.producingJUnitFormat(xmlFile);
runner.addPlugin(plugin);


results = runner.run(suite);

t = table(results);
disp(t);
disp(repmat('#',1,80));
for test = results
if test.Failed
disp(test.Name);
end
end
catch e
disp(getReport(e,'extended'));
bdclose('all');
exit(1);
end

save(['FilterWizardTests_',datestr(now,'dd_mm_yyyy-HH:MM:SS'),'.mat'],'t');
bdclose('all');
exit(any([results.Failed]));

0 comments on commit 924f0cd

Please sign in to comment.