2017年9月23日土曜日

ノイズ・ジェネレータ―の実験

回路図

※回路図はLTSpiceで書いたが、シミュレーションできない。

「達人と作るアナログシンセサイザー入門」とLe coin de F4GRXさんの記事を参考にしました。



Analog 2.0の回路図は公式サイトに掲載されています。http://gaje.jp/analog20/noise_mixer.html

定数はcoin de F4GRXさんの記事を引用。gaje.jpさんのブログ記事によるとノイズ発生用のTrはBC547がいいと書いてあるが、手持ちの2SC1815を使った。

Trのベース・エミッタ間に逆電圧をかけるとノイズが発生する(アバランシェ降伏というらしい)ことを利用した回路で、そのままではレベルが低いのでエミッタ接地増幅回路で電圧増幅している。(Analog2.0はPNP Trのエミッタ接地)

Trのベース・エミッタの絶対定格(2SC1815の場合は5V)を越えて電圧をかける必要があるので、Trは壊れる。

Q2のエミッタ接地回路はC2で接地されているので交流の増幅率はhFEになる。

電源電圧が低いとノイズの出力レベルが低いので、後段にOPAMPの非反転増幅回路も入れてみた。

回路図

OPAMPはNJM4580を使い、電源は両電源とし、電源電圧を変えながら測定してみた。

ブレッドボード配線図


電源電圧:±2.5V VCC-VEE実測値:5.0V

ch1:OUT2 ch2:OUT1

ノイズはほとんど発生しない。

電源電圧:±5V VCC-VEE実測値:9.97V

ch1:OUT2 ch2:OUT1

OUT1:460.0mV
OUT2:2,060mV

10Vかけるとノイズが発生する。

電源電圧:±6V VCC-VEE実測値:11.95V

ch1:OUT2 ch2:OUT1

OUT1:1,380mV
OUT2:5,760mV

電源電圧:±7.5V VCC-VEE実測値:14.98V

ch1:OUT2 ch2:OUT1

OUT1:2,880mV
OUT2:10,560mV

電源電圧を上げると出力ノイズレベルも大きくなる。

WaveSpectraでFFT


WaveSpectraで可聴帯域のスペクトルを見てみた。信号レベルが大きいとオーディオ・インターフェイスが心配なので一部のみ。オーディオ・インターフェイスの入力はGuitar入力(入力インピーダンス:1MΩ)にした。

電源電圧:±5V VCC-VEE実測値:9.97V
オペアンプによる増幅前

電源電圧:±5V VCC-VEE実測値:9.97V
オペアンプによる増幅後

電源電圧:±7.5V VCC-VEE実測値:14.98V
オペアンプによる増幅前

オペアンプによる増幅前だと1kHz以下が減衰している。

オシロによるFFT


電源電圧:±7.5V VCC-VEE実測値:14.98V
オペアンプによる増幅前

全幅1kHz(100Hz/Div)で特に減衰しているようにも見えない。

オーディオ・インターフェイスの入力が影響しているかもしれないので、OPAMPをTL072(FETタイプで入力インピーダンスが高い)のボルテージフォロア、回路図のR4を1MΩにしてOUT2を測定。

電源電圧:±7.5V VCC-VEE実測値:14.98V
TL072 ボルテージフォロア

低域の減衰はかなり抑えられる。

エミッタ接地の出力インピーダンスが4.7kΩ程度あるのとC3でAC結合しているのが影響しているのか?C2の容量もあやしい。

実験後のTrの特性


AVRトランジスタテスターで実験後Trの特性を測定してみた。

Q1(2SC1815-GR)
B=297
Vf=690mV

Q2(2SC1815-Y)
B=172
Vf=706mV

Q1はもっとわかりやすく壊れるかと思ったがそうでもないようだ。

メモ:


アバランシェ降伏によるノイズはツェナーダイオードでもできるらしい。

トラ技2015年8月号の「楽器エフェクタ製作集」にはCMOSロジックICのインバーター(Unbuffer)を使ったノイズ・ジェネレーターの回路が載っている。74HCシリーズでもできるんだろうか?

2017年9月18日月曜日

KIK01 作戦検討その2

AD8402 Wein Bridge DCODual OTA VCAを組み合わせて音出ししてみた。


前半は振幅と周波数のエンベロープをいじって、中盤は音域を高くしてスネア・タムっぽくしたもの、後半は過大入力をいれてOverDriveしている。

