diff --git a/.gitignore b/.gitignore index 5a990ae..51b730b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore Wearable/ +*.csv +*.mat +*.txt # User-specific files *.rsuser diff --git a/Cheby1Filter.cpp b/Cheby1Filter.cpp index 524f8c3..6a71d89 100644 --- a/Cheby1Filter.cpp +++ b/Cheby1Filter.cpp @@ -6,7 +6,7 @@ Cheby1Filter::Cheby1Filter(){} // type: Lowpass, Highpass, bandPass, bandStop -Cheby1Filter::Cheby1Filter(int order, int ripple, double wn1, double wn2, double srate, char type) { +Cheby1Filter::Cheby1Filter(int order, double ripple, double wn1, double wn2, double srate, char type) { order_ = order; ripple_ = ripple; srate_ = srate; diff --git a/Cheby1Filter.h b/Cheby1Filter.h index 63f832d..0bf5dee 100644 --- a/Cheby1Filter.h +++ b/Cheby1Filter.h @@ -6,11 +6,11 @@ #define M_PI 3.1415926 class Cheby1Filter { -public: +public: Eigen::Tensor b_; Eigen::Tensor a_; Cheby1Filter(); - Cheby1Filter(int order, int ripple, double wn1, double wn2, double srate, char type); + Cheby1Filter(int order, double ripple, double wn1, double wn2, double srate, char type); private: int order_; diff --git a/Preprocess.cpp b/Preprocess.cpp index 9627282..9562bb9 100644 --- a/Preprocess.cpp +++ b/Preprocess.cpp @@ -17,9 +17,11 @@ Preprocess::Preprocess(int s_rate, int subbands, int electrodes, int num_samples // Lowpass, Highpass, bandPass, bandStop bsf_ = std::make_unique(4, 2, 47, 53, s_rate_, 's'); bpf_ = std::make_unique(subbands); + std::vector passband = { 6, 14, 22, 30, 38, 46, 54, 62, 70, 78 }; for (int i = 0; i < subbands; i++) { - bpf_[i] = Cheby1Filter(4, 1, 9 * (i + 1), 90, s_rate_, 'p'); + //bpf_[i] = Cheby1Filter(4, 1, 9 * (i + 1), 90, s_rate_, 'p'); + bpf_[i] = Cheby1Filter(6, 0.5, passband[i], 90, s_rate_, 'p'); } } diff --git a/README.md b/README.md index a9a4b35..6ea930e 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,252 @@ ## TRCA-cpp-src - Cheby1Filter类: 带通、带阻滤波器设计 + - Preprocess类: notch滤波、filterBank、detrend、均值计算、标准差计算 + - TRCA类: TRCA算法实现 -- utils: 包含数据函数、调试函数,其中一部分数据函数应该放到别的类里面 -- vstudio默认gb2312编码, vs code默认utf8编码, 大部分含中文注释代码的文件已经转换为utf8编码 -## TRCA-dll -- 具体实现参照[dll.cpp](./dll.cpp), python调用参照[dllvalid.py](./dllvalid.py) +- utils: 包含数据函数、调试函数 + - TODO: 其中一部分数据函数应该放到别的类里面 + +- vstudio默认gb2312编码,vs code默认utf8编码,大部分含中文注释代码的文件已经转换为utf8编码 + +## TRCA.dll +- 具体实现参照[dll.cpp](./dll.cpp),python调用参照[dllValid.py](./dllValid.py)、[onlineValid.py](./onlineValid.py) + +### FilterBank +完成notch滤波、filterBank滤波(最多10组6阶带通,[{6, 14, 22, 30, 38, 46, 54, 62, 70, 78},90])、去直流、标准化操作,滤波器设计为Cheby1 + +- 输入(2指针、7int) + - darray: double指针(行优先的4D数组,[轮数,刺激数,电极数,信号点数]),一般情况下,轮数=1,刺激数=trials数即可 + + - dout: double指针(行优先的4D数组,[轮数*刺激数,filterBank数,电极数,信号点数]) + + - s_rate: int(采样率) + + - subbands: int(filterBank数量) + + - len: int(轮数) + + - stimulus: int(刺激数) + + - electrodes: int(电极数) + + - num_samples: int(信号点数) + + - debug: int,传入1进入调试,将filterBank数据覆盖写入路径下csv文件 + +- 输出 + - dout: 指针拷贝数据 + + - 返回错误码(还没做,下同) + ### TrcaTrain -- 输入 - - darray: double指针(行优先的4D数组, [训练轮数, 刺激数, 电极数, 信号点数]) - - pTemplate: double指针(4D数组, [刺激数, filterBank数, 电极数, 信号点数]) - - pU: double指针(4D数组, [filterBank数量, 刺激数, 电极数, 1]) - - s_rate: int(采样率) - - subbands: int(filterBank数量) - - train_len: int(训练轮数) - - stimulus: int(刺激数) - - electrodes: int(电极数) - - num_samples: int(信号点数) +完整的TRCA训练流程,filterBank+TrcaTrainOnly + +- 输入(3指针、7int) + - darray: double指针(行优先的4D数组,[训练轮数,刺激数,电极数,信号点数]) + + - pTemplate: double指针(4D数组,[刺激数,filterBank数,电极数,信号点数]),一般不考虑该数组的存储主序,因为会直接输入给Test使用,当前输出的是列优先的数据,**下同** + + - pU: double指针(4D数组,[filterBank数量,刺激数,电极数,1]),一般不考虑该数组的存储主序,因为会直接输入给Test使用,当前输出的是列优先的数据,**下同** + + - s_rate: int(采样率) + + - subbands: int(filterBank数量) + + - train_len: int(训练轮数) + + - stimulus: int(刺激数) + + - electrodes: int(电极数) + + - num_samples: int(信号点数) + + - debug: int,传入1时将templates和u覆盖写入路径下csv文件,传入2时将input、filterBank数据、templates和u覆盖写入路径下csv文件 + - 输出 - - 计算得到的template和U通过memcpy的方式copy到pTemplate和pU地址上 - - 返回错误码(还没做) + - pTemplate: 指针拷贝数据 + + - pU: 指针拷贝数据 + + - 返回错误码 + + +### TrcaTrainOnly +只执行Trca训练功能 + +- 输入(3指针、7int) + - darray: double指针(行优先的4D数组,[训练轮数*刺激数,filterBank数,电极数,信号点数]),即filterBank完成后的数据 + + - pTemplate: double指针(4D数组,[刺激数,filterBank数,电极数,信号点数]) + + - pU: double指针(4D数组,[filterBank数量,刺激数,电极数,1]) + + - s_rate: int(采样率) + + - subbands: int(filterBank数量) + + - train_len: int(训练轮数) + + - stimulus: int(刺激数) + + - electrodes: int(电极数) + + - num_samples: int(信号点数) + + - debug: int,传入1时将templates和u覆盖写入路径下csv文件,传入2时将input、filterBank数据、templates和u覆盖写入路径下csv文件 + +- 输出 + - pTemplate: 指针拷贝数据 + + - pU: 指针拷贝数据 + + - 返回错误码 + ### TrcaTest -- 输入 - - darray: double指针(行优先的3D数组, [测试次数, 电极数, 信号点数]) - - pTemplate: train得到的指针 - - pU: train得到的指针 - - pPred: int指针(1D数组, [测试次数]) - - s_rate: 同上 - - subbands: 同上 - - stimulus: 同上 - - electrodes: 同上 - - num_samples: 同上 +完整的TRCA测试流程,filterBank+TrcaTestOnly + +- 输入(5指针、7int) + - darray: double指针(行优先的4D数组,[1,测试次数,电极数,信号点数]) + + - pTemplate: double指针,train得到的指针 + + - pU: double指针,train得到的指针 + + - pcoeff: double指针(1D数组,[测试次数*stimulus]) + + - pPred: int指针(1D数组,[测试次数]) + + - s_rate: int(采样率) + + - subbands: int(filterBank数量) + + - test_len: int(训练轮数) + + - stimulus: int(刺激数) + + - electrodes: int(电极数) + + - num_samples: int(信号点数) + + - debug: int,传入1时进入调试,将templates、u和filterBank数据覆盖写入路径下csv文件 + +- 输出 + - pPred: 指针拷贝数据 + + - pcoeff: 指针拷贝数据 + + - 返回错误码 + +### TrcaTestOnly +只执行Trca测试功能 + +- 输入(5指针、7int) + - darray: double指针(行优先的4D数组,[1*测试次数,filterBank数,电极数,信号点数]) + + - pTemplate: double指针,train得到的指针 + + - pU: double指针,train得到的指针 + + - pcoeff: double指针(1D数组,[测试次数*stimulus]) + + - pPred: int指针(1D数组,[测试次数]) + + - s_rate: int(采样率) + + - subbands: int(filterBank数量) + + - test_len: int(训练轮数) + + - stimulus: int(刺激数) + + - electrodes: int(电极数) + + - num_samples: int(信号点数) + + - debug: int,传入1时进入调试,将templates、u和输入数据覆盖写入路径下csv文件 + +- 输出 + - pPred: 指针拷贝数据 + + - pcoeff: 指针拷贝数据 + + - 返回错误码 + +### TrcaTestCsv +完整的TRCA测试流程,filterBank+TrcaTestOnly,使用csv文件输入template和u + +- 输入(5指针、7int) + - darray: double指针(行优先的4D数组,[1,测试次数,电极数,信号点数]) + + - pTemplate: char指针,存放templates的csv文件路径 + + - pU: char指针,存放u的csv文件路径 + + - pcoeff: double指针(1D数组,[测试次数*stimulus]) + + - pPred: int指针(1D数组,[测试次数]) + + - s_rate: int(采样率) + + - subbands: int(filterBank数量) + + - test_len: int(训练轮数) + + - stimulus: int(刺激数) + + - electrodes: int(电极数) + + - num_samples: int(信号点数) + + - debug: int,传入1时进入调试,将templates、u和filterBank数据覆盖写入路径下csv文件 + - 输出 - - 计算得到的标签通过memcpy方式拷贝到pPred - - 返回错误码(还没做) + - pPred: 指针拷贝数据 + + - pcoeff: 指针拷贝数据 + + - 返回错误码 + +### TrcaTestOnlyCsv +只执行Trca测试功能,使用csv文件输入template和u + +- 输入(5指针、7int) + - darray: double指针(行优先的4D数组,[1,测试次数,电极数,信号点数]) + + - pTemplate: char指针,存放templates的csv文件路径 + + - pU: char指针,存放u的csv文件路径 + + - pcoeff: double指针(1D数组,[测试次数*stimulus]) + + - pPred: int指针(1D数组,[测试次数]) + + - s_rate: int(采样率) + + - subbands: int(filterBank数量) + + - test_len: int(训练轮数) + + - stimulus: int(刺激数) + + - electrodes: int(电极数) + + - num_samples: int(信号点数) + + - debug: int,传入1时进入调试,将templates、u和filterBank数据覆盖写入路径下csv文件 + +- 输出 + - pPred: 指针拷贝数据 + + - pcoeff: 指针拷贝数据 + + - 返回错误码 + ## 测试 -- dllvalid.py: 使用[SSVEP-AnaTool](https://github.com/pikipity/SSVEP-Analysis-Toolbox)测试, 需确认lib版本, 也可使用本repo中提供的lib -- 使用Wearable-SSVEP(wet)数据集测试, 其中使用SSVEPAnalysisToolbox库测试时, 需要确认库get_data方法截取的数据是否正确, 需比照lib代码和数据集说明 \ No newline at end of file +- dllvalid.py: 使用[SSVEP-AnaTool](https://github.com/pikipity/SSVEP-Analysis-Toolbox)测试,需确认toolbox版本,也可使用本repo中提供的toolbox + +- 使用Wearable-SSVEP(wet)数据集测试,其中使用SSVEPAnalysisToolbox库测试时,需要确认库get_data方法截取的数据是否正确,需比照toolbox代码和数据集说明 + +- 测试数据重排请使用可控的循环实现,避免调用transpose等api \ No newline at end of file diff --git a/TRCA.cpp b/TRCA.cpp index 01bca70..b109b89 100644 --- a/TRCA.cpp +++ b/TRCA.cpp @@ -25,7 +25,7 @@ Trca::Trca(int subbands, int stimulus, int electrodes, int num_samples, int trai } else { for (int i = 0; i < subbands_; i++) { - filter_banks_weights(i) = pow(i+1, -1.25) + 0.15; + filter_banks_weights(i) = pow(i+1, -1.25) + 0.25; } } filter_banks_weights_ = filter_banks_weights; @@ -86,9 +86,10 @@ Eigen::Tensor Trca::trcaU(const Eigen::Tensor& trials) con } Eigen::Tensor Trca::predict(const Eigen::Tensor& trials, const Eigen::Tensor& templates, - const Eigen::Tensor& U, const Eigen::Tensor& V) const { + const Eigen::Tensor& U, const Eigen::Tensor& V, std::vector &coeff) const { Eigen::Tensor pred_labels(trials.dimension(0)); Eigen::array, 1> product_dims = { Eigen::IndexPair(1, 0) }; + for (int i = 0; i < trials.dimension(0); i++) { Eigen::Tensor r = tensor1to2(filter_banks_weights_). contract(canoncorrWithUV(trials.chip<0>(i), templates, U, V), product_dims); @@ -97,6 +98,7 @@ Eigen::Tensor Trca::predict(const Eigen::Tensor& trials, cons if (r(j) == max_coeff(0)) { pred_labels(i) = j; } + coeff.push_back(r(j)); } } return pred_labels; diff --git a/TRCA.dll b/TRCA.dll deleted file mode 100644 index 6d2b612..0000000 Binary files a/TRCA.dll and /dev/null differ diff --git a/TRCA.h b/TRCA.h index 4dbfd04..dc7cc51 100644 --- a/TRCA.h +++ b/TRCA.h @@ -5,10 +5,10 @@ class Trca { public: ~Trca(); - Trca(int subbands, int stimulus, int electrodes, int num_samples, int train_len=1, int fb_weights_type=1); + Trca(int subbands, int stimulus, int electrodes, int num_samples, int train_len=1, int fb_weights_type=0); Eigen::Tensor fit(const Eigen::Tensor& trials, const Eigen::Tensor& templates); Eigen::Tensor predict(const Eigen::Tensor& trials, const Eigen::Tensor& templates, - const Eigen::Tensor& U, const Eigen::Tensor& V) const; + const Eigen::Tensor& U, const Eigen::Tensor& V, std::vector& coeff) const; private: int subbands_; diff --git a/TRCA.sln b/TRCA.sln index d3516fb..74b7568 100644 --- a/TRCA.sln +++ b/TRCA.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.7.34024.191 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TRCA", "TRCA.vcxproj", "{95A805F6-EFC1-4F9F-ACD5-C88D3F110DA2}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "..\test\test.vcxproj", "{FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -21,6 +23,14 @@ Global {95A805F6-EFC1-4F9F-ACD5-C88D3F110DA2}.Release|x64.Build.0 = Release|x64 {95A805F6-EFC1-4F9F-ACD5-C88D3F110DA2}.Release|x86.ActiveCfg = Release|Win32 {95A805F6-EFC1-4F9F-ACD5-C88D3F110DA2}.Release|x86.Build.0 = Release|Win32 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Debug|x64.ActiveCfg = Debug|x64 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Debug|x64.Build.0 = Debug|x64 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Debug|x86.ActiveCfg = Debug|Win32 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Debug|x86.Build.0 = Debug|Win32 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Release|x64.ActiveCfg = Release|x64 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Release|x64.Build.0 = Release|x64 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Release|x86.ActiveCfg = Release|Win32 + {FB92ABE4-E904-46F7-9BAB-7B92CA3352A3}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TRCA.vcxproj b/TRCA.vcxproj index da42136..5cb6185 100644 --- a/TRCA.vcxproj +++ b/TRCA.vcxproj @@ -153,6 +153,9 @@ + + + diff --git a/TRCA.vcxproj.filters b/TRCA.vcxproj.filters index 1d20274..af9143b 100644 --- a/TRCA.vcxproj.filters +++ b/TRCA.vcxproj.filters @@ -51,4 +51,9 @@ 头文件 + + + 资源文件 + + \ No newline at end of file diff --git a/dll.cpp b/dll.cpp index 3778285..b1a156b 100644 --- a/dll.cpp +++ b/dll.cpp @@ -2,21 +2,48 @@ #include #include "dll.h" +extern "C" __declspec(dllexport) int FilterBank(double* darray, double* dout, + int s_rate, int subbands, int len, int stimulus, int electrodes, int num_samples, int debug) +{ + std::unique_ptr pe = std::make_unique(s_rate, subbands, electrodes, num_samples); + Eigen::Tensor trials = Eigen::Tensor(len * stimulus, subbands, electrodes, num_samples); + + Eigen::Tensor dtensor = Eigen::TensorMap>( + darray, len, stimulus, electrodes, num_samples); + Eigen::Tensor input = dtensor.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); + + for (int block = 0; block < len; block++) { + for (int i = 0; i < stimulus; i++) { + Eigen::Tensor single_trial = pe->notch(input.chip(block, 0).chip(i, 0)); + trials.chip<0>(block * stimulus + i) = pe->filterBank(single_trial); + } + } + // Convert train_trials to row-major order + Eigen::Tensor trials_rows = trials.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); + memcpy(dout, trials_rows.data(), trials_rows.size() * sizeof(double)); + + if (debug != 0) { + tensor4dToCsv(trials, "./filterBank_dll.csv"); + } + + return 0; +} + extern "C" __declspec(dllexport) int TrcaTrain(double* darray, double* pTemplate, double* pU, - int s_rate, int subbands, int train_len, int stimulus, int electrodes, int num_samples) + int s_rate, int subbands, int train_len, int stimulus, int electrodes, int num_samples, int debug) { std::unique_ptr pe = std::make_unique(s_rate, subbands, electrodes, num_samples); std::unique_ptr te = std::make_unique(subbands, stimulus, electrodes, num_samples, train_len); Eigen::Tensor train_trials = Eigen::Tensor(train_len * stimulus, subbands, electrodes, num_samples); Eigen::Tensor templates = Eigen::Tensor(stimulus, subbands, electrodes, num_samples); - Eigen::Tensor U_trca_ = Eigen::Tensor(subbands, stimulus, electrodes, 1); + Eigen::Tensor U_trca = Eigen::Tensor(subbands, stimulus, electrodes, 1); -//行优先->列优先:转置 -//列优先->行优先:reshape,其中double需要cast到float上面才能reshape, -// reshape之后要赋值给tensor float变量之后才能cast到double,原因是reshape传回参数不能被cast解析 + //行优先->列优先:map之后转置 + //列优先->行优先:map之后reshape,其中double需要cast到float上面才能reshape, + // reshape之后要赋值给tensor float变量之后才能cast到double,原因是reshape传回参数不能被cast解析 Eigen::Tensor dtensor = Eigen::TensorMap>( darray, train_len, stimulus, electrodes, num_samples); - Eigen::Tensor input = dtensor.swap_layout().shuffle(Eigen::array{3,2,1,0}); + Eigen::Tensor input = dtensor.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); //@zikai 4维:(训练次数,目标数,电极通道数,单通道数据) //@zikai train_trials init,优化trials分割 @@ -27,35 +54,172 @@ extern "C" __declspec(dllexport) int TrcaTrain(double* darray, double* pTemplate } } templates = calculateTemplates(train_trials, stimulus, train_len); - U_trca_ = te->fit(train_trials, templates); + U_trca = te->fit(train_trials, templates); + if (debug == 1) { + tensor4dToCsv(templates, "./templates_dll.csv"); + tensor4dToCsv(U_trca, "./u_dll.csv"); + } + else if (debug == 2) { + tensor4dToCsv(input, "./input_dll.csv"); + tensor4dToCsv(train_trials, "./trials_fb_dll.csv"); + tensor4dToCsv(templates, "./templates_dll.csv"); + tensor4dToCsv(U_trca, "./u_dll.csv"); + } memcpy(pTemplate, templates.data(), templates.size() * sizeof(double)); - memcpy(pU, U_trca_.data(), U_trca_.size() * sizeof(double)); + memcpy(pU, U_trca.data(), U_trca.size() * sizeof(double)); + return 0; } -extern "C" __declspec(dllexport) int TrcaTest(double* darray, double* pTemplate, double* pU, int* pPred, - int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples) -{ +extern "C" __declspec(dllexport) int TrcaTrainOnly(double* darray, double* pTemplate, double* pU, + int s_rate, int subbands, int train_len, int stimulus, int electrodes, int num_samples, int debug) +{ + std::unique_ptr te = std::make_unique(subbands, stimulus, electrodes, num_samples, train_len); + Eigen::Tensor templates = Eigen::Tensor(stimulus, subbands, electrodes, num_samples); + Eigen::Tensor U_trca = Eigen::Tensor(subbands, stimulus, electrodes, 1); + + Eigen::Tensor dtensor = Eigen::TensorMap>( + darray, train_len*stimulus, subbands, electrodes, num_samples); + Eigen::Tensor train_trials = dtensor.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); + + templates = calculateTemplates(train_trials, stimulus, train_len); + U_trca = te->fit(train_trials, templates); + + if (debug == 1) { + tensor4dToCsv(templates, "./templates_dll.csv"); + tensor4dToCsv(U_trca, "./u_dll.csv"); + } + else if (debug == 2) { + tensor4dToCsv(train_trials, "./input_dll.csv"); + tensor4dToCsv(templates, "./templates_dll.csv"); + tensor4dToCsv(U_trca, "./u_dll.csv"); + } + memcpy(pTemplate, templates.data(), templates.size() * sizeof(double)); + memcpy(pU, U_trca.data(), U_trca.size() * sizeof(double)); + + return 0; +} + +extern "C" __declspec(dllexport) int TrcaTest(double* darray, double* pTemplate, double* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug) +{ std::unique_ptr pe = std::make_unique(s_rate, subbands, electrodes, num_samples); std::unique_ptr te = std::make_unique(subbands, stimulus, electrodes, num_samples); Eigen::Tensor test_trial = Eigen::Tensor(test_len, subbands, electrodes, num_samples); - Eigen::Tensor dtensor = Eigen::TensorMap>( - darray, test_len, electrodes, num_samples); - Eigen::Tensor input = dtensor.swap_layout().shuffle(Eigen::array{2, 1, 0}); + Eigen::Tensor dtensor = Eigen::TensorMap>( + darray, 1, test_len, electrodes, num_samples); + Eigen::Tensor input = dtensor.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); + Eigen::Tensor templates = Eigen::TensorMap>( - pTemplate, subbands, stimulus, electrodes, num_samples); + pTemplate, stimulus, subbands, electrodes, num_samples); Eigen::Tensor U_trca = Eigen::TensorMap>( pU, subbands, stimulus, electrodes, 1); //@zikai test_trials init for (int i = 0; i < test_len; i++) { - Eigen::Tensor single_trial = pe->notch(input.chip(i, 0)); + Eigen::Tensor single_trial = pe->notch(input.chip(0, 0).chip(i, 0)); test_trial.chip<0>(i) = pe->filterBank(single_trial); } - Eigen::Tensor pred = te->predict(test_trial, templates, U_trca, U_trca); + std::vector coeff; + Eigen::Tensor pred = te->predict(test_trial, templates, U_trca, U_trca, coeff); + + if (debug != 0) { + tensor4dToCsv(templates, "./ptr_templates_dll.csv"); + tensor4dToCsv(U_trca, "./ptr_u_dll.csv"); + tensor4dToCsv(test_trial, "./ptr_filterBank_dll.csv"); + } memcpy(pPred, pred.data(), pred.size() * sizeof(int)); + memcpy(pcoeff, coeff.data(), coeff.size() * sizeof(double)); + return 0; } + +extern "C" __declspec(dllexport) int TrcaTestOnly(double* darray, double* pTemplate, double* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug) +{ + std::unique_ptr te = std::make_unique(subbands, stimulus, electrodes, num_samples); + + Eigen::Tensor dtensor = Eigen::TensorMap>( + darray, test_len, subbands, electrodes, num_samples); + Eigen::Tensor test_trial = dtensor.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); + + Eigen::Tensor templates = Eigen::TensorMap>( + pTemplate, stimulus, subbands, electrodes, num_samples); + Eigen::Tensor U_trca = Eigen::TensorMap>( + pU, subbands, stimulus, electrodes, 1); + + std::vector coeff; + Eigen::Tensor pred = te->predict(test_trial, templates, U_trca, U_trca, coeff); + if (debug != 0) { + tensor4dToCsv(templates, "./ptr_templates_dll.csv"); + tensor4dToCsv(U_trca, "./ptr_u_dll.csv"); + tensor4dToCsv(test_trial, "./ptr_filterBank_dll.csv"); + } + memcpy(pPred, pred.data(), pred.size() * sizeof(int)); + memcpy(pcoeff, coeff.data(), coeff.size() * sizeof(double)); + + return 0; +} + +extern "C" __declspec(dllexport) int TrcaTestCsv(double* darray, char* pTemplate, char* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug) +{ + std::unique_ptr pe = std::make_unique(s_rate, subbands, electrodes, num_samples); + std::unique_ptr te = std::make_unique(subbands, stimulus, electrodes, num_samples); + Eigen::Tensor test_trial = Eigen::Tensor(test_len, subbands, electrodes, num_samples); + + Eigen::Tensor dtensor = Eigen::TensorMap>( + darray, 1, test_len, electrodes, num_samples); + Eigen::Tensor input = dtensor.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); + + Eigen::Tensor templates = tensor4dFromCsv(pTemplate, stimulus, subbands, electrodes, num_samples); + Eigen::Tensor U_trca = tensor4dFromCsv(pU, subbands, stimulus, electrodes, 1); + + //@zikai test_trials init + for (int i = 0; i < test_len; i++) { + Eigen::Tensor single_trial = pe->notch(input.chip(0, 0).chip(i, 0)); + test_trial.chip<0>(i) = pe->filterBank(single_trial); + } + + std::vector coeff; + Eigen::Tensor pred = te->predict(test_trial, templates, U_trca, U_trca, coeff); + + if (debug != 0) { + tensor4dToCsv(templates, "./csv_templates_dll.csv"); + tensor4dToCsv(U_trca, "./csv_u_dll.csv"); + tensor4dToCsv(test_trial, "./csv_filterBank_dll.csv"); + } + memcpy(pPred, pred.data(), pred.size() * sizeof(int)); + memcpy(pcoeff, coeff.data(), coeff.size() * sizeof(double)); + + return 0; +} + +extern "C" __declspec(dllexport) int TrcaTestOnlyCsv(double* darray, char* pTemplate, char* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug) +{ + std::unique_ptr te = std::make_unique(subbands, stimulus, electrodes, num_samples); + + Eigen::Tensor dtensor = Eigen::TensorMap>( + darray, test_len, subbands, electrodes, num_samples); + Eigen::Tensor test_trial = dtensor.swap_layout().shuffle(Eigen::array{3, 2, 1, 0}); + + Eigen::Tensor templates = tensor4dFromCsv(pTemplate, stimulus, subbands, electrodes, num_samples); + Eigen::Tensor U_trca = tensor4dFromCsv(pU, subbands, stimulus, electrodes, 1); + + std::vector coeff; + Eigen::Tensor pred = te->predict(test_trial, templates, U_trca, U_trca, coeff); + + if (debug != 0) { + tensor4dToCsv(templates, "./csv_templates_dll.csv"); + tensor4dToCsv(U_trca, "./csv_u_dll.csv"); + tensor4dToCsv(test_trial, "./csv_filterBank_dll.csv"); + } + memcpy(pPred, pred.data(), pred.size() * sizeof(int)); + memcpy(pcoeff, coeff.data(), coeff.size() * sizeof(double)); + + return 0; +} \ No newline at end of file diff --git a/dll.h b/dll.h index 1bc2dd1..0925a36 100644 --- a/dll.h +++ b/dll.h @@ -3,9 +3,21 @@ #include "Preprocess.h" #include "Trca.h" +extern "C" __declspec(dllexport) int FilterBank(double* darray, double* dout, + int s_rate, int subbands, int len, int stimulus, int electrodes, int num_samples, int debug); + extern "C" __declspec(dllexport) int TrcaTrain(double* darray, double* pTemplate, double* pU, - int s_rate, int subbands, int train_len, int stimulus, int electrodes, int num_samples); -extern "C" __declspec(dllexport) int TrcaTest(double* darray, double* pTemplate, double* pU, int* pPred, - int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples); + int s_rate, int subbands, int train_len, int stimulus, int electrodes, int num_samples, int debug); +extern "C" __declspec(dllexport) int TrcaTrainOnly(double* darray, double* pTemplate, double* pU, + int s_rate, int subbands, int train_len, int stimulus, int electrodes, int num_samples, int debug); + +extern "C" __declspec(dllexport) int TrcaTest(double* darray, double* pTemplate, double* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug); +extern "C" __declspec(dllexport) int TrcaTestOnly(double* darray, double* pTemplate, double* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug); +extern "C" __declspec(dllexport) int TrcaTestCsv(double* darray, char* pTemplate, char* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug); +extern "C" __declspec(dllexport) int TrcaTestOnlyCsv(double* darray, char* pTemplate, char* pU, double* pcoeff, + int* pPred, int s_rate, int subbands, int test_len, int stimulus, int electrodes, int num_samples, int debug); #endif // DLL_H \ No newline at end of file diff --git a/dllvalid.py b/dllvalid.py index 3154e0e..dec8831 100644 --- a/dllvalid.py +++ b/dllvalid.py @@ -56,13 +56,13 @@ def original(): trials=all_trials, channels=ch_used, sig_len=tw) - a = np.array(X_train) + X_train = np.array(X_train) recog_model.fit(X=X_train, Y=Y_train, ref_sig=ref_sig, freqs=freqs) a = np.array(recog_model.model['template_sig']) b = np.array(recog_model.model['U']) - - write_4d_array_to_csv(a, 'template_ori.csv') - write_4d_array_to_csv(b, 'u_ori.csv') + # write_4d_array_to_csv(X_train, 'train_ori.csv') + # write_4d_array_to_csv(a, 'template_ori.csv') + # write_4d_array_to_csv(b, 'u_ori.csv') # Get testing data and test the recognition model X_test, Y_test = dataset.get_data(sub_idx=sub_idx, @@ -71,7 +71,7 @@ def original(): channels=ch_used, sig_len=tw) X_test = np.array(X_test) - write_4d_array_to_csv(X_test, 'test_ori.csv') + # write_4d_array_to_csv(X_test, 'test_ori.csv') pred_label = recog_model.predict(X_test) acc = cal_acc(Y_true=Y_test, Y_pred=pred_label[0]) @@ -103,23 +103,30 @@ def dll(): # Get training data and train the recognition model ref_sig = dataset.get_ref_sig(tw, harmonic_num) freqs = dataset.stim_info['freqs'] - + dll = ctypes.cdll.LoadLibrary('./x64/Release/TRCA.dll') ########################################### TRAIN ############################################### + DEBUG = 0 X_train, Y_train = dataset.get_data(sub_idx=sub_idx, blocks=train_block_list, trials=all_trials, channels=ch_used, sig_len=tw) - - arr = np.array(X_train) - X_train = arr.reshape((9, 12, 8, 500)) - dll = ctypes.cdll.LoadLibrary('./TRCA.dll') - pX_train = X_train.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + + X_train = np.array(X_train).reshape((9, 12, 8, 500)) template = np.empty((12, 5, 8, 500), dtype=np.double) U = np.empty((5, 12, 8, 1), dtype=np.double) + X_train_fb = np.empty((9*12, 5, 8, 500)) + + pX_train = X_train.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) dTemplate = template.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) # double pointer Template dU = U.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) - dll.TrcaTrain(pX_train, dTemplate, dU, 250, 5, 9, 12, 8, 500) + pX_train_fb = X_train_fb.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + + if RUN_TEST_SPLIT: + dll.FilterBank(pX_train, pX_train_fb, 250, 5, 9, 12, 8, 500, DEBUG) + dll.TrcaTrainOnly(pX_train_fb, dTemplate, dU, 250, 5, 9, 12, 8, 500, DEBUG) + else: + dll.TrcaTrain(pX_train, dTemplate, dU, 250, 5, 9, 12, 8, 500, DEBUG) ########################################### TEST ############################################### X_test, Y_test = dataset.get_data(sub_idx=sub_idx, blocks=test_block_list, @@ -127,15 +134,24 @@ def dll(): channels=ch_used, sig_len=tw) arr = np.array(X_test) - arr = arr.reshape((1, 12, 8, 500)).squeeze() + arr = arr.reshape((1, 12, 8, 500)) ans = [] for i in range(0, 12): - X_test = arr[i, :, :] + X_test = arr[:, i, :, :] Pred = np.empty((1), dtype=int) + X_test_fb = np.empty((1, 5, 8, 500)) + coeff = np.empty((12), dtype=np.double) pX_test = X_test.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) dPred = Pred.ctypes.data_as(ctypes.POINTER(ctypes.c_int)) - dll.TrcaTest(pX_test, dTemplate, dU, dPred, 250, 5, 1, 12, 8, 500) + pX_test_fb = X_test_fb.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + dcoeff = coeff.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + + if RUN_TEST_SPLIT: + dll.FilterBank(pX_test, pX_test_fb, 250, 5, 1, 1, 8, 500, DEBUG) + dll.TrcaTestOnly(pX_test_fb, dTemplate, dU, dcoeff, dPred, 250, 5, 1, 12, 8, 500) + else: + dll.TrcaTest(pX_test, dTemplate, dU, dcoeff, dPred, 250, 5, 1, 12, 8, 500, DEBUG) Pred = np.ctypeslib.as_array(ctypes.cast(dPred, ctypes.POINTER(ctypes.c_int)), Pred.shape) ans.append(Pred[0]) acc = cal_acc(Y_true=Y_test, Y_pred=ans) @@ -144,6 +160,7 @@ def dll(): RUN_TEST = 1 +RUN_TEST_SPLIT = 0 RUN_ORI = 0 RUN_BOTH = 0 diff --git a/main.cpp b/main.cpp index f257def..df10bbb 100644 --- a/main.cpp +++ b/main.cpp @@ -1,73 +1,27 @@ -#include "Preprocess.h" -#include "Trca.h" #include -#include -#include - -/*void trcaTest(int subject, std::string path);*/ +#include +#include int main() { - //@zikai 23.12.2 内存释放问题 - /*getchar(); - for (int subject = 20; subject < 30; subject++) { - std::cout << "S0" << subject << std::endl; - std::string path="./data/S0"+std::to_string(subject)+".csv"; - trcaTest(subject, path); - }*/ - return 0; -} -/* -void trcaTest(int subject, std::string path) { - SSVEP* data = new SSVEP(); - PreprocessEngine* pe; - TrcaEngine* te; - data->loadCsv(path); - pe = new PreprocessEngine(data); - te = new TrcaEngine(data); - - //@zikai 4维:(训练次数,目标数,电极通道数,单通道数据) - auto start = std::chrono::high_resolution_clock::now(); - for (int block = 0; block < data->train_len_; block++) { - for (int stimulus = 0; stimulus < data->stimulus_; stimulus++) { - Eigen::Tensor single_trial = data->getSingleTrial(block, stimulus); - single_trial = pe->notch(single_trial); - data->train_trials_.chip<0>(block * data->stimulus_ + stimulus) = pe->filterBank(single_trial); - } - } - auto end = std::chrono::high_resolution_clock::now(); - std::cout << "Train preprocess elapsed time: " << std::chrono::duration(end - start).count() << " ms\n"; - - start = std::chrono::high_resolution_clock::now(); - data->calculateTemplates(); - te->fit(); - end = std::chrono::high_resolution_clock::now(); - std::cout << "Fit elapsed time: " << std::chrono::duration(end - start).count() << " ms\n"; - - start = std::chrono::high_resolution_clock::now(); - for (int block = data->train_len_; block < data->blocks_; block++) { - for (int stimulus = 0; stimulus < data->stimulus_; stimulus++) { - Eigen::Tensor single_trial = data->getSingleTrial(block, stimulus); - single_trial = pe->notch(single_trial); - data->test_trials_.chip<0>((block-data->train_len_) * data->stimulus_ + stimulus) = pe->filterBank(single_trial); + // col-major 2x3 tensor + Eigen::Tensor col_major_tensor(2, 3); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + col_major_tensor(i, j) = i * 3 + j; } - } - end = std::chrono::high_resolution_clock::now(); - std::cout << "Test preprocess elapsed time: " << std::chrono::duration(end - start).count() << " ms\n"; - - start = std::chrono::high_resolution_clock::now(); - Eigen::Tensor pre_labels = te->predict(); - end = std::chrono::high_resolution_clock::now(); - std::cout << "Predict elapsed time: " << std::chrono::duration(end - start).count() << " ms\n"; + } + std::cout << "Col-major tensor:\n" << col_major_tensor << "\n"; - double acc = 0, itr = 0; - for (int i = 0; i < pre_labels.dimension(0); i++) { - if (pre_labels(i) == data->test_labels_(i)) { - acc = acc + double(1) / pre_labels.dimension(0); - } + double* data = new double[6]; + memcpy(data, col_major_tensor.data(), col_major_tensor.size() * sizeof(double)); + for (int i = 0; i < 6; i++) { + std::cout << data[i] << ", "; } - std::cout << "acc: " << acc*100 << "%\n"; - - //return 0; -}*/ + std::cout << std::endl; + Eigen::TensorMap> col_major_tensor2(data, 2, 3); + std::cout << "Col-major tensor2:\n" << col_major_tensor << "\n"; + delete[] data; + return 0; +} \ No newline at end of file diff --git a/onlineValid.py b/onlineValid.py new file mode 100644 index 0000000..caba07e --- /dev/null +++ b/onlineValid.py @@ -0,0 +1,119 @@ +import scipy.io +import numpy as np +import ctypes + +file = 'S6_benchmark.mat' +mat_data = scipy.io.loadmat(file) +####################### Benchmark ########################## +# trials = np.transpose(numpy_data, (3, 2, 0, 1)) # 不能用这个 +if file == 'S6_benchmark.mat': + numpy_data = np.array(mat_data['data']) + # 64, 1500, 40, 6 + trials = np.empty((6, 40, 64, 500)) + for i in range(0, numpy_data.shape[3]): + for j in range(0, numpy_data.shape[2]): + for k in range(0, numpy_data.shape[0]): + trials[i, j, k, :] = numpy_data[k, 500:1000, j, i] + +####################### 自采 ####################### +if file == "s2_online_12_new_avg95.mat": + numpy_data = np.array(mat_data['data']) + # 8, 250, 8, 10 + trials = np.empty((10, 8, 8, 250)) + for i in range(0, numpy_data.shape[3]): + for j in range(0, numpy_data.shape[2]): + for k in range(0, numpy_data.shape[0]): + trials[i, j, k, :] = numpy_data[k, :, j, i] + +####################### 自采2 ####################### +if file == "unity_trca_debug.mat": + numpy_data = np.array(mat_data['data']) + # 4, 5, 8, 500 + trials = np.empty((5, 4, 8, 500)) + for i in range(0, numpy_data.shape[1]): + for j in range(0, numpy_data.shape[0]): + for k in range(0, numpy_data.shape[2]): + trials[i, j, k, :] = numpy_data[j, i, k, :] + +stimulus = trials.shape[1] +electrodes = trials.shape[2] +num_samples = trials.shape[3] +subbands = 5 +s_rate = 250 +train_len = trials.shape[0] - 1 + +train = trials[0:train_len,:,:,:] +test = trials[train_len,:,:,:].reshape((1, -1, electrodes, num_samples)) + +dll = ctypes.cdll.LoadLibrary('./x64/Release/TRCA.dll') +template = np.empty((stimulus, subbands, electrodes, num_samples), dtype=np.double) +u = np.empty((subbands, stimulus, electrodes, 1), dtype=np.double) +train_fb = np.empty((9*stimulus, subbands, electrodes, num_samples)) + +ptrain = train.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) +ptemplate = template.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) +pu = u.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) +ptrain_fb = train_fb.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + +########################################### TRAIN ############################################### +SPLIT_API = 0 +DEBUG = 0 +FROM_CSV = 0 + +if SPLIT_API: + print('train split') + dll.FilterBank(ptrain, ptrain_fb, + s_rate, subbands, train_len, + stimulus, electrodes, num_samples, DEBUG) + dll.TrcaTrainOnly(ptrain_fb, ptemplate, pu, + s_rate, subbands, train_len, stimulus, + electrodes, num_samples, FROM_CSV + DEBUG) +else: + print('train combined') + dll.TrcaTrain(ptrain, ptemplate, pu, + s_rate, subbands, train_len, stimulus, + electrodes, num_samples, FROM_CSV + DEBUG) + +########################################### TEST ############################################### +ans = [] +ans_coeff = [] +for i in range(0, test.shape[1]): + single_test = test[:, i, :, :] + pred = np.empty((1), dtype=int) + coeff = np.empty((stimulus), dtype=np.double) + test_fb = np.empty((1, subbands, electrodes, num_samples)) + + ptest = single_test.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + ppred = pred.ctypes.data_as(ctypes.POINTER(ctypes.c_int)) + pcoeff = coeff.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + ptest_fb = test_fb.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) + + if FROM_CSV: + ptemplate = ctypes.c_char_p(b"./templates_dll.csv") + pu = ctypes.c_char_p(b"./u_dll.csv") + + if SPLIT_API: + dll.FilterBank(ptest, ptest_fb, + s_rate, subbands, 1, 1, + electrodes, num_samples, DEBUG) + if FROM_CSV: + dll.TrcaTestOnlyCsv(ptest_fb, ptemplate, pu, pcoeff, ppred, + s_rate, subbands, 1, stimulus, + electrodes, num_samples, DEBUG) + else: + dll.TrcaTestOnly(ptest_fb, ptemplate, pu, pcoeff, ppred, + s_rate, subbands, 1, stimulus, + electrodes, num_samples, DEBUG) + elif FROM_CSV: + dll.TrcaTestCsv(ptest, ptemplate, pu, pcoeff, ppred, + s_rate, subbands, 1, stimulus, + electrodes, num_samples, DEBUG) + else: + dll.TrcaTest(ptest, ptemplate, pu, pcoeff, ppred, + s_rate, subbands, 1, stimulus, + electrodes, num_samples, DEBUG) + pred = np.ctypeslib.as_array(ctypes.cast(ppred, ctypes.POINTER(ctypes.c_int)), pred.shape) + coeff = np.ctypeslib.as_array(ctypes.cast(pcoeff, ctypes.POINTER(ctypes.c_double)), coeff.shape) + ans.append(pred[0]) + ans_coeff.append(coeff) +print(ans) diff --git a/response.m b/response.m new file mode 100644 index 0000000..c50b5c0 --- /dev/null +++ b/response.m @@ -0,0 +1,39 @@ +% 读取 CSV 文件 +data = csvread('filter_a_b_dll.csv'); + +% 获取滤波器系数的行数 +[num_rows, ~] = size(data); + +% 采样频率 +fs = 250; + +% 循环读取每组滤波器系数并绘制响应曲线 +for i = 1:2:num_rows-1 + % 获取滤波器系数 + A = data(i, :); + B = data(i+1, :); + + % 计算频率响应 + [H, w] = freqz(B, A); + + % 计算幅频响应和相频响应 + Hf = abs(H); % 取幅度值实部 + Hx = angle(H); % 取相位值对应相位角 + + % 绘制幅频响应曲线 + figure; + subplot(2, 1, 1); + plot(w * fs / (2 * pi), 20 * log10(Hf)); % 幅值变换为分贝单位 + title(['滤波器组 ' num2str((i+1)/2) ' 幅频特性曲线']); + xlabel('频率 (Hz)'); + ylabel('幅值 (dB)'); + grid on; + + % 绘制相频响应曲线 + subplot(2, 1, 2); + plot(w * fs / (2 * pi), Hx); + title(['滤波器组 ' num2str((i+1)/2) ' 相频特性曲线']); + xlabel('频率 (Hz)'); + ylabel('相位 (弧度)'); + grid on; +end \ No newline at end of file diff --git a/utils.cpp b/utils.cpp index a19a1ff..d6f0df7 100644 --- a/utils.cpp +++ b/utils.cpp @@ -19,6 +19,33 @@ Eigen::Tensor calculateTemplates(Eigen::Tensor& train_tria return templates; } +Eigen::Tensor tensor4dFromCsv(const char* path, int dim0, int dim1, int dim2, int dim3) { + double* darray = new double[dim0 * dim1 * dim2 * dim3]; + std::ifstream file(path); + std::string line; + int i = 0, j = 0, k = 0, l = 0, index = 0; + + while (std::getline(file, line)) { + std::stringstream ss(line); + std::string value; + while (std::getline(ss, value, ',')) { + darray[index++] = std::stod(value); + if (l++ == dim3) { + l = 0; + if (k++ == dim2) { + k = 0; + if (j++ == dim1) { + j = 0; + i++; + } + } + } + } + } + Eigen::Tensor tensor = Eigen::TensorMap>(darray, dim3, dim2, dim1, dim0); + return tensor.shuffle(Eigen::array{3, 2, 1, 0 }); +} + Eigen::Tensor tensor1to2(const Eigen::Tensor& tensor) { Eigen::Tensor tensor1(1, tensor.dimension(0)); tensor1.chip<0>(0) = tensor; @@ -177,11 +204,16 @@ void tensor4dToCsv(const Eigen::Tensor& tensor, const char* path) { void WriteToFile(double data) { std::ofstream file("./debug.txt", std::ios::app); if (file.is_open()) { - file << data; - file << "\n"; + file << data << ','; file.close(); } } - +void WriteToFile(char data) { + std::ofstream file("./debug.txt", std::ios::app); + if (file.is_open()) { + file << data; + file.close(); + } +} diff --git a/utils.h b/utils.h index 9ee9a8e..6963fbe 100644 --- a/utils.h +++ b/utils.h @@ -6,6 +6,7 @@ // DATA UTILS Eigen::Tensor calculateTemplates(Eigen::Tensor& tensor, int stimulus_, int train_len_); +Eigen::Tensor tensor4dFromCsv(const char* path, int dim0, int dim1, int dim2, int dim3); Eigen::Tensor tensor1to2(const Eigen::Tensor& tensor1); Eigen::Tensor transpose(const Eigen::Tensor& tensor); Eigen::Tensor rowCompanion(const Eigen::Tensor& input); @@ -21,6 +22,7 @@ void tensor2dToCsv(const Eigen::Tensor& tensor, const char* path, int void tensor3dToCsv(const Eigen::Tensor& tensor, const char* path, int flag = 0); void tensor4dToCsv(const Eigen::Tensor& tensor, const char* path); void WriteToFile(double data); +void WriteToFile(char data); template void TensorTodArray(Eigen::Tensor tensor, double* array) {