キノコの自省録

日々適当クリエイト

Raspberry Pi + YMZ294でのノイズ対策にコンデンサを使用する

前回はアナログフォトカプラでスピーカーを絶縁し、ノイズの少ない電源を用意しました。

kinokorori.hatenablog.com

今回はコンデンサでノイズ除去。アンプ周辺の回路図はこんな感じにしました。47μFはアルミ電解コンデンサです。ちなみに今までサボってYMZ294近辺のデカップリングコンデンサすら配置していませんでしたが、それも配置。

f:id:kinokorori:20170516004818p:plain

電源のパスコンもちょっと効果ありましたが、信号線(IN+,IN-)側の効果が大きく、ほとんどノイズが聞こえなくなりました。グランドノイズが大きいということですかね。ただ、全体的なボリュームが若干下がってしまう上に、少し音がマイルドになってしまいます。47μFから10μFに変更すると、PSG特有の元のとんがった音がある程度保存されますが、ちょっとだけノイズが気になります。22μFあたりが丁度よさげな感じ。なお、全体的なゲインが下がってしまうので、抵抗を1Kから100Ωに変更しています。

ノイズ対策にはコンデンサを使いましょうとか、アンプ回路を見ると、コンデンサが大量に配置されてたりしますが、実際に試してみると、おーなるほど、という感じです。オーディオも楽器もやらないソフト屋にとっては割と新鮮な体験だったりします。結構コンデンサ容量は勘だったり試行錯誤だったりという話を聞きますが、確かに入れ替えてみるとノイズ感がガラッと変わりますね。

非常に素人感満載ですが、動画も撮ってみました。

youtu.be

Raspberry Pi + YMZ294でのノイズ対策にアナログフォトカプラを使ってみる

前のエントリで、ドレミファソラシドを鳴らしてみましたが、凄くノイズが乗っています。

Raspberry piでYMZ294を鳴らす - キノコの自省録

ラズパイに挿しただけで、ピギャーピーという感じのけたたましいノイズが乗ります。以下のエントリの時にも書きましたが、シールド線使ったところでどうにもなりませんでした。

PSGで風色メロディ - キノコの自省録

ノイズの原因と対策

ノイズの原因は電源です。電源はラズパイから引っ張っているので、ラズパイの電源がノイジーだということです。ピュアオーディオマニアが発電所を評価したりマイ電信柱買ったりと、電源にやたらこだわる理由がちょっとだけわかった気がします。ちょっとだけ。電源ってこんなにノイズが乗るんですねえ。

ということで、スピーカー電源にラズパイのピンを使わず、どこかで電気的に絶縁してノイズ対策を施してみます。どこかで、といっても、2か所しかありません。

  1. ラズパイとYMZ294の間をフォトカプラで繋いで絶縁する
  2. YMZ294のSO出力とアンプ間を絶縁する

1はデジタルですが、なにしろピン数が多いため、かなりヘビーです。あまりやりたいと思わない、というかこんなことするならノイズの少ないArduino使います。2はSO出力だけなので配線は楽チンですが、アナログです。アナログの絶縁ってどうやるんでしょう・・・

※もう一つ、ラズパイに使っているUSB電源から5V/GND線を横取りしてスピーカー電源につなぐという方法もアリだと思います。

アナログフォトカプラ

アナログフォトカプラみたいなものはなんかないですかね?と検索したら、すぐ出てきました。

CdS+LED アナログ・フォトカプラ MI0202CL: 半導体 秋月電子通商-電子部品・ネット通販

フォトカプラというかフォトレジスタですね。構造は至って単純で、片側にLED、片側にCdSを取り付けて箱に閉じ込めているだけです。LEDの光量に応じて、CdSの抵抗値が上下するという仕組みです。なるほど。なので、CdSサイドはただの可変抵抗と考えればいいということです。スピーカーユニットを鳴らすには、抵抗の変動に応じて、電圧を上下させる必要があります。単純に繋いだ場合、変動するのは電流になってしまうので、GNDとの間に抵抗を繋いで並列回路構成にする必要があります。

MI0202CLのLED順方向電流は最大40mAです。YMZ294のSO電流を調べたところ、大体15mA~20mAで変動しています。なので、直挿ししてOK。

ということで、回路はこんな感じになりました。大分単純です。

f:id:kinokorori:20170512003343p:plain

鳴らしてみる

ちゃんと鳴るか心配でしたが、ちゃんと音が出ました。YMZ294を直挿しした時に比べると、音が丸くなっています。音が丸くなるというか、Lo-Fiっぽいです。これはこれでなかなか味があって良いかもという感じなのですが、たまにボツ音が乗ります。うーん。

電源はいくつか試したのですが、一番静かだったのが乾電池でした。ノイズがほとんど聞こえません。AC/DC変換しないせいですかね。ちょっと驚きました。

とりあえず動画。最初はラズパイ直での再生、0:57あたりから、MI0202CLで絶縁して、アンプ電源に乾電池を使用したバージョンです。ノイズ比較も行っています。

youtu.be

コンデンサでのノイズ除去も試してみようかなあと思いますが、とりあえず今回はこの辺で。

シャイニングゴッドチェリー

シャイニングゴッドチェリー描きました。

【アイドルマスターシンデレラガールズ】「シャイニングゴッドチェリー」イラスト/kinokorori [pixiv]

6年前のGWから絵を練習しようと決めたので、GWにはなるべく絵を描くようにしています。最初から比べると上手くはなったけど、具体的に何が変わったかと言われると説明できない。

プロダクト設計にはDtoDの当てはまりが良さそう……な気がする

タイトル通り、かなりフワっとしているお話になります。

上流設計、特にどういう製品を作っていこうか、というプロダクト設計には、DtoD(Discover to Deliver)というフレームワークの当てはまりが良さそうだなあと思ったお話です。

私自身、DtoDについて詳しく調べたり本を読んだりしているわけではありませんので、こんなものがあるんだ、という参考程度に。

Discover to Deliverとは

米国EBG Consulting社のエレン・ゴッテスディーナーさんとメアリー・ゴーマンさんが、2015年に考案したフレームワークです。割と最近ですね。本家はこちらです。

Discover To Deliver

日本では、オージス総研がまとめています。

DtoD手法に基づくアジャイル要求 | 株式会社オージス総研

こちらのページでは、こんな風に紹介されています。

  1. ワークショップの活用 専門家単独で行うのではなく、顧客、業務、技術という異なる視点の人々が参加するワークショップを開催して、迅速にニーズをより多面的に理解し、表現し、開発内容を検討し、合意を形成する。

  2. 多様なモデルの活用 ワークショップで、ニーズや開発内容を軽量でとっつきやすい様々なモデル(短文記述を含む)により多面的に表現し、理解する。これらは、「プロダクトの7側面」という形でまとめられる。

  3. 分析者の役割の変更 分析者がワークショップのファシリテーターモデラーの役割を担うことで、プロダクトオーナーの役割を分担する。

個人的には、「プロダクトの7側面」がとても当てはまりの良いモデルだと感じました。

プロダクトの7側面

オージス総研のページにも少し紹介がありますが、ソフトウェア開発にはユーザストーリーマッピングスクラムといった開発フレームワークがあります。これらのフレームワークはかなり浸透してきてはいますが、如何せんソフトウェア開発に直結していることもあって、少し技術者寄りな側面が否めない部分があります。特にスクラムはそうですね、。そして、ユーザーストーリーマッピングも、それだけではプロダクト設計を考える上では、不十分です。開発すべき部分ではない部分、例えばクレーム対応や在庫管理といった点は、ユーザーストーリーマッピングにはなかなか登場しないと思います。

少し話が脇道にそれますが、私の関わっているプロダクトオーナーは非技術者が多いせいなのか、プロダクトの方針について全く整理されていない状態で、新規プロダクトの話を持ち掛けられることが多いです。はっきり言ってしまうと、顧客要望をそのまま伝達しているようにしか見えません。せめて、プロダクトの指針くらいは決めて欲しいのですが、ある部分について顧客要望がない場合「何も言ってこないんですよ」と言ってくることがあります。ないならないでプランを立てるのがプロダクトオーナーの役割だと思うので、それを技術者に言うのはどうかと思います。

じゃあ、プロダクトオーナーに対して、「せめてこのくらいは考えたり、顧客からヒアリングしてほしい」というのは何ですか、と聞かれると、なかなかうまく整理して話せなかったりします。そこで、このプロダクトの7側面です。よくまとまってるなあと感じました(もしかしたら曲解しているかもしれませんが)。

プロダクトの7側面は、以下の通りです。

ユーザ

プロダクトの使用者です。どういう使用者を想定しているのか、という部分を考えましょう、ということです。ユーザストーリーマッピングも、ここにある程度含まれます。使用者を主眼に置いた分析といえば、ペルソナが有名ですね。

稀に、プロダクトの納入先(要するに顧客)が使用者のスコープを想定していない場合がありますが、だからといってユーザ分析をしなくていいわけではないと思います。ちょっと考えただけでも、万人向けなのか、弱い部分をターゲットにするのか、強い部分をさらに伸ばすのかのプランがあり、それによってプロダクトの方針が変わります。顧客が外部企業の場合、それらのプランを提示するのもプロダクトオーナーの役目だと思います。

