電子ボリュームICをAカーブ減衰特性で制御する

以前アナログボリュームで使っていたボリュームを電子ボリュームで置き換えるためにその特性を電子ボリュームICで再現する。

 

このページの中でOctaveで計算している換算表は以下のページで計算できます。

電子ボリュームICの減衰特性(A:対数,B:直線,C:逆対数など)を計算する

参考にするボリュームの減衰曲線

TAPER
ALPS RK27ボリュームの減衰特性

目標とするボリュームの減衰曲線はALPS RK27ボリュームのA(15A)曲線(ボリューム50%位置で出力は入力の15%,指数変化)を参考にします。
見た感じ3つの直線でできているので,ボリュームの減衰曲線も3つの直線で作ることにした。

電子ボリュームIC LM1972の減衰特性

LM1972データシート
LM1972データシート

設定値0~127,128(mute)をLM1972に設定した時の減衰量グラフがFIGURE 3で,途中から減衰ステップが0.5dB刻みから1.0dBへと変化する特性になっています。
2つの直線の関数で単純な1次関数ではないのでこれを目的の減衰特性にするテーブルを用意するスクリプトを作る。

GNU Octaveで電子ボリュームの設定値0から31とLM1972の設定値をAカーブで設定するテーブルを作る

GNU Octave用減衰テーブル計算スクリプト を作った.
(注:実際の15A曲線は使いにくかったので,これは15A曲線ではありません)

%
% 電子ボリュームの減衰値を計算する
% http://ak1211.com
% Copyright (c) 2015 Akihiro Yamamoto
%
%
% This software is released under the MIT License.
% http://opensource.org/licenses/mit-license.php
%

%
% 減衰率-設定値表を作る
%

% LM1972の設定値 - 減衰量
global lm1972_table = [ 0.0 -0.5 -1.0 -1.5 -2.0 -2.5 -3.0 -3.5 -4.0 -4.5 -5.0 -5.5 -6.0 -6.5 -7.0 -7.5 -8.0 -8.5 -9.0 -9.5 -10.0 -10.5 -11.0 -11.5 -12.0 -12.5 -13.0 -13.5 -14.0 -14.5 -15.0 -15.5 -16.0 -16.5 -17.0 -17.5 -18.0 -18.5 -19.0 -19.5 -20.0 -20.5 -21.0 -21.5 -22.0 -22.5 -23.0 -23.5 -24.0 -24.5 -25.0 -25.5 -26.0 -26.5 -27.0 -27.5 -28.0 -28.5 -29.0 -29.5 -30.0 -30.5 -31.0 -31.5 -32.0 -32.5 -33.0 -33.5 -34.0 -34.5 -35.0 -35.5 -36.0 -36.5 -37.0 -37.5 -38.0 -38.5 -39.0 -39.5 -40.0 -40.5 -41.0 -41.5 -42.0 -42.5 -43.0 -43.5 -44.0 -44.5 -45.0 -45.5 -46.0 -46.5 -47.0 -47.5 -48.0 -49.0 -50.0 -51.0 -52.0 -53.0 -54.0 -55.0 -56.0 -57.0 -58.0 -59.0 -60.0 -61.0 -62.0 -63.0 -64.0 -65.0 -66.0 -67.0 -68.0 -69.0 -70.0 -71.0 -72.0 -73.0 -74.0 -75.0 -76.0 -77.0 -78.0 ];

%
% LM1972の設定値に対応したdBを返す
% 0 <= param <= 126
%
function retval = LM1972_decibel_of_set_values (param)
    global lm1972_table;
    retval = lm1972_table (param+1);
endfunction

%
% dBに対応したLM1972の設定値を返す
%
function retval = LM1972_set_values_of_decibel (dB)
    global lm1972_table;
    dB05 = 0.5*floor(dB/0.5);
    dB10 = floor(dB);
    if any (lm1972_table == dB05)
        retval = find (lm1972_table == dB05) - 1;
    elseif any (lm1972_table == dB10)
        retval = find (lm1972_table == dB10) - 1;
    else
        error ("out of bounds");
    end
endfunction

%
% PGA2311の設定値
%

%
% PGA2311の設定値に対応したdBを返す
% 1 <= N <= 255
%
function retval = PGA2311_decibel_of_set_values (N)
    retval = 31.5 - (0.5 * (255-N));
endfunction

