カテゴリー
Filter

Flutterで角を丸くする

 TextFieldやDropdownButtonの角を丸くしてみた。結局ConainerのBorderを丸くして角が丸くなったように見せるだけだった。

Flutterで角を丸くする
Flutterで角を丸くする
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    String dropdownValue = 'One';
    return Scaffold(
      backgroundColor: Colors.grey,
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ClipRRect(
              borderRadius: BorderRadius.all(Radius.circular(30)),
              child: Container(
                width: 200,
                height: 100,
                color: Colors.yellow,
                child: Padding(
                  padding: const EdgeInsets.all(8),
                  child: const TextField(
                    obscureText: true,
                    decoration: InputDecoration(
                      border: InputBorder.none,
                      labelText: 'Pass',
                    ),
                  ),
                ),
              ),
            ),
            Gap(20),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 5),
              width: 200,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.blue),
                borderRadius: BorderRadius.circular(20),
              ),
              child: const TextField(
                obscureText: true,
                decoration: InputDecoration(
                  border: InputBorder.none,
                  labelText: 'Pass',
                ),
              ),
            ),
            Gap(20),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 5),
              width: 200,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.blue),
                borderRadius: BorderRadius.circular(20),
              ),
              child: DropdownButton<String>(
                value: dropdownValue,
                icon: const Icon(Icons.arrow_downward),
                iconSize: 24,
                elevation: 16,
                style: const TextStyle(color: Colors.deepPurple),
                onChanged: (String? newValue) {},
                items: <String>['One', 'Two', 'Free', 'Four']
                    .map<DropdownMenuItem<String>>((String value) {
                  return DropdownMenuItem<String>(
                    value: value,
                    child: Text(value),
                  );
                }).toList(),
              ),
            ),
            Gap(20),
            Text(
              'You have pushed the button this many times:',
              style: TextStyle(color: Colors.white),
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
カテゴリー
Filter

アクティブバンドパスフィルタ4

 オペアンプ二段増幅型バンドパスフィルタが思いのほか上手く出来たので4個並べてみました。

4チャンネルバンドパスフィルタ
3,148Hz付近
7,680Hz付近
11,294Hz付近
17,455Hz付近
上部 -6, +6両電源(LM386)
下部 4チャンネル化するためのフィルター
#include <iostream>
#include <windows.h>
#include <math.h>
#include <MMSystem.h>

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

void createWave(LPWORD lpData, size_t frequency, size_t sampling, WORD amplitude) {
    size_t wavelength = sampling / frequency;
    double d = 360.0 / wavelength;
    double pi = 3.14159265359;
    for (int i = 0; i < wavelength; i++) {
        lpData[i] = (WORD)(amplitude * sin(d * (i % wavelength) / 180.0 * pi));
    }
}

int main() {

    WAVEFORMATEX wfe;
    static HWAVEOUT hWaveOut;
    static WAVEHDR whdr;
    static LPWORD lpWave;
    static LPWORD lpData;

    // 最初と最後の1sは出力しないので3以上とする
    size_t terms = 7;

    size_t i, j, start, end;
    size_t frequency = 400;
    size_t sampling = 192000;
    size_t wavelength = sampling / frequency;

    wavelength = sampling / frequency;
    wfe.wFormatTag = WAVE_FORMAT_PCM;
    wfe.nChannels = 2;
    wfe.wBitsPerSample = 16;
    wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
    wfe.nSamplesPerSec = (DWORD)sampling;
    wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;
    waveOutOpen(&hWaveOut, 0, &wfe, 0, 0, CALLBACK_NULL);
    lpWave = (LPWORD)calloc(sizeof(WORD), wfe.nChannels * sampling * terms);

    end = sampling * wfe.nChannels * 1;
    WORD amplitude = 32767;
    for (i = 0; i < end; i++) {
        lpWave[i] = 0;
    }

    // 最初の1sは出力しない
    start = sampling * wfe.nChannels * 1;
    end = wfe.nChannels * sampling * terms;
    // 最後の1sは出力しない
    end -= sampling * wfe.nChannels * 1;

    size_t valWavelength;
    size_t valFrequency;

    lpData = (LPWORD)calloc(sizeof(WORD), wavelength);
    createWave(lpData, frequency, sampling, amplitude);
    for (i = start, j = 0; i < end; i += 2) {
        lpWave[i] = lpData[j];
        ++j;
        if (j >= wavelength) { j = 0; }
    }
    free(lpData);

    for (i = start + 1, j = 0; i < end; i += 2) {
        if (j == 1) {
            valFrequency = frequency + ((i - start) * (20000.0 - frequency)) / (sampling * wfe.nChannels * (terms - 2));
            valWavelength = sampling / valFrequency;
            lpData = (LPWORD)calloc(sizeof(WORD), valWavelength);
            createWave(lpData, valFrequency, sampling, amplitude);
        }
        lpWave[i] = lpData[j];
        ++j;
        if (j >= valWavelength) {
            j = 0;
            free(lpData);
        }
    }

    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;

}

 可聴範囲を4分割し多チャンネル化できました。普通のPCであればステレオサウンド出力は付いているので左右に適用すれば8チャンネル、フィルタをもっと丁寧に作ればそれ以上も可能と思います。

カテゴリー
Filter

アクティブバンドパスフィルタ3

 流石にアクティブバンドフィルターは期待通りの性能を出せました。低周波領域でもオペアンプを使えば部品点数も少なく理想的なフィルタが作れそうです。続いて信号の分離性を高めるためQの高いフィルタで実験してみました。

R1=220200Ω
R2=4771Ω
R3=4630Ω
C1=2677pF
IC=UPC741C
Q=46.851
f0=12649.593Hz

二段増幅型バンドパスフィルタで400Hzから20kHzをスイープしている様子

 このくらいのQであれば信号の分離ができそうです。

400Hz付近
12kHz付近
20kHz付近
オペアンプ二段増幅型バンドパスフィルタ
オペアンプ二段増幅型バンドパスフィルタ

 部品点数も少なくQが高いバンドフィルタを作ることができました。これであればPCのサウンドライン出力に複数の信号を混合し受け側で分離すればライン1チャンネルを複数チャンネルにすることができそうです。1つのプログラム、1つのチャンネル、1つの受け側となるので波形単位の制御が必要なデジタル信号処理にも耐えられると思います。

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

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

void createWave(LPWORD lpData, size_t frequency, size_t sampling, WORD amplitude) {
    size_t wavelength = sampling / frequency;
    double d = 360.0 / wavelength;
    double pi = 3.14159265359;
    for (int i = 0; i < wavelength; i++) {
        lpData[i] = (WORD)(amplitude * sin(d * (i % wavelength) / 180.0 * pi));
    }
}

int main() {

    WAVEFORMATEX wfe;
    static HWAVEOUT hWaveOut;
    static WAVEHDR whdr;
    static LPWORD lpWave;
    static LPWORD lpData;

    // 最初と最後の1sは出力しないので3以上とする
    size_t terms = 7;

    size_t i, j, start, end;
    size_t frequency = 400;
    size_t sampling = 384000;
    size_t wavelength = sampling / frequency;

    wavelength = sampling / frequency;
    wfe.wFormatTag = WAVE_FORMAT_PCM;
    wfe.nChannels = 2;
    wfe.wBitsPerSample = 16;
    wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
    wfe.nSamplesPerSec = (DWORD)sampling;
    wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;
    waveOutOpen(&hWaveOut, 0, &wfe, 0, 0, CALLBACK_NULL);
    lpWave = (LPWORD)calloc(sizeof(WORD), wfe.nChannels * sampling * terms);

    end = sampling * wfe.nChannels * 1;
    WORD amplitude = 32767;
    for (i = 0; i < end; i++) {
        lpWave[i] = 0;
    }

    // 最初の1sは出力しない
    start = sampling * wfe.nChannels * 1;
    end = wfe.nChannels * sampling * terms;
    // 最後の1sは出力しない
    end -= sampling * wfe.nChannels * 1;

    size_t valWavelength;
    size_t valFrequency;
    for (i = start, j = 0; i < end; i += 2) {
        if (j == 0) {
            valFrequency = frequency + ((i - start) * (20000.0- frequency)) / (sampling * wfe.nChannels * (terms - 2));
            valWavelength = sampling / valFrequency;
            lpData = (LPWORD)calloc(sizeof(WORD), valWavelength);
            createWave(lpData, valFrequency, sampling, amplitude);
        }
        lpWave[i] = lpData[j];
        ++j;
        if (j >= valWavelength) {
            j = 0;
            free(lpData);
        }
    }

    lpData = (LPWORD)calloc(sizeof(WORD), wavelength);
    createWave(lpData, frequency, sampling, amplitude);
    for (i = start+1, j = 0; i < end; i += 2) {
        lpWave[i] = lpData[j];
        ++j;
        if (j >= wavelength) { j = 0; }
    }
    free(lpData);

    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;

}
カテゴリー
Filter

アクティブバンドパスフィルタ2

 パッシブバンドフィルタが上手くいかなかったのでオペアンプを使用してアクティブバンドフィルタの実験を行いました。

Multiple Feedback Band Pass Filter
Multiple Feedback Band Pass Filter

R1=4649Ω
R2=4763Ω
R3=477.8kΩ
C1=287pF
C2=295pF
IC=UPC741C
Q=7.125
f0=16314.28Hz

パッシブバンドフィルタ

 可聴周波数をスイープして出力しフィルタを通した様子です。フィルタが機能しているのが判ります。しかし、複数の信号を狭い帯域に載せるにはもっとQが高くないと分離が上手くいかないような気がします。

400Hz付近
11kHz付近、コンデンサの容量が小さいのでブレッドボードの影響を受けている模様
20kHz付近
オペアンプ多重帰還型バンドパスフィルタ
オペアンプ多重帰還型バンドパスフィルタ
#include <iostream>
#include <windows.h>
#include <math.h>
#include <MMSystem.h>

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

void createWave(LPWORD lpData, size_t frequency, size_t sampling, WORD amplitude) {
    size_t wavelength = sampling / frequency;
    double d = 360.0 / wavelength;
    double pi = 3.14159265359;
    for (int i = 0; i < wavelength; i++) {
        lpData[i] = (WORD)(amplitude * sin(d * (i % wavelength) / 180.0 * pi));
    }
}

int main() {

    WAVEFORMATEX wfe;
    static HWAVEOUT hWaveOut;
    static WAVEHDR whdr;
    static LPWORD lpWave;
    static LPWORD lpData;

    // 最初と最後の1sは出力しないので3以上とする
    size_t terms = 7;

    size_t i, j, start, end;
    size_t frequency = 400;
    size_t sampling = 384000;
    size_t wavelength = sampling / frequency;

    wavelength = sampling / frequency;
    wfe.wFormatTag = WAVE_FORMAT_PCM;
    wfe.nChannels = 2;
    wfe.wBitsPerSample = 16;
    wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
    wfe.nSamplesPerSec = (DWORD)sampling;
    wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;
    waveOutOpen(&hWaveOut, 0, &wfe, 0, 0, CALLBACK_NULL);
    lpWave = (LPWORD)calloc(sizeof(WORD), wfe.nChannels * sampling * terms);

    end = sampling * wfe.nChannels * 1;
    WORD amplitude = 32767;
    for (i = 0; i < end; i++) {
        lpWave[i] = 0;
    }

    // 最初の1sは出力しない
    start = sampling * wfe.nChannels * 1;
    end = wfe.nChannels * sampling * terms;
    // 最後の1sは出力しない
    end -= sampling * wfe.nChannels * 1;

    size_t valWavelength;
    size_t valFrequency;
    for (i = start, j = 0; i < end; i += 2) {
        if (j == 0) {
            valFrequency = frequency + ((i - start) * (20000.0- frequency)) / (sampling * wfe.nChannels * (terms - 2));
            valWavelength = sampling / valFrequency;
            lpData = (LPWORD)calloc(sizeof(WORD), valWavelength);
            createWave(lpData, valFrequency, sampling, amplitude);
        }
        lpWave[i] = lpData[j];
        ++j;
        if (j >= valWavelength) {
            j = 0;
            free(lpData);
        }
    }

    lpData = (LPWORD)calloc(sizeof(WORD), wavelength);
    createWave(lpData, frequency, sampling, amplitude);
    for (i = start+1, j = 0; i < end; i += 2) {
        lpWave[i] = lpData[j];
        ++j;
        if (j >= wavelength) { j = 0; }
    }
    free(lpData);

    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;

}
カテゴリー
Filter

パッシブバンドフィルター

 PCのサウンドラインに複数の信号を混合して出力し受け側で利用するためにはフィルタで分離する必要があります。早速簡単なLCフィルターで実験してみました。手持ちに丁度良いコイルが無かったので小信号トランスで代用しました。

Passive Band Pass Filter
Passive Band Pass Filter

R=1305Ω
L=494mH
C=4633pF
Q=7.912
f0=3326.791Hz

パッシブフィルターの性能

 400Hzから20kHzまでスイープして信号を出力してみましたが、実用にできるほどの分離性はみられませんでした。

パッシブバンドフィルタ
RLC パッシブバンドフィルタ

 扱っているのが低周波なので性能の良いコイルを小さく作らないと使い物にならないことがわかりました。

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

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

void createWave(LPWORD lpData, size_t frequency, size_t sampling, WORD amplitude) {
    size_t wavelength = sampling / frequency;
    double d = 360.0 / wavelength;
    double pi = 3.14159265359;
    for (int i = 0; i < wavelength; i++) {
        lpData[i] = (WORD)(amplitude * sin(d * (i % wavelength) / 180.0 * pi));
    }
}

int main() {

    WAVEFORMATEX wfe;
    static HWAVEOUT hWaveOut;
    static WAVEHDR whdr;
    static LPWORD lpWave;
    static LPWORD lpData;

    // 最初と最後の1sは出力しないので3以上とする
    size_t terms = 7;

    size_t i, j, start, end;
    size_t frequency = 400;
    size_t sampling = 384000;
    size_t wavelength = sampling / frequency;

    wavelength = sampling / frequency;
    wfe.wFormatTag = WAVE_FORMAT_PCM;
    wfe.nChannels = 2;
    wfe.wBitsPerSample = 16;
    wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
    wfe.nSamplesPerSec = (DWORD)sampling;
    wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;
    waveOutOpen(&hWaveOut, 0, &wfe, 0, 0, CALLBACK_NULL);
    lpWave = (LPWORD)calloc(sizeof(WORD), wfe.nChannels * sampling * terms);

    end = sampling * wfe.nChannels * 1;
    WORD amplitude = 32767;
    for (i = 0; i < end; i++) {
        lpWave[i] = 0;
    }

    // 最初の1sは出力しない
    start = sampling * wfe.nChannels * 1;
    end = wfe.nChannels * sampling * terms;
    // 最後の1sは出力しない
    end -= sampling * wfe.nChannels * 1;

    size_t valWavelength;
    size_t valFrequency;
    for (i = start, j = 0; i < end; i += 2) {
        if (j == 0) {
            valFrequency = frequency + ((i - start) * (20000.0- frequency)) / (sampling * wfe.nChannels * (terms - 2));
            valWavelength = sampling / valFrequency;
            lpData = (LPWORD)calloc(sizeof(WORD), valWavelength);
            createWave(lpData, valFrequency, sampling, amplitude);
        }
        lpWave[i] = lpData[j];
        ++j;
        if (j >= valWavelength) {
            j = 0;
            free(lpData);
        }
    }

    lpData = (LPWORD)calloc(sizeof(WORD), wavelength);
    createWave(lpData, frequency, sampling, amplitude);
    for (i = start+1, j = 0; i < end; i += 2) {
        lpWave[i] = lpData[j];
        ++j;
        if (j >= wavelength) { j = 0; }
    }
    free(lpData);

    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;

}