我使用名为KFR的DSP库来编写一些执行各种操作的相当简单的命令行程序。不幸的是,这个库需要在VS中使用LLVM平台工具集(或者不使用VS),因为它与标准MSVC不兼容。这有点打破了智能感知,因此调试有点棘手。
无论如何,我目前遇到了这个问题,我的构建失败并返回链接错误,说我有多个定义和定义在别处的符号。 apparently I define this somewhere?
我担心这可能与命名空间冲突有关,但现在我确定它不可能,而且我真的不知道定义冲突在哪里。我查看了所有依赖项,无法找到任何看起来像重新定义此错误返回的内容。
如果有人能帮我解决问题,我真的很感激。
代码如下。请原谅这个烂摊子,我没有长时间处理它并且远未完成(我也只使用了几个月的c ++)。
在预编译的标题中:
#pragma once
#define _USE_MATH_DEFINES
#include "targetver.h"
#include <getopt.h>
#include <stdio.h>
#include <tchar.h>
#include <all.hpp> //kfr header
#include <math.h>
#include <complex>
主要项目:
#include "stdafx.h"
/*forward declarations*/
void usage(void);
int parse_args(int, char**);
double damping();
int n_factorial(int);
double ERB(double);
std::vector<std::complex<double>> expand_poly(std::vector<std::complex<double>>);
std::vector<std::complex<double>> formSOS(std::vector<std::complex<double>>, std::vector<std::complex<double>>);
std::vector<std::complex<double>> sosfun(int, int, std::vector<std::complex<double>>, std::complex<double>, int);
std::vector<std::complex<double>> zp2tf(std::vector<std::complex<double>>, std::vector<std::complex<double>>, std::vector<std::complex<double>>);
/*global variables*/
double fc = NULL;
unsigned long fs = NULL;
int order = NULL;
int type = NULL;
char* types[] = { "classic", "allpole", "onediff", "twodiff" };
const std::complex<double> i(0.0, 1.0);
/* parse input arguments*/
int parse_args(int argc, char **argv)
{
int c, i;
char* p;
int tmp;
struct option longopts[] =
{
{ "SamplingRate", required_argument, NULL, 'fs' }, // makes sense to put fs first because it establishes a reasonable range for fc
{ "frequency", required_argument, NULL, 'fc' },
{ "Order", required_argument, NULL, 'n' },
{ "type", required_argument, NULL, 't' }
};
opterr = 0;
optopt = '!';
while ((c = getopt_long(argc, argv, "fs:fc:n:t", longopts, &i)) != -1)
{
switch (c)
{
case 'fs':
if (optarg == NULL)
throw std::invalid_argument("After -fs, the filter frequency should be provided.");
atoi(optarg) <= 0 ?
throw std::invalid_argument("fs cannot be negative") :
fs = atoi(optarg);
break;
case 'fc':
if (optarg == NULL)
throw std::invalid_argument("After -fc, the sampling rate should be provided.");
(atof(optarg) <= 0 || atof(optarg) > fs / 2) ?
throw std::invalid_argument("the filter centre frequency may not be negative or more than half the sampling rate.") :
fc = atof(optarg);
break;
case 'n':
if (optarg == NULL)
throw std::invalid_argument("After -n, the filter order should be provided");
atoi(optarg) <= 0 || atoi(optarg) % 2 != 0 ?
throw std::invalid_argument("Order cannot must be a positive number that is divisible by two.") :
order = atoi(optarg);
break;
case 't':
if (optarg == NULL)
throw std::invalid_argument("After -t, the filter type should be provided");
for (int ii = 0; ii < 4; ++ii)
{
if (!strcmp(optarg, types[ii])) // check if type optarg matches any of the given types
{
type = ii;
break;
}
}
if (type == NULL) // if still null, optarg is not a type, throw error
throw std::invalid_argument("Unknown type argument given, see usage.");
break;
default:
throw std::invalid_argument("The command line contains unknown arguments.");
}
}
return 1;
}
int main(int argc, char** argv)
{
/* arguments - fc, fs, order, type*/
if (!parse_args(argc, argv))
throw std::invalid_argument("Unknown arguments provided, see usage."); // parse_args should throw an error before this, but whatever
if (order == NULL)
{
std::cout << "No order argument (-n) was provided - the default value will be used.";
order = 4;
}
if (type == NULL)
{
std::cout << "No type argument (-t) was provided - the default value will be used.";
type = 0;
}
/* Initialise type invariants */
double b = damping(); // determines filter bandwidth
double t_theta = 2 * M_PI*fc / fs; // theoretical pole angle
switch(type)
{
case 0: // implement classic gammatone
{
std::complex<double> c_theta = log(exp(-b * exp(t_theta * i))) * i; // corrected pole angle
std::complex<double> pole = exp(-b - i*c_theta);
double zero = pole.real();
std::vector<std::complex<double>> poles = { pole, conj(pole) };
std::complex<double> a0 = pow(abs(
((cos(t_theta) + i*sin(t_theta)) - exp(-b)*cos(c_theta)) /
((cos(t_theta) + i*sin(t_theta) - exp(-b)*cos(c_theta) + exp(-b)*i*sin(c_theta)) *
(cos(t_theta) + i*sin(t_theta) - exp(-b) * cos(c_theta) - exp(-b) * i * sin(c_theta)))), -1); // gain for unity at fc
}
case 1: // implement allpole gammatone
{
std::complex<double> c_theta = acos(2 * exp(b)*cos(t_theta) / (exp(2 * b) + 1)); // corrected pole angle
std::vector<std::complex<double>> poles = { exp(-b - i*c_theta), conj(exp(-b - i*c_theta)) };
std::complex<double> a0 = abs(
1. + (2. * (-exp(-b)*cos(c_theta)))* cos(t_theta)
- i * (2. * (-exp(-b)*cos(c_theta))) * sin(t_theta)
+ exp(-2 * b) * cos(2 * t_theta)
- i * exp(-2 * b) * sin(2 * t_theta));
}
case 2: // implement onediff gammatone
{
std::complex<double> c_theta = acos(2 * exp(b)*cos(t_theta) / (exp(2 * b) + 1)); // corrected pole angle for allpole stages
std::complex<double> d_theta = acos(exp(-b) / 2 + exp(i * t_theta) / (double)2 + exp(i * t_theta) / (double)2 + exp(b) / 2 - (double)1);
// corrected pole angle for one-zero stages
std::vector<std::complex<double>> a_poles = { exp(-b - i * c_theta), conj(exp(-b - i * c_theta)) };
std::vector<std::complex<double>> d_poles = { exp(-b - i * d_theta), conj(exp(-b - i * d_theta)) };
std::complex<double> d_zero = { 1.0, 0.0 };
std::complex<double> a0_a = abs(
1. + (2. * (-exp(-b)*cos(c_theta)))* cos(t_theta)
- i * (2. * (-exp(-b)*cos(c_theta))) * sin(t_theta)
+ exp(-2 * b) * cos(2 * t_theta)
- i * exp(-2 * b) * sin(2 * t_theta));
std::complex<double> a0_d = abs(
(1. + (2. * (-exp(-b) * cos(d_theta))) * cos(t_theta)
- i * (2. * (-exp(-b) * cos(d_theta))) * sin(t_theta)
+ exp(-2 * b) * cos(2 * t_theta)
- i* exp(-2 * b) * sin(2 * t_theta))
/ (1 + -1 * cos(t_theta) - i * (-1 * sin(t_theta))));
}
case 3: // implement twodiff gammatones
{
std::complex<double> c_theta = acos(2 * exp(b)*cos(t_theta) / (exp(2 * b) + 1)); // corrected pole angle for allpole stages
std::complex<double> d_theta = acos(exp(-b) / 2 + exp(i * t_theta) / (double)2 + exp(i * t_theta) / (double)2 + exp(b) / 2 - (double)1);
// corrected pole angle for one-zero stages
/*std::complex<double> a_pole = exp(-b - i * c_theta);
std::complex<double> d_pole = exp(-b - i * d_theta);*/
std::vector<std::complex<double>> a_poles = { exp(-b - i * c_theta), conj(exp(-b - i * c_theta))};
std::vector<std::complex<double>> d_poles = { exp(-b - i * d_theta), conj(exp(-b - i * d_theta))};
std::complex<double> d_zero = { 1.0, 0.0 };
std::complex<double> a0_a = abs(
1. + (2. * (-exp(-b)*cos(c_theta)))* cos(t_theta)
- i * (2. * (-exp(-b)*cos(c_theta))) * sin(t_theta)
+ exp(-2 * b) * cos(2 * t_theta)
- i * exp(-2 * b) * sin(2 * t_theta));
std::complex<double> a0_d = abs(
(1. + (2. * (-exp(-b) * cos(d_theta))) * cos(t_theta)
- i * (2. * (-exp(-b) * cos(d_theta))) * sin(t_theta)
+ exp(-2 * b) * cos(2 * t_theta)
- i* exp(-2 * b) * sin(2 * t_theta))
/ (1 + -1 * cos(t_theta) - i * (-1 * sin(t_theta))));
}
}
return 0;
}
double damping()
{
double factor = pow(n_factorial(order - 1), 2) / (M_PI*n_factorial(2 * order - 2) * pow(2, -(2 * order - 2)));
return 2 * M_PI * factor * ERB(fc) / fs;
}
int n_factorial(int n)
{
return (n == 1 || n == 0) ? 1 : n_factorial(n - 1)*n;
}
double ERB(double f)
{
return 24.7 + f / 9.265;
}
std::vector<std::complex<double>> expand_poly(std::vector<std::complex<double>> roots)
{
std::vector<std::complex<double>> result{1};
for (int ii = 0; ii < roots.size(); ++ii)
{
std::vector <std::complex<double>> tmp{ result.begin(), result.end() };
for (auto &item : tmp)
item *= (-roots[ii]);
result.push_back(0);
for( int jj = 1; jj < result.size(); ++jj)
{
result[jj] += tmp[jj - 1];
}
}
return result;
}
/* below is pretty much a copy of zp2sos from matlab but with all the impossible cases removed */
std::vector<std::complex<double>> formSOS(std::vector<std::complex<double>> poles, std::vector<std::complex<double>> zeroes)
{
int lz = zeroes.size();
int lp = poles.size();
std::vector<std::complex<double>> sos;
if(!lz) // no zeroes (all-pole)
{
sos; // sosfun
return sos;
}
if(!(lz % 2)) // even number of zeroes
{
sos; // sosfun2
sos; // sosfun
return sos;
}
sos; // sosfun2
if (lz == lp) // equal zeroes and poles
{
sos; // last pole
return sos;
}
// get num den using zp2tf
// assign sos
sos; // sosfun
return sos;
}
std::vector<std::complex<double>> sosfun(int start, int stop, std::vector<std::complex<double>> poles, std::vector<std::complex<double>> sos, int version)
{
/*switch (version)
case 1:
case 2:*/
std::vector<std::complex<double>> placeholder{0};
return placeholder;
}
std::vector<std::complex<double>> zp2tf(std::vector<std::complex<double>> z, std::vector<std::complex<double>> p, std::complex<double> k)
{
std::vector<std::complex<double>> den;
std::vector<std::complex<double>> num;
std::vector<std::complex<double>> p_coeff = expand_poly(p);
for (int ii = 0; ii<p_coeff.size(); ++ii)
{
den[ii] = p_coeff[ii].real();
}
if(!z.size())
{
num = { {0.0, 0.0}, {0.0, 0.0}, k };
num.insert(num.end(), den.begin(), den.end());
// add num, den to same std::vector, return
}
std::vector<std::complex<double>> z_coeff = expand_poly(z);
for(int ii = 0; ii<z_coeff.size(); ++ii)
{
num[ii] = (z_coeff[ii] * k).real();
}
num.insert(num.end(), den.begin(), den.end());
return num;
}
答案 0 :(得分:0)
鉴于即使没有cpp代码,关于kfr模块如何导致错误的评论,也许kfr与您正在使用的其他标头兼容。试试这个:
这样你就会有一个单独的模块(cpp文件),仅提供与kfr相关的资源。然后编写自己的自定义界面来访问它,但kfr的所有细节都没有暴露给其他模块。
BTW最小化共享标头可以避免混淆命名空间,并且有助于最大限度地减少大型程序的编译时间。理想情况下,尽可能多的#includes只包含cpp文件中的#c;需要知道&#34;基础。如果您只使用特定cpp文件中共享标头中的一个函数,请考虑直接在使用cpp文件中将该函数声明为&#34; extern&#34;,它会被抬起来查看链接时间,但如果更改标题,则不会导致重新编译。这也是每个标头有一个类的好理由,标题中只有类方法声明,而不是代码本身。然后,您只需要#include cpp文件中所需的简单内容,以了解哪个类是哪个类,并且更改实现不会导致整个程序被重新编译。
答案 1 :(得分:0)
也许您使用过期版本的KFR。
类似问题已于2016年9月6日修复: https://github.com/kfrlib/kfr/commit/8340aaa1bf6fd31b4f8c5c868de3025fc0e4e5c5
尝试更新到最新的主版本并再次检查。
原生Visual Studio支持计划于下周发布。然后,LLVM将不需要与Visual Studio一起使用。