%
% dBに対応したLM1972の設定値を返す
%
function retval = PGA2311_set_values_of_decibel (dB)
    if (-95.5 <= dB && dB <= 31.5)
        retval = floor(255 - (31.5-dB)/0.5);
    else
        error ("out of bounds");
    end
endfunction

%
% 作成する電子ボリュームマップベクタ
%
function retval = make_electric_volume_vect (rotation_travel, ideal_a_curve)
    % 電子ボリュームは3つの角度の関数で構成

    %
    % 1つめの関数
    %
    a = ideal_a_curve(1) / 0.5;
    p = 0;
    q = 0;
    f1 = a*(rotation_travel-p)+q;

    %
    % 2つめの関数
    %
    a = 1/2;    % 1 : 2
    p = 0.65;   % 65%
    q = 0.10;   % 10%
    f2 = a*(rotation_travel-p)+q;

    %
    % 3つめの関数
    %
    a = (1.0 - ideal_a_curve(30)) / (1.0 - 30/32);
    p = 1.0-(1/a);
    q = 0;
    f3 = a*(rotation_travel-p)+q;

    % 電子ボリュームカーブ
    evol_curve = max(f1, max(f2, f3));

    retval = evol_curve;
endfunction

%
%
%
format short g;
clf;

% ボリュームの段階数
volume_steps = 0:31;

% ボリューム段階[steps] - 回転位置[%]
rotation_travel = linspace (0.0, 1.0, length(volume_steps));

%
% 理想Aカーブボリューム
% y = exp(a*x) / exp(a)
% y = exp(a*x-a)
% y = exp(a(x-1))
%
% exp(a(x-1)) = y
% a(x-1) = log(y)
% a = log(y) / (x-1)
%
% 回転位置 50% は 出力電圧 15%
%
times_of_A = log(0.15) / (0.5-1);

% 理想Aカーブボリューム
ideal_a_curve = exp(times_of_A*(rotation_travel-1));

% 理想Aカーブボリュームのプロット
subplot (2,1,1);
hold on;
%plot (rotation_travel, ideal_a_curve, 'cm-@*')
plot (volume_steps, ideal_a_curve, 'cm-@*')

evol_curve = make_electric_volume_vect (rotation_travel, ideal_a_curve);

% 電子ボリュームカーブのプロット
%plot (rotation_travel, evol_curve, 'cb-@o')
plot (volume_steps, evol_curve, 'cb-@o')

% 目盛とか
axis ([ [min(volume_steps) max(volume_steps)], [0.0 1.0] ]);
grid minor;
xlabel ('volume steps');
ylabel ('Vout/Vin');
legend ('ideal A curved volume', 'electric volume curve', "location", 'north');
hold off;

% Aカーブボリュームのプロット
subplot (2,1,2);
hold on;
plot (volume_steps, 20*log10(ideal_a_curve), 'cm-@*')

%
% LM1972電子ボリュームのデシベル
%
evol_curve(1) = 10^(-78.0 / 20);  % ボリューム0は取りあえず -78dB
attenuetor_dB = 20 * log10 (evol_curve);
%
% LM1972の設定値
lm1972_param = arrayfun (@LM1972_set_values_of_decibel, attenuetor_dB);
% LM1972の減衰量
lm1972_att = arrayfun (@LM1972_decibel_of_set_values, lm1972_param);
%
printf ("// LM1972_attenuetor_dB\n")
printf ("%3.1f, ", lm1972_att)
printf("\n")
%

% LM1972電子ボリュームのプロット
plot (volume_steps, lm1972_att, "cb-@o;simulate LM1972 volume at decibel;")

%
% PGA2311電子ボリュームのデシベル
%
evol_curve(1) = 10^(-95.5 / 20);  % ボリューム0は取りあえず -95.5dB
attenuetor_dB = 20 * log10 (evol_curve);
%
% PGA2311の設定値
PGA2311_param = arrayfun (@PGA2311_set_values_of_decibel, attenuetor_dB);
% PGA2311の減衰量
PGA2311_att = arrayfun (@PGA2311_decibel_of_set_values, PGA2311_param);
%
printf ("// PGA2311_attenuetor_dB\n")
printf ("%3.1f, ", PGA2311_att)
printf("\n")
%


% PGA2311電子ボリュームのプロット
plot (volume_steps, PGA2311_att, "cg-@o;simulate PGA2311 volume at decibel;")

