電音の歩み

電子楽器を中心とし、ものづくり関係も含めて紹介していきます。

Frequency Shifter の検討(その3) 二相正弦波発振器

f:id:hhh_yama:20180810234932j:plain

                 grapf 1

f:id:hhh_yama:20180810234944j:plain

                circuit 1

二相正弦波発振器

Frequency Shifter を構成するには、下式のcos(αt) , sin(αt) 二相の変調用の正弦状波発振器が必要です。

  f:id:hhh_yama:20180810235423p:plain

私がFrequency Shifterに期待する効果が、

  (A) 周波数シフト(上下) & 倍音構成を崩す

  (B) ディチューンによるコーラス効果

です。

 

変調用発振器の発振周波数としては、(A)の為には原音の音高以上の可変域が必要になり、

(B)の為には0.1 Hz以下までの超低周波まで可変域の下限が必要です。

また、応用を広げる意味では VCO にしたいところですが、今回は早く結果・効果が知りたいのでVCOは諦めることにします。

 

また、簡単な構成で低歪みな正弦状波を出力したいので、ファンクションジェネレータ方式にはしないで、正弦状波を直接発振する方式とします。

 

選んだ方式は、二重積分ループを使った状態変数型の発振回路です。

 circuit1 がその回路です。

U2,U3が反転積分器でU1で反転させてメジャーループを構成しています。

out2を cos out とすると、それをU1で反転した -cos を反転積分した out1 は、sin outになり、

それをさらに反転積分した out2 は cos になり正帰還ループになります。

またout1からのマイナーループもあり振幅の安定化を計っています。

 

発振周波数は、二つの積分器の時定数を変えることにより行います。

C=C1=C2, R=R3=R4 とすると発振周波数は、f = 1/(2π C R )になります。

実際には、2連VRを使うことになります。例えば100KのVRを使うとき直列に例えば1Kの抵抗を接続します。このように、この構成でそこそこ実用的に可変できる範囲は二桁程度です。それ以上欲張ると、周波数の高域の可変カーブが急峻になりすぎ使えません。また、2連VRのトラッキング誤差が高域で顕著になるので発振が安定しなくなります。

したがって、目標の可変域を得るためには、Cを何段階かに切り替えることにします。

 

積分時定数を変える方法として、2連VRで入力電圧をアッテネートした上でその電圧を固定のRを使った積分器を使う構成もあります。 この構成はA型VRを使うと周波数の可変カーブが自然になるので私もよく使っていましたが、低周波側では積分器の入力電圧が低くなるため、オフセットバイアス電圧の影響が顕著になるためやはり可変範囲を大きく出来ないので、採用しないことにしました。

 

この定数でシミュレーションしたのがPhoto1です。

発振ループゲインの調整は、R7を増減します。

R7を大きくしすぎると発振が止まり、小さくしすぎるとout1の正弦状波出力のつぶれが増えてきます。out2の歪みは変化しません。

 

周波数切り替えで、Cを切り替えたときR7 の調整値が変わらなければ良いのですが。

 

 

 

 

 

 

Frequency Shifter の検討(その2) Dome Filterの検討

f:id:hhh_yama:20180808101443j:plain

graph 1

f:id:hhh_yama:20180808101458j:plain

circuit1

 

Dome Filter ?

入力された原音の基音と高調波の位相を90°シフトするフィルタをDome Filterと呼びます。

ヒルベルト変換のアナログ近似で、実部用と虚部用の二つのAll Pass Filter ( Phase Shifter )で構成します。

各Phase Shifterは、オーディオ帯域を出来るだけ直線的に位相をシフトするため、一段で180°シフトできる一次のPhase Shifterをつなぎ目を滑らかに6段つないで広帯域に直線的位相シフトをしています。graph1の上と下のカーブがcircuit1の上段と下段のPhase Shifterの特性です。

20Hzから20KHzの範囲でほぼ直線に見え、上段と下段の出力間の位相差は90°になるようにしています。実際シミュレーションではこの範囲でほぼ90°になっています。

この特性を得るにはR,Cの精度が相当必要と思われますが、時定数のRの値が全て異なるのでこれを実装するのは大変です。

実際どんな音が得られれば良いのかも未知数ですので、今回の試作では5%以下で良いつもりでやります。

 

入力された原音の基音と倍音を全て90°位相シフトするのは、アナログでは不可能(?)なので、このような少しごまかしっぽい構成がとられています。

人間の耳はオーディオ信号の位相が変化しても分からないということで、上段の出力を原音の代わりとみなすことで、90°シフトを実現していると理解しています。

 

 

Frequency Shifter の検討(その1) 原理と構成について

 

 

f:id:hhh_yama:20180806233831p:plain 

                                       Fig1

f:id:hhh_yama:20180806004201j:plain

 

Freqency Shifterって?

 

長い入院生活の間で何か面白いモジュールの検討をしたいと思っていました。

そのとき頭に浮かんだのが、Freqency Shifter です。

かなりマイナーなモジュールで、私自身も実際の製品を見たことも無く、音を聞いたこともありません。

 なぜ思いついたかというと、10年近く前ですが、houshu氏が学会で京都に来たとき、折角だからということで夜に京都でお会いし飲む機会がありました。

そのとき、彼が話題のひとつとして持ってきてくれたのがFreqency Shifterで、資料としてたしかUSP(米国特許)を見せて貰ったように思います。

このモジュールがどれほど音作り効果が期待できるかはともかく、技術的な面白さに大層興奮したことだけは記憶しています。

 

検討に入る前のおぼろげな私の理解

・Ring Modulatorで得られるピッチシフトは、必ず二つの周波数(和と差の周波数)が発生する。

 多くの場合不協和の2音が現れるので、倍音が多い原音を入れるとすぐ濁ってしまうので、きれいな音を出すには、原音は倍音の少ないものに限定される。または、あえて濁った音を出す使い方になる。

・なんとかして和や差だけの周波数が得られれば、濁らせずにピッチシフトができ、より広範囲な応用ができそう。

・Ring Modulatorでの4象限乗算を90度位相のずれた、sineとcosで各々行えば、差の出力を打ち消すことが出来そうである。

・自分で発生する変調信号では、sineと同時にcosも出力するの構成が可能。

 しかし、入力される任意の原音(倍音も含めて)に対して90度位相のずれた信号(倍音含む)を作るのは困難。たぶん不可能だろう。(各倍音を検出して90度位相のずれた信号を作るデジタル的な手法は×。原音には和音や打楽器音なども来るため。)

・dome filterという巧妙な技術により原音を二相化できそう。

 ポイントは原音の全ての倍音を二相化するのでは無く、位相の絶対的なシフトは気にせず(耳では位相だけがずれても違いは分からないはずなので)相対的に90度位相のずれた出力を出す二組のPhase Shifter(広域に直線的に位相がシフトよう設計された)の二組の出力を、sineとcosとする。

 dome filterはFreqency Shiftwerのキモですので次回詳しく説明します。

 

 今回の検討

 病室からhoushu氏にメールして、moog他の資料のURLを教えて頂き、時間を掛けて検討を進めました。

 その結果を整理すると、

 

(1) Freqency Shifter(FS) は Ring Modulator(RM) の発展系である。

   ・Ring Modulator(RM)

 RMの機能を数式で表すと、原音を正弦状波 cos(ωt)、変調波も正弦状波 cos(αt)とすると、

両信号の4象限乗算になるので、  

f:id:hhh_yama:20180806000410p:plain

となり、よく知られているように、両信号の和の周波数の正弦状波と、差の周波数の正弦状波がミックスされたものになります。

実用的には変調波には正弦状波が用いられますが、原音には何が入力されるか解かりません。

倍音も含む場合は、例えば2倍音に対しても式(1)からα加算とα減算のミックスが生成されます。

倍音に対して一定周波数が加減算されるので、ピッチか変わる効果と倍音構成が崩れる効果が得られます。

 

 ・Freqency Shifter(FS)

 ピッチシフト効果を狙うためには、和のみや差のみを取り出したいところです。

 それが得られる数式が、三角関数の加法定理です。

f:id:hhh_yama:20180806003340p:plain

  (2A)を用いると和のみが得られ、(2B)で差が得られます。

 これを実現するには、二つのRing Modulator と加減算器が必要で、

 構成を図で表すとFig.1 のようになります。

 変調側のsin(αt)を作るのは、cos(αt)とsin(αt)を発振する二相発振器で可能ですが、

 もっと難しいのは、sin(ωt)を作ることです。

 これには、上で説明したDome filterを使います。

 

6809/Z80マシーンを発掘しました(5) 動かしてみました!

大分メンテしたら、安定に動くようになりました。

どんな感じかは動画で見てください。

8" フロッピーの迫力ある動作音も懐かしいです。

 

youtu.be

6809/Z80マシーンを発掘しました(4) マルチCPUの仕組み(2) ソフト編

マルチCPUの仕組み(2) ソフト編

動いているCPUが自分自身を停止させ、相手を動かせるハードの仕組みについては、

6809/Z80マシーンを発掘しました(3) マルチCPUの仕組み(1) ハード編 - 電音の歩み

を見てください。

とてもシンプルなハードですが、シンプルすぎてどのように使えば良いのか疑問にもたれた方もあるでしょう。

 

実際、このハードだけではCPUを交互に動かせるだけなので何もできません。

これを活かすソフト面での仕掛けが、「CPU Manager」です。

