2017年9月30日土曜日

ノイズ・ジェネレーター NOS01の設計

今回作るノイズジェネレーターは、NOS01という名前にした。

電源電圧: ±5V
出力波形: White Noise / 疑似 Pink Noise (-6dB/oct) / 疑似 Blue Noise (-6dB/oct)
出力振幅: 1Vp-p程度(Pink Noise) ~ 7Vp-p程度(Blue Noise)
出力インピーダンス: 1kΩ~1.5kΩ程度

回路図

ブレッドボードテスト用配線図



2017年9月28日木曜日

ノイズ・ジェネレータ White Noise/Pink Noise/Blue Noise

White NoiseにState Variable Filterをかけようと思っていたが、Pink Noiseは電力密度が1/f、Blue Noiseはfに比例ということで、周波数スペクトルはPink Noiseは-3dB/oct、Bule Noiseは+3dB/octのようだ。

フィルターだと1次フィルターの傾斜の半分に相当するので、2次(12dB/oct)のSVFは過剰。まだ多いがCR1次フィルタでやってみることにした。

±6dB/octだと定義としてはRed Noise/Purple Noiseというようだ。Webで見て回るとちゃんとリニアな±3dB/octにしようとするとめんどくさくなりそう。(「Elliott Sound Products」さんの記事「TECHLIB.COM」さんの記事など)

CR1次フィルタはカットオフ周波数以上/以下は6dB/octで減衰するが、通過域は平坦なので、カットオフ周波数を可聴帯域の外に設定した。なんちゃってPink Noise/Blue Noiseになってしまうが、お試しで使うのでまあだいたいということで。

シミュレーション回路図

CRフィルターで削るとWhite Noiseに比べてトータルの音量が下がってしまうので、後段に非反転増幅回路を入れて音量を調節した。

AC解析

CRフィルターや増幅回路の定数は厳密に求めたものではなく、聞いた感じできめた。

White Noise



おおもとのWhite Noise発生回路も前回実験した回路の定数を多少変更した。

ACカップリングのC1、C2の値は10uFだと電位が落ち着くまで時間がかかるので1uFに下げた。

fc = 1 / (2 * π * 1uF * 100kΩ) ≒ 1.59Hz

ブレッドボードで実験




OPAMPはFET入力のTL072を使った。

電源電圧:±5V

出力波形


Pink Noise

ch1:White Noise ch2:Pink Noise

Blue Noise

ch1:White Noise ch2:Blue Noise

WaveSpectraでFFT


White Noise

Pink Noise

100Hzから1kHzの区間を見ると傾きはだいたい-20dB/dec(-6dB/oct)

Blue Noise

傾きはだいたい+20dB/dec(+6dB/oct)

録音してYouTubeにあげた。


Analog 2.0のPink Noiseフィルター


gaje.jpさんのAnalog 2.0で使われているPink Noise用のフィルターをシミュレーションしてみた。

シミュレーション回路図

AC解析

100Hzから1kHzで約-13dB、1kHzから10kHzで約-7dBになっている。

反転増幅回路のLPFで極を2つ(?)作って傾斜をなだらかにして、だいたい-10dB/octdecの傾斜にしているようだ。

2017年9月25日月曜日

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

前回実験した回路

この回路のC1とR1の決め方がよくわからないので、ノイズ源として使っているQ1を電圧源に変えてAC解析してみた。

シミュレーション回路図

AC解析

C1をパラメータ解析してみると、どうやらC1がノイズの周波数分布に影響して、低域の減衰の原因になっているようだ。←確証なしです。

Second Hand Synthさんの記事Dick Cappelsさんの記事を参考に、もう少し素直に見える回路も実験してみた。

回路図

Q1で発生したノイズをQ2のエミッタ接地回路で増幅、C3とR4でACカップリングしてU1の非反転増幅回路(101倍)で増幅し、さらにU2の非反転増幅回路(4.3倍)で増幅した。OPAMPはTL072を使った。

前回の回路と比べるとOUT1の出力が小さく、後段の増幅率をかなり大きくしている。(Trの品種や個体差でノイズの出力レベルがかなり変わるようなのでもう少し調べないと、どうなのかはわからないです。)

U1とU2の間のC1とR7はU1の増幅回路のオフセット電圧が大きく、電位が偏ってしまうので(とりあえず)ACカップリングしてみた。

ブレッドボード図


電源電圧±4.5V (VCC-VEE実測値:9.00V)

ch1:OUT2 ch2:OUT1

電源が9Vだとノイズが発生しない。

電源電圧±5.0V (VCC-VEE実測値:9.99V)

ch1:OUT2 ch2:OUT1

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

電源電圧±7.5V (VCC-VEE実測値:14.91V)

ch1:OUT2 ch2:OUT1

電源電圧を上げるとOUT1(OPAMPによる増幅前)のノイズの振幅は大きくなるが、増幅後はレベルが下がっている。

前回と比べると、OUT2(OPAMPの増幅後)の波形がまばらになっているが、これはOPAMPによる増幅率が大きく周波数特性が悪化しているためだと思う。(OPAMPは増幅率が上がると周波数特性が悪化する)

WaveSpectraでFFT



この回路では可聴帯域の低域の減衰が見られない。

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 Wien Bridge DCODual OTA VCAを組み合わせて音出ししてみた。


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

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

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

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

KIK01 Proto04の構成



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

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

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

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


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


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

処理のタイミングを計測

ch1:D8 ch2:D9

ch1は一回のタイマ割り込み処理の最初と最後でH/L、ch2はAD8402 Wien Bridge DCOにSPI送信する最初と最後でH/Lさせている。AD8402 Wien 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 Wien Bridge DCOとDual OTA DCAで構成できた。

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

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

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

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

痛し痒し(@@;

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


Wien 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);
}


<追記:2017.10.03>

Page Buffer Modeで使う場合、do while()ループ内でu8g2.clearBuffer()、u8g2.sendBuffer()は不要とご指摘いただいたので、スケッチを修正しました。

</追記>

クラス指定を
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の他にも専用のライブラリが多数公開されています。


AD8402 Wien Bridge DCO はんだ付け完了

回路図

基板図

部品面

ハンダ面

消費電流 3mA
10kΩ負荷、100Hz出力時。

Github:
https://github.com/ryood/SPI_Wein_Bridge_Osc

メモ:


増幅率を決める5kΩのトリムPOTは調整がちょっとむずかしいので、多回転タイプの方が良かったかも。