Skip to content

Commit 2c2d131

Browse files
committed
add original MATLAB scripts used to develop AGC algorithms
1 parent 7a6b972 commit 2c2d131

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

docs/MATLAB/OpossumAGC.m

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
%% OpossumAGC Automatic gain control with hysteresis control of noisy signals
2+
%
3+
% Copyright (c) 2017-2021 Winry R. Litwa-Vulcu. All rights reserved.
4+
%
5+
% This program is free software: you can redistribute it and/or modify
6+
% it under the terms of the GNU General Public License as published by
7+
% the Free Software Foundation, either version 3 of the License, or
8+
% (at your option) any later version.
9+
%
10+
% This program is distributed in the hope that it will be useful,
11+
% but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
% GNU General Public License for more details.
14+
%
15+
% You should have received a copy of the GNU General Public License
16+
% along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
clc; close all hidden; clearvars; %drawnow; pause(0.05);
19+
20+
volume = 34;
21+
audio_level = 3452;
22+
range_mB = 600;
23+
range_step_mB = 50;
24+
25+
noiseline = @(start, stop, len, noiselevel) rot90((randn(1, len) .* noiselevel) ...
26+
+ linspace(start, stop, len), -1);
27+
segment_length = @(x) round(abs(x * randn));
28+
29+
raw_audio_level = ([noiseline(3000, 4000, segment_length(1001), 30)
30+
noiseline(4000, 2800, segment_length(1001), 40)
31+
noiseline(2800, 6500, segment_length(1001), 50)
32+
noiseline(6500, 7000, segment_length(1001), 45)
33+
noiseline(7000, 6300, segment_length(1001), 55)
34+
noiseline(6300, 4000, segment_length(1001), 50)
35+
noiseline(4000, 4500, segment_length(1001), 35)
36+
noiseline(4500, 1800, segment_length(1001), 30)
37+
noiseline(1800, 1700, segment_length(1001), 20)
38+
noiseline(1700, 3600, segment_length(1001), 30)]);
39+
40+
mean_audio_level = zeros(size(raw_audio_level));
41+
mbuff = raw_audio_level(1) * ones(1, 32);
42+
buff_indx_32 = 1;
43+
for k = 1:length(raw_audio_level)
44+
if (buff_indx_32 > 32)
45+
buff_indx_32 = 1;
46+
end
47+
if (raw_audio_level(k) > mbuff(buff_indx_32))
48+
mbuff(buff_indx_32) = mbuff(buff_indx_32) ...
49+
+ (raw_audio_level(k) - mbuff(buff_indx_32)) / 2;
50+
else
51+
mbuff(buff_indx_32) = mbuff(buff_indx_32) .* (31/32);
52+
end
53+
mean_audio_level(k) = mean(mbuff);
54+
55+
buff_indx_32 = buff_indx_32 + 1;
56+
end
57+
58+
dB_CoefTable = [2053, 2175, 2303, 2440, 2584;
59+
2738, 2900, 3072, 3254, 3446;
60+
3651, 3867, 4096, 4339, 4596;
61+
4868, 5157, 5462, 5786, 6129;
62+
6492, 6876, 7284, 7715, 8173];
63+
levels_raw = bitshift(uint32(audio_level .* dB_CoefTable), -12);
64+
65+
[v_map, a, b, C] = com.programming.OpossumVolumeMap(volume, range_mB, range_step_mB);
66+
67+
v = b:-1:a
68+
C
69+
70+
%VolOut_absolute_mB = fliplr(rot90(reshape(c(v_map - a + 1), 5, 5), -1))
71+
dBFastRelativeLevel_mB = levels_raw
72+
VolOut_setting = fliplr(rot90(reshape(v_map - 1, 5, 5), -1))
73+
74+
% ##################################################################################################
75+
[vol, volOut] = deal(volume);
76+
DB_FAST_COEFFICIENT_COUNT = numel(dB_CoefTable);
77+
levels_raw = sort(double(levels_raw(:)));
78+
79+
80+
indx = 1 * ones(length(raw_audio_level), 1);
81+
indx(1) = 13;
82+
prev_indx = 1;
83+
for m = 2:length(raw_audio_level)
84+
for k=DB_FAST_COEFFICIENT_COUNT:-1:1
85+
if (levels_raw(k) < mean_audio_level(m))
86+
if (abs(prev_indx - (k)) > 1)
87+
indx(m) = (k);
88+
prev_indx = indx(m);
89+
break;
90+
else
91+
indx(m) = prev_indx;
92+
break;
93+
end
94+
end
95+
end
96+
end
97+
98+
H = plotyy((1:length(raw_audio_level))./10, raw_audio_level, ...
99+
(1:length(raw_audio_level))./10, v_map(indx));
100+
hold on;
101+
plot(H(1), (1:length(raw_audio_level))./10, mean_audio_level, 'r');
102+
L = line([zeros(1, 25); length(raw_audio_level) .* ones(1, 25)], [levels_raw.'; levels_raw.']);
103+
set(L(13), 'lineWidth', 3);
104+
set(H(1), 'YLim', [min(levels_raw), max(levels_raw)]);
105+
set(H(2), 'YLim', [a, b]);
106+
set(H(2), 'YGrid', 'on', 'YMinorGrid', 'off', 'YTick', 1, 'YMinorTick', 'on', 'YTickMode', 'auto');
107+
A2 = get(H(2), 'Children');
108+
set(A2(1), 'LineWidth', 2);
109+
110+
%figure(2); plot(indx)

