2021/04/12

mongodb 帳號驗證權限

資料庫的權限有四種

  1. readAnyDatabase 任何資料庫的唯讀權限
  2. userAdminAnyDatabase 任何資料庫的讀寫權限
  3. userAdminAnyDatabase 任何資料庫用戶的管理權限
  4. dbAdminAnyDatabase 任何資料庫的管理權限

以往在啟動 mongodb 時,就直接指定 mongod.conf

mongod -f $MONGODB_HOME/conf/mongod.conf

這時候可用 mongo client 連接資料庫

./mongo

查看有沒有 users

db.system.users.find()

查看 user

show users

建立 admin 資料庫的管理者帳號

use admin

db.createUser({
  user : "root",
  pwd : "password",
  roles : [
    "clusterAdmin",
    "dbAdminAnyDatabase",
    "userAdminAnyDatabase",
    "readWriteAnyDatabase"
  ]
})

重新啟動 mognodb (加上 --auth 參數)

mongod --auth -f $MONGODB_HOME/conf/mongod.conf

再次查看 users

> use admin
> db.system.users.find()
Error: error: {
    "ok" : 0,
    "errmsg" : "command find requires authentication",
    "code" : 13,
    "codeName" : "Unauthorized"
}
> show users
2020-09-02T11:36:48.994+0800 E QUERY    [js] Error: command usersInfo requires authentication :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.getUsers@src/mongo/shell/db.js:1763:1
shellHelper.show@src/mongo/shell/utils.js:859:9
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1

驗證後,就可以查看 users

> use admin
switched to db admin
> db.auth("root", "password")
1
> show users
{
    "_id" : "admin.root",
    "user" : "root",
    "db" : "admin",
    "roles" : [
        {
            "role" : "clusterAdmin",
            "db" : "admin"
        },
        {
            "role" : "dbAdminAnyDatabase",
            "db" : "admin"
        },
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        },
        {
            "role" : "readWriteAnyDatabase",
            "db" : "admin"
        }
    ],
    "mechanisms" : [
        "SCRAM-SHA-1",
        "SCRAM-SHA-256"
    ]
}

針對資料庫,建立管理者

use admin

db.createUser({
  user : "maxkit",
  pwd : "password",
  roles : [
    {role:"readWrite", db:"larzio"}
  ]
})

針對資料庫,建立一般使用者

use larzio

db.createUser({
  user : "maxkit",
  pwd : "max168kit",
  roles : [
    {role:"readWrite", db:"larzio"}
  ]
})

刪除帳號

use admin

db.dropUser("maxkit")

關閉 mognodb

mongo 127.0.0.1:27017 -u root -p 'password' --authenticationDatabase 'admin' --eval "db.getSiblingDB('admin').shutdownServer()"

References

Mongodb 創建管理員帳號與普通帳號

2021/03/29

DSP 應用

數位音樂合成 digital music synthesis、數位語音合成 digital speech synthesis、數位語音辨識 digital speech recognition

數位音樂合成 digital music synthesis

使用訊號產生技術,包含週期性訊號及非週期性訊號,並透過數位訊號的排列組合,產生數位音樂

音樂的基本概念

音樂的基本構成要素:音高 pitch、節拍 beats、節奏 tempo

聲音的高低稱為音高 pitch,唱名:Do, Re, Mi, Fa, So, La, Si,對應的英語音名:C, D, E, F, G, A, B

鋼琴鍵盤的排列方式,是依照音高的順序,以中央 C 為基準向左右延伸,兩個相同音名鍵盤之間,有 8 個鍵盤,因此稱為八度音 octave。相鄰白鍵是相差一個全音,相鄰的白鍵與黑鍵,相差一個半音。

音高、音頻對照表:頻率,單位為赫茲。括號內為距離中央C(261.63赫茲)的半音距離。

0 1 2 3 4 5 6 7 8 9
C 16.352 (−48) 32.703 (−36) 65.406 (−24) 130.81 (−12) 261.63 (0) 523.25 (+12) 1046.5 (+24) 2093.0 (+36) 4186.0 (+48) 8372.0 (+60)
C♯/D♭ 17.324 (−47) 34.648 (−35) 69.296 (−23) 138.59 (−11) 277.18 (+1) 554.37 (+13) 1108.7 (+25) 2217.5 (+37) 4434.9 (+49) 8869.8 (+61)
D 18.354 (−46) 36.708 (−34) 73.416 (−22) 146.83 (−10) 293.66 (+2) 587.33 (+14) 1174.7 (+26) 2349.3 (+38) 4698.6 (+50) 9397.3 (+62)
D♯/E♭ 19.445 (−45) 38.891 (−33) 77.782 (−21) 155.56 (−9) 311.13 (+3) 622.25 (+15) 1244.5 (+27) 2489.0 (+39) 4978.0 (+51) 9956.1 (+63)
E 20.602 (−44) 41.203 (−32) 82.407 (−20) 164.81 (−8) 329.63 (+4) 659.26 (+16) 1318.5 (+28) 2637.0 (+40) 5274.0 (+52) 10548 (+64)
F 21.827 (−43) 43.654 (−31) 87.307 (−19) 174.61 (−7) 349.23 (+5) 698.46 (+17) 1396.9 (+29) 2793.8 (+41) 5587.7 (+53) 11175 (+65)
F♯/G♭ 23.125 (−42) 46.249 (−30) 92.499 (−18) 185.00 (−6) 369.99 (+6) 739.99 (+18) 1480.0 (+30) 2960.0 (+42) 5919.9 (+54) 11840 (+66)
G 24.500 (−41) 48.999 (−29) 97.999 (−17) 196.00 (−5) 392.00 (+7) 783.99 (+19) 1568.0 (+31) 3136.0 (+43) 6271.9 (+55) 12544 (+67)
G♯/A♭ 25.957 (−40) 51.913 (−28) 103.83 (−16) 207.65 (−4) 415.30 (+8) 830.61 (+20) 1661.2 (+32) 3322.4 (+44) 6644.9 (+56) 13290 (+68)
A 27.500 (−39) 55.000 (−27) 110.00 (−15) 220.00 (−3) 440.00 (+9) 880.00 (+21) 1760.0 (+33) 3520.0 (+45) 7040.0 (+57) 14080 (+69)
A♯/B♭ 29.135 (−38) 58.270 (−26) 116.54 (−14) 233.08 (−2) 466.16 (+10) 932.33 (+22) 1864.7 (+34) 3729.3 (+46) 7458.6 (+58) 14917 (+70)
B 30.868 (−37) 61.735 (−25) 123.47 (−13) 246.94 (−1) 493.88 (+11) 987.77 (+23) 1975.5 (+35) 3951.1 (+47) 7902.1 (+59) 15804 (+71)

樂曲中,每一個音都有自己的節拍 beats,代表這個音的時間長短,在五線譜中,節拍是用 音符 notes 表示,包含:全音符、二分音符、四分音符等等。ex: 五線譜中的拍號為 C 或 4/4,代表每一個小節有 4 拍,全音符代表這個音佔滿整個小節,因此為 4 拍,二分音符是全音符的一半,是 2 拍

另一個元素是節奏 tempo,就是音樂的快慢或速度。目前節奏通常是以每分鐘的節拍數 beats per minutes 決定。音樂的節奏包含:慢板、行板、中板、快板,與音樂要表達的情感有關。

小蜜蜂

import numpy as np
import wave
import struct

# 音符:音高 pitch + 節拍 beat
def note( pitch, beat ):
    fs = 44000
    amplitude = 30000
    # C, D, E, F, G, A, B 的頻率
    frequency = np.array( [ 261.6, 293.7, 329.6, 349.2, 392.0, 440.0, 493.9 ] )
    num_samples = beat * fs

    t = np.linspace( 0, beat, num_samples, endpoint = False )
    # 淡出效果
    a = np.linspace( 0, 1, num_samples, endpoint = False )

    # 弦波
    x = amplitude * a * np.cos( 2 * np.pi * frequency[ pitch - 1 ] * t )
    return x

def main():
    file = "little_bee.wav" # 檔案名稱

    # 音高 pitch
    pitches = np.array( [ 5, 3, 3, 4, 2, 2, 1, 2, 3, 4, 5, 5, 5,    \
                          5, 3, 3, 4, 2, 2, 1, 3, 5, 5, 3,          \
                          2, 2, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, 4, 5, \
                          5, 3, 3, 4, 2, 2, 1, 3, 5, 5, 1 ] )

    # 節拍 beat
    beats = np.array( [ 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2,    \
                        1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 4,          \
                        1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, \
                        1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 4 ] )

    tempo = 0.5                 # 節奏(每拍0.5秒)
    fs = 44000

    # 時間總長度 = 節拍總和 * 節奏
    duration = sum( beats ) * tempo
    # 總樣本數 = 時間總長度 * 頻率
    num_samples = int( duration * fs )

    num_channels = 1            # 通道數
    samwidth = 2                # 樣本寬度
    num_frames = num_samples    # 音框數 = 樣本數
    comptype = "NONE"           # 壓縮型態
    compname = "not compressed" # 無壓縮

    num_notes = np.size( pitches )

    y = np.array( [ ] )
    for i in range( num_notes ):
        x = note( pitches[i], beats[i] * tempo )
        y = np.append( y, x )

    wav_file = wave.open( file, 'w' )
    wav_file.setparams(( num_channels, samwidth, fs, num_frames, comptype, compname ))

    for s in y:
        wav_file.writeframes( struct.pack( 'h', int( s ) ) )

    wav_file.close( )

