一、任务
设计并制作一个放大器非线性失真研究装置,其组成如图1所示,图中的K1和K2为1×2切换开关,晶体管放大器只允许有一个输入端口和一个输出端口。
二、要求
三、说明
线性放大器输入为正弦信号时,其非线性失真表现为输出信号中出现谐波分量,常用总谐波失真(THD:total harmonic distortion)衡量线性放大器的非线性失真程度。
THD定义:若线性放大器输入电压吗,μi= Uicosωt ,其含有非线性失真的输出交流电压为μo=Uo1cos(ωt+φ1)+Uo2cos(2ωt+φ2)+Uo3cos(3ωt+φ3)+Uoncos(nωt+φn),则有:
在完成设计要求的第(6)项时,谐波取到五次即可,即:
GPT-4o给出的设计方案:
设计并制作一个放大器非线性失真研究装置,通过控制切换开关K1和K2来选择不同的输入信号和测量输出。晶体管放大器处理输入信号,采集测量模块记录输出信号,最终在示波器上显示波形以分析放大器的失真特性。
信号源:
晶体管放大器:
采集测量模块:
切换开关K1和K2:
晶体管放大器原理图:
输入信号 -> 晶体管放大器 (BJT 或 MOSFET) -> 输出信号
^ |
| v
电阻网络调节放大倍率 反馈电路稳幅
采集测量电路原理图:
放大器输出 -> ADC -> 数字处理器 (MCU) -> 显示结果
开关控制电路:
信号源 -> K1切换信号 -> 放大器输入
|
放大器输出 -> K2切换信号 -> 采集测量/示波器
晶体管放大器(如2N3904或IRF540N):
模拟数字转换器(ADC):
微控制器(MCU):
以下为采集处理和输出控制的核心代码:
#include "stm32f4xx.h"
#define ADC_CHANNEL_NUM 1
#define ADC_BUFFER_SIZE 1024
volatile uint16_t adc_buffer[ADC_BUFFER_SIZE];
void ADC_IRQHandler(void) {
if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET) {
static int index = 0;
adc_buffer[index++] = ADC_GetConversionValue(ADC1);
if (index == ADC_BUFFER_SIZE) index = 0; // Buffer循环
}
}
void init_ADC(void) {
/* 初始化ADC通道,配置其采样时间等参数 */
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_SoftwareStartConv(ADC1);
}
void TIM3_IRQHandler(void) {
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
/* 处理采样数据,计算失真 */
// 处理函数,根据adc_buffer中的数据计算失真度
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
void init_timer(void) {
/* 初始化定时器,用于定时触发失真计算 */
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 1 kHz
TIM_TimeBaseStructure.TIM_Prescaler = 84 - 1; // 1 MHz
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
}
int main(void) {
SystemInit();
init_ADC();
init_timer();
while (1) {
// 主循环,处理其他操作
}
}
计算THD的C代码:
以下是用C语言实现计算THD的代码示例,假设我们已经采集到了放大器的输出信号并进行了FFT变换以获取频谱数据。
这个示例中,频谱数据数组 fft_output
包含0到最高次各谐波分量的幅值:
#include <stdio.h>
#include <math.h>
// 伪示例:假设FFT输出的数组,元素代表对应频率的幅值
#define NUM_HARMONICS 10
double fft_output[NUM_HARMONICS] = { // 伪数据
1.0, // 基波幅值
0.1, // 二次谐波幅值
0.05, // 三次谐波幅值
// 其他次谐波 ...
};
// 计算THD的函数
double calculate_thd(double fft_output[], int num_harmonics) {
double fundamentalFreqValue = fft_output[0];
double harmonicSumSquared = 0.0;
// 累加每一个谐波(从二次谐波开始)的平方
for (int i = 1; i < num_harmonics; i++) {
harmonicSumSquared += fft_output[i] * fft_output[i];
}
// 计算THD
double thd = sqrt(harmonicSumSquared) / fundamentalFreqValue * 100.0;
return thd;
}
int main() {
double thd = calculate_thd(fft_output, NUM_HARMONICS);
printf("Total Harmonic Distortion (THD): %.2f%%\n", thd);
return 0;
}
fft_output
数组,这里假设该步骤已经完成。
#define SINE_TABLE_SIZE 256
const uint16_t sine_table[SINE_TABLE_SIZE] = {
2048, 2098, 2148, 2198, 2248, 2298, 2348, 2397, 2447, 2496, 2545, 2594, 2642, 2690, 2738, 2785,
2832, 2879, 2925, 2971, 3016, 3061, 3106, 3150, 3193, 3236, 3278, 3320, 3361, 3401, 3441, 3480,
3518, 3556, 3592, 3628, 3663, 3697, 3731, 3763, 3795, 3826, 3856, 3885, 3913, 3940, 3966, 3992,
4016, 4040, 4062, 4084, 4104, 4124, 4142, 4159, 4176, 4191, 4205, 4218, 4230, 4241, 4251, 4260,
4267, 4274, 4279, 4284, 4287, 4289, 4290, 4289, 4287, 4284, 4279, 4274, 4267, 4260, 4251, 4241,
4230, 4218, 4205, 4191, 4176, 4159, 4142, 4124, 4104, 4084, 4062, 4040, 4016, 3992, 3966, 3940,
3913, 3885, 3856, 3826, 3...
/* (Values continue in similar manner to form a sine wave) */
};
#include "stm32f4xx_hal.h"
TIM_HandleTypeDef htim1;
uint32_t sine_index = 0;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
void Error_Handler(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM1_Init();
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
while (1)
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, sine_table[sine_index]);
sine_index = (sine_index + 1) % SINE_TABLE_SIZE;
HAL_Delay(1);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 4095;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim1);
}
static void MX_GPIO_Init(void)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Error_Handler(void)
{
while(1)
{
// Error handler
}
}
TIM1->CCR1
值。这段代码可以在STM32CubeMX生成的基本框架上进行修改和应用,通过适当调整波形点数和采样速率,可以实现更高质量的正弦波输出。
这个题目考察的知识点:
通过这些知识点的学习和实践,学生将能深入理解放大器非线性失真特性及其对信号质量的影响。