Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: Amplitude Modulation (AM) SDR TX for Teensy 4.X code request

  1. #1
    Junior Member stefanodi's Avatar
    Join Date
    May 2022
    Location
    Vicenza Italy
    Posts
    7

    Amplitude Modulation (AM) SDR TX for Teensy 4.X code request

    Hello everybody. A friend told me I was wrong and they didn't understand the question in my previous post.
    I write my request for help in another way:
    is it possible to have a code for Teensy 4.X to build a TX SDR in amplitude modulated (AM)?
    Thanks in advance for those who will have the kindness to help me.
    Stefano.

  2. #2
    Senior Member
    Join Date
    Dec 2016
    Posts
    178
    The Teensy Audio library has sine wave generators and multipliers, the combination of which does AM. This is in 16-bit integer. See the Teensy Audio Design Tool.

    Alternatively, this can be done in floating point where there is an explicit amplitude modulator that includes a sine wave generator. See the corresponding F32 Design Tool. In general, the floating point library has more SDR related classes whereas the integer library has more music related ones.

  3. #3
    Junior Member stefanodi's Avatar
    Join Date
    May 2022
    Location
    Vicenza Italy
    Posts
    7
    Quote Originally Posted by Bob Larkin View Post
    The Teensy Audio library has sine wave generators and multipliers, the combination of which does AM. This is in 16-bit integer. See the Teensy Audio Design Tool.

    Alternatively, this can be done in floating point where there is an explicit amplitude modulator that includes a sine wave generator. See the corresponding F32 Design Tool. In general, the floating point library has more SDR related classes whereas the integer library has more music related ones.

    Thanks Bob for the reply.
    The project is based on an RTX type I & Q mixer card.
    I would like to build an "old style" RTX, without many controls and easy to build, but ALL SDR.
    My problem is generating the modulated amplitude.
    If you can help me I will be grateful.

    I have already tested the OpenAudio Arduino Library and I think it will be my next project as soon as this is finished.
    Thank you and good day!
    Stefano

    Attached is the photo of the project only for the TX part:
    Click image for larger version. 

Name:	txparts.jpg 
Views:	28 
Size:	95.5 KB 
ID:	28847


    Code:
    // GUItool: begin automatically generated code
    AudioInputI2S            audioInput;     //xy=135.88888549804688,347.0000457763672
    AudioFilterFIR           TX_hilbert_45;  //xy=356.8888931274414,499.00008392333984
    AudioFilterFIR           TX_hilbert_m45; //xy=359.88893127441406,230.0000123977661
    
    AudioSynthWaveform       15Khz_Sine_Gen;      //
    
    AudioFilterFIR           fir1;           //
    
    AudioEffectMultiply      multiply1;      //
    
    AudioFilterFIR           fir2;           //
    
    AudioMixer4              Q_Switch; //xy=943.8887786865234,515.0000038146973
    AudioMixer4              I_Switch; //xy=952.8888320922852,252.00001907348633
    AudioOutputI2S           audioOutput;    //xy=1180.888816833496,388.9999723434448
    AudioConnection          patchCord1(audioInput, 0, TX_hilbert_m45, 0);
    AudioConnection          patchCord2(audioInput, 1, TX_hilbert_45, 0);
    AudioConnection          patchCord3(TX_hilbert_45, 0, Q_Switch, 0);
    AudioConnection          patchCord4(TX_hilbert_m45, 0, I_Switch, 0);
    
    AudioConnection          patchCord5(15Khz_Sine_Gen, 0, multiply1, 1);
    AudioConnection          patchCord6(fir1, 0, multiply1, 0);
    AudioConnection          patchCord7(multiply1, fir2);
    
    AudioConnection          patchCord8(fir2, 0, I_Switch, 1);
    
    AudioConnection          patchCord9(Q_Switch, 0, audioOutput, 1);
    AudioConnection          patchCord10(I_Switch, 0, audioOutput, 0);
    AudioControlSGTL5000     audioShield;    //xy=346.8889274597168,134.99999952316284
    // GUItool: end automatically generated code

  4. #4
    Senior Member
    Join Date
    Dec 2016
    Posts
    178
    Hi Stefanodi - What you have produces double sideband suppressed carrier. You need to add in a constant carrier level, like 1.0. This is like vout = [1 + m(t)]*sin2*pi*15000*t wher m(t) is the modulating waveform that you have as a sine wave. Something like

    Code:
    AudioSynthWaveformDc     dc1;            //xy=71,634
    AudioInputI2S            i2s2;           //xy=76,754
    AudioSynthWaveform       waveform1;      //xy=78,688
    AudioFilterFIR           fir1;           //xy=219,754
    AudioMixer4              mixer1;         //xy=220,670
    AudioEffectMultiply      multiply1;      //xy=359,699
    AudioOutputI2S           i2s1;           //xy=449,759
    AudioConnection          patchCord1(dc1, 0, mixer1, 0);
    AudioConnection          patchCord2(i2s2, 0, fir1, 0);
    AudioConnection          patchCord3(waveform1, 0, mixer1, 1);
    AudioConnection          patchCord4(fir1, 0, multiply1, 1);
    AudioConnection          patchCord5(mixer1, 0, multiply1, 0);
    AudioConnection          patchCord6(multiply1, 0, i2s1, 0);
    AudioControlSGTL5000     sgtl5000_1;     //xy=230,821
    The mixer does the addition of the 1 and the modulating waveform coming from the ADC. This is lacking in beauty and should be built into a single AM modulator class. But getting started is more important. I did not try this flow and I hope it is a correct implementation.

  5. #5
    Junior Member stefanodi's Avatar
    Join Date
    May 2022
    Location
    Vicenza Italy
    Posts
    7
    Quote Originally Posted by Bob Larkin View Post
    Hi Stefanodi - What you have produces double sideband suppressed carrier. You need to add in a constant carrier level, like 1.0. This is like vout = [1 + m(t)]*sin2*pi*15000*t wher m(t) is the modulating waveform that you have as a sine wave. Something like

    Code:
    AudioSynthWaveformDc     dc1;            //xy=71,634
    AudioInputI2S            i2s2;           //xy=76,754
    AudioSynthWaveform       waveform1;      //xy=78,688
    AudioFilterFIR           fir1;           //xy=219,754
    AudioMixer4              mixer1;         //xy=220,670
    AudioEffectMultiply      multiply1;      //xy=359,699
    AudioOutputI2S           i2s1;           //xy=449,759
    AudioConnection          patchCord1(dc1, 0, mixer1, 0);
    AudioConnection          patchCord2(i2s2, 0, fir1, 0);
    AudioConnection          patchCord3(waveform1, 0, mixer1, 1);
    AudioConnection          patchCord4(fir1, 0, multiply1, 1);
    AudioConnection          patchCord5(mixer1, 0, multiply1, 0);
    AudioConnection          patchCord6(multiply1, 0, i2s1, 0);
    AudioControlSGTL5000     sgtl5000_1;     //xy=230,821
    The mixer does the addition of the 1 and the modulating waveform coming from the ADC. This is lacking in beauty and should be built into a single AM modulator class. But getting started is more important. I did not try this flow and I hope it is a correct implementation.
    Thanks again Bob for your availability.
    I tried the code and the Amplitude Modulation and it works.
    However, it functions as a controlled carrier.
    Only in the presence of an incoming audio signal, it generates radio frequency.
    Maybe my values ​​of the audio shield setup are wrong?
    Here is the test code with my I-Q Mixer:

    Code:
    /* File: AM_TEST_TX-2.ino
     * Project's name: "Old Style A.M. RTX"
     * Initial project request by Stefano Homebrew
     * @ https://forum.pjrc.com/forum.php
     * Forum code by BOB LARKIN
     * Developed for Teensy 4.0 https://www.pjrc.com/teensy/
     * Audio shield PCM1808 & PCM5102A
     */
    //****
    #include <Wire.h>                         
    #include <si5351.h> 
    #include <ILI9341_t3.h>
    #include <Audio.h>  
    #include <SPI.h>
    #include <SerialFlash.h>
    //****Display ILI9341
    #define TFT_DC    9
    #define TFT_CS    10
    #define TFT_RST   255  
    #define TFT_MOSI  11
    #define TFT_SCLK  13
    #define TFT_MISO  12
    
    #define BLACK    0x0000//My alternative colors
    #define MARRONE  0x5041//My alternative colors
    
    #define IF_FREQ 15000//****sine gen.
    
    //****var pll frequency init.
    volatile long freq = 27125000;//Tested in free 11Meters band
    volatile uint32_t vfoFreq = 0;//for next implementations
    
    //****var print frequency
    byte unita,decine,centinaia,migliaia,decinemigliaia,centmigliaia,milioni ;  //variabili stampa freq.
    
    //****************
    AudioInputI2S            i2s2;           
    AudioSynthWaveformDc     dc1;            
    AudioSynthWaveform       waveform1;     
    
    AudioFilterBiquad        biquad1;        //FILTER AUDIO INPUT
    
    AudioMixer4              mixer1;      
    AudioEffectMultiply      multiply1;   
    AudioOutputI2S           i2s1;      
    
    AudioConnection          patchCord1(i2s2, 0, biquad1, 0);
    AudioConnection          patchCord2(dc1, 0, mixer1, 0);
    AudioConnection          patchCord3(waveform1, 0, mixer1, 1);
    AudioConnection          patchCord4(biquad1, 0, multiply1, 1);
    AudioConnection          patchCord5(mixer1, 0, multiply1, 0);
    AudioConnection          patchCord6(multiply1, 0, i2s1, 0);
    AudioControlSGTL5000     sgtl5000_1;
    
    //*******
    ILI9341_t3 tft=ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
    Si5351 si5351;  
    
    //************************
    
    void setup() {
      Serial.begin(9600);
      
    //****init ILI9341  
      tft.begin();
      tft.setRotation(3);
      tft.fillScreen(ILI9341_BLACK);
      
    //*****DISPLAY REM
      tft.setCursor(2, 232);
      tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
      tft.setTextSize(1); 
      tft.print("AM_TEST_TX-2"); 
       
    //*****PLL SET
      si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
      si5351.set_correction(210000, SI5351_PLL_INPUT_XO);//My XTAL correction
      si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
      si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_6MA);
      si5351.set_freq(freq * 400ULL, SI5351_CLK2);
    
    //*****Audio shield SETUP
      AudioNoInterrupts();
      AudioMemory(16);
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);   
      sgtl5000_1.volume(1.0);
      
      waveform1.begin(1.0,IF_FREQ,WAVEFORM_SINE);
      dc1.amplitude(1.0);
      
      mixer1.gain(0,1);
      mixer1.gain(1,1);
    
      biquad1.setLowpass(0,6000,0.7);
      biquad1.setHighpass(1,100,0.7);
    
      AudioInterrupts();
      
      delay(100);
        stampafrq();
    }
    
    //*****************LOOP
    void loop() {
    
    }
    
    //***************PRINT @frequency DISPLAY
    void stampafrq()
    {       
       vfoFreq=freq; ///////////////////////////////////////////////////
        milioni = int(vfoFreq/1000000);
        centmigliaia = ((vfoFreq/100000)%10);
        decinemigliaia = ((vfoFreq/10000)%10);
        migliaia = ((vfoFreq/1000)%10);
        centinaia = ((vfoFreq/100)%10);
        decine = ((vfoFreq/10)%10);
        unita = ((vfoFreq/1)%10);
    //******************************************
        tft.fillRect(112, 44, 169, 32, BLACK);
        tft.setTextSize(3);
        tft.setCursor(121,44);
        tft.setTextColor(ILI9341_WHITE);
        tft.print(milioni);//
        tft.print(".");
        tft.print(centmigliaia);
        tft.print(decinemigliaia);
        tft.print(migliaia);
        tft.print(".");
        tft.print(centinaia);
        tft.print(decine);             
    }

  6. #6
    Senior Member
    Join Date
    Dec 2016
    Posts
    178
    I'm sorry, I added the carrier onto the 15 kHz and not the modulating voltage. Correcting that:#include <Audio.h>

    Code:
    AudioSynthWaveformDc     dc1;            //xy=80,871
    AudioInputI2S            i2s2;           //xy=83,989
    AudioSynthWaveformSine   sine1;          //xy=164,514
    AudioFilterFIR           fir1;           //xy=224,981
    AudioSynthWaveform       waveform1;      //xy=240,1027
    AudioMixer4              mixer1;         //xy=242,901
    AudioEffectMultiply      multiply1;      //xy=381,930
    AudioOutputI2S           i2s1;           //xy=471,990
    AudioConnection          patchCord1(dc1, 0, mixer1, 0);
    AudioConnection          patchCord2(i2s2, 0, fir1, 0);
    AudioConnection          patchCord3(fir1, 0, mixer1, 1);
    AudioConnection          patchCord4(waveform1, 0, multiply1, 1);
    AudioConnection          patchCord5(mixer1, 0, multiply1, 0);
    AudioConnection          patchCord6(multiply1, 0, i2s1, 0);
    AudioControlSGTL5000     sgtl5000_1;     //xy=250,1081
    Also, the 1.0 for the DC is fine in float, but for this I16 you need to reduce that to 0.5 to allow room for the AM increase.

    Is this closer?

  7. #7
    Senior Member
    Join Date
    Dec 2016
    Posts
    178
    stefanodi, just to make it visible for those without your hardware, I built an AM generator only and used a Queue to output the final waveform to the Serial Plotter. As it sits, it runs 50% modulation. Oh, and I also brought the input from a sine wave generator. Here is the INO:
    Code:
    // AM waveform fc = 11025 Hz, fm=441 Hz.
    // Teensy audio
    // Turn on Tools>Serial Plotter to see output
    // Bob L
    
    #include <Audio.h>
    
    #define IF_FREQ 11025.0  //15000//****sine gen.
    
    AudioSynthWaveformSine   sine1;
    AudioSynthWaveformDc     dc1;            //xy=80,871
    AudioInputI2S            i2s2;           //xy=83,989
    AudioFilterBiquad        biquad1;           //xy=224,981
    AudioSynthWaveform       waveform1;      //xy=240,1027
    AudioMixer4              mixer1;         //xy=242,901
    AudioEffectMultiply      multiply1;      //xy=381,930
    AudioRecordQueue         queue1;
    AudioOutputI2S           i2s1;           //xy=471,990
    AudioConnection          patchCord1(dc1, 0, mixer1, 0);
    AudioConnection          patchCord2(sine1, 0, biquad1, 0);
    AudioConnection          patchCord3(biquad1, 0, mixer1, 1);
    AudioConnection          patchCord4(waveform1, 0, multiply1, 1);
    AudioConnection          patchCord5(mixer1, 0, multiply1, 0);
    AudioConnection          patchCord6(multiply1, 0, queue1, 0);
    AudioControlSGTL5000     sgtl5000_1;     //xy=250,1081
    
    void setup() {
      Serial.begin(9600); delay(1000);
      AudioMemory(16);
      sgtl5000_1.enable();
      // The modulating waveform
      //sine1.amplitude(0.5f);     // 100% AM modulation
      sine1.amplitude(0.25f);     // 50% AM modulation
      sine1.frequency(441.0f);
      // The carrier, moved to fs/4 to minimize beats with the sample rate
      // Only a problem when looking at Serial Plotter, OK at 15 kHz over the air
      waveform1.begin(1.0f,IF_FREQ,WAVEFORM_SINE);
      dc1.amplitude(0.5f);    // Leave room for AM modulation
      mixer1.gain(0,1);
      mixer1.gain(1,1);
      biquad1.setLowpass(0,6000,0.7);  // Not needed for sine wve,
      biquad1.setHighpass(1,100,0.7);  //   but generally a good idea
      queue1.begin();
    }
    
    void loop() {
      static int count = 0;
      if(queue1.available() > 0)
         {
         count++;
         int16_t* pi = queue1.readBuffer();
         for (int ii=0; ii<128; ii++)
           if(count<10) Serial.println(*(pi+ii));
         queue1.freeBuffer();
         }
    }
    And also, my post #6 had an extra unconnected sine wave generator---not being use and harmless.

    Have fun with all this!

  8. #8
    Junior Member stefanodi's Avatar
    Join Date
    May 2022
    Location
    Vicenza Italy
    Posts
    7
    Quote Originally Posted by Bob Larkin View Post
    stefanodi, just to make it visible for those without your hardware, I built an AM generator only and used a Queue to output the final waveform to the Serial Plotter. As it sits, it runs 50% modulation. Oh, and I also brought the input from a sine wave generator. Here is the INO:
    Code:
    // AM waveform fc = 11025 Hz, fm=441 Hz.
    // Teensy audio
    // Turn on Tools>Serial Plotter to see output
    // Bob L
    
    #include <Audio.h>
    
    #define IF_FREQ 11025.0  //15000//****sine gen.
    
    AudioSynthWaveformSine   sine1;
    AudioSynthWaveformDc     dc1;            //xy=80,871
    AudioInputI2S            i2s2;           //xy=83,989
    AudioFilterBiquad        biquad1;           //xy=224,981
    AudioSynthWaveform       waveform1;      //xy=240,1027
    AudioMixer4              mixer1;         //xy=242,901
    AudioEffectMultiply      multiply1;      //xy=381,930
    AudioRecordQueue         queue1;
    AudioOutputI2S           i2s1;           //xy=471,990
    AudioConnection          patchCord1(dc1, 0, mixer1, 0);
    AudioConnection          patchCord2(sine1, 0, biquad1, 0);
    AudioConnection          patchCord3(biquad1, 0, mixer1, 1);
    AudioConnection          patchCord4(waveform1, 0, multiply1, 1);
    AudioConnection          patchCord5(mixer1, 0, multiply1, 0);
    AudioConnection          patchCord6(multiply1, 0, queue1, 0);
    AudioControlSGTL5000     sgtl5000_1;     //xy=250,1081
    
    void setup() {
      Serial.begin(9600); delay(1000);
      AudioMemory(16);
      sgtl5000_1.enable();
      // The modulating waveform
      //sine1.amplitude(0.5f);     // 100% AM modulation
      sine1.amplitude(0.25f);     // 50% AM modulation
      sine1.frequency(441.0f);
      // The carrier, moved to fs/4 to minimize beats with the sample rate
      // Only a problem when looking at Serial Plotter, OK at 15 kHz over the air
      waveform1.begin(1.0f,IF_FREQ,WAVEFORM_SINE);
      dc1.amplitude(0.5f);    // Leave room for AM modulation
      mixer1.gain(0,1);
      mixer1.gain(1,1);
      biquad1.setLowpass(0,6000,0.7);  // Not needed for sine wve,
      biquad1.setHighpass(1,100,0.7);  //   but generally a good idea
      queue1.begin();
    }
    
    void loop() {
      static int count = 0;
      if(queue1.available() > 0)
         {
         count++;
         int16_t* pi = queue1.readBuffer();
         for (int ii=0; ii<128; ii++)
           if(count<10) Serial.println(*(pi+ii));
         queue1.freeBuffer();
         }
    }
    And also, my post #6 had an extra unconnected sine wave generator---not being use and harmless.

    Have fun with all this!
    Great! Now it's really good! I think, some other RADIO NOSTALGIC will be happy. Thanks again Bob!
    Stefano.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •