This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS1291: Instantaneous Amplitude Logged Waveform When input a Sine Wave in higher frequency > 200Hz

Part Number: ADS1291

Tool/software:

Dear Sir/Madam,

We are currently designing a system using the ADS1291 for an ECG application. During testing, we used a RIGOL DG1032 waveform generator to produce a sine wave signal (5 mV, 0.5 Hz – 500 Hz).

We observed that at higher frequencies (above 200 Hz), the sine wave begins to exhibit an amplitude modulation effect, resembling an envelope distortion coupled by a low-frequency signal around 1.4 Hz to 1.5 Hz, as shown in the image below.

Could you please advise what might be causing this envelope-like distortion?
We suspect it may be related to the waveform generator or an interaction with the ADS1291 input configuration, but would appreciate your insight.

Thank you for your support!

BR
Joe


  • Hi Joe,

    What is the sampling rate of the ADS1291? Can you share the register configuration Address || Data?

    Regards,

    Ryan

  • Hi Ryan,

    Thank you for your response!

    We’ve set the PGA gain to 4 and configured the sampling rate to 2 kSPS. The corresponding configuration files are attached for your reference.

    We’ve also probed the signal directly at the input stage and confirmed that there is no amplitude modulation present at that point, effectively ruling out issues with the waveform generator or hardware front-end design.

    Additionally, we experimented with adjusting the C filter (originally 4.7 nF) between PGA1N and PGA1P to see if the issue might be due to higher-frequency aliasing folding into lower frequencies. However, changing the capacitor value didn’t help resolve the distortion.

    We are now considering whether the Sinc-3 digital filter might be contributing to this behavior. According to the datasheet, a 500 Hz sine wave input should only experience around -3 dB attenuation, so theoretically it shouldn't be causing this issue.

    Do you have any insights on this? Would increasing the sampling rate to 4 kSPS or 8 kSPS potentially help in our use case?

    Thank you!

    Best regards,
    Joe



    /**
     * @file    ADS1291.c
     * @brief   See ADS1291.h
     *
     * 
     */
    
    /* ========
       Includes
       ======== */
    
    /* header for this module */
    #include "ADS1291.h"
    
    /* headers from other modules */
    #include "spi.h"
    #include "timer_config.h"
    
    
    
    /* ==================================
       Implementation of global functions
       ================================== */
    boolean ADS1291_Init()
    {
        // Setup registers. Initialize with defaults and then change the needed ones.
        ADS1291_Registers_t registers;
        
        // CONFIG1
        registers.config1.value = REG_CONFIG1_RESET_VALUE;
        registers.config1.bits.DR = IECG_SAMPLING_2K_HZ;
        
        // CONFIG2
        registers.config2.value = REG_CONFIG2_RESET_VALUE;
        registers.config2.bits.PDB_REFBUF = 1U;
        
        // CH1SET
        registers.ch1set.value = REG_CH1SET_RESET_VALUE;
        registers.ch1set.bits.GAIN1 = ADS1291_Get_Gain(ADS1291_GAIN);
    
    #if 0
        // Enable Test Signal
        registers.config2.bits.INT_TEST = 1U;
        registers.config2.bits.TEST_FREQ = 1U;
        registers.ch1set.bits.MUX1 = CH_INPUT_TEST_SIGNAL;
    #endif
        
        //CH2SET
        registers.ch2set.value = REG_CH2SET_RESET_VALUE;
        registers.ch2set.bits.PD2 = 1U;
        registers.ch2set.bits.MUX2 = CH_INPUT_SHORTED;
    
        //RLD_SENSE
        registers.rldsense.value = REG_RLDSENS_RESET_VALUE;
        registers.rldsense.bits.PDB_RLD = 1U;
        registers.rldsense.bits.RLD1P = 1U;
        registers.rldsense.bits.RLD1N = 1U;
            
        // GPIO
        registers.gpio.value = REG_GPIO_RESET_VALUE;
        registers.gpio.bits.GPIOC1 = ADS1291_GPIO_MODE_OUTPUT;
        registers.gpio.bits.GPIOC2 = ADS1291_GPIO_MODE_OUTPUT;
        registers.gpio.bits.GPIOD1 = 0U;
        registers.gpio.bits.GPIOD2 = 0U;
        
        // Others - Default
        registers.loff.value = REG_LOFF_RESET_VALUE;
        registers.loffsense.value = REG_LOFF_SENSE_RESET_VALUE;
        registers.loffstat.value = REG_LOFF_STAT_RESET_VALUE;
        registers.resp1.value = REG_RESP1_RESET_VALUE;
        registers.resp2.value = REG_RESP2_RESET_VALUE;
        
            
        // Write all registers
        boolean ret = ADS1291_Send_Command(CMD_SDATAC);
        ret &= ADS1291_Write_Register(ADS1291_REG_CONFIG1, registers.config1.value); 
        ret &= ADS1291_Write_Register(ADS1291_REG_CONFIG2, registers.config2.value);
        ret &= ADS1291_Write_Register(ADS1291_REG_CH1SET, registers.ch1set.value);
        ret &= ADS1291_Write_Register(ADS1291_REG_CH2SET, registers.ch2set.value);
        ret &= ADS1291_Write_Register(ADS1291_REG_LOFF_SENSE, registers.loffsense.value);
        ret &= ADS1291_Write_Register(ADS1291_REG_LOFF_STAT, registers.loffstat.value); 
    
        // Must be written
        ret &= ADS1291_Write_Register(ADS1291_REG_RESP1, registers.resp1.value);
        ret &= ADS1291_Write_Register(ADS1291_REG_RESP2, registers.resp2.value);
    
        // Optional
        ret &= ADS1291_Write_Register(ADS1291_REG_LOFF, registers.loff.value);
        ret &= ADS1291_Write_Register(ADS1291_REG_RLDSENS, registers.rldsense.value);
        ret &= ADS1291_Write_Register(ADS1291_REG_GPIO, registers.gpio.value);
    
        // Start continuous read mode
        ret &= ADS1291_Send_Command(CMD_START);
        ret &= ADS1291_Send_Command(CMD_RDATAC);
        
        return ret;
    }
    
    boolean ADS1291_Send_Command(uint8_t command) 
    {
        uint8_t tx_data[3] = {0x00, 0x00, command};
        SPI_WriteRead_Blocking(ADS1291_SPI_ID,  tx_data, NULL, sizeof(tx_data));
        return mpTRUE;
    }
    
    boolean ADS1291_Write_Register(uint8_t reg, uint8_t value) 
    {
        uint8_t tx_data[3] = {value, 0x00, CMD_WREG | reg};
        SPI_WriteRead_Blocking(ADS1291_SPI_ID, tx_data, NULL, sizeof(tx_data));
        return mpTRUE;
    }
    
    uint32_t ADS1291_Read_Data()
    {
        uint32_t tx_data = 0U;
        uint32_t status =  0U;
        uint32_t  ch1_data= 0U;
        
        /* Transfer 2 - 24 bit words */
        SPI_WriteRead_Blocking(ADS1291_SPI_ID, &tx_data, &status, sizeof(status));
        SPI_WriteRead_Blocking(ADS1291_SPI_ID, &tx_data, &ch1_data, sizeof(ch1_data));
    
        return ch1_data;
    }
    
    uint8_t ADS1291_Get_Gain(uint8_t gain)
    {
        uint8_t gainEnum = CH_GAIN_6;
        switch (gain)
        {
            case 1:
            {
                gainEnum = CH_GAIN_1;
                break;
            }
            case 2:
            {
                gainEnum = CH_GAIN_2;
                break;
            }
            case 3:
            {
                gainEnum = CH_GAIN_3;
                break;
            }
            case 4:
            {
                gainEnum = CH_GAIN_4;
                break;
            }
            case 6:
            {
                gainEnum = CH_GAIN_6;
                break;
            }
            case 8:
            {
                gainEnum = CH_GAIN_8;
                break;
            }
            case 12:
            {
                gainEnum = CH_GAIN_12;
                break;
            }
            default:
            {
                break;
            }
            
        }
        
        return gainEnum;
    }
    
    int32_t ADS1291_ConvertRawTo_mV (uint32_t RawSample)
    {
        uint32_t raw_value = RawSample;
        if( 0U < (raw_value & 0x800000U)) { // Check MSB for sign
            raw_value |= 0xFF000000U; // Sign-extend to 32 bits
        }
        int32_t signed_value = (int32_t)raw_value; // Cast to signed integer
    
        // Compute voltage in microvolts, scaled by 1000 to retain precision
        int64_t scaled_voltage = (int64_t)signed_value * ADS1291_V_FACTOR;
    
        // Remove scaling factor and cast to 16-bit ECG sample
        return (int32_t)(scaled_voltage / SCALING_FACTOR);
    }
    
    ADS1291_MP01.h