任务名称
2020年_E题:放大器非线性失真研究装置
任务要求
难度

一、任务
设计并制作一个放大器非线性失真研究装置,其组成如图1所示,图中的K1和K2为1×2切换开关,晶体管放大器只允许有一个输入端口和一个输出端口。 

二、要求

  1. K1和K2均投到各自的“1”端子,外接信号源输出频率 1kHz、峰峰值 20mV 的正弦波作为晶体管放大器输入电压μi ,要求输出无明显失真及四种失真波形μo,且μo的峰峰值不低于 2V。外接示波器测量晶体管放大器输出电压μo波形
  2. 放大器能够输出无明显失真的正弦电压μo (10 分)
  3. 放大器能够输出有“顶部失真”的电压μo (15 分)
  4. 放大器能够输出有“底部失真”的电压μo(15 分)
  5. 放大器能够输出有“双向失真”的电压μo (15 分)
  6. 放大器能够输出有“交越失真”的电压μo(15 分)
  7. 分别测量并显示上述五种输出电压μo的“总谐波失真”近似值 (20 分)
  8. 其他 (10 分)
  9. 设计报告 (20 分)

三、说明

  1. 限用晶体管、阻容元件、模拟开关等元器件设计并实现图1中的受控晶体管放大器,其输出的各种失真或无明显失真的信号必须出自该晶体管放大电路,禁用预存失真波形数据进行D/A转换等方式输出各种失真信号。
  2. 在设计报告中,应结合电路设计方案阐述出现各种失真的原因。
  3. 无明显失真及四种具有非线性失真电压μo的示意波形如图2所示ω: 
  4. 总谐波失真定义:
    • 线性放大器输入为正弦信号时,其非线性失真表现为输出信号中出现谐波分量,常用总谐波失真(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)项时,谐波取到五次即可,即:

  5. 对THD自动测量期间,不得有任何人工干预。
  6. K1和K2的“2”端子用于作品测试
参考答案

GPT-4o给出的设计方案:


一、方案设计概要

设计并制作一个放大器非线性失真研究装置,通过控制切换开关K1和K2来选择不同的输入信号和测量输出。晶体管放大器处理输入信号,采集测量模块记录输出信号,最终在示波器上显示波形以分析放大器的失真特性。

二、方案论证及理论分析

  1. 信号源

    • 提供1kHz、峰峰值20mV的正弦波信号作为输入,保证输入信号稳定一致。
  2. 晶体管放大器

    • 放大电路设计要点在于要能显现失真特性,如无明显示真、剪切失真和交越失真等。
    • 正常放大输出以展示无明显失真及准确增益,确保输出峰峰值不低于2V。
  3. 采集测量模块

    • 数字采集电路,用于捕捉放大器输出信号,并计算失真度。
  4. 切换开关K1和K2

    • 控制信号源的输入和输出路径,以便于不同测试模式的切换。

三、重要指标分析

  1. 信号源频率和稳定性:1kHz频率稳定,峰峰值为20mV的正弦波。
  2. 输出信号类型和失真度分析
    • 无明显失真:准确传递输入信号。
    • 正交失真、顶部失真、底部失真、交越失真:分析五种失真模式。
  3. 响应时间和检测周期:实时捕捉信号变化,能够准确测量和显示不同失真波形。

四、原理图设计要点

  1. 晶体管放大器原理图

    输入信号 -> 晶体管放大器 (BJT 或 MOSFET) -> 输出信号
                       ^                         |
                       |                         v
                电阻网络调节放大倍率      反馈电路稳幅
    
  2. 采集测量电路原理图

    放大器输出 -> ADC -> 数字处理器 (MCU) -> 显示结果
    
  3. 开关控制电路

    信号源 -> K1切换信号 -> 放大器输入
                                    |
    放大器输出 -> K2切换信号 -> 采集测量/示波器
    

五、核心器件的设计要点

  1. 晶体管放大器(如2N3904或IRF540N)

    • 高频率响应特性和低噪声,确保放大器的稳定性和高增益特性。
  2. 模拟数字转换器(ADC)

    • 选择高精度ADC,如AD7680,确保高分辨率和采样速度。
  3. 微控制器(MCU)

    • 选择STM32系列,具有足够的处理能力和接口资源,用于信号处理和数据传输。

六、MCU程序设计 (C代码)

以下为采集处理和输出控制的核心代码:

#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;
}
  1. 数据采集和FFT变换
    • 在真实应用中,你需要从放大器输出中采集信号并通过FFT变换获得 fft_output 数组,这里假设该步骤已经完成。
  2. 准确性
    • 确保采样率高于信号最高频率的两倍(Nyquist定理),以防止混叠。
  3. 预处理
    • 采集信号前可采用滤波和去除直流分量等预处理,提高结果准确性。

以下是一段用于单片机(例如使用STM32微控制器)的C代码示例,通过PWM输出生成正弦波。简单来说,我们通过PWM占空比的变化来逼近正弦波的形状,可以使用一个预计算的正弦波表来进行快速查找:

STM32例程:

  1. 预计算的正弦波表(注意:实际应用中,可以根据需求增加更多的点以提高精度):
#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) */
};
  1. 初始化PWM和定时器相关函数
#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
    }
}

代码解释:

  1. 预计算正弦表:定义一个包含256个点的正弦波查找表。
  2. 初始化
    • 初始化系统时钟。
    • 初始化TIM1作为PWM输出,并设置周期和占空比。
    • 初始化GPIO用于PWM输出。
  3. 主循环
    • 每1毫秒从正弦表中读取一个值,设置PWM占空比,通过修改 TIM1->CCR1 值。
    • 由于我们使用预计算的正弦波查找表,可以确保输出接近理想的正弦波。

这段代码可以在STM32CubeMX生成的基本框架上进行修改和应用,通过适当调整波形点数和采样速率,可以实现更高质量的正弦波输出。


这个题目考察的知识点:

  1. 信号源及放大器设计:要求学生理解并设计一个包含信号源和放大电路的系统,考虑放大器的非线性失真特性。
  2. 谐波失真分析:需要掌握谐波失真的概念,并通过测量各谐波分量来计算总谐波失真(THD)。
  3. 数据采集与处理:设计信号采集系统,使用微控制器和ADC模块进行精确的数据采集,并通过软件进行数据处理和分析。
  4. 频谱分析:利用频谱分析方法,如快速傅立叶变换(FFT),分析信号的频谱特点,理解线性和非线性失真的区别。
  5. 实验设计与测试:熟悉实验设计的基本流程,能够制定并实施测试方案,对测试结果进行分析和改进。

通过这些知识点的学习和实践,学生将能深入理解放大器非线性失真特性及其对信号质量的影响。

 

硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号