main()

數位語音合成 digital speech synthesis

也就是 TTS, Text to Speech 的技術。

python 套件

  • Pyttsx Text to Speech
  • gTTS Text to Speech
  • eSpeak

數位語音辨識 digital speech recognition

Speech To Text

發展的技術:隱藏式馬可夫模型(Hidden Markov Models)、動態時間扭曲(Dynamic Time Warping, DTW)、人工神經網路(Artificial Neural Networks)、深度學習 (Deep Learning)、點對點自動語音辨識 (End-to-End Automatic Speech Recognition)。語音辨識率的準確度受到許多因素影響:雜訊、男生/女生、成人/兒童、口音、語意

新的人工智慧技術:遞迴神經網路 (Recurrent Neural Network, RNN),同時結合長短期記憶 (Long-Short Term Memory, LSTM)的技術最具代表性。AI 技術將成為語音辨識的主流

python 語音辨識 library: SpeechRecognition,支援許多 engines/apis

  • CMU Sphinx
  • Google Speech Recognition
  • Google Cloud Speech API
  • Wit.ai
  • Microsoft Bing Voice Recognition
  • Houndify API
  • IBM Speech to Txt
  • Snowboy Hotword Detection

References

數位訊號處理:Python程式實作(附範例光碟)(第二版)

2021/03/22

時頻分析

時間-頻率分析 Time-Frequency Analysis,首先介紹時頻分析的概念及數學工具 短時間傅立葉轉換 (Short-Time Fourier Transform, STFT),最後介紹範例與結果,用時頻圖 (spectrogram) 表示。

基本概念

通常輸入訊號是 non-stationary 訊號,會跟著時間改變。也就是頻率分量通常會隨著時間改變,因此無法在單一的頻譜分析非靜態(non-stationary)的訊號

例如一首歌曲,在不同時間點的頻率,會隨著時間改變,進而組成一首歌曲。人類發出的語音訊號,說話時每個字的音頻不同,進而組成一個句子。

為了分析或特性化 non-stationary 訊號,需要使用時間頻率分析技術,簡稱時頻分析技術

時頻分析 Time-Frequency Analysis:是訊號分析技術,同時包含時間域與頻率域,以時頻表示法Time-Frequency Representations 呈現。

因為時頻分析包含時間域與頻率域,可表示成二維訊號,稱為時頻表示法 Time-Frequency Representations ,通常是以二維圖形呈現

短時間傅立葉轉換

Short-Time Fourier Transform, STFT

STFT 定義:

\(STFT\{x(t)\}(τ, ω) = X(τ, ω) = \int_{-∞}^{∞}x(t)w(t-τ)e^{-jωt} {\rm d}t\)

其中 \(w(t)\) 為窗函數,通常是以原點為中心,包含 rectangular, hanning, gaussian window function 等等

注意 \(w, ω\) 代表不同的意義


離散短時間傅立葉轉換 Discrete STFT

定義:

\(STFT\{x[n]\}(m, ω) = X(m, ω) = \sum_{-∞}^{∞}x[n]w(n-m)e^{-jωn}\)

其中 \(w[n]\) 為窗函數

雖然 \(ω\) 是連續的,但因為 DSP 是用 快速傅立葉轉換 FFT 進行運算,因此頻率 \(ω\) 也會是離散的資料


時頻分析示意圖:

先將輸入訊號分成不同時間的區塊,通常是短暫且固定的時間,透過窗函數的運算,取得訊號區塊,每個訊號區塊,在經過傅立葉轉換,運算結果為複數,構成二維矩陣。最後,組合不同時間點訊號區塊的頻譜分析結果。

時頻圖 Spectrogram

