我正在尝试从两个正弦波中创建一个调制波形。要做到这一点,我需要模(Fmodf)知道一个特定频率的正弦(Lo_frequency)在那个时候(T)的振幅。但是,当执行以下行时,我会遇到一个严重的错误:
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);你知道为什么这会给我带来严重的错误吗?
编辑1:
我与my_fmodf交换了fmodf:
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
float n = x / y;
return x - n * y;
}但是仍然会发生硬故障,当我调试它时,它甚至没有跳入这个函数(My_fmodf)。
以下是发生此错误的整个函数:
int* create_wave(int* message){
/* Mixes the message signal at 10kHz and the carrier at 40kHz.
* When a bit of the message is 0 the amplitude is lowered to 10%.
* When a bit of the message is 1 the amplitude is 100%.
* The output of the STM32 can't be negative, thats why the wave swings between
* 0 and 256 (8bit precision for faster DAC)
*/
static int rf_frequency = 10000;
static int lo_frequency = 40000;
static int sample_rate = 100000;
int output[sample_rate];
int index, mix;
float j, t;
for(int i = 0; i <= sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = my_fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += (float) 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = 115 + sin1(j) * 0.1f;
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}编辑2:
我修正了警告:函数返回局部变量的地址- way local -addr,就像"chux - Reinstate“建议的那样。
int* create_wave(int* message){
static uint16_t rf_frequency = 10000;
static uint32_t lo_frequency = 40000;
static uint32_t sample_rate = 100000;
int *output = malloc(sizeof *output * sample_rate);
uint8_t index, mix;
float j, n, t;
for(int i = 0; i < sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = (uint8_t) floor(115 + sin1(j) * 0.1f);
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}但现在我明白了这句话的缺点:
output[i] = mix;编辑3:
由于前面的代码包含一个不适合于STM32F303K8的16 it的非常大的缓冲区数组,所以我需要对其进行更改。
现在,我使用了一个“乒乓”缓冲区,其中我使用DMA的回调来“前半传输”和“完全传输”:
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
for(uint16_t i = 0; i < 128; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
}
void HAL_DAC_ConvCpltCallbackCh1 (DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
for(uint16_t i = 128; i < 256; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
message_index++;
if (message_index >= 16) {
message_index = 0;
// HAL_DAC_Stop_DMA (&hdac1, DAC_CHANNEL_1);
}
}它按照我想要的方式运作:

但是产生的正弦的频率太低了。我上限在20千赫左右,但我需要40千赫。我把时钟增加了8倍,这样就可以把一个最大限度地用掉了:

。我仍然可以减少计数器周期(目前是50 ),但是当我这样做时,中断回调似乎要比下一个周期花费更长的时间。至少,当我这样做的时候,输出会变得非常扭曲。
我也试图通过只取8正弦值来降低精度,但是我不能再这样做了,因为输出不再像正弦波了。
有什么想法吗?我如何优化回调,以减少时间?还有其他想法吗?
发布于 2020-10-15 12:19:18
是否会导致stm32中的硬故障?
这是导致这里的硬故障的其他代码问题。
未能编译并发出大量警告
最佳代码提示:启用所有警告。@KamilCuk
反馈比堆栈溢出更快。
我希望在一个功能良好的编译器上类似于下面的内容。
return output;
warning: function returns address of local variable [-Wreturn-local-addr]返回本地对象
无法返回本地数组。而是分配。
// int output[sample_rate];
int *output = malloc(sizeof *output * sample_rate);
return output;调用代码将需要free()指针。
超出范围的数组访问
static int sample_rate = 100000;
int output[sample_rate];
// for(int i = 0; i <= sample_rate; i++){
for(int i = 0; i < sample_rate; i++){
...
output[i] = mix;
}堆栈溢出?
static int sample_rate = 100000; int output[sample_rate];是一个大的局部变量。也许分配或者尝试更小的东西?
高级:精度损失
一个好的fmodf()不会失去精确性。要获得更精确的答案,请考虑中间结果的double数学。更多的是采用更好的方法。
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
double n = 1.0 * x / y;
return (float) (x - n * y);
}--我可以不使用其他函数吗?
是。代码还有其他问题。
发布于 2020-10-16 21:14:32
1每10 is的值仅为100 this,对此宏来说不算太多。在我的设计中,我产生>5 5MSPS信号,没有任何问题。通常,我有一个缓冲区和DMA循环模式。首先,我填充缓冲区并开始生成。当一半传输DMA中断失败时,我会用新的数据填充缓冲区的前半部分。传输的完全中断是琐碎的,我填满了下半场,这个过程又重复了一遍。
https://stackoverflow.com/questions/64371032
复制相似问题