標籤:

幾億的數據讀取作圖怎樣做到速度快呢?

具體情況是這樣的:本人採用幾十M的數據採集卡,採集了9億數據,存儲為二進位bin文件,利用MATLAB對bin讀取,簡單對數據進行線性變換,然後就plot作圖,作圖很慢,1-2分鐘,但是圖像出來後,對圖像局部放大,根本卡的就不行。
需求很簡單,就是把這9億數據一個不拉全部作圖顯示,局部放大不卡。

那麼,什麼工具能做到呢?

bin文件百度雲,有興趣的試試O(∩_∩)O哈!http://pan.baidu.com/s/1hscauva

fip=fopen(1.bin","rb");%讀取bin文件
[dat,num]=fread(fip,[1,inf],"uint16");
MATLAB里就是這樣讀取bin的贊


九億數據的二進位數據文件,大約有多大?

考慮換c++吧。我這邊處理的數據文件最大有6GB,用Qt寫程序,Qwt繪圖。

首先載入文件進行預處理,按照數據單元生成索引,這段耗時基本等同於磁碟順序讀取。

然後數據顯示時,只要是1-1的變換,那麼直接用model-view機制,在model中現場變換,數據處理耗時忽略,界面繪圖耗時大約十秒。

不過我這邊,單條曲線數據點只有幾十萬量級。

要到億這個量級的話,需要修改model,model主要提供下面三個方法:

Rect boundingRect() const;

size_t size() const;

Point sample(size_t i) const;

這裡是給定x值,獲取y值。如果是極坐標曲線,也有對應的QwtPolar控制項。

考慮到顯示器一般水平方向解析度也就2k級別,所以可以將數據進行分段,每段映射為一個點。

這裡的話,可以考慮按照10000:1、1000:1、100:1分別進行映射,映射過程就放在文件載入過程中,並且把映射結果緩存到磁碟。

映射過程耗時基本也可以忽略,耗時還是等同於把文件順序讀一遍。磁碟消耗為源文件大小的1.11%。

然後,默認全選的情況下,使用10000:1的數據填充model,將其讀入內存或者在磁碟中就地查詢都可以。

當縮放比例增大時,酌情降低映射比率,最終降低到1:1,縮放比例減小時就反過來操作。

這樣的話,最終數據量依舊可以壓縮到1w-10w這個量級,繪圖壓力已經很小了。


可以考慮根據當前顯示的區域來繪圖,再一個區域內只需要畫出足夠的點而不是所有的點:

function main
fid = fopen("1.bin", "rb");
y = fread(fid, "*uint16");
fclose(fid);
n = numel(y);
x = 1 : 1000 : n;
hLine = plot(x, y(x));
addlistener(gca, "XLim", "PostSet", @xlimPostChangeCallback);
function xlimPostChangeCallback(~, evnt)
ax = evnt.AffectedObject;
xl = round(get(ax, "xlim")) + [-1 1];
t = ceil(diff(xl) / 10000);
xdata = max(1, xl(1) - t) : t : min(n, xl(2) + t);
ydata = y(xdata);
set(hLine, "xdata", xdata, "ydata", ydata)
end
end

這段代碼的目的是每次 xlim 改變之後根據當前的 xlim 繪製相應的圖形

初始狀態是按照每 1000 個點採樣一次來繪製的,在整體的圖像上和你直接用上億個點繪圖效果應該沒有多大區別,不過繪圖時間可以大大縮短。

而當放大時,會根據放大後的區域重新在該區域上採樣,這樣即使你放大到 1 的尺度上也不會漏掉任何一個數據點

另外,新版的 fplot,fsurf 等函數也會利用類似原理處理縮放:

FPLOT and Friends


matlab不了解

opengl有sparse texture的相關擴展

vulkan直接支持sparse resources

都能做到maga map渲染

實質上就是分塊 多級緩衝 流式載入


可以採用OpenGL 中mipmap 的思想,對原始數據進行降採樣處理,至於降採樣的方法可以是抽取,也可滑動窗口平均。如此處理,得到多個中間層。在作圖顯示時,根據縮放的大小選擇合適的中間層顯示。這類似sample 時計算LOD.


我想你的9億數據應該是個數字,如力值,溫度,感測器數據等。

採集時用數據,存儲數據時建議用二進位,對這種數據,可以用c++通過流模式,用數組讀取,然後用雙緩衝區繪圖的方式,一次顯示出來。


應該說 Matlab 不是適合觀察幾億個點的工具。

Matlab 畫圖時,是要把圖上所有點的信息都放在內存里的,因為用戶有可能要用滑鼠對圖象進行「取點觀察坐標」等操作,它要時刻準備好。雖然在你這個例子里沒有用到這個操作,但 Matlab 並不知道。另外,Matlab 通常的使用場景不會出現上億個點,所以它沒有針對上億個點的情形進行優化。

所以,鑒於你的需求比較特殊,你需要尋找專用的工具;或者用 Qt 之類的圖形庫自己編寫一個工具,捨棄沒有必要的功能,而針對你「數據量大」的特點做專門的優化。需要優化的地方包括:

  • 觀察全局時,會有很多點是重疊在屏幕上同一個像素上的,這些點可以只畫一次;
  • 觀察局部時,只畫觀察範圍以內的點,你需要把這些點快速篩選出來。

為了做到這兩點,可能需要使用一些高級的數據結構來組織你的上億個點,例如 k-d tree。我倒是沒親自寫過這種程序,不知道這是不是最適合的數據結構。


我不認為在同一個界面上顯示9億條數據是一個合理的要求。如果你見過哪個軟體是這麼做的,請讓我見識一下。

極大量的數據處理基本上就兩種思路,要麼上多台機器做分散式計算,要麼利用局部性原理。你要分析自己的情況屬於哪一種。


肉眼看不完這麼多的數據的plot,首先應該選擇合適的可視化方法,對於高頻成分,plot明顯不是最好的。

對於直流,低頻為主的數據,先分區,降採樣,不僅是平均值,要畫出每一區極大極小和均值,再看自己關注哪些,篩選出來。

對於高頻信號,先做個高通去零漂,分段計算fourier,段可以取大一點,點數多可以用相位補齊,這樣基本就是O(n)的時間了,然後展示其spectrogram,關注的區域放大了看,精細的畫就好。


不考慮簡化的話,cfd有個後處理軟體叫paraview,應該是後處理速度最快的軟體。

下面是超過50W個核心3萬個節點處理60億的網格單元的處理結果,具體可以看看Kitware Prepares SC16 Presentation On Record-Breaking In Situ Simulation Run。

加上並行演算法以後我覺得繪製你所需要的數據應該會快點。


分tile唄,地圖顯示軟體都是這麼做的。


matlab有這麼高的性能了?9億數據2分鐘出圖?

個人覺得還是把數據分區間,繪圖時採樣,放大基本就是重繪。


抽樣,別一次全讀進內存就行


別太實在了,分tile吧。

另外如果,有10000個點要表示在十個像素寬的區域上,每一個像素寬的區域需要表示100個點,那麼你看到的應該是一個100個點最小y值到最大y值的直線。map reduce一下就。出來非常近似的折線圖了。


仔細想想吧,你的屏幕解析度不過幾百萬像素,程序窗口還只是佔據了其中的一部分。所謂地把幾億個數據一個不落顯示出來顯然是不可能的,有很多點都被計算機自動忽略掉了。比較可行的方法是要麼一塊一塊地把圖像取出來顯示並作變換;要麼變換後在顯示整幅圖像的時候間隔取點,使最終取出點的總數符合屏幕解析度,並用這些點生成預覽圖像。


正確的做法應該是給數據取樣,而不是依次繪製。人眼的解析度都有限,何況是機器呢


推薦閱讀:

Matlab啟動後,current folder顯示processing,然後就很卡,不能用了怎麼辦?
matlab如何很好的處理比較大的數據?
如何用matlab編寫人拔禾苗,禾苗變高的這一系列動作?
如何算是精通MATLAB?

TAG:MATLAB | OpenGL |