C++ 给定单个正弦波值和周期,递归创建正弦波

C++ 给定单个正弦波值和周期,递归创建正弦波,c++,octave,C++,Octave,我试图为倍频程编写一个.oct函数,给定一个在-1和1之间的正弦波值和正弦波周期,返回一个周期长度的正弦波向量,向量中的最后一个值就是给定的正弦波值。到目前为止,我的代码是: #include <octave/oct.h> #include <octave/dColVector.h> #include <math.h> #define PI 3.14159265 DEFUN_DLD (sinewave_recreate, args, , "args(0) s

我试图为倍频程编写一个.oct函数,给定一个在-1和1之间的正弦波值和正弦波周期,返回一个周期长度的正弦波向量,向量中的最后一个值就是给定的正弦波值。到目前为止,我的代码是:

#include <octave/oct.h>
#include <octave/dColVector.h>
#include <math.h>
#define PI 3.14159265

DEFUN_DLD (sinewave_recreate, args, , "args(0) sinewave value, args(1) is period")
{
octave_value_list retval;

double sinewave_value = args(0).double_value (); 
double period = args(1).double_value ();  
ColumnVector output_sinewave(period);                
double degrees_inc = 360 / period;
double output_sinewave_degrees;

output_sinewave_degrees = asin( sinewave_value ) * 180 / PI;
output_sinewave(period-1) = sin( output_sinewave_degrees * PI / 180 );

for (octave_idx_type ii (1); ii < period; ii++) // Start the loop
   {
   output_sinewave_degrees = output_sinewave_degrees - degrees_inc;

   if ( output_sinewave_degrees < 0 )
   {
   output_sinewave_degrees += 360 ;
   }  

   output_sinewave( period-1-ii ) = sin( output_sinewave_degrees * PI / 180 );
   }

retval(0) = output_sinewave;                                                          

return retval;                                                                        
}
#包括
#包括
#包括
#定义PI 3.14159265
DEFUN_DLD(正弦波,args,“args(0)正弦波值,args(1)为周期”)
{
倍频程值列表检索;
双正弦波_值=args(0)。双_值();
double period=args(1)。double_值();
列向量输出_正弦波(周期);
双度数=360/周期;
双输出正弦波度;
输出_正弦波_度=asin(正弦波_值)*180/PI;
输出正弦波(周期-1)=sin(输出正弦波角度*PI/180);
对于(倍频程_idx_类型ii(1);ii<周期;ii++)//启动循环
{
输出正弦波度=输出正弦波度-度;
中频(输出_正弦波_度<0)
{
输出正弦波角度+=360;
}  
输出正弦波(周期1-ii)=sin(输出正弦波角度*PI/180);
}
retval(0)=输出_正弦波;
返回返回;
}

但结果参差不齐。我的意思是,它有时能相当准确地再现正弦波,而其他时候,它就差得很远了。我简单地通过创建一个给定的正弦波来确定这一点,将最后一个时间值插入函数中,通过时间倒转重新创建正弦波,然后比较两者的曲线图。很明显,我做错了什么,但我似乎不知道是什么

你可以尝试一种更简单的方法。 回想一下,如果

y = sin(x)
那么
y
的一阶导数将等于

dy/dx = cos(x)
因此,在计算的每一步中,你都要将某个delta加到当前值
y
中,该delta等于

dy = cos(x) * dx
但这可能会降低你的准确度,这是一个副作用。你可以随便调查一下。嗯


似乎稍加改进的方程式更准确:

dy = cos(x + dx/2) * dx

看一看

你可以尝试一种更简单的方法。 回想一下,如果

y = sin(x)
那么
y
的一阶导数将等于

dy/dx = cos(x)
因此,在计算的每一步中,你都要将某个delta加到当前值
y
中,该delta等于

dy = cos(x) * dx
但这可能会降低你的准确度,这是一个副作用。你可以随便调查一下。嗯


似乎稍加改进的方程式更准确:

dy = cos(x + dx/2) * dx

看一看

让我们从一些三角恒等式开始:

sin(x)^2 + cos(x)^2 == 1
sin(x+y) == sin(x)*cos(y) + sin(y)*cos(x)
cos(x+y) == cos(x)*cos(y) - sin(x)*sin(y)
给定点
x
处的正弦和余弦,我们可以在预先计算
sd=sin(d)
cd=cos(d)
后,精确计算大小步长
d
后的值:

给定初始正弦值,可以计算初始余弦值:

cos(x) = sqrt(1 - sin(x)^2)

请注意,有两种可能的解决方案,对应于两个可能的平方根值。还要注意,这些恒等式中的所有角度都以弧度为单位,
d
如果返回波浪,则需要为负。

让我们从一些三角恒等式开始:

sin(x)^2 + cos(x)^2 == 1
sin(x+y) == sin(x)*cos(y) + sin(y)*cos(x)
cos(x+y) == cos(x)*cos(y) - sin(x)*sin(y)
给定点
x
处的正弦和余弦,我们可以在预先计算
sd=sin(d)
cd=cos(d)
后,精确计算大小步长
d
后的值:

给定初始正弦值,可以计算初始余弦值:

cos(x) = sqrt(1 - sin(x)^2)

请注意,有两种可能的解决方案,对应于两个可能的平方根值。还要注意,这些恒等式中的所有角度都以弧度为单位,
d
如果你返回波,则需要为负。

Mike注意到cos(x)有两种可能的解决方案,这让我意识到我需要解决正弦波的相位模糊问题。我的第二个成功尝试是:

#include <octave/oct.h>
#include <octave/dColVector.h>
#include <math.h>
#define PI 3.14159265

DEFUN_DLD (sinewave_recreate_3, args, , "args(0) sinewave value, args(1) is period, args(2) is the phase")
{
octave_value_list retval;

double sinewave_value = args(0).double_value (); 
double period = args(1).double_value ();  
double phase = args(2).double_value ();
ColumnVector output_sinewave(period);                
double X0 = asin(sinewave_value);

if (sinewave_value < 0 & phase > 180 & phase < 270)
 {
 X0 = PI + (0 - X0); 
 }

if (sinewave_value < 0 & phase >= 270)
 {
 X0 = X0 + 2 * PI; 
 }

if (sinewave_value > 0 & phase > 90)
 {
 X0 = PI - X0; 
 }

if (sinewave_value > 0 & phase < 0)
 {
 X0 = X0 + PI / 2; 
 }

double dx = PI / 180 * (360/period);

for (octave_idx_type ii (0); ii < period; ii++) // Start the loop
 {
 output_sinewave(period-1-ii) = sin(X0 - dx * ii); 
 }

retval(0) = output_sinewave;                                                          

return retval;                                                                        
}
#包括
#包括
#包括
#定义PI 3.14159265
DEFUN_DLD(正弦波3,args,“args(0)正弦波值,args(1)为周期,args(2)为相位”)
{
倍频程值列表检索;
双正弦波_值=args(0)。双_值();
double period=args(1)。double_值();
双相位=args(2)。双_值();
列向量输出_正弦波(周期);
双X0=asin(正弦波_值);
中频(正弦波_值<0,相位>180,相位<270)
{
X0=PI+(0-X0);
}
中频(正弦波_值<0和相位>=270)
{
X0=X0+2*PI;
}
中频(正弦波_值>0和相位>90)
{
X0=PI-X0;
}
中频(正弦波_值>0,相位<0)
{
X0=X0+PI/2;
}
双dx=PI/180*(360/周期);
对于(倍频程_idx_类型ii(0);ii<周期;ii++)//启动循环
{
输出_正弦波(周期-1-ii)=sin(X0-dx*ii);
}
retval(0)=输出_正弦波;
返回返回;
}

也要感谢Keynslug。

Mike提到cos(x)有两种可能的解决方案,这让我意识到我需要解决正弦波的相位模糊问题。我的第二个成功尝试是:

#include <octave/oct.h>
#include <octave/dColVector.h>
#include <math.h>
#define PI 3.14159265

DEFUN_DLD (sinewave_recreate_3, args, , "args(0) sinewave value, args(1) is period, args(2) is the phase")
{
octave_value_list retval;

double sinewave_value = args(0).double_value (); 
double period = args(1).double_value ();  
double phase = args(2).double_value ();
ColumnVector output_sinewave(period);                
double X0 = asin(sinewave_value);

if (sinewave_value < 0 & phase > 180 & phase < 270)
 {
 X0 = PI + (0 - X0); 
 }

if (sinewave_value < 0 & phase >= 270)
 {
 X0 = X0 + 2 * PI; 
 }

if (sinewave_value > 0 & phase > 90)
 {
 X0 = PI - X0; 
 }

if (sinewave_value > 0 & phase < 0)
 {
 X0 = X0 + PI / 2; 
 }

double dx = PI / 180 * (360/period);

for (octave_idx_type ii (0); ii < period; ii++) // Start the loop
 {
 output_sinewave(period-1-ii) = sin(X0 - dx * ii); 
 }

retval(0) = output_sinewave;                                                          

return retval;                                                                        
}
#包括
#包括
#包括
#定义PI 3.14159265
DEFUN_DLD(正弦波3,args,“args(0)正弦波值,args(1)为周期,args(2)为相位”)
{
倍频程值列表检索;
双正弦波_值=args(0)。双_值();
double period=args(1)。double_值();
双相位=args(2)。双_值();
列向量输出_正弦波(周期);
双X0=asin(正弦波_值);
中频(正弦波_值<0,相位>180,相位<270)
{
X0=PI+(0-X0);
}
中频(正弦波_值<0和相位>=270)
{
X0=X0+2*PI;
}
中频(正弦波_值>0和相位>90)
{
X0=PI-X0;
}
中频(正弦波_值>0,相位<0)
{
X0=X0+PI/2;
}
双d