diff --git a/examples/CESSB1/CESSB1.ino b/examples/CESSB1/CESSB1.ino new file mode 100644 index 0000000..6caf23e --- /dev/null +++ b/examples/CESSB1/CESSB1.ino @@ -0,0 +1,218 @@ +/* CESSB1.ino + * + * This INO tests the Dave Hershberger Controlled Envelope Single Sideband + * transmit generator radioCESSBtransmit_F32. This was developed By W9GR + * with the aim to "allow your rig to output more average power while + * keeping peak envelope power PEP the same". The increase in perceived + * loudness can be up to 4dB without any audible increase in distortion + * and without making you sound "processed." See radioCESSBTransmit_F32.h + * for more information and references. + * + * Your microSD card must have the WAV file W9GR48.WAV loaded to it. Source: + * https://github.com/chipaudette/OpenAudio_ArduinoLibrary/blob/master/utility/ + * + * The SD card may connect to different pins, depending on the + * hardware you are using. Configure the SD card + * pins to match your hardware. It is set for T4.x Rev D PJRC + * Teensy Audio Adaptor card here. + * + * This example code is in the public domain. + */ + +#include +#include +#include +#include +#include "OpenAudio_ArduinoLibrary.h" + +// Normal input is from the WAV file with W9GR voice. +// An alternative is two tones. Compile that with the following define. +// #define USE_TWO_TONE + +// T3.x supported sample rates: 2000, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 44117, 48000, +// 88200, 88235 (44117*2), 95680, 96000, 176400, 176470, 192000 +// T4.x supports any sample rate the codec will handle. +const float sample_rate_Hz = 48000.0f; +const int audio_block_samples = 128; // Always 128, which is AUDIO_BLOCK_SAMPLES from AudioStream.h +AudioSettings_F32 audio_settings(sample_rate_Hz, audio_block_samples); + +#ifdef USE_TWO_TONE +AudioSynthWaveformSine_F32 sine3(audio_settings); //xy=231,444 +AudioSynthWaveformSine_F32 sine4(audio_settings); //xy=259,345 +AudioMixer4_F32 mixer4_4; //xy=405,427 +#endif +AudioSDPlayer_F32 playWav1(audio_settings); //xy=111,51 +radioCESSBtransmit_F32 cessb1(audio_settings); +RadioIQMixer_F32 iqMixer2(audio_settings); //xy=100,300 +AudioFilter90Deg_F32 filter90deg1(audio_settings); //xy=250,300 +RadioIQMixer_F32 iqMixer1(audio_settings); //xy=250,150 +AudioAnalyzeRMS_F32 rms1; //xy=300,50 +AudioMixer4_F32 mixer4_1; //xy=400,310 +AudioMixer4_F32 mixer4_2; //xy=400,150 +AudioOutputI2S_F32 audioOutput(audio_settings); //xy=520,250 +AudioAnalyzeFFT1024_F32 fft1; //xy=550,125 + +#ifdef USE_TWO_TONE +AudioConnection_F32 patchCorda(sine3, 0, mixer4_4, 1); +AudioConnection_F32 patchCordb(sine4, 0, mixer4_4, 0); +AudioConnection_F32 patchCordc(mixer4_4, 0, cessb1, 0); +#else +AudioConnection_F32 patchCord5(playWav1, 0, cessb1, 0); +#endif +AudioConnection_F32 patchCord1(cessb1, 0, iqMixer1, 0); +AudioConnection_F32 patchCord2(cessb1, 1, iqMixer1, 1); +AudioConnection_F32 patchCord9(iqMixer1, 0, mixer4_2, 0); +AudioConnection_F32 patchCord10(iqMixer1, 1, mixer4_2, 1); +AudioConnection_F32 patchCord13(mixer4_2, fft1); // Transmitter output +// mixer4_2 is transmitter SSB output, iqMixer2 is receiver input +AudioConnection_F32 patchCord14(mixer4_2, 0, iqMixer2, 0); +AudioConnection_F32 patchCord3(iqMixer2, 0, filter90deg1, 0); +AudioConnection_F32 patchCord4(iqMixer2, 1, filter90deg1, 1); +AudioConnection_F32 patchCord7(filter90deg1, 0, mixer4_1, 0); +AudioConnection_F32 patchCord8(filter90deg1, 1, mixer4_1, 1); +AudioConnection_F32 patchCord11(mixer4_1, 0, audioOutput, 0); +AudioConnection_F32 patchCord12(mixer4_1, 0, audioOutput, 1); +AudioControlSGTL5000 sgtl5000_1; //xy=582,327 + +// Use these with the Teensy 4.x Rev D Audio Shield (NOT for T3.x) +#define SDCARD_CS_PIN 10 +#define SDCARD_MOSI_PIN 11 +#define SDCARD_SCK_PIN 13 + +// Filter for AudioFilter90Deg_F32 hilbert1, for the test receiver. +#include "hilbert251A.h" + +// This provides information about the current WAV file to this .INO +struct wavData* pCurrentWavData; +struct levels* pLevelData; +uint32_t writeOne = 0; + +uint32_t cntFFT = 0; + +void setup() { // ********** SETUP ********** + Serial.begin(9600); delay(1000); + Serial.println("*** F32 WAV from SD Card ***"); + AudioMemory_F32(70, audio_settings); + + pCurrentWavData = playWav1.getCurrentWavData(); + + sgtl5000_1.enable(); + + SPI.setMOSI(SDCARD_MOSI_PIN); + SPI.setSCK(SDCARD_SCK_PIN); + Serial.print("SD.begin() returns "); + Serial.println(SD.begin(SDCARD_CS_PIN)); + +#ifdef USE_TWO_TONE + // Two-tone test, multiples of 48000/1024 Hz + sine3.frequency(468.75f); + sine3.amplitude(0.5f); + + sine4.frequency(703.125f); + sine4.amplitude(0.5f); +#endif + + // Build the CESSB SSB transmitter + cessb1.setSampleRate_Hz(48000.0f); // Required + // Set input, correction, and output gains + float32_t Pre_CESSB_Gain = 1.5f; // Sets the amount of clipping, 1.0 to 2.0f, 3 is excessive + cessb1.setGains(Pre_CESSB_Gain, 2.0f, 1.0f); + cessb1.setSideband(false); // true reverses the sideband + pLevelData = cessb1.getLevels(0); // Gets pointer to struct + + // Generate SSB at 15 kHz + iqMixer1.useTwoChannel(true); + iqMixer1.useSimple(false); // enables setGainOut() + // Following if cessb1.setSideband(false), otherwise reverse + + // Compensate for window loss in FFT as well as x2 for mixers + iqMixer1.setGainOut(2.76f); + iqMixer1.frequency(13650); // 13650 for LSB, 16350 for USB + mixer4_2.gain(1, 1.0f); // 1.0f for LSB, -1.0f for USB + + // A receiver for the SSB transmitter + iqMixer2.frequency(15000.0f); + iqMixer2.useTwoChannel(false); + + filter90deg1.begin(hilbert251A, 251); // Set the Hilbert transform FIR filter + mixer4_1.gain(0, -1.0f); // LSB + for USB + audioOutput.setGain(0.05); // <<< Output volume control + fft1.setOutputType(FFT_DBFS); + fft1.windowFunction(AudioWindowBlackmanHarris1024); + fft1.setNAverage(16); +} + +void playFile(const char *filename) +{ + + if(playWav1.isPlaying()) + return; + Serial.println(""); + Serial.print("Playing file: "); + Serial.println(filename); + // Allow for running the WAV file at a sub-rate from the Audio rate + // Two of these are defined above for 1 and 4 sub rates. +// playWav1.setSubMult(&wavQuarter); + // Start playing the file. This sketch continues to + // run while the file plays. + playWav1.play(filename); + // A brief delay for the library read WAV info + delay(25); + + Serial.print("WAV file format = "); Serial.println(pCurrentWavData->audio_format); + Serial.print("WAV number channels = "); Serial.println(pCurrentWavData->num_channels); + Serial.print("WAV File Sample Rate = "); Serial.println(pCurrentWavData->sample_rate); + Serial.print("Number of bits per Sample = "); Serial.println(pCurrentWavData->bits); + Serial.print("File length, seconds = "); + Serial.println(0.001f*(float32_t)playWav1.lengthMillis(), 3); +} + +void loop() { + // Thanks to W9GR for the test files. These are intended for testing + // the CESSB radio transmission system (see CESSB1.ino in the examples) + // but work well to provide a voice bandwidth test of WAV file reading. +#ifndef USE_TWO_TONE + playFile("W9GR48.WAV"); // filenames are always uppercase 8.3 format +#endif + + if(fft1.available() && ++cntFFT>100 && cntFFT<102) + { + for(int kk=0; kk<512; kk++) + { + Serial.print(46.875f*(float32_t)kk); Serial.print(","); + Serial.println(fft1.read(kk)); + } + } + + if(cessb1.levelDataCount() > 300) // Typically 300 to 3000 + { + cessb1.getLevels(1); // Cause write of data to struct & reset + +/* // Detailed Report Uncomment to print + Serial.print(10.0f*log10f(pLevelData->pwr0)); + Serial.print(" In Ave Pwr Out "); + Serial.println(10.0f*log10f(pLevelData->pwr1)); + Serial.print(20.0f*log10f(pLevelData->peak0)); + Serial.print(" In Peak Out "); + Serial.println(20.0f*log10f(pLevelData->peak1)); + Serial.print(pLevelData->peak0, 6); + Serial.print(" In Peak Volts Out "); + Serial.println(pLevelData->peak1, 6); + Serial.print("Enhancement = "); + Serial.print((10.0f*log10f(pLevelData->pwr1) - 20.0f*log10f(pLevelData->peak1)) - + (10.0f*log10f(pLevelData->pwr0) - 20.0f*log10f(pLevelData->peak0)) ); + Serial.println(" dB"); + */ + +/* + // CSV Report suitable for entering to spread sheet, Uncomment to print + // InAve, InPk, OutAve, OutPk, EnhancementdB + Serial.print(pLevelData->pwr0, 5); Serial.print(","); + Serial.print(pLevelData->peak0, 5); Serial.print(","); + Serial.print(pLevelData->pwr1, 5); Serial.print(","); + Serial.print(pLevelData->peak1, 5); Serial.print(","); + Serial.println((10.0f*log10f(pLevelData->pwr1) - 20.0f*log10f(pLevelData->peak1)) - + (10.0f*log10f(pLevelData->pwr0) - 20.0f*log10f(pLevelData->peak0)) ); + */ + } + } // End loop() diff --git a/examples/CESSB1/CESSB1BlockDiagram.png b/examples/CESSB1/CESSB1BlockDiagram.png new file mode 100644 index 0000000..b6e90f0 Binary files /dev/null and b/examples/CESSB1/CESSB1BlockDiagram.png differ diff --git a/examples/CESSB1/hilbert251A.h b/examples/CESSB1/hilbert251A.h new file mode 100644 index 0000000..745db86 --- /dev/null +++ b/examples/CESSB1/hilbert251A.h @@ -0,0 +1,253 @@ +// Following is 251 term Hilbert FIR filter +float32_t hilbert251A[]={ +0.0000003255, +0.0000000000, +0.0000030702, +0.0000000000, +0.0000089286, +0.0000000000, +0.0000183061, +0.0000000000, +0.0000316287, +0.0000000000, +0.0000493436, +0.0000000000, +0.0000719193, +0.0000000000, +0.0000998451, +0.0000000000, +0.0001336320, +0.0000000000, +0.0001738120, +0.0000000000, +0.0002209393, +0.0000000000, +0.0002755899, +0.0000000000, +0.0003383625, +0.0000000000, +0.0004098790, +0.0000000000, +0.0004907853, +0.0000000000, +0.0005817525, +0.0000000000, +0.0006834782, +0.0000000000, +0.0007966881, +0.0000000000, +0.0009221383, +0.0000000000, +0.0010606178, +0.0000000000, +0.0012129515, +0.0000000000, +0.0013800041, +0.0000000000, +0.0015626848, +0.0000000000, +0.0017619529, +0.0000000000, +0.0019788241, +0.0000000000, +0.0022143787, +0.0000000000, +0.0024697715, +0.0000000000, +0.0027462425, +0.0000000000, +0.0030451312, +0.0000000000, +0.0033678928, +0.0000000000, +0.0037161183, +0.0000000000, +0.0040915578, +0.0000000000, +0.0044961498, +0.0000000000, +0.0049320558, +0.0000000000, +0.0054017033, +0.0000000000, +0.0059078375, +0.0000000000, +0.0064535860, +0.0000000000, +0.0070425380, +0.0000000000, +0.0076788436, +0.0000000000, +0.0083673390, +0.0000000000, +0.0091137048, +0.0000000000, +0.0099246683, +0.0000000000, +0.0108082660, +0.0000000000, +0.0117741868, +0.0000000000, +0.0128342256, +0.0000000000, +0.0140028938, +0.0000000000, +0.0152982506, +0.0000000000, +0.0167430570, +0.0000000000, +0.0183664064, +0.0000000000, +0.0202060801, +0.0000000000, +0.0223120327, +0.0000000000, +0.0247516963, +0.0000000000, +0.0276183140, +0.0000000000, +0.0310445375, +0.0000000000, +0.0352256211, +0.0000000000, +0.0404611696, +0.0000000000, +0.0472354231, +0.0000000000, +0.0563851215, +0.0000000000, +0.0694911881, +0.0000000000, +0.0899418673, +0.0000000000, +0.1265473875, +0.0000000000, +0.2116132716, +0.0000000000, +0.6358933477, +0.0000000000, +-0.6358933478, +0.0000000000, +-0.2116132717, +0.0000000000, +-0.1265473876, +0.0000000000, +-0.0899418674, +0.0000000000, +-0.0694911882, +0.0000000000, +-0.0563851216, +0.0000000000, +-0.0472354232, +0.0000000000, +-0.0404611697, +0.0000000000, +-0.0352256212, +0.0000000000, +-0.0310445376, +0.0000000000, +-0.0276183141, +0.0000000000, +-0.0247516964, +0.0000000000, +-0.0223120328, +0.0000000000, +-0.0202060802, +0.0000000000, +-0.0183664065, +0.0000000000, +-0.0167430571, +0.0000000000, +-0.0152982507, +0.0000000000, +-0.0140028939, +0.0000000000, +-0.0128342257, +0.0000000000, +-0.0117741869, +0.0000000000, +-0.0108082661, +0.0000000000, +-0.0099246684, +0.0000000000, +-0.0091137049, +0.0000000000, +-0.0083673391, +0.0000000000, +-0.0076788437, +0.0000000000, +-0.0070425381, +0.0000000000, +-0.0064535861, +0.0000000000, +-0.0059078376, +0.0000000000, +-0.0054017034, +0.0000000000, +-0.0049320559, +0.0000000000, +-0.0044961499, +0.0000000000, +-0.0040915579, +0.0000000000, +-0.0037161184, +0.0000000000, +-0.0033678929, +0.0000000000, +-0.0030451313, +0.0000000000, +-0.0027462426, +0.0000000000, +-0.0024697716, +0.0000000000, +-0.0022143788, +0.0000000000, +-0.0019788242, +0.0000000000, +-0.0017619530, +0.0000000000, +-0.0015626849, +0.0000000000, +-0.0013800042, +0.0000000000, +-0.0012129516, +0.0000000000, +-0.0010606179, +0.0000000000, +-0.0009221384, +0.0000000000, +-0.0007966882, +0.0000000000, +-0.0006834783, +0.0000000000, +-0.0005817526, +0.0000000000, +-0.0004907854, +0.0000000000, +-0.0004098791, +0.0000000000, +-0.0003383626, +0.0000000000, +-0.0002755900, +0.0000000000, +-0.0002209394, +0.0000000000, +-0.0001738121, +0.0000000000, +-0.0001336321, +0.0000000000, +-0.0000998452, +0.0000000000, +-0.0000719194, +0.0000000000, +-0.0000493437, +0.0000000000, +-0.0000316288, +0.0000000000, +-0.0000183062, +0.0000000000, +-0.0000089287, +0.0000000000, +-0.0000030703, +0.0000000000, +-0.0000003256};