定義:\(|X(m, ω)|^2\),其中 \(X(m, ω)\) 是 STFT 的結果

將 \(X(m, ω)\) 的二維複數矩陣結果,取強度 (magnitude) 平方,則形成二維的時數矩陣,就可以用二維的圖形呈現,稱為 spectrogram

STFT 主要缺點是解析度問題,由於窗函數的寬度固定,取得訊號區塊大小不同,使得時間域與頻率域的解析度也有所不同。

如訊號區塊的寬度較窄,則時間域解析度較佳,但在頻率域的解析度較差 (左圖)。

ex: 若數位訊號由弦波組成,時間長度為 10s,第一秒頻率 20Hz,第二秒頻率 40Hz,第三秒頻率 60Hz,遞增至 200Hz,取樣頻率為 1000Hz。假設窗函數為 rectangular window function,區塊長度為 100, 200, 500, 1000,求訊號的 STFT,以 spectrogram 表示。

import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt

print( "Short-Time Fourier Transform" )
# n = eval( input( "Enter the length of segment: " ) )

def plot(x, fs, n, plotpos):
    f, t, Zxx = signal.stft( x, fs, window = 'boxcar', nperseg = n )

    plt.subplot(plotpos)
    plt.pcolormesh( t, f, abs(Zxx) )
    plt.xlabel( 'Time(Second)'+' (n='+str(n)+')' )
    plt.ylabel( 'Frequency(Hz)' )

fs = 1000
t = np.linspace( 0, 1, fs )

x = np.array( [ ] )
for i in range( 10 ):
    segment = np.cos( 2 * np.pi * ( ( i + 1 ) * 20 ) * t )
    x = np.append( x, segment )

# n: the length of segment
n = 100
plot(x, fs, n, '221')

n = 200
plot(x, fs, n, '222')

n = 500
plot(x, fs, n, '223')

n = 1000
plot(x, fs, n, '224')

plt.show( )

當弦波頻率增加,由於區塊長度不同,讓時間域與頻率域的解析度結果不同。當區塊長度增加,時間域的解析度越來越差,但頻率域的解析度越來越好。

時頻圖通常用 colormap 色彩圖呈現,亮度較高代表強度越大。

目前有一種 wavelet transform,可克服 STFT 的解析度問題。在高頻範圍,時間解析度較好,在低頻範圍,頻率解析度較好。


f, t, Zxx = signal.stft( x, fs, window = 'boxcar', nperseg = n ) 的部分可改用 SciPy 的 spectrogram 函式

f, t, Zxx = signal.spectrogram( x, fs )

import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt

print( "Short-Time Fourier Transform" )
# n = eval( input( "Enter the length of segment: " ) )

def plot(x, fs):
    f, t, Zxx = signal.spectrogram( x, fs )

    plt.pcolormesh( t, f, abs(Zxx) )
    plt.xlabel( 'Time(Second)' )
    plt.ylabel( 'Frequency(Hz)' )

fs = 1000
t = np.linspace( 0, 1, fs )

x = np.array( [ ] )
for i in range( 10 ):
    segment = np.cos( 2 * np.pi * ( ( i + 1 ) * 20 ) * t )
    x = np.append( x, segment )

plot(x, fs)

plt.show( )

結果為

wav 的時頻分析

STFT 時頻圖

wav file 的 STFT 時頻圖

import numpy as np
import wave
from scipy.io import wavfile
import struct
import scipy.signal as signal
import matplotlib.pyplot as plt

infile  = input( "Input File: " )
fs, x = wavfile.read( infile )

# nperseg: 區塊長度 1000
f, t, Zxx = signal.stft( x, fs, nperseg = 1000 )

plt.pcolormesh( t, f, abs( Zxx ) )
plt.xlabel( 'Time(Second)' )
plt.ylabel( 'Frequency(Hz)' )

plt.show( )

sample rate: 11025Hz 的 wav file

SciPy 時頻圖(spectrogram)

import numpy as np
import wave
from scipy.io import wavfile
import struct
import scipy.signal as signal
import matplotlib.pyplot as plt

infile  = input( "Input File: " )   
fs, x = wavfile.read( infile )  
f, t, Zxx = signal.spectrogram( x, fs )

plt.pcolormesh( t, f, abs( Zxx ) )
plt.xlabel( 'Time(Second)' )
plt.ylabel( 'Frequency(Hz)' )

plt.show( )

跟上面的例子一樣的語音檔

References

數位訊號處理:Python程式實作(附範例光碟)(第二版)