parent
2118306ed9
commit
c8291c2d32
@ -0,0 +1,207 @@ |
|||||||
|
/*
|
||||||
|
* radioCWModulator_F32.cpp |
||||||
|
* |
||||||
|
* Created: Bob larkin W7PUA March 2023 |
||||||
|
* |
||||||
|
* License: MIT License. Use at your own risk. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "radioCWModulator_F32.h" |
||||||
|
#include "sinTable512_f32.h" |
||||||
|
|
||||||
|
void radioCWModulator_F32::update(void) { |
||||||
|
float32_t keyData[128]; // CW key down and up, 0.0f and 1.0f
|
||||||
|
float32_t modulateCW[128]; // Storage for data to modulate sine wave
|
||||||
|
uint16_t index, i; |
||||||
|
float32_t a, b; |
||||||
|
audio_block_f32_t *blockOut; |
||||||
|
|
||||||
|
blockOut = AudioStream_F32::allocate_f32(); // Output block
|
||||||
|
if (!blockOut) return; |
||||||
|
|
||||||
|
// A new character cannot enter sendBuffer during an interrupt, but
|
||||||
|
// the state IDLE_CW can be created by some other state ending.
|
||||||
|
// So it needs to be in the audio sample loop.
|
||||||
|
|
||||||
|
// We always generate CW at 12 ksps. The number of data points in this
|
||||||
|
// generation varies to provide 128 output output points after
|
||||||
|
// interpolation to 48 or 96 ksps.
|
||||||
|
for(i=0; i<nSamplesPerUpdate; i++) |
||||||
|
{ |
||||||
|
timeMsF += timeSamplesMs; |
||||||
|
timeMsI = (uint32_t)(0.5 + timeMsF); |
||||||
|
|
||||||
|
if(!enableXmit) // Just leave the key up and no new characters
|
||||||
|
{ |
||||||
|
levelCW = 0.0f; |
||||||
|
goto noXmit; |
||||||
|
} |
||||||
|
|
||||||
|
switch(stateCW) |
||||||
|
{ |
||||||
|
case IDLE_CW: |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
if(((indexW-indexR)&0X1FF) > 0) // Get next char, if available
|
||||||
|
{ |
||||||
|
c = sendBuffer[indexR]; |
||||||
|
if (c>95) |
||||||
|
c -= 64; // Convert lc to caps
|
||||||
|
else |
||||||
|
c -= 32; // Move subscript to (0, 63)
|
||||||
|
ic = mc[(int)c]; // Ch to morse code lookup
|
||||||
|
if (c==27) // Long Dash from ';'
|
||||||
|
{ |
||||||
|
stateCW = LONG_DASH; |
||||||
|
levelCW = 1.0f; |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
} |
||||||
|
else if (ic==0X17) // A space character
|
||||||
|
{ |
||||||
|
stateCW = WORD_SPACE; |
||||||
|
levelCW = 0.0f; |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
} |
||||||
|
else if(ic>1 && (ic & 1)==0x01) |
||||||
|
{ |
||||||
|
stateCW = DASH_CW; |
||||||
|
levelCW = 1.0f; |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
} |
||||||
|
else if(ic>1 && (ic & 1)==0X00) |
||||||
|
{ |
||||||
|
stateCW = DOT_CW; |
||||||
|
levelCW = 1.0f; |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
} |
||||||
|
else if(ic==0X01) |
||||||
|
{ |
||||||
|
stateCW = IDLE_CW; |
||||||
|
levelCW = 0.0f; |
||||||
|
} |
||||||
|
} // end, if new character
|
||||||
|
break; |
||||||
|
case DASH_CW: |
||||||
|
if(timeMsI > dashCW) // Finished dash
|
||||||
|
{ |
||||||
|
levelCW = 0.0f; |
||||||
|
if(ic>1) ic >>= 1; // Shift right 1
|
||||||
|
if(ic==1) |
||||||
|
stateCW = CHAR_SPACE; |
||||||
|
else |
||||||
|
stateCW = DOT_DASH_SPACE; |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
} |
||||||
|
break; |
||||||
|
case DOT_CW: |
||||||
|
if(timeMsI > dotCW) |
||||||
|
{ |
||||||
|
levelCW = 0.0f; |
||||||
|
if(ic>1) ic >>= 1; // Shift right 1
|
||||||
|
if(ic==1) |
||||||
|
stateCW = CHAR_SPACE; |
||||||
|
else |
||||||
|
stateCW = DOT_DASH_SPACE; |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
} |
||||||
|
break; |
||||||
|
case DOT_DASH_SPACE: |
||||||
|
if(timeMsI > ddCW) // Just finished
|
||||||
|
{ |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
if(ic>1 && (ic & 1)==0x01) |
||||||
|
{ |
||||||
|
stateCW = DASH_CW; |
||||||
|
levelCW = 1.0f; |
||||||
|
} |
||||||
|
else if(ic>1 && (ic & 1)==0X00) |
||||||
|
{ |
||||||
|
stateCW = DOT_CW; |
||||||
|
levelCW = 1.0f; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
stateCW = IDLE_CW; |
||||||
|
levelCW = 0.0; |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
case CHAR_SPACE: |
||||||
|
if(timeMsI > chCW+ddCW) // Just finished sending a character
|
||||||
|
// chCW+ddCW sounds better than chCW to me.
|
||||||
|
{ |
||||||
|
indexR++; // Sending is ended, bump the read index
|
||||||
|
indexR = indexR & 0X1FF; // Confine to (0, 511)
|
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
stateCW = IDLE_CW; |
||||||
|
break; |
||||||
|
} |
||||||
|
case WORD_SPACE: |
||||||
|
if(timeMsI > spCW) // Just finished sending a space
|
||||||
|
{ |
||||||
|
indexR++; // Sending is ended, bump the read index
|
||||||
|
indexR = indexR & 0X1FF; // Confine to (0, 511)
|
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
stateCW = IDLE_CW; |
||||||
|
break; |
||||||
|
} |
||||||
|
case LONG_DASH: |
||||||
|
if(timeMsI > longDashCW) // Just finished sending a long dash
|
||||||
|
{ |
||||||
|
levelCW = 0.0f; |
||||||
|
stateCW = CHAR_SPACE; |
||||||
|
timeMsF = 0.0f; |
||||||
|
timeMsI = 0; |
||||||
|
break; |
||||||
|
} |
||||||
|
} // end switch
|
||||||
|
noXmit: |
||||||
|
keyData[i] = levelCW; |
||||||
|
} // end, over all 128 times
|
||||||
|
|
||||||
|
arm_fir_f32(&GaussLPFInst, keyData, keyData, nSamplesPerUpdate); |
||||||
|
|
||||||
|
// INTERPOLATE - Interpolate here to support higher sample rates,
|
||||||
|
// while using the same spectral LPF. To this point we have 128, 32
|
||||||
|
// or 16 "active" data points for 12, 48, or 96ksps.
|
||||||
|
//
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 i
|
||||||
|
// 0 0 0 0 1 1 1 1 2 2 i/4
|
||||||
|
// t 0 0 0 t 0 0 0 t 0 i==4*(i/4)
|
||||||
|
//
|
||||||
|
if(nSample > 1) // Only needs interpolation if >1
|
||||||
|
{ |
||||||
|
for(i=0; i<128; i++) |
||||||
|
{ |
||||||
|
if( i==(nSample*(1/nSample)) ) |
||||||
|
modulateCW[i]= keyData[i/nSample]; |
||||||
|
else |
||||||
|
modulateCW[i] = 0.0f; |
||||||
|
} |
||||||
|
arm_fir_f32(&interpolateLPFInst, modulateCW, keyData, 128); |
||||||
|
} |
||||||
|
|
||||||
|
// Interpolation is done, now amplitude modulate CW onto a sine wave.
|
||||||
|
for (i=0; i < 128; i++) |
||||||
|
{ |
||||||
|
phaseS += phaseIncrement; |
||||||
|
if (phaseS > 512.0f) phaseS -= 512.0f; |
||||||
|
index = (uint16_t) phaseS; |
||||||
|
float32_t deltaPhase = phaseS - (float32_t)index; |
||||||
|
// Read two nearest values of input value from the sine table
|
||||||
|
a = sinTable512_f32[index]; |
||||||
|
b = sinTable512_f32[index+1]; |
||||||
|
blockOut->data[i] = magnitude*keyData[i]*(a+(b-a)*deltaPhase); |
||||||
|
} |
||||||
|
AudioStream_F32::transmit(blockOut); |
||||||
|
AudioStream_F32::release (blockOut); |
||||||
|
} |
@ -0,0 +1,356 @@ |
|||||||
|
/*
|
||||||
|
* radioCWModulator_F32.h For the OpenAudio_TeensyArduino library |
||||||
|
* (floating point audio). |
||||||
|
* MIT License - Copyright March 2023 Bob Larkin, original write |
||||||
|
* |
||||||
|
* Parts of this are based on Audio Library for Teensy 3.x and 4.x that is |
||||||
|
* Copyright (c) 2023, Paul Stoffregen, paul@pjrc.com |
||||||
|
* |
||||||
|
* Development of the Teensy audio library was funded by PJRC.COM, LLC by sales of |
||||||
|
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop |
||||||
|
* open source software by purchasing Teensy or other PJRC products. |
||||||
|
* |
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
|
* of this software and associated documentation files (the "Software"), to deal |
||||||
|
* in the Software without restriction, including without limitation the rights |
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
|
* copies of the Software, and to permit persons to whom the Software is |
||||||
|
* furnished to do so, subject to the following conditions: |
||||||
|
* |
||||||
|
* The above copyright notice, development funding notice, and this permission |
||||||
|
* notice shall be included in all copies or substantial portions of the Software. |
||||||
|
* |
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||||
|
* THE SOFTWARE. |
||||||
|
*/ |
||||||
|
/* The method comes directly from the UHFA program for the DSP-10 project of 1999
|
||||||
|
* by Bob Larkin. Much of the code comes from there, as well. |
||||||
|
* |
||||||
|
* Sample rates: The CW is generated at a sample rate of 12 ksps. This |
||||||
|
* supports a good Gaussian filter to limit the spectral width which is |
||||||
|
* equivalent to removing "key clicks." To use higher sample rates, the |
||||||
|
* generation is only done for every 2nd, 4th or 8th sample. The output |
||||||
|
* for sample rates above 12 ksps are interpolated. The supported sample |
||||||
|
* rates become 11.025, 12, 44.1, 48, 50, 88, 96 and 100 ksps or others |
||||||
|
* in those general ranges. |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
#ifndef radioCWModulator_F32_h_ |
||||||
|
#define radioCWModulator_F32_h_ |
||||||
|
|
||||||
|
#include "Arduino.h" |
||||||
|
#include "AudioStream_F32.h" |
||||||
|
|
||||||
|
class radioCWModulator_F32 : public AudioStream_F32 |
||||||
|
{ |
||||||
|
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
|
||||||
|
//GUI: shortName:DetCTCSS
|
||||||
|
public: |
||||||
|
radioCWModulator_F32(void) : AudioStream_F32(0, NULL) { |
||||||
|
sample_rate_Hz = AUDIO_SAMPLE_RATE; |
||||||
|
block_size = AUDIO_BLOCK_SAMPLES; |
||||||
|
initCW(); |
||||||
|
} |
||||||
|
// Option of AudioSettings_F32 change sample rate (always 128 block size):
|
||||||
|
radioCWModulator_F32(const AudioSettings_F32 &settings) : AudioStream_F32(0, NULL) { |
||||||
|
sample_rate_Hz = settings.sample_rate_Hz; |
||||||
|
block_size = AUDIO_BLOCK_SAMPLES; |
||||||
|
initCW(); |
||||||
|
} |
||||||
|
|
||||||
|
// Values for stateCW
|
||||||
|
#define IDLE_CW 0 |
||||||
|
#define DASH_CW 1 |
||||||
|
#define DOT_CW 2 |
||||||
|
#define DOT_DASH_SPACE 3 |
||||||
|
#define CHAR_SPACE 4 |
||||||
|
#define WORD_SPACE 5 |
||||||
|
#define LONG_DASH 6 |
||||||
|
|
||||||
|
void initCW(void) { // Public, but primarily for building objects. Not required in INO.
|
||||||
|
for(int kk=0; kk<512; kk++) |
||||||
|
sendBuffer[kk] = 0; |
||||||
|
indexW = 0; |
||||||
|
indexR = 0; |
||||||
|
setCWSpeedWPM(speedWPM); |
||||||
|
arm_fir_init_f32(&interpolateLPFInst, 59, &interpolateLPF[0], &interpolateLPFState[0], 128); |
||||||
|
setSampleRate_Hz(sample_rate_Hz); |
||||||
|
setFrequency(600.0f); |
||||||
|
} |
||||||
|
|
||||||
|
// Enables the operation of the update(). This is needed when there
|
||||||
|
// are separate transmit and receive times.
|
||||||
|
void enableTransmit(bool _transmit) { |
||||||
|
enableXmit = _transmit; |
||||||
|
} |
||||||
|
|
||||||
|
bool getEnableTransmit(void) { |
||||||
|
return enableXmit; |
||||||
|
} |
||||||
|
|
||||||
|
uint16_t getBufferSpace(void) { |
||||||
|
return 512 - ((indexW - indexR) & 0X1FF); |
||||||
|
} |
||||||
|
|
||||||
|
// Place character into queue for sending
|
||||||
|
bool sendCW(uint16_t _ch) { |
||||||
|
if(getBufferSpace() > 0) |
||||||
|
{ |
||||||
|
sendBuffer[indexW++] = _ch; |
||||||
|
indexW &= 0X1FF; |
||||||
|
return true; |
||||||
|
} |
||||||
|
else |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool sendStringCW(char* _pStr) |
||||||
|
{ |
||||||
|
uint16_t space = getBufferSpace(); |
||||||
|
uint16_t size = strlen(_pStr); |
||||||
|
// Serial.print(space); Serial.print(" space size "); Serial.println(size);
|
||||||
|
if(space < size) return false; |
||||||
|
for(int kk=0; kk<(int)strlen(_pStr); kk++) |
||||||
|
sendCW( (uint16_t)*(_pStr+kk) ); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void setCWSpeedWPM(uint16_t _speed) { |
||||||
|
uint16_t kk = 0; |
||||||
|
while(tCW[kk].speedWPM < _speed) |
||||||
|
kk++; |
||||||
|
speedIndex = kk; |
||||||
|
dotCW = (uint32_t)tCW[kk].dot; /* msec per dot */ |
||||||
|
dashCW = (uint32_t)tCW[kk].dash; /* msec per dash */ |
||||||
|
ddCW = (uint32_t)tCW[kk].dd; /* msec between dot or dash */ |
||||||
|
chCW = (uint32_t)tCW[kk].ch; /* msec at end of each char */ |
||||||
|
spCW = (uint32_t)tCW[kk].sp; /* msec for space char */ |
||||||
|
} |
||||||
|
|
||||||
|
void setFrequency(float32_t _freq) { // Defaults to 600 Hz
|
||||||
|
frequencyHz = _freq; |
||||||
|
if (frequencyHz < 0.0f) |
||||||
|
frequencyHz = 0.0f; |
||||||
|
if (frequencyHz > sample_rate_Hz/2.0f) |
||||||
|
frequencyHz = sample_rate_Hz/2.0f; |
||||||
|
phaseIncrement = 512.0f * frequencyHz / sample_rate_Hz; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void setLongDashMs(uint32_t _longDashMs) { // Defaults to 1000 mSec
|
||||||
|
longDashCW = _longDashMs; |
||||||
|
} |
||||||
|
|
||||||
|
// See note above on sample rates.
|
||||||
|
void setSampleRate_Hz (float32_t fs_Hz) { // (const float32_t &fs_Hz) {
|
||||||
|
sample_rate_Hz = fs_Hz; |
||||||
|
timeSamplesMs = 1000.0f/sample_rate_Hz; // In millisec
|
||||||
|
if(sample_rate_Hz>11000.0f && sample_rate_Hz<12100.0f) |
||||||
|
{ |
||||||
|
nSample = 1; |
||||||
|
nSamplesPerUpdate = 128; |
||||||
|
} |
||||||
|
else if(sample_rate_Hz>44000.0f && sample_rate_Hz<50100.0f) |
||||||
|
{ |
||||||
|
nSample = 4; |
||||||
|
nSamplesPerUpdate = 32; |
||||||
|
} |
||||||
|
else if(sample_rate_Hz>88000.0f && sample_rate_Hz<100100.0f) |
||||||
|
{ |
||||||
|
nSample = 8; |
||||||
|
nSamplesPerUpdate = 16; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
Serial.print(sample_rate_Hz); |
||||||
|
Serial.println(" sample rate not supported."); |
||||||
|
nSample = 4; |
||||||
|
nSamplesPerUpdate = 32; |
||||||
|
} |
||||||
|
arm_fir_init_f32(&GaussLPFInst, 145, &firGaussCoeffs[0], &GaussState[0], nSamplesPerUpdate); |
||||||
|
setFrequency(frequencyHz); |
||||||
|
} |
||||||
|
|
||||||
|
// The amplitude, a, is the peak, as in zero-to-peak. This produces outputs
|
||||||
|
// ranging from -a to +a.
|
||||||
|
void amplitude(float32_t _a) { |
||||||
|
if (_a < 0.0f) |
||||||
|
_a = 0.0f; |
||||||
|
magnitude = _a; |
||||||
|
} |
||||||
|
|
||||||
|
virtual void update(void); |
||||||
|
|
||||||
|
private: |
||||||
|
uint8_t sendBuffer[512]; // Circular send buffer
|
||||||
|
uint16_t indexW = 0; // Write index in to buffer
|
||||||
|
uint16_t indexR = 0; // Read index into buffer
|
||||||
|
float32_t sample_rate_Hz = AUDIO_SAMPLE_RATE; |
||||||
|
int16_t block_size = 128; |
||||||
|
int16_t nSample = 4; //
|
||||||
|
int16_t nSamplesPerUpdate = 32; |
||||||
|
uint16_t stateCW = IDLE_CW; |
||||||
|
uint8_t c = 0; |
||||||
|
uint16_t ic = 0; // Current character as integer
|
||||||
|
bool enableXmit = true; |
||||||
|
float32_t levelCW = 0.0f; // sample by sample
|
||||||
|
float32_t frequencyHz = 600.0f; |
||||||
|
float32_t phaseIncrement = 512.0f*frequencyHz/sample_rate_Hz; |
||||||
|
float32_t phaseS = 0.0f; |
||||||
|
float32_t magnitude = 1.0f; |
||||||
|
|
||||||
|
float32_t timeSamplesMs = 1000.0f/sample_rate_Hz; // In millisec
|
||||||
|
float32_t timeMsF = 0.0f; // Update the event clock
|
||||||
|
uint32_t timeMsI = 0; // This is easier to use
|
||||||
|
uint16_t speedWPM = 13; |
||||||
|
uint16_t speedIndex = 8; |
||||||
|
|
||||||
|
uint32_t dotCW; /* msec per dot */ |
||||||
|
uint32_t dashCW; /* msec per dash */ |
||||||
|
uint32_t ddCW; /* msec between dot or dash */ |
||||||
|
uint32_t chCW; /* msec at end of each char */ |
||||||
|
uint32_t spCW; /* msec for space char */ |
||||||
|
uint32_t longDashCW = 1000; |
||||||
|
|
||||||
|
float32_t* firGaussCoeffs = coeffLPFGaussCW70; |
||||||
|
arm_fir_instance_f32 GaussLPFInst; |
||||||
|
float32_t GaussState[128 + 145]; |
||||||
|
|
||||||
|
arm_fir_instance_f32 interpolateLPFInst; |
||||||
|
float32_t interpolateLPFState[128 + 59]; |
||||||
|
|
||||||
|
/* The following mc[] table defines the morse code sequences
|
||||||
|
* in terms of bits. Starting from lsb and continuing until only one |
||||||
|
* "1" remains, send a dot for a "0" and a dash for a "1", with |
||||||
|
* a right shift after each dot or dash. */ |
||||||
|
|
||||||
|
/* sp " $ ' */ |
||||||
|
const uint16_t mc[64] = {0x17,0x01,0x52,0x01,0xC8,0x01,0x01,0x5E, |
||||||
|
|
||||||
|
/* ( ) , - . / */ |
||||||
|
0x2D,0x6D,0x01,0x01,0x73,0x61,0x6A,0x29, |
||||||
|
|
||||||
|
/* 0 1 2 3 4 5 6 7 */ |
||||||
|
0x3f,0x3e,0x3c,0x38,0x30,0x20,0x21,0x23, |
||||||
|
|
||||||
|
/* ; = long dash 8 9 : ; = KN ? */ |
||||||
|
0x27,0x2f,0x47,0x01,0x01,0x31,0x2D,0x4C, |
||||||
|
|
||||||
|
/* @ A B C D E F G */ |
||||||
|
0x5a,0x06,0x11,0x15,0x09,0x02,0x14,0x0b, |
||||||
|
|
||||||
|
/* H I J K L M N O */ |
||||||
|
0x10,0x04,0x1e,0x0d,0x12,0x07,0x05,0x0f, |
||||||
|
|
||||||
|
/* P Q R S T U V W */ |
||||||
|
0x16,0x1b,0x0a,0x08,0x03,0x0c,0x18,0x0e, |
||||||
|
|
||||||
|
/* X Y Z AR AS SK Err _ */ |
||||||
|
0x19,0x1d,0x13,0x2A,0x22,0x68,0x80,0x6C}; |
||||||
|
|
||||||
|
/* The following set the weightings vs. code speed in wpm
|
||||||
|
* by selecting the delays for |
||||||
|
* .dot length of a dot in ms |
||||||
|
* .dash length of a dash in ms |
||||||
|
* .dd time between dots and dashes, ms |
||||||
|
* .ch time between characters of the same word, ms |
||||||
|
* .sp time duration between words, ms */ |
||||||
|
struct cw_data { |
||||||
|
uint16_t speedWPM; |
||||||
|
uint16_t dot; /* msec per dot */ |
||||||
|
uint16_t dash; /* msec per dash */ |
||||||
|
uint16_t dd; /* msec between dot or dash */ |
||||||
|
uint16_t ch; /* msec at end of each char */ |
||||||
|
uint16_t sp; /* msec for space char */ |
||||||
|
}; |
||||||
|
/* Note: Code speed can be any. There are 5 times in milliseconds that
|
||||||
|
* set the actual speed and weighting. The index (0, 28) allows 29 of these |
||||||
|
* that are initialized to 5 WPM to 50 WPM with nominal weightings. */ |
||||||
|
struct cw_data tCW[29] = { |
||||||
|
{ 5, 150, 530, 150, 900,1200}, |
||||||
|
{ 6, 140, 480, 140, 750,1000}, |
||||||
|
{ 7, 125, 430, 125, 550, 800}, |
||||||
|
{ 8, 120, 400, 120, 400, 725}, |
||||||
|
{ 9, 120, 380, 120, 300, 560}, |
||||||
|
{ 10, 120, 360, 120, 240, 480}, |
||||||
|
{ 11, 110, 330, 110, 220, 440}, |
||||||
|
{ 12, 100, 300, 100, 200, 400}, |
||||||
|
{ 13, 92, 276, 92, 184, 368}, |
||||||
|
{ 14, 86, 258, 86, 172, 344}, |
||||||
|
{ 15, 80, 240, 80, 160, 320}, |
||||||
|
{ 16, 75, 225, 75, 150, 300}, |
||||||
|
{ 17, 70, 212, 70, 142, 283}, |
||||||
|
{ 18, 66, 200, 66, 134, 267}, |
||||||
|
{ 19, 63, 189, 63, 126, 252}, |
||||||
|
{ 20, 60, 180, 60, 120, 240}, |
||||||
|
{ 21, 57, 171, 57, 114, 230}, |
||||||
|
{ 22, 55, 164, 55, 109, 220}, |
||||||
|
{ 23, 52, 157, 52, 105, 210}, |
||||||
|
{ 24, 50, 150, 50, 100, 200}, |
||||||
|
{ 25, 48, 144, 48, 96, 192}, |
||||||
|
{ 26, 47, 138, 47, 91, 185}, |
||||||
|
{ 27, 45, 133, 45, 88, 179}, |
||||||
|
{ 28, 43, 129, 43, 86, 172}, |
||||||
|
{ 29, 41, 124, 41, 83, 166}, |
||||||
|
{ 30, 40, 120, 40, 80, 160}, |
||||||
|
{ 35, 34, 103, 34, 69, 138}, |
||||||
|
{ 40, 30, 90, 30, 60, 120}, |
||||||
|
{ 50, 24, 72, 24, 48, 96}}; |
||||||
|
|
||||||
|
// CW LPF Gaussian 12 ksps, 70 Hz at 3 dB
|
||||||
|
float32_t coeffLPFGaussCW70[145] = { |
||||||
|
0.0000000994f, 0.0000002465f, 0.0000005437f, 0.0000010924f, 0.0000020348f, |
||||||
|
0.0000035609f, 0.0000059142f, 0.0000093971f, 0.0000143746f, 0.0000212771f, |
||||||
|
0.0000306017f, 0.0000429118f, 0.0000588363f, 0.0000790660f, 0.0001043500f, |
||||||
|
0.0001354903f, 0.0001733351f, 0.0002187713f, 0.0002727164f, 0.0003361089f, |
||||||
|
0.0004098986f, 0.0004950364f, 0.0005924635f, 0.0007031003f, 0.0008278357f, |
||||||
|
0.0009675161f, 0.0011229345f, 0.0012948202f, 0.0014838290f, 0.0016905333f, |
||||||
|
0.0019154139f, 0.0021588516f, 0.0024211200f, 0.0027023793f, 0.0030026708f, |
||||||
|
0.0033219125f, 0.0036598959f, 0.0040162835f, 0.0043906075f, 0.0047822700f, |
||||||
|
0.0051905436f, 0.0056145733f, 0.0060533799f, 0.0065058635f, 0.0069708087f, |
||||||
|
0.0074468905f, 0.0079326809f, 0.0084266565f, 0.0089272066f, 0.0094326423f, |
||||||
|
0.0099412055f, 0.0104510798f, 0.0109603999f, 0.0114672630f, 0.0119697396f, |
||||||
|
0.0124658847f, 0.0129537493f, 0.0134313915f, 0.0138968878f, 0.0143483444f, |
||||||
|
0.0147839080f, 0.0152017763f, 0.0156002085f, 0.0159775353f, 0.0163321678f, |
||||||
|
0.0166626067f, 0.0169674505f, 0.0172454031f, 0.0174952809f, 0.0177160188f, |
||||||
|
0.0179066758f, 0.0180664400f, 0.0181946320f, 0.0182907087f, 0.0183542653f, |
||||||
|
0.0183850369f, 0.0183828991f, 0.0183478684f, 0.0182801008f, 0.0181798905f, |
||||||
|
0.0180476675f, 0.0178839942f, 0.0176895623f, 0.0174651874f, 0.0172118049f, |
||||||
|
0.0169304634f, 0.0166223192f, 0.0162886292f, 0.0159307439f, 0.0155500995f, |
||||||
|
0.0151482106f, 0.0147266612f, 0.0142870968f, 0.0138312154f, 0.0133607587f, |
||||||
|
0.0128775032f, 0.0123832512f, 0.0118798218f, 0.0113690419f, 0.0108527375f, |
||||||
|
0.0103327249f, 0.0098108024f, 0.0092887417f, 0.0087682803f, 0.0082511135f, |
||||||
|
0.0077388875f, 0.0072331919f, 0.0067355538f, 0.0062474314f, 0.0057702081f, |
||||||
|
0.0053051882f, 0.0048535913f, 0.0044165491f, 0.0039951010f, 0.0035901916f, |
||||||
|
0.0032026682f, 0.0028332785f, 0.0024826695f, 0.0021513865f, 0.0018398728f, |
||||||
|
0.0015484699f, 0.0012774182f, 0.0010268582f, 0.0007968321f, 0.0005872861f, |
||||||
|
0.0003980729f, 0.0002289548f, 0.0000796069f,-0.0000503789f,-0.0001614900f, |
||||||
|
-0.0002542886f,-0.0003294068f,-0.0003875421f,-0.0004294517f,-0.0004559477f, |
||||||
|
-0.0004678910f,-0.0004661861f,-0.0004517752f,-0.0004256325f,-0.0003887583f, |
||||||
|
-0.0003421730f,-0.0002869118f,-0.0002240186f,-0.0001545404f,-0.0000795219f}; |
||||||
|
|
||||||
|
/* FIR filter designed with http://t-filter.appspot.com
|
||||||
|
Fs = 96000 Hz [48000] |
||||||
|
0 Hz to 4000 Hz [0 to 2000] actual ripple = 0.05 dB |
||||||
|
11000 Hz to 48000 Hz [5500 to 24000] actual atten = -93.1 dB */ |
||||||
|
float32_t interpolateLPF[59] = { |
||||||
|
-0.000052355f,-0.000146720f,-0.000307316f,-0.000517033f,-0.000721194f,-0.000819999f, |
||||||
|
-0.000680277f,-0.000169005f, 0.000793689f, 0.002172809f, 0.003767656f, 0.005194993f, |
||||||
|
0.005927352f, 0.005395822f, 0.003149023f,-0.000960853f,-0.006611837f,-0.012919698f, |
||||||
|
-0.018466308f,-0.021473003f,-0.020108212f,-0.012880252f, 0.000965492f, 0.021140621f, |
||||||
|
0.046185831f, 0.073574790f, 0.100053429f, 0.122161788f, 0.136838160f, 0.141979757f, |
||||||
|
0.136838160f, 0.122161788f, 0.100053429f, 0.073574790f, 0.046185831f, 0.021140621f, |
||||||
|
|
||||||
|
0.000965492f,-0.012880252f,-0.020108212f,-0.021473003f,-0.018466308f,-0.012919698f, |
||||||
|
-0.006611837f,-0.000960853f, 0.003149023f, 0.005395822f, 0.005927352f, 0.005194993f, |
||||||
|
0.003767656f, 0.002172809f, 0.000793689f,-0.000169005f,-0.000680277f,-0.000819999f, |
||||||
|
-0.000721194f,-0.000517033f,-0.000307316f,-0.000146720f,-0.000052355f}; |
||||||
|
|
||||||
|
}; |
||||||
|
#endif |
Loading…
Reference in new issue