カテゴリー
Generator

ジェネレーター4

 PCのラインからサウンドを出力しその信号をそのままデジタル回路で使用することができるか実験してみました。

その1 矩形波のまま使用
 信号のレベルが少し低いのでHighが5V程度になるまでトランジスタやオペアンプで増幅してみましたが次の問題が発生しました。

問題1 一波長でON・OFFの繰り返しを継続して出力する時は波形が乱れない。一波長でOFFのみが間にあると前後の波形が大きく乱れる。

問題2 一定時間だけONの信号が出せない。常に正負交互の交流信号を出力しないと信号が出てこないか前後の波形が乱れる。

問題3 出力の終わりに意図しない波形が出力されデジタル素子が誤動作をしてしまう。


 

その2 矩形波を止めて正弦波にする
 矩形波は多くの高調波を含んでいるので正弦波のみであれば状況が改善すると思い実験してみましたが問題を全て解決できませんでした。

問題1 解決できた。

問題2 波長を低くすればある程度の期間ONにできる。矩形波でも同様。

問題3 改善されない。


 

その3 常に信号を出している状態にする
 AMラジオの様に常に搬送波を出力しそれにデータである信号を乗せてみました。

問題1 再燃した。

問題2 その2と同じ解決できる。

問題3 若干改善した。


 

結論

 PCのサウンド出力はアプリから要求された信号を忠実に送出するのではなく独自の制御を行っているため振幅に意味を持たせる方法ではデジタルデータとしてそのまま使用できないことが解りました。


 

AM変調
AM変調
AM変調(拡大)
AM変調(拡大)
#include <iostream>
#include <string>
#include <windows.h>
#include <math.h>
#include <MMSystem.h>

#pragma comment (lib, "winmm.lib")

int main() {

    WAVEFORMATEX wfe1;
    static HWAVEOUT hWaveOut1;
    static WAVEHDR whdr1;
    static LPBYTE lpWave1;
    static LPBYTE lpDataA;
    static LPBYTE lpDataB;

    int i, j, len1, start, end;
    int f1;
    size_t terms = 300;
    int sampling = 192000;
    size_t size;
    double pi = 3.14159265359;

    f1 = 15000;
    len1 = sampling / f1;
    wfe1.wFormatTag = WAVE_FORMAT_PCM;
    wfe1.nChannels = 2;
    wfe1.wBitsPerSample = 8;
    wfe1.nBlockAlign = wfe1.nChannels * wfe1.wBitsPerSample / 8;
    wfe1.nSamplesPerSec = sampling;
    wfe1.nAvgBytesPerSec = wfe1.nSamplesPerSec * wfe1.nBlockAlign;
    waveOutOpen(&hWaveOut1, 0, &wfe1, 0, 0, CALLBACK_NULL);
    size = terms * wfe1.nChannels;
    lpWave1 = (LPBYTE)calloc(wfe1.nAvgBytesPerSec, size);

    for (i = 0; i < sampling * terms * wfe1.nChannels; i++) {
        lpWave1[i] = 128;
    }

    start = sampling * wfe1.nChannels * 1;
    end = start + len1 * wfe1.nChannels * f1 * terms;

    double d = 360.0 / len1;
    lpDataA = (LPBYTE)calloc(wfe1.nAvgBytesPerSec, len1);
    for (i = 0; i < len1; i++) {
        lpDataA[i] = (BYTE)(70.0 * sin(d * (i % len1) / 180.0 * pi) + 127.5);
    }

    for (i = start, j = 0; i < end; i++) {
        if ((i % 2) == 0) {
            lpWave1[i] = lpDataA[j];
            ++j;
            if (j >= len1) { j = 0; }
        }
    }

    int a = 300;
    lpDataB = (LPBYTE)calloc(wfe1.nAvgBytesPerSec, len1*a);
    for (i = 0; i < len1*a; i++) {
        lpDataB[i] = (BYTE)(50.0 * sin(d * i / 180.0 * pi / a) + 127.5);
    }

    for (i = start, j = 0; i < end; i++) {
        if ((i % 2) == 1) {
            if (((i / 2 / len1)+0) % 8 < 8 ) {
                lpWave1[i] = lpWave1[i-1] + lpDataB[j] - 128;
                ++j;
                if (j >= len1*a) { j = 0; }
            }
            else { lpWave1[i] = 128; }
        }
    }

    whdr1.lpData = (LPSTR)lpWave1;
    whdr1.dwBufferLength = wfe1.nAvgBytesPerSec * terms;
    whdr1.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
    whdr1.dwLoops = 1;
    waveOutPrepareHeader(hWaveOut1, &whdr1, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut1, &whdr1, sizeof(WAVEHDR));
    
    char str[128];
    std::cout << "hello, world\n";
    std::cin >> str;

}

 