インターフェイス

APIというより、どれくらいの企業や人が関わり合いを持つか、という部分です。顧客企業と自社、ユーザのみの関係で完結することは稀でしょう。例えば、プロダクトがハードウェアを含む場合、絶対に物流や倉庫が登場します。故障対応はどうするのか、ハードウェアが自社開発ではない場合、カスタマイズはどうするのか、在庫管理は顧客企業がやるのか、自社がやるのか、いろいろ考えることがあるはずです。これを考えないで技術屋に投げると100%怒られます。

アクション

トリガーです。これはユーザストーリーマッピングユースケースで考えることになると思います。

データ、制御

DtoDの資料をさらっと読む限り、業務フローや法務規制を検討するようです。技術寄り、例えばRDBのデータ構造をどうするかといった系統のものではないと思います。業務フローというのであれば、これは本当に大事で、作ったシステムが客先にマッチしない場合、受け入れを拒否されることすらあると思います。データは、顧客マスタや発注伝票なども含むかもしれません。そういう意味では、確かにプロダクト設計の段階で、絶対に把握しておく必要があります。

環境

どういう場面やシチュエーションで使用されるか、ということだと思っています。業務フローのように「流れ」を伴うものではなく、もう少し定性的なものでしょう。プロダクトの使用環境が、静かで薄暗い環境だと思っていたのに、屋外+凄いノイズ環境下でした、となった場合、プロダクトがそもそも使用できないということも考えられます。

品質特性

ソフト屋(特にサーバ屋)の場合、想定ユーザ数とアクセス頻度は絶対気にしますし、ハードウェアの場合は耐性試験などの指針にもなるので、技術者からプロダクトオーナーに、どうなってんの?と聞くことも多いと思います。非技術者にとっては何をどう気にすべきなのかわからないので、ある程度、技術屋からインプットする必要があると思います。

メモリやストレージ、CPUはどのくらいのスペックを用意すればよいのかなどは、顧客要望、およびコストと絡む場合が多いため、技術者とプロダクトオーナー間で調整が必要になるでしょう。

まとめ

正直DtoDについてそこまで調べてないのにエントリを書くのもどうかとためらったのですが、紹介してみました。というのも、プロダクトの7側面は、プロダクトオーナー自身も気にかけていて欲しいし、技術者側も、これが足りないよ、とプロダクトオーナーにつっつくべき項目として、割と当てはまりが良いと思ったためです。

PSGで風色メロディ

YMZ294のみ使用して、風色メロディを鳴らしてみました。PSG3音を使用しています。ノイズサウンドはなし。

今回はRaspberry Piを使用したのですが、めちゃくちゃ環境ノイズが乗ってます。一応1m300円くらいのシールド線を使用しているものの、それだけじゃいかんともしがたいようで。色々調べて回ると、完全を目指すならば電気的に絶縁ということなので、そうするとフォトカプラですかね。とりあえずラズパイ直だと少し厳しそうな模様。まあシンプルにいくならArduinoにすればいいのですが。

ちなみに曲のプログラムに当たっては、MMLパーサを自作して、MMLで書いています。MMLパーサ+シーケンサコードもそのうちアップするかも。

f:id:kinokorori:20170416221049j:plain:w300

音符の長さの計算式

半分はおおまぬけな話。

以前のエントリで、音符の長さとテンポから、実時間長を計算する式を公開しました。

X分音符の時間長と音階周波数の計算メソッド - キノコの自省録

数式とプログラムで表現すると、こんな感じです。

【数式】 D=\frac{60}{T}\cdot\frac{4}{L} (T=テンポ, L=X分音符, 求める長さDは秒)

# python
def get_duration(tempo = 120, note_len = 4):
    base_ms = 60.0 / tempo
    note_rate = 4.0 / note_len
    return base_ms * note_rate
// C/C++
double getDuration(double tempo, int note_len) {
    double base_ms = 60.0 / tempo;
    double note_rate = 4.0 / note_len;
    return base_ms * note_rate;
}

この式は全く正しいので、問題なく使用できます(tempoに0を入力すると落ちますが)。

例えば、テンポT=140の8分音符の長さを算出しますと、

D=\frac{60}{140}\cdot\frac{4}{8}=\frac{60}{280}≒0.214秒

です。

以下、音符の長さにまつわる間抜けなお話。

符点4分音符は3分音符ではない

「2分音符と4分音符の間なんだから、3分音符と同じでしょ」と、ずっと勘違いしていました。同様に、符点8分音符は6分音符だと思っていたということです。