ジャンル的には、Techno → Psy Trance → Hard Styleっぽいかんじでしょうか(^q^?

キックマシン KIK01 Nucleo(mbed)でプロトタイピング」ですべて内部演算をしていたものと比べて出音は丸い感じになってるかな?

XSplitで録音/録画して、YouTubeにあげているのでわかりにくかもしれません。

KIK01 Proto04の構成



消費電流
NucleoF446 + AD8402 Wein Bridge DCO: 100mA~120mA
Dual OTA VCA: ±17mA

NucleoF446はまあまあいい量の電力を食いよりますね。

mbed repository:
https://os.mbed.com/users/ryood/code/KIK01_Proto04/ Revision:23

サンプリングレートの問題


今回は元になる波形はWein Bridgeからアナログ的に出力していて音声出力のためのサンプリングレートではないが、一定の周期で波形の周波数と振幅を更新しているのでその周期の問題です。


WaveSpectraでスペクトルを見たものだが、32,000Hzあたりにピークが出ている。これは上記サンプリング周期によるデジタル的な歪だと思う。直接音にしなくても、離散処理するとこんなとこにまで影響が現れる。

処理のタイミングを計測

ch1:D8 ch2:D9

ch1は一回のタイマ割り込み処理の最初と最後でH/L、ch2はAD8402 Wein Bridge DCOにSPI送信する最初と最後でH/Lさせている。AD8402 Wein Bridge DCOは2回送信しているので間に細い線で分割されている。

周期は31usで、逆数をとって約32,258Hz。

タイマ割り込み一回分の処理時間は16.3us、SPI通信で11.7us(カーソルで測定)とほとんどがSPI通信に食われている。エンベロープを対数カーブにする浮動小数点演算や内蔵DACからの出力はch1とch2のHの時間の差分で行っていて、処理が重そうなわりにほとんど消費していない。

ch1の間隔を見るとまだ余裕がありそうだが、これ以上処理の間隔を縮めると処理が追いつかず、入力系の処理ができなくなる。入力系の処理はMCP3008と遅~いSPI通信を行っている。

PSoC 5LPはCortex-M3でFPUが載っていないが、SPI通信はNucleoをmbedで使うよりも高速なので使ってみる手はあるかも。

または、Nucleoをmbedではなくネイティブ環境でやってみる。←かなりめんどくさい(@@;

でもまあ、32,000Hzは可聴帯域外だし、高速化できたとしてもエイリアスの出る周波数が高くなるだけで消えるわけではないので、とりあえずは一旦妥協する方向で。

Dual OTA VCAのエンベロープ波形の発振



上図はDual OTA VCAの回路の一部で、R8とC3で1次LPFを構成してエンベロープ波形を滑らかにしている。ところが、R8を0Ω側に回し切ると発振してしまう。

抵抗値を少し上げる(正常

ch1:エンベロープ入力 ch2:エンベロープLPF通過後

抵抗値ほぼ0Ω(発振)

ch1:エンベロープ入力 ch2:エンベロープLPF通過後

拡大(発振波形)

R8を0ΩにするとIC3Aのボルテージフォロアの出力をIC4Aの非反転入力(インピーダンス高)に直接つないでいることになり、GNDに落としているC8がもろに容量性負荷というやつになっていると思う。

発振しないようにするには、固定抵抗でゲタをはかすべきだと思うが、トリムPOTをちょっとだけプラス側に回しておけば大丈夫なので、今後気をつけることにする。←もう少し理論的なことも調べる。

KIK01の第二次作戦



図の下半分あたりは、AD8402 Wein Bridge DCOとDual OTA DCAで構成できた。

キック音源としては、Atackでかすかにシャンシャンいう音を混ぜたい。サンプリング音源と混ぜてもいいが、アナログシンセではノイズ・ジェネレーターを使っていることが多いので試しにやってみたい。

ホワイトノイズを発生させて、フィルターを通してピンクノイズやブルーノイズにしてみる。ノイズ系はシーケンサーから制御するのは振幅変調のみ。フィルターはSVFを考えていて、カットオフ周波数やレゾナンスのパラメータは普通のPOTで手で設定する。フィルターにエンベロープをかけても面白いかも知れないので後で差し替えられるようにしておく。

NucleoF446は、SPIが3系統付いていてSPI制御はしやすいが、DACは2個しかない。

NucleoF303は、DACが3系統使えるがSPIが1系統しかなく、演算速度も若干遅い。

痛し痒し(@@;

サイン波出力部分の改良案


Wein Bridgeは周波数が高くなると出力振幅が小さくなるので、周波数が高くなると振幅が大きくなるように補正してVCAにエンベロープを出力するようにして、ようすを見てみる。

プログラム上でexp()関数を使ってエンベロープ波形をアナログチックにしているが、Digital Filterのプログラムを書いてIIRを通して違いを見てみる。Digitalフィルターのパラメータはプログラム上で計算するのは大変なので、いくつか用意しておいて切り替えられるようにする。

メモ:


現状でもエンベロープ設定用にPOTx16を使っているが、ノイズジェネレーターのエンベロープ波形を設定するとなるとさらに8個ぐらいは必要そう。

POTをズラッと並べた方がパラメータいじりは楽だが、コンパクトにしたい気もするなぁ・・・

2017年9月16日土曜日

u8g2のFull BufferとPage Buffer


この間、u8g2で描画テストをしてみてSRAMを消費しすぎていたので原因を考えてみた。
#define RULER_STR "ABCDEFGHI012345678901234567890"
としていて、
u8g2.drawStr(0,10,RULER_STR); // write something to the internal memory
u8g2.drawStr(0,21,RULER_STR);  // write something to the internal memory
u8g2.drawStr(0,32,RULER_STR);  // write something to the internal memory
と、「#define」した文字列を3回も定義していることになるので、これが原因かも?と思って「#define」のところを「const char*」に変更してみた。

「const char*」なら定義は1回なので1/3になるはずだが・・・

Arduinoのスケッチ
<HiLetgo_IIC_OLED_SSD1306_128x32_u8g2_F_FontTest.ino>

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED

void setup(void) {
  u8g2.begin();
}

const char* RULER_STR = "ABCDEFGHI012345678901234567890";

void loop(void) {
  u8g2.clearBuffer();                   // clear the internal memory
  u8g2.setFont(u8g2_font_8x13_tf);  // choose a suitable font  
  u8g2.drawStr(0,10,RULER_STR); // write something to the internal memory
  u8g2.drawStr(0,21,RULER_STR);  // write something to the internal memory
  u8g2.drawStr(0,32,RULER_STR);  // write something to the internal memory
  u8g2.sendBuffer();                    // transfer internal memory to the display
  delay(1000);

  u8g2.setDrawColor(1);
  u8g2.drawBox(0, 0, 128, 32);
  u8g2.sendBuffer();
  delay(1000);  
}

ビルドの結果は
最大30720バイトのフラッシュメモリのうち、スケッチが9650バイト(31%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が1512バイト(73%)を使っていて、ローカル変数で536バイト使うことができます。
となって、SRAMの消費量は「#define」の時と同じ1512バイト。この程度は最適化されるようだ。

Arduino IDEと言っても中でavr-gccでGCCを使っている。さすがGCCは賢い(^q^!

<追記:2017.09.18>

文字列定数はSRAMではなくフラッシュメモリに格納されると思うので、フラッシュメモリの使用状況も比較。

「#define」時
最大32256バイトのフラッシュメモリのうち、スケッチが9644バイト(29%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が1512バイト(73%)を使っていて、ローカル変数で536バイト使うことができます。

「const char*」時
最大30720バイトのフラッシュメモリのうち、スケッチが9650バイト(31%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が1512バイト(73%)を使っていて、ローカル変数で536バイト使うことができます。

フラッシュメモリの使用量は「const char*」の方が増えている(@@;

</追記>

Page Buffer


ということはFull Bufferだと転送用バッファでメモリ領域を専有しているのでは?と思って、Page単位のクラスを使ってみた。

Arduinoのスケッチ
<HiLetgo_IIC_OLED_SSD1306_128x32_1_FontTest.ino>

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>

U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED

void setup(void) {
  u8g2.begin();
}

const char* RULER_STR = "ABCDEFGHI012345678901234567890";

void loop(void) {
  u8g2.firstPage();
  do {
    u8g2.clearBuffer();         // clear the internal memory
    u8g2.setFont(u8g2_font_8x13_tf);  // choose a suitable font
    u8g2.drawStr(0,10,RULER_STR); // write something to the internal memory
    u8g2.drawStr(0,21,RULER_STR);  // write something to the internal memory
    u8g2.drawStr(0,32,RULER_STR);  // write something to the internal memory
    u8g2.sendBuffer();          // transfer internal memory to the display
  } while (u8g2.nextPage());
  delay(1000);

  u8g2.firstPage();
  do {
    u8g2.clearBuffer();         // clear the internal memory
    u8g2.setDrawColor(1);
    u8g2.drawBox(0, 0, 128, 32);
    u8g2.sendBuffer();
  } while (u8g2.nextPage());
  delay(1000);
}


クラス指定を
U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED
に変更した(クラス名の途中のFを1にする)。描画の仕方もPage単位で「do while()」で回すように変更。
最大30720バイトのフラッシュメモリのうち、スケッチが9730バイト(31%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が616バイト(30%)を使っていて、ローカル変数で1432バイト使うことができます。
Full Bufferが1512Bなのに対して、Page Bufferだと616Bで済んでいる。

ただし、ページ単位の書き換えだと書き換えが上から下へとダラダラした描画になる。ベースマシンのシーケンサーのStep表示みたいなリアルタイム書き換えだと見栄えがよくない。

アニメーションさせようと思うと、昔のパソコンの裏VRAMやDirect Drawみたいな感じでFull Bufferを使ったほうがいいと思う。

メモ:


SSD1306はu8glibやu8g2の他にも専用のライブラリが多数公開されています。