docs/MATLAB/OpossumVolumeMap.m

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
function [v_map, a, b, C] = OpossumVolumeMap(volume, range_mB, range_step_mB)
2+
%% OpossumVolumeMap generates a volume map v_map for a given input volume and range
3+
%
4+
% Copyright (c) 2017-2021 Winry R. Litwa-Vulcu. All rights reserved.
5+
%
6+
% This program is free software: you can redistribute it and/or modify
7+
% it under the terms of the GNU General Public License as published by
8+
% the Free Software Foundation, either version 3 of the License, or
9+
% (at your option) any later version.
10+
%
11+
% This program is distributed in the hope that it will be useful,
12+
% but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
% GNU General Public License for more details.
15+
%
16+
% You should have received a copy of the GNU General Public License
17+
% along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+
volume(volume < 1) = 1;
20+
volume(volume > 64) = 64;
21+
22+
offset_mB = linspace(0, 2 * range_mB, round((2 * range_mB)/50) + 1);
23+
24+
gain_mB = [-10950; -9290; -9030; -8680;
25+
-8430; -8080; -7830; -7470;
26+
-7220; -6870; -6620; -6270;
27+
-6020; -5670; -5420; -5060;
28+
-4810; -4560; -4370; -4210;
29+
-3960; -3760; -3600; -3340;
30+
-3150; -2980; -2720; -2520;
31+
-2350; -2160; -1970; -1750;
32+
-1640; -1540; -1440; -1310;
33+
-1200; -1090; -990; -890;
34+
-710; -600; -500; -340;
35+
-190; -50; 50; 120;
36+
160; 200; 240; 290;
37+
340; 390; 440; 490;
38+
540; 590; 650; 700;
39+
760; 820; 880; 950];
40+
41+
% determine the levels within the range
42+
a = 1;
43+
b = 64;
44+
if (volume ~= 1)
45+
for k = volume-1:-1:1
46+
if ((gain_mB(k) - gain_mB(volume)) < -range_mB);
47+
a = k + 1;
48+
break;
49+
end
50+
end
51+
end
52+
if (volume ~= numel(gain_mB))
53+
for k = volume+1:numel(gain_mB);
54+
if ((gain_mB(k) - gain_mB(volume)) > range_mB)
55+
b = k - 1;
56+
break;
57+
end
58+
end
59+
end
60+
61+
v = b:-1:a;
62+
sizeof_v = numel(v);
63+
c_normal = (gain_mB(v) - gain_mB(volume));
64+
65+
v_map = zeros(25, 1);
66+
skip_zero_indx = 0;
67+
map_indx = 1;
68+
for k=1:numel(offset_mB)
69+
if (c_normal(map_indx) == 0)
70+
skip_zero_indx = 1;
71+
end
72+
if ((map_indx + skip_zero_indx) <= sizeof_v)
73+
if ((range_mB - c_normal(map_indx + skip_zero_indx)) < ((k - 1) * range_step_mB))
74+
map_indx = map_indx + 1;
75+
end
76+
end
77+
v_map(k) = v(map_indx);
78+
end
79+
80+
C = [gain_mB(v), c_normal, (range_mB - c_normal)];
81+
end

0 commit comments

Comments
 (0)