【今週の関心記事】2018/8/25

akiba-pc.watch.impress.co.jp

Phison製コントローラICを使用したM.2ドライブ。
PCIeカードとしても使用可能なところが特徴的。

ICはデータの圧縮機能までコントローラで担っている。
しかもICベンダの独自仕様。
単なるバッファや規格変換だけでなく、そういうところに付加価値をつけてるんですね。

ascii.jp

M.2ドライブをUSB外付けドライブに変換するケース。
USB3.1 Gen2の10Gbpsを活用して書き込み読み込みともに非常に高速。

ICはJMicron製のPCIe Gen3 x2-USB3.1 Gen2変換ICを使用。
この手のブリッジICは規格が立ち上がる度に登場するが、付加価値があんまりない。
しかも、高速IFはRevision更新が2-3年単位とめちゃくちゃ早いので、陳腐化も早い。
このICもこの用途しか使い道がないのではないかと思うと、短命で終わりそうですね。

【Serdes】Dual Dirac MethodをPythonで実装

Dual Dirac MethodをPythonで実装してみた。

Dual Dirac Methodの技術参考資料 (Keysight)
https://www.keysight.com/upload/cmc_upload/All/dualdirac1.pdf

1. Jitter Dataの準備

解析するモチーフをまず定義する。
Data Rate: 10Gbps (1UI=100psec)
Rj: 1ps RMS
Dj: 14ps PP (±7ps)のSj
Sample Size: 1MUI

Jitter Dataのデータは、各行に各UI毎のJitter値として、text file dataを作成。
RjとDjそれぞれのデータを作成してから、それらの和を取ることでTjのデータを作成することにした。

1.1 Rjの生成プログラム

乱数でRjデータを発生させ、rj.csvに保存。

import numpy as np
import csv

#Sample size
intSize = 1000000

#Jitter RMS = 1ps
fltJitterRms = 1e-12

#Generate random pattern
arrData = np.random.normal(0, fltJitterRms, intSize)

#Output Data
arrWriteData = []
for i,d in enumerate(arrData):
        arrWriteData.append([])
        arrWriteData[i].append(d)

with open('rj.csv', 'w') as f:
        wr = csv.writer(f)
        wr.writerows(arrWriteData)

1.2 Dj(Sj)の生成プログラム

14ps-pp, 周波数100MHzの正弦波でSjを発生し、sj.csvに保存。

import numpy as np
import csv

#Sample size 
intSize = 1000000
#Time step : 1UI = 100ps
fltStepTime = 100e-12

#Noise frequency = 101MHz
fltNoiseFreq = 101e6
#Noise Amp = 14ps-pp
fltNoiseAmp = 14e-12 / 2

#Generate sin pattern
arrTime = np.arange(0, intSize*fltStepTime, fltStepTime)
arrData = []
for t in arrTime:
	d = fltNoiseAmp*np.sin(2*np.pi*fltNoiseFreq*t)
	arrData.append(d)

#Output Data
arrWriteData = []
for i,d in enumerate(arrData):
	arrWriteData.append([])
	arrWriteData[i].append(d)

with open('sj.csv', 'w') as f:
	wr = csv.writer(f)
	wr.writerows(arrWriteData)

1.3 RjとDjの合成

rj.csv, sj.csvをコマンド因数で受け取り、2つのジッタの和を取り、rjsj.csvに保存。

import numpy as np
import csv 
import sys

args = sys.argv
path = []
path.append(args[1])
path.append(args[2])

arrData = []

#Read path[0] data
with open(path[0], 'r') as f:
	rr = csv.reader(f)
	for rd in rr:
		arrData.append(float(rd[0]))

#Add path[1] data
with open(path[1], 'r') as f:
	rr = csv.reader(f)
	for i,rd in enumerate(rr):
		arrData[i] += float(rd[0])

#Output data
arrWriteData = []
for i,d in enumerate(arrData):
	arrWriteData.append([])
	arrWriteData[i].append(d)

with open('rjsj.csv', 'w') as f:
	wr = csv.writer(f)
	wr.writerows(arrWriteData)

1.4 生成したジッタデータの確認

結果確認用にヒストグラムプロットのプログラムも作った。