この図は、発掘したソースコードを見て、私が再発見しながら書いた「CPU Manager」の動作フローです。左半分は6809コード、右半分はZ80コードです。

仕組みはとてもシンプルですが、驚くほどパワフルです。

 

この「CPU Manager」の狙いは、

 (1) 6809からZ80の関数を、Z80から6809の関数を引数付きでコールできる。

         ( ACCA, X ) は、 ( Areg , HLreg )に相互に引き継がれます。 

 (2)相互の関数コールは、多重にできる。

だけです。

 これができれば、相手のCPUの関数も自在に利用できることになりますよね。

 

f:id:hhh_yama:20180303131015j:plain

  

まず、基本動作を説明します。

Z80側の初期化

Resetが掛かると最初に6809が動き出すので6809側の色々な初期化は自由にできますがZ80側の初期化も必要です。

話を簡単にするため、ここには書いていない6809側の初期化コードで、Z80をResetから起動しSPを設定し、< 0 >のルートでCHG_CPUのポイントまで導き、制御を6809の初期化コードに戻します。(Z80 のRESET後の例外的な動きのためハードでもRESETを記憶するD-FFが付いています)

これで Z80 側の準備もできました。

 

重要なのは、CHG_CPU(どちらのCPUからも切替ポートにダミーライトすると相手に制御が移る)のポイントは、どちらのCPUも1箇所しか無いことです

 

■6809からZ80の関数をコールする動作

6809でZ80の関数(サブルーチン)を呼びたいときは、

    CALLZ80  address

というマクロを記述します。 

実際の命令は、

    JSR CALZ80

    FDB address

というコードが生成されます。

シーケンス< A >

JSR 命令の後ろに続くコーリングシーケンスのアドレスを取り出し、引数メモリの (PC) に格納し、" CFLG = 0"にします。これは、6809からZ80をコールすることを意味します。 

さらに、 X レジスタを ( XREG )、 ACCA を( AREG )に書き込み、CHG_CPUポイントでCPUを Z80 に切り替えます。

シーケンス< 2 >< 4 >< 5 >

6809は停止し、Z80は CHG_CPUポイントから動き出します。

( XREG )を HL レジスタに、( AREG ) を A レジスタにロードし、CFLG をチェックします。

ここでは CFLG は 0 なので、( PC )のアドレスのサブルーチンをコールします。

関数から戻ってくると、今度は CFLG は 6809 に Z80 から帰ってきたことを示すために" CFLG = 0" に再設定し、HL と A レジスタを書き戻し、CHG_CPUポイントでCPUを 6809 切り替えます。

シーケンス< B >< C >

CHG_CPUポイントから戻ってきた6809は、レジスタの引き継ぎを行い、 CFLG をチェックし ここでは CFLGが 0 なので、Z80 の関数から戻ってきたことが分かり、リターンします。

 ここが重要なポイントですが、もしこのとき CFLG が 1 であった場合、6809からコールしたZ80の関数から戻ってきたのでは無く、そのZ80の関数の中からさらに6809の関数をコールしたことになり、シーケンス< C >ではなくシーケンス< D >に向かいます。

 このCFLG の仕組みと、6809 と Z80 それぞれのスタックの働きにより、何重にでも多重コールが実現できることになります。

 

話が飛びましたが、こんどはZ80から6809を呼ぶ動作を説明します。

 

Z80から6809の関数をコールする動作

 シーケンス< 1 >

    CALL  CALL6809

    DW     address

と記述すると、シーケンス < 1 >に入り、" CFLG = 1"として CHG_CPU に行き、制御を 6809に移します。

シーケンス< B >< D >< E >

6809はレジスタを引き継ぎ、 CFLG が 1 であることを確認し、addressの関数を間接アドレッシングのJSR命令でコールします。

戻ってくると6809関数からの復帰を知らせるため、CFLG を再度 1 に設定し<

CHG_CPUポイントからZ80に復帰します。

シーケンス< 2 > 

レジスタを引き継ぎ、CFLGが 1 なので6809からの帰還と見なしRETします。

 

■6809からZ80の関数をコールし、その関数は6809の関数をコールしているときの動作

6809で書かれたアプリケーションソフトが CP/M で動作している様子を見てみましょう。アプリは既に動いており、スクリーンに文字を表示しようととしています。

6809コードのアプリですので、Z80コードのCP/MAPI をコールするためには、CALLZ80機能を使います。

ここまでで、CFLG=0 でシーケンス < A><2 > < 4 >まで来ました。

 

CP/MAPI は さらにZ80コードのBIOSをコールします。

ところが呼ばれたBIOS の大半のAPI はそのまま 6809 で書かれた ROM内ルーチンをコールするだけで済ませています。

即ち、CFLG=1 として、シーケンス< 1 >< B >< D >と進みます。

< D >で呼ばれたROM内の6809コードで文字表示を行い、CFLG = 1として< E >