当たり前ですが、X分音符というのは、その長さが「全音符/X」という意味です。4分音符は1/4=0.25, 8分音符は1/8=0.125, 合わせると符点4分音符は0.375になります。一方、3分音符は1/3=0.333なので、微妙に短いということがわかります。ちなみに3分音符は2分音符の3連符と同じです。

符点4分音符をX分音符で表現できるか、というと、それは無理です。計算すると、8/3(≒2.67)分音符になります。

なんで気づいたかというと、作ったばかりのMMLパーサに対して、符点やタイなどのチェックをしている時です。やたらと酷い音ズレが発生したため、シーケンサーのコードのせいなのか、パーサのコードのせいなのか、上記音符の時間長計算のせいなのかと色々調べた結果、あっと気づいてしまったわけです。

パーティクルで魔法エフェクト(3) - 氷魔法編

関連記事

パーティクルで魔法エフェクト(1) - 炎魔法編 - キノコの自省録

パーティクルで魔法エフェクト(2) - 光魔法編 - キノコの自省録

f:id:kinokorori:20170327235357p:plain:w120

ウィッチクライドでは、いくつかの魔法をParticle Systemを使って表現しています。

今回は氷魔法を紹介。

氷魔法概要

前回も書きましたが、ウィッチクライドの攻撃魔法は、エフェクトを詠唱の長さに応じて3レベルに分けています。長いほど派手です。今回紹介するのは1レベル目。一番シンプルなエフェクトです。

ターゲットに雪の結晶っぽいパーティクルをワッと表示させ、外側に向かって移動+小さくなっていくエフェクトです。画像にするとこんな感じです。

f:id:kinokorori:20170410214620j:plain:w250f:id:kinokorori:20170410214622j:plain:w250f:id:kinokorori:20170410214623j:plain:w250

ムービーはこちら。

youtu.be

エフェクト実装解説

見た通り非常にシンプルで、基本は1秒間パーティクルシステムを表示しているだけです。パーティクル単体はこれです。実装にも使われています。完全不透明なので、アルファブレンディングしません。

f:id:kinokorori:20170410214913p:plain

パーティクルシステムの実装をそのまま載せておきます。Cocos-2d2なので、Objective-Cですが、他のパーティクルシステムでも基本大差ありません。

+ (CCParticleSystem*)particleIce {
    CCParticleSystem* particle = [CCParticleSystemQuad node];
    particle.texture = [[CCTextureCache sharedTextureCache] addImage:@"ice@2x.png"];
    
    particle.totalParticles = 20;
    particle.life = 1.0;
    particle.lifeVar = .3;
    particle.startSize = 60;
    particle.startSizeVar = 20;
    particle.endSize = 0;
    particle.endSizeVar = 0;
    particle.angle = 0;
    particle.angleVar = 360;
    particle.startSpin = 0;
    particle.startSpinVar = 360;
    particle.endSpin = 0;
    particle.endSpinVar = 360;
    particle.position = ccp(0,0);
    particle.posVar = ccp(10,10);
    
    //emitter setting
    particle.emissionRate = 400;
    particle.emitterMode = kCCParticleModeGravity;
    particle.duration = .3;
    particle.speed = 50;
    particle.speedVar = 20;
    particle.gravity = ccp(0, 0);
    particle.radialAccel = .2;
    particle.radialAccelVar = 0;
    particle.tangentialAccel = .3;
    particle.tangentialAccelVar = 0;
    
    //Color setting
    particle.startColor = ccc4f(5.0, 6.0, 1.0, 0.6);
    particle.endColor = ccc4f(1.0, 1.0, 1.0, 0.4);
    particle.startColorVar = ccc4f(0, 0.03, 0.01, 0);
    particle.endColorVar = ccc4f(0.04, 0.02, 0.02, 0);
    
    particle.autoRemoveOnFinish = YES;
    
    return particle;
    
}

ポイントとしては、まずターゲット中央付近、(-10,-10)〜(10,10)にエミッションします。

    particle.position = ccp(0,0);
    particle.posVar = ccp(10,10);

さらに、パーティクルに回転をかけます。

    particle.startSpin = 0;
    particle.startSpinVar = 360;
    particle.endSpin = 0;
    particle.endSpinVar = 360;

進行方向を360°全方位として、速度を30〜70の間に設定します。

    particle.angle = 0;
    particle.angleVar = 360;
    particle.speed = 50;
    particle.speedVar = 20;

パーティクル終了時のサイズを0に固定しているので、どんどん小さくなります。

    particle.endSize = 0;
    particle.endSizeVar = 0;

主な設定値はこんなところです。ゲーム中では、1秒経過後にパーティクルを削除しています。