import numpy as np
import csv
import sys
import matplotlib.pyplot as plt

args = sys.argv
path = args[1]
arrData = []

#Read data file
with open(path, 'r') as f:
        rr = csv.reader(f)
        for rd in rr:
                arrData.append(float(rd[0]))

#Plot Histgram
plt.figure()
plt.hist(arrData, bins=100, normed=True)
plt.show()

1.1で作ったrj.csvヒストグラム。ちゃんと正規分布が得られている。

f:id:kent_s:20180817140053p:plain
rj.csv

1.2で作ったsj.csvヒストグラム。正弦波による特徴的なジッタ分布が得られてる。

f:id:kent_s:20180817140241p:plain
sj.csv

1.3で作ったrjsj.csvの分布。正弦波に正規分布が重畳されているのが分かる。

f:id:kent_s:20180817140407p:plain
rjsj.csv

2. Dual Dirac Methodの実装

2.1 BERプロットの作成

1.3で作ったrjsj.csvを使ってBERプロットを作成。
1UIを1000等分にスライスし、ジッタがx番目の各スライスに含まれる確率をJ(x)と定義。
次にJ(x)の積分により、BER(x)を求めています。
出力はber.csvへのファイル出力です。

import numpy as np
import csv 
import sys
import matplotlib.pyplot as plt

fltUi = 100e-12
intRange = 1000

args = sys.argv
path = args[1]
arrJx = np.zeros(intRange, dtype='float')
intSize = sum(1 for line in open(path))

# Read Jitter Data
with open(path, 'r') as f:
	rr = csv.reader(f)
	for rd in rr:
		d = float(rd[0])/fltUi*intRange
		idx = int(round(d))
		arrJx[idx] += 1/float(intSize)

# Cal BER
arrBer = np.zeros(intRange, dtype='float')

for i in range(intRange/2, 0, -1):
	arrBer[i] = arrBer[i+1] + arrJx[i]

for i in range(-intRange/2, 0, 1):
	arrBer[i] = arrBer[i-1] + arrJx[i]

arrBer[0] = (arrBer[-1]+arrBer[1])/2 + arrJx[0]

#Generate Time axis
arrT = np.arange(0, fltUi, fltUi/intRange)

#Plot BER
plt.figure()
plt.plot(arrT, arrBer)
plt.yscale('log')
plt.show()

#Write BER
arrWriteData = []
for i,d in enumerate(arrBer):
	arrWriteData.append([])
	arrWriteData[i].append(d)

with open('ber.csv', 'w') as f:
	wr = csv.writer(f)
	wr.writerows(arrWriteData)

BER(x)の出力です。1MUI(=1e6UI)のデータなのでy軸は1e-6で切れています。

f:id:kent_s:20180817172225p:plain

左側のバスタブを拡大。
f:id:kent_s:20180817172340p:plain

BER=1e-5の後半あたりから曲線が荒い。
これもサンプル数が1MUIの為、BER=5e-5付近で精度が落ちている為。
x=7psec(赤で示したあたり)がDjが無くなるポイントだが非常に滑らか。
つまり、このプロットからRjを予測するのは困難。

2.2 Qプロットの作成

2.1で作ったber.csvからQプロットを作成。
信号遷移率ρTは1とした。
今回のデータは毎サイクルにジッタが発生しているので、信号遷移率は100%となる。

import numpy as np
import csv 
import sys
import matplotlib.pyplot as plt
from scipy import special

fltUi = 100e-12
intRange = 1000
fltRho = 1

args = sys.argv
path = args[1]

#Read BER data
arrBer = []
with open(path, 'r') as f:
	rr = csv.reader(f)
	for rd in rr:
		arrBer.append(float(rd[0]))

#Calc Q plot
arrQ = []
for ber in arrBer:
	q = np.sqrt(2) * special.erfinv(1 - 1/fltRho*ber)
	arrQ.append(q)

#Generate Time axis
arrT = np.arange(0, fltUi, fltUi/intRange)

#Plot Q
plt.figure()
#plt.scatter(np.arange(intRange), arrQ)
plt.plot(arrT, arrQ)
plt.ylim(8, 0)
plt.show()

#Output Data
arrWriteData = []
for i,d in enumerate(arrQ):
	arrWriteData.append([])
	arrWriteData[i].append(d)

with open('q.csv', 'w') as f:
	wr = csv.writer(f)
	wr.writerows(arrWriteData)

Q(x)の出力。
f:id:kent_s:20180817172742p:plain

左のバスタブの拡大。
f:id:kent_s:20180817172849p:plain

バスタブカーブが線形に近いことが確認できる。この線形性を利用してσを計算できる。
x=7psecのSjが無くなるポイントだが、変曲点よりも外側に来ている。
これは参考資料にある通り、Djのpp点Dj(pp)よりも、正規分布中心Dj(δδ)の方が内側に来ることが理由。

2.3 σの計算

最後にσの計算を行う。
BERのバスタブ底は精度が無いので、BER=2e-5のところで近似することにした。
BER=2e-5 ⇒ Q=4.265 (信号遷移率=1の時)なので、Q=4.265のところでfittingを取る。

import numpy as np
import csv 
import sys
import matplotlib.pyplot as plt
from scipy import special

fltUi = 100e-12
intRange = 1000
fltRho = 1

args = sys.argv
path = args[1]

#Read Q data
arrQ = []
with open(path, 'r') as f:
	rr = csv.reader(f)
	for rd in rr:
		arrQ.append(float(rd[0]))

#Search Q 
fltQs = 4.265

def getNearestIndex(list, val):
	return (abs(np.asarray(list) - val)).argmin()

intIlt = getNearestIndex(arrQ[:intRange/2], fltQs)
intIrt = getNearestIndex(arrQ[intRange/2:], fltQs) + intRange/2

#Generate Time axis
arrT = np.arange(0, fltUi, fltUi/intRange)

#Fitting
FitLt = np.polyfit(arrT[intIlt-2:intIlt+2], arrQ[intIlt-2:intIlt+2], 1)
FitRt = np.polyfit(arrT[intIrt-2:intIrt+2], arrQ[intIrt-2:intIrt+2], 1)

print FitLt
print FitRt

#Plot Q
plt.figure()
plt.scatter(arrT, arrQ, c='red')
plt.plot(arrT, np.poly1d(FitLt)(arrT))
plt.plot(arrT, np.poly1d(FitRt)(arrT))
plt.ylim(8, 0)
plt.xlim(0, fltUi)
plt.show()

QプロットとQ=4.265での線形近似直線。
f:id:kent_s:20180818054121p:plain

線形近似の係数はax+bとすると、バスタブ左側はa=9.19e11, b=-5.35. 右側はa=-1.04e12, b=97.0となった。

1/aがRjのσとなるが、計算すると、σ@左=1.1ps, σ@右=1.0psと計算できた。
これは1.1でRjを生成した時の1ps RMSと一致しており、Dual Dirac Methodで正しく見積もれていることが確認できた。

Dj(δδ)=-b/aなので、Dj(δδ)@左=5.8ps, Dj(δδ)@右=-6.3psとなる。
ここからBER=1e-12として、Tj=Dj(δδ)+7*σで見積もると、それぞれ13ps, -13psで、トータル26psとなる。
Dj(pp)=7psだったので、Tj=Dj(pp)+7σで見積もった場合は±14psとなるが、それよりも1psずつ悲観性を無くすことができている。

【Serdes】RjとJTFの関係

PCI Expressなどの高速SerdesのSystemの中で、TXのPLLとRXのCDRはジッタを抑制するフィルタの役割を果たす。これは、ジッタトランスファファンクション(Jitter Transfer Function: JTF)として数学的なモデル化が出来る。

下図の青線がUSB3.1 Gen2のリファレンスとして記載されているRX CDRのJTFである。一方、TX PLL側は同図の赤線のようになる。

RX側のHigh Pass FilterとTX側のLow Pass Filterの組み合わせにより、全帯域のJitterは抑制される。ただし、10MHz付近に関してはスイートスポットとなり、この帯域のジッタは排除することが出来ない。

f:id:kent_s:20180729094817p:plain

JTFはDetermistic Jitter(Dj)を抑える上で効果があることは容易に理解できる。Djは周波数分布が限定されており、その分布がJTFの不感帯に入っていなければ、抑制できると分かるからだ。

では、Random Jitterに対して、これらのフィルタは効くのだろうか?このことをPythonを使ったSimulationで検討した。

検証方法

検証モチーフはUSB3.1 Gen2である。手順をいかに示す。

  1. 乱数を使用し、1ps RMSの時系列データを作成
  2. 1をフーリエ変換
  3. 2にCDRのJTFを乗算
  4. 3を逆フーリエ変換し時系列波形を再生
  5. 4の標準偏差を計算

Simulationに使ったPythonのプログラムを本記事の末尾に記載する。

検証結果

結果は下記の通り、JTFによってほとんどジッタは減っていないことが分かった。

  • JTF通過前ジッタ: 1.00006781201 ps RMS
  • JTF通過後ジッタ: 0.996609674857 ps RMS

周波数スペクトルで見ると、下図の通り、JTFによって低周波数成分は明確に減衰していることは分かる。
ランダムジッタは非常に広い帯域で分布しており、かつ、広域側の強度が強い。したがって、低域側だけの減衰では効果が少ないことが原因と思われる。
にしても、RMSでここまで変化量が少ないというのはとても興味深い。

JTF通過前
f:id:kent_s:20180729105559p:plain

JTF通過後
f:id:kent_s:20180729105632p:plain

ソースコード

import numpy as np
import matplotlib.pyplot as plt

#Sample size
intSize = 1000000
#Time step : 1UI = 100ps
fltStepTime = 100e-12
#Freqency step : 10kHz
fltStepFreq = 1/(intSize*fltStepTime)

#Jitter RMS = 1ps
fltJitterRms = 1e-12

#Generate random pattern
arrData = np.random.normal(0, fltJitterRms, intSize)
arrTime = np.arange(0, intSize*fltStepTime, fltStepTime)

#Generate fft pattern
arrFftData = np.fft.fft(arrData)
arrFftFreq = np.fft.fftfreq(intSize,fltStepTime)

#Calc jitter suppressed spectrum
ks = 0.707
w3dB = 2 * np.pi * 1.5 * 10**7
wn = w3dB / (1 + 2 * ks**2 + ((1 + 2 * ks**2)**2 + 1)**0.5)**(-0.5)
arrFltFftData = np.zeros(intSize, complex)
for i in range(intSize):
        s = 2 * np.pi * arrFftFreq[i] * 1j
        arrFltFftData[i] = (s**2 / (s**2 + 2*ks*wn*s + wn**2)) * arrFftData[i]

#Calc jitter suppressed time domain data
arrFltData = np.fft.ifft(arrFltFftData)

#Output jitter RMS value
print np.std(arrData.real)
print np.std(arrFltData.real)

#Plot Raw Jitter @ Time Domain
#plt.figure()
#plt.plot(arrTime, arrData)

#Plot Raw Jitter @ Histgram
#plt.figure()
#plt.hist(arrData)

#Plot Raw Jitter @ Freq Domain
plt.figure()
plt.plot(arrFftFreq, abs(arrFftData))
plt.axis([1e6,max(arrFftFreq),0,max(abs(arrFftData))])
plt.xscale("log")

#Plot Filtered Jitter @ Time Domain
#plt.figure()
#plt.plot(arrTime, arrFltData.real)

#Plot Filtered Jitter @ Freq Domain
plt.figure()
plt.plot(arrFftFreq, abs(arrFltFftData))
plt.axis([1e6,max(arrFftFreq),0,max(abs(arrFftData))])
plt.xscale("log")

plt.show()

iPhone6sのバッテリー交換を諦めた話

iPhone6sのバッテリー無償交換プログラムが始まって大分経ったかと思う。

僕は思いっきり対象機種で、バッテリー切れによるシャットダウンが頻発していた。一日持たないどころか、1時間くらいウェブブラウジングするだけでバッテリー切れになる。気温低下に弱いのか、冬場は突然シャットダウンすることも多かった。はっきり言って、携帯として使えない状態。

すぐにでも無償交換をしたかったのだが、近所にAppleストアが無く行けなかった。首都圏はともかく、Appleストアは関西ではすごく少ない。Appleストアには電車で片道一時間くらいかけて、心斎橋まで行かなければならない。車はもちろん止める場所もないので、何かのついでに寄ることも出来ない。

なかなか時間を作ることが出来ないでいたのだが、仕事の大きな山場が過ぎ、ようやく時間が出来たので、Appleストア心斎橋まで行ってきた。

Appleストアの様子

心斎橋駅徒歩5分。おしゃれなビルの1・2階がAppleストアだった。洒落た美容院のように全面曇りガラスだった。

ストア内は平日昼間にも関わらず客で溢れかえっていた。しかし、客に対して店員の数が非常に多く、店に入ってすぐ店員に話しかけられた。流暢な日本語を話す白人だった。

予約時刻と名前を告げると、「ただいま込み合っているので10分ほどお待ちください」と言われた。混みあってるのに10分でできるのか~と思い、待つことに。

店内にはBose製のスピーカーなど、Apple製ではない商品も多く展示されていた。Appleは自前で作っている商品も増えてきた印象だったので、もっと前面に自社製品が展示されているのかと思いきや、意外でした。

しかし、買い物する気は全くないので、ウィンドウショッピングはすぐに飽きた。シアター席というのが空いていたので、そこに座った。シアターではiPhoneの使い方みたいなのがレクチャーされていたが、特に興味なく、Kindleに没頭。

約束の10分を大幅に上回り、30分が経った頃に名前が呼ばれた。10分って何やってん白人。応対してくれたのは、さっきの白人とは別のおしゃれパーマをかけた若者だった。

いざ、バッテリー交換…?

「バッテリーの消耗が早いんです」

と伝えると、店員は手持ちのiPadを操作して、私の機種が無償交換プログラムの対象であることを確認。

「ディスプレイが破損していますが、交換しますか?」

スマホはディスプレイが割れていると修理不可能と聞いたことがあったので、何となく予想していた。あまりお金はかけたくないので、

「出来ればしない方向で」

「ディスプレイが破損しているので、バッテリー交換の際に、ディスプレイが嵌らないリスクがございます」

「はい」

「その場合は、ディスプレイ交換をすることになりますが、リスクをご承知おきいただけますか?」

「ディスプレイ交換することになった場合は、いくらかかるんですか?」

「1万7~8千円になります」

「⁉」

「バッテリー交換は無償なのですが、ディスプレイ交換は有償になります」

エンジニアとしての視点からディスプレイ交換になる確率は結構高いと思った。多分、ディスプレイを外した瞬間に端っこが欠ける。端っこが欠けてツメがなくなって、はまらなくなる…。むしろ無事にはまる確率の方が低い。大阪の心斎橋に器用な修理工がいるとも思えなかった。

何となくディスプレイ交換になる可能性は低くはない気がしていた。それでも4~5千円なら出してもいいかなと思っていたが、まさかの2万円弱。3年前の機種に対して2万弱もかけられるか~!ということでiPhone6sのバッテリー交換は諦めました。

iPhone卒業

Appleの瑕疵で不完全なバッテリーを積んだiPhoneを正規の値段で掴まされたのに、その交換が2万円弱とは。決して安くない買い物だけに、腑に落ちないですね…。

落として割ったのはこっちですが、ディスプレイの割れは端っこの1cmくらいの領域で表示には全く影響しないところです。もしバッテリーが正常であれば、修理の必要もありませんでした。

iPhone4s → iPhone5c → iPhone6sと使ってきた僕でしたが、これを機にiPhoneは卒業することにしました。修理のためにAppleストアまで出向くのももう嫌ですし、Appleストアでの店員の対応も何か馬鹿にされた気分でした。天下のAppleで働いてるんだぞ感が漂ってましたね。(バイトのくせに…。)

次はiPhoneに変えて何を買うかをブログネタにしようかと思います。

WiFiストレージ検討

スマホの容量不足によく陥る。

一時期はiPhoneiCloudで有料のストレージを使用していた。が、このサービス、自動でバックアップをしてくれる訳じゃないんです。

というか、どのデータがCloudに保存されているのかすら分からない。さらにいうと、Cloudに移動するための操作方法もよく分からない。

拡張メモリ的に、iPhone内蔵のストレージが大きく見えるような工夫が欲しかったですね。

Apple純正のサービスだし、てっきりシームレスにデータをバックアップしてくれるのかと思った。

ということで最近、考えているのが外部ストレージにバックアップを取る、というやり方。で、見つけたのがWiFiストレージというジャンル。

WiFiストレージとは?

WiFiカードリーダとも呼ばれる。WiFi経由でSDカードや外付けHDDにデータをバックアックすることができる。

無線LANルータ・モバイルバッテリーの機能が内蔵されたものも多い。1台3役で10000円弱だ。

以下の記事のように、多数のメーカーが参入している。

 

matome.naver.jp

欲しいものがない

このジャンル、便利かどうかはソフト次第と思う。いかにシームレスにデータをバックアップできるか。

ファイルを一個一個コピーしないとデータが移せないみたいな、そういう不便な機種は避けたいですね。

また、先に書いたように拡張ストレージとして使えるのが好ましいが、今のところそういう機種は無い。欲しいものが出てくるまで待ち、ですね。

ソフトの問題だと、実際に使うまで分からないところであり、失敗するには一万円は高いです。

【LIVA-Z】Dual Display化しますた

もともと使ってたのが16inchのDisplayでした。非常に小さくてエクセルをやるにも不便を感じていました。

贅沢は言わない。だけど、不便を感じないくらいのサイズのDisplayが欲しいなと思っていました。

また、エンジニアという仕事柄、職場ではDual Displayを使っていました。メイン画面に作業するソフトを立ち上げて、サブに参考資料を写す。このやり方ですごく作業は効率化されました。

新しいDisplayを買うついでに、折角なので家のPCもDual Display化することにしました。

LIVA-ZのDual Display 

LIVA-Zにはmini Display Port(mDP)とHDMIの2つのディスプレイインターフェースがあります。それぞれ別のディスプレイに繋げば、Dual Displayができます。

f:id:kent_s:20180627170244p:plain

Displayの調達

自宅のPC環境にはとにかくお金をかけない主義です。なので、Displayは近所の中古ショップで購入しました。

新Displayは2160円でDELL製の21inchがあったのでこれを購入。半年前に買った古い16inchのDisplayはMITSUBISHI製の2000円くらいのものでした。

同じ価格なのに大画面のものが手に入ってラッキーでした。

変換アダプタ

LIVA-ZのポートがmDPとHDMIなのに対し、中古ショップで買ったのはVGAインターフェースでした。安いディスプレイ・古いディスプレイは古い規格のVGAのものしかないのです。

この規格の差は変換アダプタで解消することができます。

mDP to VGAはこちらを購入。1000円くらいです。

 HDMI to VGAはこちら。同じく1000円くらいです。

 接続!

新ディスプレイはmDPで、旧ディスプレイはHDMIで接続しました。

LIVA-Zは立ち上げ時のブート画面をmDPの画面に出力する仕様のようです。mDP/HDMIを最初は逆に繋いでいたのですが、僕は大きい新ディスプレイをメインに使いたかったので、入れ替えました。メインディスプレイはmDPに繋ぎましょう。

f:id:kent_s:20180627165219p:plain

Windowsなので、接続すれば空気を読んで良い感じに表示してくれます。

気に入らないことがあれば、デスクトップ上で、右クリック→「ディスプレイ設定」を辿れば、設定を変更できます。

IoT機器の固体認証向け新PUF技術、東芝が開発

IoT機器の固体認証向け新PUF技術、東芝が開発 - EE Times Japan

 

これを見た時、ニュースリリースするほどの技術か、と目を疑った。それほど小さい成果。大学の研究室の遊びでやるレベルでしょう。

 

そもそもPUFは肝になるのは回路構成ではない。シリコンの個体差を利用していることそのものが肝であって、実施方法はあんまり重要ではない。実施方法なんて、それこそ無限にある。

回路規模が大きかったのをシンプルにしたことが成果のような書き方をしているが、従来方式と新方式で、回路面積は多少変わるけど、コストにインパクトを与えることはない。つまり、課題の捉え方が間違っている。

 

デモ機もあんまり見栄えの良いものではない。今や3Dプリンタでデモ機の筐体くらい簡単に作れるのだし、もうちょっとだけお金を掛ければ良いのになと思った。

 

これをニュースリリースにしようと考えた人は、よっぽど技術に暗い人なのではないか。