カテゴリー
Generator

ジェネレーター3

矩形波をパソコンのラインから出力

 パソコンから20Hzの矩形波をライン出力してみました。LEDが8個並んでいるのはいずれシリアルパラレル変換するためです。今回は並列に接続しているので同じように動作します。下記のコードは4CH出力していますが、動画のLEDのボードに接続しているのはデバイス0のLeftです。

#include <iostream>
#include <string>
#include <windows.h>
#include <MMSystem.h>

#pragma comment (lib, "winmm.lib")

int main() {

    WAVEFORMATEX wfe;
    static HWAVEOUT hWaveOut;
    static WAVEHDR whdr;
    static LPBYTE lpWave;
    WAVEFORMATEX wfe2;
    static HWAVEOUT hWaveOut2;
    static WAVEHDR whdr2;
    static LPBYTE lpWave2;
    int i, len, start, end;
    int frequency = 20;
    int terms = 10;
    int sampling = 192000;

    wfe.wFormatTag = WAVE_FORMAT_PCM;
    wfe.nChannels = 2;
    wfe.wBitsPerSample = 8;
    wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
    wfe.nSamplesPerSec = sampling;
    wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;
    waveOutOpen(&hWaveOut, 0, &wfe, 0, 0, CALLBACK_NULL);
    lpWave = (LPBYTE)calloc(wfe.nAvgBytesPerSec, terms * wfe.nChannels);

    wfe2.wFormatTag = WAVE_FORMAT_PCM;
    wfe2.nChannels = 2;
    wfe2.wBitsPerSample = 8;
    wfe2.nBlockAlign = wfe2.nChannels * wfe2.wBitsPerSample / 8;
    wfe2.nSamplesPerSec = sampling;
    wfe2.nAvgBytesPerSec = wfe2.nSamplesPerSec * wfe2.nBlockAlign;
    waveOutOpen(&hWaveOut2, 2, &wfe2, 0, 0, CALLBACK_NULL);
    lpWave2 = (LPBYTE)calloc(wfe2.nAvgBytesPerSec, terms * wfe2.nChannels);

    // 立ち上がりは出力を0にする
    for (i = 0; i < sampling * terms * wfe.nChannels; i++) {
        lpWave[i] = 128;
        lpWave2[i] = 128;
    }

    len = sampling / frequency; 

    // 最初の8サイクルは出力しない
    start = len * 8 * wfe.nChannels;
    start = 0;
    // 8サイクル波形を出力する
    end = start + len * 32 * wfe.nChannels;
    printf("start=%d, end=%d\n", start, end);

    for (i = start; i < end; i++) {
        if ((i % 2) == 0) {
            if ((i/2) % len < len / 2) { lpWave[i] = 228; }
            else { lpWave[i] = 28; }}}

    len /= 2;
    for (i = start; i < end; i++) {
        if ((i % 2) == 1) {
            if ((i / 2) % len < len / 2) { lpWave[i] = 228; }
            else { lpWave[i] = 28; }}}

    len *= 2;
    for (i = start; i < end; i++) {
        if ((i % 2) == 1) {
            if ((i / 2) % len < len / 2) { lpWave2[i] = 228; }
            else { lpWave2[i] = 28; }
        }
    }

    len /= 2;
    for (i = start; i < end; i++) {
        if ((i % 2) == 0) {
            if ((i / 2) % len < len / 2) { lpWave2[i] = 228; }
            else { lpWave2[i] = 28; }
        }
    }

    whdr.lpData = (LPSTR)lpWave;
    whdr.dwBufferLength = wfe.nAvgBytesPerSec * terms;
    whdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
    whdr.dwLoops = 1;
    waveOutPrepareHeader(hWaveOut, &whdr, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut, &whdr, sizeof(WAVEHDR));

    whdr2.lpData = (LPSTR)lpWave2;
    whdr2.dwBufferLength = wfe.nAvgBytesPerSec * terms;
    whdr2.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
    whdr2.dwLoops = 1;
    waveOutPrepareHeader(hWaveOut2, &whdr2, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut2, &whdr2, sizeof(WAVEHDR));

    char str[128];
    std::cout << "hello, world\n";
    std::cin >> str;

 

デバイス0の出力
カテゴリー
Generator

ジェネレーター2

 WindowsPCのサウンド出力を使って可聴範囲のジェネレーターを作ることができましたがチャンネルが二つでは足りないので追加してみました。

USB to 3.5mmオーディオケーブル
USB to 3.5mmオーディオケーブル

 USBのオーディオ出力を接続しPC本体の出力と合わせてステレオ出力×2=4チャンネルになります。

PC本体の出力
USBオーディオの出力(LとRを換えてみました)
#include <iostream>
#include <string>
#include <windows.h>
#include <MMSystem.h>

#pragma comment (lib, "winmm.lib")

int main() {

    WAVEFORMATEX wfe;
    static HWAVEOUT hWaveOut;
    static WAVEHDR whdr;
    static LPBYTE lpWave;
    WAVEFORMATEX wfe2;
    static HWAVEOUT hWaveOut2;
    static WAVEHDR whdr2;
    static LPBYTE lpWave2;
    int i, len, start, end;
    int terms = 1;
    int sampling = 192000;
    int frequency = 500;

    wfe.wFormatTag = WAVE_FORMAT_PCM;
    wfe.nChannels = 2;
    wfe.wBitsPerSample = 8;
    wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
    wfe.nSamplesPerSec = sampling;
    wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;
    waveOutOpen(&hWaveOut, 0, &wfe, 0, 0, CALLBACK_NULL);
    lpWave = (LPBYTE)calloc(wfe.nAvgBytesPerSec, terms * wfe.nChannels);

    wfe2.wFormatTag = WAVE_FORMAT_PCM;
    wfe2.nChannels = 2;
    wfe2.wBitsPerSample = 8;
    wfe2.nBlockAlign = wfe2.nChannels * wfe2.wBitsPerSample / 8;
    wfe2.nSamplesPerSec = sampling;
    wfe2.nAvgBytesPerSec = wfe2.nSamplesPerSec * wfe2.nBlockAlign;
    waveOutOpen(&hWaveOut2, 2, &wfe2, 0, 0, CALLBACK_NULL);
    lpWave2 = (LPBYTE)calloc(wfe2.nAvgBytesPerSec, terms * wfe2.nChannels);

    // 立ち上がりは出力を0にする
    for (i = 0; i < sampling * terms * wfe.nChannels; i++) {
        lpWave[i] = 128;
        lpWave2[i] = 128;
    }

    len = sampling / frequency; 

    // 最初の8サイクルは出力しない
    start = len * 8 * wfe.nChannels;
    // 8サイクル波形を出力する
    end = start + len * 8 * wfe.nChannels;
    printf("start=%d, end=%d\n", start, end);

    for (i = start; i < end; i++) {
        if ((i % 2) == 0) {
            if ((i/2) % len < len / 2) { lpWave[i] = 228; }
            else { lpWave[i] = 28; }}}

    len /= 2;
    for (i = start; i < end; i++) {
        if ((i % 2) == 1) {
            if ((i / 2) % len < len / 2) { lpWave[i] = 228; }
            else { lpWave[i] = 28; }}}

    len *= 2;
    for (i = start; i < end; i++) {
        if ((i % 2) == 1) {
            if ((i / 2) % len < len / 2) { lpWave2[i] = 228; }
            else { lpWave2[i] = 28; }
        }
    }

    len /= 2;
    for (i = start; i < end; i++) {
        if ((i % 2) == 0) {
            if ((i / 2) % len < len / 2) { lpWave2[i] = 228; }
            else { lpWave2[i] = 28; }
        }
    }

    whdr.lpData = (LPSTR)lpWave;
    whdr.dwBufferLength = wfe.nAvgBytesPerSec * terms;
    whdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
    whdr.dwLoops = 1;
    waveOutPrepareHeader(hWaveOut, &whdr, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut, &whdr, sizeof(WAVEHDR));

    whdr2.lpData = (LPSTR)lpWave2;
    whdr2.dwBufferLength = wfe.nAvgBytesPerSec * terms;
    whdr2.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
    whdr2.dwLoops = 1;
    waveOutPrepareHeader(hWaveOut2, &whdr2, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut2, &whdr2, sizeof(WAVEHDR));

    char str[128];
    std::cout << "hello, world\n";
    std::cin >> str;

}

 

4チャンネルあればデータに1CH、制御に3CH使えるのでUSBにマイコンをつながなくても様々なデジタル部品の制御ができそうです。

カテゴリー
Tools

測定器

テスター

MT-4095
MT-4095
Tester-TC1
Tester-TC1
カテゴリー
Generator

ジェネレーター

電子回路を作る時は何かと発振器が必要になります。

様々な信号発生器がありますが可聴範囲内であればパソコンでできそうです。

パソコンなら細かな波形をデザインできるのでかえって専用機のジェネレーターよりも良いかも。

例えばWindows PCで以下のようなコードを実行します。

#include <iostream>
#include <string>
#include <windows.h>
#include <MMSystem.h>
#include <math.h>

#pragma comment (lib, "winmm.lib")

int main() {

    WAVEFORMATEX wfe;
    static HWAVEOUT hWaveOut;
    static WAVEHDR whdr;
    static LPBYTE lpWave;
    int i, len, start, end;
    int terms = 1;
    int sampling = 44100;
    int frequency = 441;

    wfe.wFormatTag = WAVE_FORMAT_PCM;
    wfe.nChannels = 2;
    wfe.wBitsPerSample = 8;
    wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
    wfe.nSamplesPerSec = sampling;
    wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;
    waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfe, 0, 0, CALLBACK_NULL);
    lpWave = (LPBYTE)calloc(wfe.nAvgBytesPerSec, terms * wfe.nChannels);

    // 立ち上がりは出力を0にする
    for (i = 0; i < sampling * terms * wfe.nChannels; i++) {
        lpWave[i] = 128;
    }

    len = sampling / frequency; 

    // 最初の10サイクルは出力しない
    start = sampling / frequency * 10;
    // 8サイクル波形を出力する
    end = start + sampling / frequency * 8 * wfe.nChannels;

    double d = 360.0 / len;
    double pi = 3.14159265359;
    for (i = start; i < end; i++) {
        if ((i % 2) == 0) {
            // 方形波 Left
            if ((i/2) % len < len / 2) {
                lpWave[i] = 228;
            }
            else {
                lpWave[i] = 28;
            }
        }
        else {
            // 正弦波 Right
            lpWave[i] = (BYTE)(100.0 * sin(d * ((i / 2) % len) / 180.0 * pi) + 127.5);
        }
    }

    whdr.lpData = (LPSTR)lpWave;
    whdr.dwBufferLength = wfe.nAvgBytesPerSec * terms;
    whdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
    whdr.dwLoops = 1;

    waveOutPrepareHeader(hWaveOut, &whdr, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut, &whdr, sizeof(WAVEHDR));

    char str[128];
    std::cout << "hello, world\n";
    std::cin >> str;

}

 

パソコンのライン出力をそのままマイク入力に接続しAudacityで表示すると、

パソコンジェネレーター出力をAudacityで表示
パソコンジェネレーター出力をAudacityで表示

のようになります。

左チャンネルは、方形波、右チャンネルは正弦波の出力ができました。2CHファンクションジェネレータの完成です。