%
% 目盛とか
%
axis ([ [min(volume_steps) max(volume_steps)], [min(PGA2311_att) max(PGA2311_att)] ]);
grid minor;
xlabel ('volume steps');
ylabel ('attenuation [dB]');
legend ( 'ideal A curved volume','LM1972 volume steps of decibel', 'PGA2311 volume steps of decibel', "location", 'southeast');
hold off;

%
% 計算結果を出力
%

printf ("// lm1972_param\n")
printf ("%3d, ", lm1972_param)
printf("\n")
%
printf ("// PGA2311_param\n")
printf ("%3d, ", PGA2311_param)
printf("\n")

%print -Ggswin32c.exe foo.png

GNU Octave用減衰テーブル計算スクリプトで作ったテーブル

シミュレーション結果
シミュレーション結果
// LM1972_attenuetor_dB
-78.0, -57.0, -51.0, -47.5, -45.0, -43.0, -41.5, -40.0, -39.0, -38.0, -37.0, -36.0, -35.5, -34.5, -34.0, -33.5, -30.0, -26.5, -24.0, -22.0, -20.5, -19.0, -18.0, -17.0, -13.5, -10.0, -7.5, -5.5, -4.0, -2.5, -1.5, 0.0,

// PGA2311_attenuetor_dB
-95.5, -57.0, -51.0, -47.5, -45.0, -43.0, -41.5, -40.0, -39.0, -38.0, -37.0, -36.0, -35.5, -34.5, -34.0, -33.5, -30.0, -26.5, -24.0, -22.0, -20.5, -19.0, -18.0, -17.0, -13.5, -10.0, -7.5, -5.5, -4.0, -2.5, -1.5, 0.0,

// lm1972_param
126, 105,  99,  95,  90,  86,  83,  80,  78,  76,  74,  72,  71,  69,  68,  67,  60,  53,  48,  44,  41,  38,  36,  34,  27,  20,  15,  11,   8,   5,   3,   0,

// PGA2311_param
  1,  78,  90,  97, 102, 106, 109, 112, 114, 116, 118, 120, 121, 123, 124, 125, 132, 139, 144, 148, 151, 154, 156, 158, 165, 172, 177, 181, 184, 187, 189, 192,

減衰曲線のグラフとAカーブ32段階電子ボリュームの減衰曲線のテーブルが得られた。このあとでボリューム0は127=muteに書き換えます。
検討中の名残でLM1972とPGA2311の減衰設定値も出てますがそれぞれのグラフは重なっています.

チャンネルをLM1972に設定する

LM1972の2つの減衰器にはそれぞれに独立した値を設定できるのですが,今回の目的はステレオ電子ボリュームなので両チャンネル(L/R)には同じ値を設定します。

LM1972データシート
LM1972データシート

LM1972のDATA-INに
Address Register(Byte 0)のbit7からbit0,
次に設定値のbit7からbit0を送り出します.

減衰値をLM1972に設定する

LM1972データシート
LM1972データシート
  1. LOAD/SHIFTピンをLに
  2. DATA-INに最上位ビット(bit7)から設定値を送り出す
  3. CLOCKピンをHに
  4. 150ns以上待って
  5. CLOCKピンをLに
  6. 設定値を送り出す, CLOCKピンをH/Lにする作業を
    すべてのデーターを送り出すまで繰り返す
  7. LOAD/SHIFTピンをHに

これを行なう関数がこの部分

ステレオAカーブ電子ボリューム設定関数

//
//電子ボリュームをsetvolにする
//
elevol_t elevol_setvolume( elevol_t setvol )
{
    static const uint8_t tVolume[32] PROGMEM = {
        // lm1972_param
        127, 105,  99,  95,  90,  86,  83,  80,  78,  76,  74,  72,  71,  69,  68,  67,  60,  53,  48,  44,  41,  38,  36,  34,  27,  20,  15,  11,   8,   5,   3,   0,
    };
    elevol_t idx = elevol_validate_volume(setvol);
    uint8_t v = pgm_read_byte(&tVolume[idx]);
    //
    //IN1 : left
    //channel selection : 0
    //
    LM1972_write( 0, v );
    //
    //IN2 : right
    //channel selection : 1
    //
    LM1972_write( 1, v );

    return idx;
}

電子ボリュームコントローラ回路

コントローラ回路
アナログ回路

電子ボリュームコントローラソフトウェア

electric_volume.h
electric_volume.c
2チャンネル電子ボリュームIC(LM1972)を32段階ステレオ電子ボリュームとして使うプログラムです。

One thought on “電子ボリュームICをAカーブ減衰特性で制御する

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください