文章目录

  • Linux CSI Tool 完整使用说明(权威版 已成功测试)
  • 1. 硬件设备
  • 2. 刷BIOS & 拆卸替换网卡
  • 3. 操作系统
  • 4. 内核编译、驱动、固件配置
  • 5. 具体使用
  • 5.1 共同准备
  • 5.2 CSI发送端
  • 5.3 CSI接收端
  • 6. CSI数据处理(Matlab & Python)
  • 6.1 Matlab方式
  • 6.2 Python方式


Linux CSI Tool 完整使用说明(权威版 已成功测试)

本文涉及到的所有文件均在以下百度网盘链接的压缩包内,请大家自取
链接: https://pan.baidu.com/s/1I67ex4KwFnItlyFCoWlQoQ
提取码: ep8b

相关链接:

1. 硬件设备

  1. 电脑设备推荐ThinkPad X201,
  2. 网卡务必使用Intel 5300网卡,spm=a1z09.2.0.0.48192e8dEszrp2&id=572509799776&_u=v3mfohc2b41c

2. 刷BIOS & 拆卸替换网卡

由于ThinkPad X201电脑的BIOS版本比较旧,因此我之前直接换装网卡之后在BIOS启动阶段就出错了,提示无法识别的硬件设备。因此我们需要在换装网卡之前利用Win PE系统刷一遍BIOS。

  1. 准备一个2G左右的U盘,准备PE系统的安装程序:WePE_32_V2.1.exe(压缩包内)
  2. 运行该程序,根据程序的指示将U盘刷成PE系统的启动盘。
  3. 准备 ThinkPad X201 的 BIOS 包:ThinkPad X201_6quj10us_SLIC21_no_whitelist.zip(压缩包内)
  4. 将BIOS包复制到U盘名为“微软PE工具箱”的分区内。
  5. 接下来将U盘插入ThinkPad X201内,启动电源,在出现初始化界面时按ThinkVantage按钮,然后出现选择菜单时按F12,在启动菜单中选择U盘。
  6. 等待进入U盘PE系统,在“微软PE工具箱”分区内解压之前下载的BIOS包,建议选择64位的文件夹(如果64bit刷BIOS失败了用32bit也行),然后双击“WinPhlash64.exe”运行,直接点击flash bios即可。
  7. 等待刷机完成后关闭电脑,接下来是拆卸和换装网卡步骤。
  8. 切断笔记本电源,拔出笔记本电池,切勿带电操作!
  9. 用十字螺丝刀拧开笔记本背面的螺丝(拧开带有键盘、触摸板图标的螺丝即可)
  10. 拧完螺丝后轻轻就可以拆开笔记本的键盘和触摸板。
  11. 原先的网卡在右下方的位置,我们需要用螺丝刀拧开螺丝后才能移除原有网卡,然后才能插入5300网卡。
  12. 由于一般天线是放在笔记本外侧的,所以需要拆除右下方的声卡板来为接线提供空间。
  13. 安装完毕后如下图所示:
  14. thinkPadL14BIOS怎么恢复禁用 thinkpad l14 bios怎么进入_wifi

3. 操作系统

操作系统推荐Ubuntu 14.06 LTS,内核版本为3.13,不过现在好像只能下载到4.4的内核版本(镜像链接:https://mirrors.zju.edu.cn/ubuntu-releases/

我用的是3.13内核版本的Ubuntu 14.06,问题应该不大,因为后面要重新编译过内核。

怎么安装系统就不说了。相信大家都没有问题。

另外,如果你能在安装系统的界面成功检测到周围的WIFI并且能连接成功,那说明你的BIOS刷机成功了,系统“认识”这款网卡。

不过还是建议大家在连着有线网的情况下安装,包括后续的安装操作。

4. 内核编译、驱动、固件配置

操作系统安装完毕后,重启进入。刚进入系统时可能会提示你是否要升级到16.04,点击否就行了。包括提示要更新软件等都略过吧。

  1. 安装相关依赖
  • 更新源
sudo apt-get update
  • 下载安装依赖包
sudo apt-get -y install git-core kernel-package fakeroot build-essential ncurses-dev
sudo apt-get -y install libnl-dev libssl-dev
sudo apt-get -y install iw
  1. 下载、编译内核
  • 准备 intel-5300-csi-github-master.tar.gz
    压缩包内有:intel-5300-csi-github-master.tar.gz,如果觉得百度网盘下载速度慢,这里提供一位博主的:
  • 解压、编译
    按顺序一步一步在终端执行以下代码
cd ~
tar -xvf intel-5300-csi-github-master.tar.gz
cd intel-5300-csi-github-master
make oldconfig # 一直按回车
make menuconfig # 在弹出的窗口选择Save,再Exit,一定要save一遍,而不是直接退出。另外可能会因为终端窗口比较小无法显示完全而报错
make -j4 # 编译内核一直都比较慢,大概半小时到一小时
sudo make install modules_install # 安装kernel module,大约15分钟
sudo make install
sudo make install modules_install # 再次安装内核模块(保险起见,一定要执行)
sudo mkinitramfs -o /boot/initrd.img-`cat include/config/kernel.release` `cat include/config/kernel.release`
make headers_install
sudo mkdir /usr/src/linux-headers-`cat include/config/kernel.release`
sudo cp -rf usr/include /usr/src/linux-headers-`cat include/config/kernel.release`/include
  • 添加刚刚编译过的内核(4.2.0版本)至启动项
cd /etc/default
sudo vi grub

注释这一行

GRUB_HIDDEN_TIMEOUT=0
  • 更新grub
sudo update-grub
  • 重启电脑,一定要在启动选项中选择4.2的内核版本进入。
  1. 替换固件
    按顺序在终端执行以下代码
cd ~
git clone https://github.com/dhalperi/linux-80211n-csitool-supplementary.git
for file in /lib/firmware/iwlwifi-5000-*.ucode; do sudo mv $file $file.orig; done
sudo cp linux-80211n-csitool-supplementary/firmware/iwlwifi-5000-2.ucode.sigcomm2010 /lib/firmware/
sudo ln -s iwlwifi-5000-2.ucode.sigcomm2010 /lib/firmware/iwlwifi-5000-2.ucode

到此,5300网卡的驱动以及CSI收发包工具都已经配置完毕。接下来分别介绍发包和收包的操作。

5. 具体使用

5.1 共同准备

在终端按顺序执行以下代码

cd ~
sudo apt-get install libpcap-dev
git clone https://github.com/dhalperi/lorcon-old.git
cd lorcon-old
./configure
make
sudo make install

5.2 CSI发送端

  1. 编译发送代码
cd ~
cd linux-80211n-csitool-supplementary/injection/
make
  1. 执行初始化脚本 inject.sh(压缩包内:inject.sh)
    在执行之前建议先查看无线网卡接口名称,一般情况下是 wlan0
iwconfig

如图所示:

thinkPadL14BIOS怎么恢复禁用 thinkpad l14 bios怎么进入_linux_02


执行脚本即参数配置:

sudo bash ./inject.sh wlan0 64 HT20

参数解释:第一个参数是无线网卡接口名称,一般是wlan0,第二个参数是信道编号,建议64,第三个是OFDM下的HT20模式

inject.sh代码:

#!/usr/bin/sudo /bin/bash
sudo service network-manager stop
WLAN_INTERFACE=$1
SLEEP_TIME=2
modprobe iwlwifi debug=0x40000
if [ "$#" -ne 3 ]; then
    echo "Going to use default settings!"
    chn=64
    bw=HT20
else
    chn=$2
    bw=$3
fi
sleep $SLEEP_TIME
ifconfig $WLAN_INTERFACE 2>/dev/null 1>/dev/null
while [ $? -ne 0 ]
do
    ifconfig $WLAN_INTERFACE 2>/dev/null 1>/dev/null
done
sleep $SLEEP_TIME
echo "Add monitor mon0....."
iw dev $WLAN_INTERFACE interface add mon0 type monitor
sleep $SLEEP_TIME
echo "Bringing $WLAN_INTERFACE down....."
ifconfig $WLAN_INTERFACE down
while [ $? -ne 0 ]
do
    ifconfig $WLAN_INTERFACE down
done
sleep $SLEEP_TIME
echo "Bringing mon0 up....."
ifconfig mon0 up
while [ $? -ne 0 ]
do
    ifconfig mon0 up
done
sleep $SLEEP_TIME
echo "Set channel $chn $bw....."
iw mon0 set channel $chn $bw
  1. 发送数据
echo 0x1c113 | sudo tee `sudo find /sys -name monitor_tx_rate`
cd ~
cd linux-80211n-csitool-supplementary/injection/
sudo ./random_packets 1000000000 100 1 1000

第一行的参数配置如果有个人需求可以参考:CSI Tool安装使用讲解

不过个人建议就这样就行了,毕竟这个工具搭建很麻烦。

random_packets的参数解释:第一个参数是累计发包数量,第二个参数是包的大小,第三个参数1代表injection MAC,用1就可以了,最后一个参数代表每隔1000微秒发一次包,即一秒发1000个包。

5.3 CSI接收端

  1. 编译接收代码
cd ~
cd linux-80211n-csitool-supplementary/netlink/
make
  1. 执行初始化脚本 monitor.sh (压缩包内:monitor.sh)
    注意:一定要采用这个脚本,其他博客上的脚本基本缺少了第2、3行内容,否则收不到包的!我尝试了好几次,才找到办法。如果发现此脚本运行后提示找不到对应的wlan接口也可尝试另外一个
sudo bash ./monitor.sh wlan0 64 HT20

信道编号要和发送端的一样

monitor.sh代码

#!/usr/bin/sudo /bin/bash
sudo modprobe -r iwlwifi mac80211
sudo modprobe iwlwifi connector_log=0x1

sudo service network-manager stop
SLEEP_TIME=2
WLAN_INTERFACE=$1
if [ "$#" -ne 3 ]; then
	echo "Going to use default settings!"
	chn=64
	bw=HT20
else
	chn=$2
	bw=$3
fi
echo "Bringing $WLAN_INTERFACE down......"
ifconfig $WLANINTERFACE down
while [ $? -ne 0 ]
do
	ifconfig $WLAN_INTERFACE down
done
sleep $SLEEP_TIME
echo "Set $WLAN_INTERFACE into monitor mode......"
iwconfig $WLAN_INTERFACE mode monitor
while [ $? -ne 0 ]
do
	iwconfig $WLAN_INTERFACE mode monitor
done
sleep $SLEEP_TIME
echo "Bringing $WLAN_INTERFACE up......"
ifconfig $WLAN_INTERFACE up
while [ $? -ne 0 ]
do
	ifconfig $WLAN_INTERFACE up
done
sleep $SLEEP_TIME
echo "Set channel $chn $bw..."
iw $WLAN_INTERFACE set channel $chn $bw

monitor.sh 备用代码

thinkPadL14BIOS怎么恢复禁用 thinkpad l14 bios怎么进入_wifi_03

  1. 执行收包程序
cd ~
cd linux-80211n-csitool-supplementary/netlink/
sudo ./log_to_file temp # temp是保存数据的文件名,强烈建议文件名改为dat后缀

由于原生的代码只能不停的收包,因此我编写了一个可以收包n秒以后自动停止的C代码(压缩包内:log_to_file.c):

使用方法如下:

cd ~
cd linux-80211n-csitool-supplementary/netlink/
sudo ./log_to_file temp 3

参数解释:temp是保存数据的文件名,3代表从检测到CSI包之后收3秒,然后退出程序。如果发送端每秒发送1000个包,那么在不丢包的情况下可以收到3000个包。如下图:

thinkPadL14BIOS怎么恢复禁用 thinkpad l14 bios怎么进入_linux_04

log_to_file.c 文件代码:

/*
 * (c) 2008-2011 Daniel Halperin <dhalperi@cs.washington.edu>
 */
#include "iwl_connector.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <linux/netlink.h>

#define MAX_PAYLOAD 2048
#define SLOW_MSG_CNT 100

int sock_fd = -1; // the socket
FILE *out = NULL;

void check_usage(int argc, char **argv);

FILE *open_file(char *filename, char *spec);

void caught_signal(int sig);

void exit_program(int code);
void exit_program_err(int code, char *func);
void exit_program_with_alarm(int sig);

int main(int argc, char **argv)
{
	/* Local variables */
	struct sockaddr_nl proc_addr, kern_addr; // addrs for recv, send, bind
	struct cn_msg *cmsg;
	char buf[4096];
	int ret;
	unsigned short l, l2;
	int count = 0;

	/* Initialize signal*/
	signal(SIGALRM, exit_program_with_alarm);

	/* Make sure usage is correct */
	check_usage(argc, argv);

	/* Open and check log file */
	out = open_file(argv[1], "w");

	/* Setup the socket */
	sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
	if (sock_fd == -1)
		exit_program_err(-1, "socket");

	/* Initialize the address structs */
	memset(&proc_addr, 0, sizeof(struct sockaddr_nl));
	proc_addr.nl_family = AF_NETLINK;
	proc_addr.nl_pid = getpid(); // this process' PID
	proc_addr.nl_groups = CN_IDX_IWLAGN;
	memset(&kern_addr, 0, sizeof(struct sockaddr_nl));
	kern_addr.nl_family = AF_NETLINK;
	kern_addr.nl_pid = 0; // kernel
	kern_addr.nl_groups = CN_IDX_IWLAGN;

	/* Now bind the socket */
	if (bind(sock_fd, (struct sockaddr *)&proc_addr, sizeof(struct sockaddr_nl)) == -1)
		exit_program_err(-1, "bind");

	/* And subscribe to netlink group */
	{
		int on = proc_addr.nl_groups;
		ret = setsockopt(sock_fd, 270, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on));
		if (ret)
			exit_program_err(-1, "setsockopt");
	}

	/* Set up the "caught_signal" function as this program's sig handler */
	signal(SIGINT, caught_signal);

	/* Poll socket forever waiting for a message */
	while (1)
	{
		/* Receive from socket with infinite timeout */
		ret = recv(sock_fd, buf, sizeof(buf), 0);
		if (ret == -1)
			exit_program_err(-1, "recv");
		/* Pull out the message portion and print some stats */
		cmsg = NLMSG_DATA(buf);
		if (count % SLOW_MSG_CNT == 0)
			printf("received %d bytes: counts: %d id: %d val: %d seq: %d clen: %d\n", cmsg->len, count, cmsg->id.idx, cmsg->id.val, cmsg->seq, cmsg->len);
		/* Log the data to file */
		l = (unsigned short)cmsg->len;
		l2 = htons(l);
		fwrite(&l2, 1, sizeof(unsigned short), out);
		ret = fwrite(cmsg->data, 1, l, out);
		++count;
		if (count == 1)
		{
			/* Set alarm */
			alarm((*argv[2] - '0'));
		}
		if (ret != l)
			exit_program_err(1, "fwrite");
	}

	exit_program(0);
	return 0;
}

void check_usage(int argc, char **argv)
{
	if (argc != 3)
	{
		fprintf(stderr, "Usage: %s <output_file> <time>\n", argv[0]);
		exit_program(1);
	}
}

FILE *open_file(char *filename, char *spec)
{
	FILE *fp = fopen(filename, spec);
	if (!fp)
	{
		perror("fopen");
		exit_program(1);
	}
	return fp;
}

void caught_signal(int sig)
{
	fprintf(stderr, "Caught signal %d\n", sig);
	exit_program(0);
}

void exit_program(int code)
{
	if (out)
	{
		fclose(out);
		out = NULL;
	}
	if (sock_fd != -1)
	{
		close(sock_fd);
		sock_fd = -1;
	}
	exit(code);
}

void exit_program_err(int code, char *func)
{
	perror(func);
	exit_program(code);
}

void exit_program_with_alarm(int sig)
{
	exit_program(0);
}

6. CSI数据处理(Matlab & Python)

Matlab和Python都可以对数据进行处理。个人推荐Matlab,更权威,Python的处理结果貌似和Matlab不一样。

这两种方式都可以将dat格式的原数据转化为csv格式。因为我采用的收发都是3根天线,每根天线都有30个子载波,一秒钟3000个包,所以最后csv的数据维度是3000 * (30 * 3 * 3)即3000 * 270的大小。

6.1 Matlab方式

  1. 下载Matlab处理dat文件的代码包。(压缩包内:01 dat_to_csi_mat.zip)
  2. 运行代码包内的data_to_csi.m脚本。
    data_to_csi.m:
csi_file = read_bf_file('temp.dat');
row = size(csi_file, 1);
temp = [];

for k = 1:row
    csi = get_scaled_csi(csi_file{k});
    csi = csi(:)';

    for m = 1:length(csi)
        csi(m) = abs(csi(m));
    end

    temp = [temp; csi];
end

writematrix(temp, 'output.csv');

6.2 Python方式

直接运行以下Python代码,注意文件路径等参数修改为自己的

import numpy as np
import math


class Bfee:

    def __init__(self):
        pass

    @staticmethod
    def from_file(filename, model_name_encode="shift-JIS"):

        with open(filename, "rb") as f:
            from functools import reduce
            # reduce(函数,list),将list中元素依次累加
            array = bytes(reduce(lambda x, y: x+y, list(f)))

        bfee = Bfee()

#         vmd.current_index = 0
        bfee.file_len = len(array)
        bfee.dicts = []
        bfee.all_csi = []

#         vmd.timestamp_low0 = int.from_bytes(array[3:7], byteorder='little', signed=False)

#         array = array[3:]

        # %% Initialize variables
        # ret = cell(ceil(len/95),1);    # % Holds the return values - 1x1 CSI is 95 bytes big, so this should be upper bound
        cur = 0                       # % Current offset into file
        count = 0                    # % Number of records output
        broken_perm = 0              # % Flag marking whether we've encountered a broken CSI yet
        # % What perm should sum to for 1,2,3 antennas
        triangle = [0, 1, 3]

        while cur < (bfee.file_len - 3):
            # % Read size and code
            # % 将文件数据读取到维度为 sizeA 的数组 A 中,并将文件指针定位到最后读取的值之后。fread 按列顺序填充 A。
            bfee.field_len = int.from_bytes(
                array[cur:cur+2], byteorder='big', signed=False)
            bfee.code = array[cur+2]
            cur = cur+3

            # there is CSI in field if code == 187,If unhandled code skip (seek over) the record and continue
            if bfee.code == 187:
                pass
            else:
                # % skip all other info
                cur = cur + bfee.field_len - 1
                continue

            # get beamforming or phy data
            if bfee.code == 187:
                count = count + 1

                bfee.timestamp_low = int.from_bytes(
                    array[cur:cur+4], byteorder='little', signed=False)
                bfee.bfee_count = int.from_bytes(
                    array[cur+4:cur+6], byteorder='little', signed=False)
                bfee.Nrx = array[cur+8]
                bfee.Ntx = array[cur+9]
                bfee.rssi_a = array[cur+10]
                bfee.rssi_b = array[cur+11]
                bfee.rssi_c = array[cur+12]
                bfee.noise = array[cur+13] - 256
                bfee.agc = array[cur+14]
                bfee.antenna_sel = array[cur+15]
                bfee.len = int.from_bytes(
                    array[cur+16:cur+18], byteorder='little', signed=False)
                bfee.fake_rate_n_flags = int.from_bytes(
                    array[cur+18:cur+20], byteorder='little', signed=False)
                bfee.calc_len = (
                    30 * (bfee.Nrx * bfee.Ntx * 8 * 2 + 3) + 6) / 8
                bfee.csi = np.zeros(
                    shape=(30, bfee.Nrx, bfee.Ntx), dtype=np.dtype(np.complex))
                bfee.perm = [1, 2, 3]
                bfee.perm[0] = ((bfee.antenna_sel) & 0x3)
                bfee.perm[1] = ((bfee.antenna_sel >> 2) & 0x3)
                bfee.perm[2] = ((bfee.antenna_sel >> 4) & 0x3)

                cur = cur + 20

                # get payload
                payload = array[cur:cur+bfee.len]
                cur = cur + bfee.len

                index = 0

                # Check that length matches what it should
                if (bfee.len != bfee.calc_len):
                    print("MIMOToolbox:read_bfee_new:size",
                          "Wrong beamforming matrix size.")

                # Compute CSI from all this crap :
                # import struct
                for i in range(30):
                    index += 3
                    remainder = index % 8
                    for j in range(bfee.Nrx):
                        for k in range(bfee.Ntx):
                            real_bin = bytes([(payload[int(index / 8)] >> remainder) | (
                                payload[int(index/8+1)] << (8-remainder)) & 0b11111111])
                            real = int.from_bytes(
                                real_bin, byteorder='little', signed=True)
                            imag_bin = bytes([(payload[int(index / 8+1)] >> remainder) | (
                                payload[int(index/8+2)] << (8-remainder)) & 0b11111111])
                            imag = int.from_bytes(
                                imag_bin, byteorder='little', signed=True)
                            tmp = np.complex(float(real), float(imag))
                            bfee.csi[i, j, k] = tmp
                            index += 16

                # % matrix does not contain default values
                if sum(bfee.perm) != triangle[bfee.Nrx-1]:
                    print('WARN ONCE: Found CSI (', filename, ') with Nrx=',
                          bfee.Nrx, ' and invalid perm=[', bfee.perm, ']\n')
                else:
                    temp_csi = np.zeros(
                        bfee.csi.shape, dtype=np.dtype(np.complex))
                    # bfee.csi[:,bfee.perm[0:bfee.Nrx],:] = bfee.csi[:,0:bfee.Nrx,:]
                    for r in range(bfee.Nrx):
                        temp_csi[:, bfee.perm[r], :] = bfee.csi[:, r, :]
                    bfee.csi = temp_csi
                # 将类属性导出为dict,并返回
                bfee_dict = {}
                bfee_dict['timestamp_low'] = bfee.timestamp_low
                bfee_dict['bfee_count'] = bfee.bfee_count
                bfee_dict['Nrx'] = bfee.Nrx
                bfee_dict['Ntx'] = bfee.Ntx
                bfee_dict['rssi_a'] = bfee.rssi_a
                bfee_dict['rssi_b'] = bfee.rssi_b
                bfee_dict['rssi_c'] = bfee.rssi_c
                bfee_dict['noise'] = bfee.noise
                bfee_dict['agc'] = bfee.agc
                bfee_dict['antenna_sel'] = bfee.antenna_sel
                bfee_dict['perm'] = bfee.perm
                bfee_dict['len'] = bfee.len
                bfee_dict['fake_rate_n_flags'] = bfee.fake_rate_n_flags
                bfee_dict['calc_len'] = bfee.calc_len
                bfee_dict['csi'] = bfee.csi

                bfee.dicts.append(bfee_dict)
                bfee.all_csi.append(bfee.csi)

        return bfee


def db(X, U):
    R = 1
    if 'power'.startswith(U):
        assert X >= 0
    else:
        X = math.pow(abs(X), 2) / R

    return (10 * math.log10(X) + 300) - 300


def dbinv(x):
    return math.pow(10, x / 10)


def get_total_rss(csi_st):
    # Careful here: rssis could be zero
    rssi_mag = 0
    if csi_st['rssi_a'] != 0:
        rssi_mag = rssi_mag + dbinv(csi_st['rssi_a'])
    if csi_st['rssi_b'] != 0:
        rssi_mag = rssi_mag + dbinv(csi_st['rssi_b'])
    if csi_st['rssi_c'] != 0:
        rssi_mag = rssi_mag + dbinv(csi_st['rssi_c'])
    return db(rssi_mag, 'power') - 44 - csi_st['agc']


def get_scale_csi(csi_st):
    # Pull out csi
    csi = csi_st['csi']
    # print(csi.shape)
    # print(csi)
    # Calculate the scale factor between normalized CSI and RSSI (mW)
    csi_sq = np.multiply(csi, np.conj(csi)).real
    csi_pwr = np.sum(csi_sq, axis=0)
    csi_pwr = csi_pwr.reshape(1, csi_pwr.shape[0], -1)
    rssi_pwr = dbinv(get_total_rss(csi_st))

    scale = rssi_pwr / (csi_pwr / 30)

    if csi_st['noise'] == -127:
        noise_db = -92
    else:
        noise_db = csi_st['noise']
    thermal_noise_pwr = dbinv(noise_db)

    quant_error_pwr = scale * (csi_st['Nrx'] * csi_st['Ntx'])

    total_noise_pwr = thermal_noise_pwr + quant_error_pwr
    ret = csi * np.sqrt(scale / total_noise_pwr)
    if csi_st['Ntx'] == 2:
        ret = ret * math.sqrt(2)
    elif csi_st['Ntx'] == 3:
        ret = ret * math.sqrt(dbinv(4.5))
    return ret


written_data = ''

bfee = Bfee.from_file('temp.dat', model_name_encode="gb2312")
for k in range(len(bfee.all_csi)):
    csi = get_scale_csi(bfee.dicts[k])

    for a in range(30):
        for b in range(3):
            for c in range(3):
                temp = abs(csi[a][b][c])
                written_data += str(temp) + ','
    written_data = written_data[: len(written_data) - 1] + '\n'
written_data = written_data[: len(written_data) - 1]

file = open('output.csv', mode='w')
file.write(written_data)
file.close()