を進み、CHG_CPUで< 2 >< 3 >と抜け6809関数コールを終えます。

この関数コールをしていたのは、< 4 >で6809から呼ばれていたZ80BIOSですので、CFLG = 0 として< 5 >に進み、CHG_CPU ポイントから、6809コードで書かれたアプリに戻ってきます。

万事うまくいくでしょう。

 

このような仕組みにより、FLEX09用に作られた6809コードのスクリーンエディタ " DUET " ですが、APIコールだけ CP/M 用に変更して、立派な CP/M アプリとして動いています。

アプリのコードも実際のBIOSの下請けコードも全部 6809 なので、このアプリの動作中はほとんど赤のLEDが点いています。

6809/Z80マシーンを発掘しました(3) マルチCPUの仕組み(1) ハード編

マルチCPUシステムの工夫

 

実家をあさっていると、このシステム(たぶん)の回路図や資料も出てきました。

今見ても面白い点があるので、一度まとめて紹介します。

 

まず一番の売りは、「6809からZ80のサブルーチンをコール」したり、逆に「Z80から6809をコール」したり自由に(多重に)できることです。

これを使って、CP/MBIOSを6809のコードで書いたりしています。

 

この機能は、ハードとソフトの連携で実現しているのですが、ハード側は、単にCPUを切り替えるだけの回路で大変シンプルです。

f:id:hhh_yama:20180222180440j:plain

■CPU切り替えのハード側の仕組アービトレーション

このシステムは、68B09(2MHz)とZ80(4Hz)、ふたつのCPUのアドレスバスとデータバスを完全にパラ接続する完全密結合のマルチCPUシステムで、ダイナミックにふたつのCPUが切り替えられます。

切替には1bitの切替ポートが用意されており、最初は6809側になっています。
6809が動いているときはZ80は*BUSREQ状態のためアドレス/データバスを開放(ハイインピーダンス状態に)して止まっています。

そこで6809が切替ポートをダミーライト(青矢印)すると、切替ポート(LS393)がZ80側に代わります。緑矢印により6809にHALTが掛けられ、6809がバスを開放して停止したのをBSとBAにより確認してから、Z80の*BUSREQを外しZ80が動き出します。

逆にZ80が切替ポートにダミーライトすると(このポートはトグル動作なので)こんどは6809側になり、Z80に*BUSREQをかけます。こんどはZ80がバスを開放して停止したのを*BASACKにより確認してから、6809の*HALTを外し6809が動き出します。

 このように6809とZ80がたすき掛けになったフリップフロップのような動作をして、とてもシンプルなバスアービトレーションを実現しています。

 

D-FFは、RESET時にZ80を起動させない働き(リセットを解除させない)をします。

最初の切り替えアドレスに6809がダミーライトして初めてZ80のリセットが外れます。

この仕掛けにより、6809側のソフトとZ80側のソフトをCPU切り替えハンドラに導くことが出来ます。

具体的には、

① リセットで起動した6809はCPU切り替えハンドラに到達し、Z80に切り替える。

Z80のリセットが外れ、Z80もCPU切り替えハンドラに到着し、6809に切り替える。

③ 制御は6809に戻り、かつZ80は切り替えハンドラで切り替えられるのを待機する状態になっている。

 

ソフト側の仕掛けは次回

 

 

6809/Z80マシーンを発掘しました(2) CPUボード

■ 6809 と Z80 マルチCPUのCPUボードです。

'81から'82頃に作ったものと思います。

 

裏面

 ジュンフロン線で手配線です。 昔は苦も無くこんな配線していたのです。

 2本切れた線がありました。わかりやすいところでしたので付けなおしました。

f:id:hhh_yama:20180222090101j:plain

 

表面の中央

中央が日立製の2MHzの68B09 、右がNECZ80です。

左のP-ROMは、4KB の2732です。アドレス$F000-$FFFF に配置されてます。

後半の$F800-$FFFF は、モトローラ製の高機能モニタプログラム Assist09 を入れています。

前半は、Assist09 の独自拡張部 (私が作りました)が入っています。

 主には、6809とZ80の切り替えサポート(互いに相手のCPUのサブルーチンをコールできる仕掛け)と、8インチフロッピーのドライバが入っています。

f:id:hhh_yama:20180222085348j:plain

 

表面の全体

上に乗っている基板は、DRAMです。

64Kbit ×8 ×2 で 128KBあります。

8bitCPUのアドレス空間(16bit )は、最大 64KBなので、2ページ分になります。

簡易MMUを使って 8KB 単位に、ページを選択できる仕組みです。

 

右上のLEDですが、赤は6809緑はZ80 が走っていること示します。

CP/Mが走っているときは両方が点滅していました。(BIOSは6809コードなので)

f:id:hhh_yama:20180222090209j:plain