mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
#35 Updates AM & NBFM decoders to use Adaptive Squelch, a power squelch that includes an adaptive noise floor monitor. Implements vectorized magnitude operations for AM & FM decoders. Adds talkgroup assignment and squelch controls to AM channel configuration editor. Implements new AM gain control that attempts to normalize audio gain quickly at beginning of call/transmission and maintains that gain across lifecycle of the call and resets the gain for the next call. (#1540)
Notes on usage: - When using either AM or FM squelch control use either the Heterodyne channelizer or if using the Polyphase channelizer, avoid using trunk tracking decoders like DMR or P25 or set the squelch threshold high enough to avoid changes in noise floor from polyphase channelizer where it can vary between using the one channel or the two-channel combined channel sources. Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,52 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.am;
|
||||
|
||||
import io.github.dsheirer.dsp.am.SquelchingAMDemodulator;
|
||||
import io.github.dsheirer.dsp.gain.AudioGainAndDcFilter;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.PrimaryDecoder;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.module.decode.analog.SquelchingAnalogDecoder;
|
||||
|
||||
public class AMDecoder extends PrimaryDecoder
|
||||
/**
|
||||
* Analog AM radio decoder module with integrated squelching control
|
||||
*/
|
||||
public class AMDecoder extends SquelchingAnalogDecoder
|
||||
{
|
||||
public AMDecoder( DecodeConfiguration config )
|
||||
{
|
||||
super( config );
|
||||
}
|
||||
private static final float DEMODULATOR_GAIN = 250.0f;
|
||||
private static final float SQUELCH_ALPHA_DECAY = 0.0004f;
|
||||
private static final float MINIMUM_GAIN = 0.5f;
|
||||
private static final float MAXIMUM_GAIN = 16.0f;
|
||||
private static final float OBJECTIVE_AUDIO_AMPLITUDE = 0.75f;
|
||||
private AudioGainAndDcFilter mAGC = new AudioGainAndDcFilter(MINIMUM_GAIN, MAXIMUM_GAIN, OBJECTIVE_AUDIO_AMPLITUDE);
|
||||
|
||||
@Override
|
||||
public DecoderType getDecoderType()
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param config for the AM channel.
|
||||
*/
|
||||
public AMDecoder(DecodeConfigAM config)
|
||||
{
|
||||
return DecoderType.AM;
|
||||
super(config, new SquelchingAMDemodulator(DEMODULATOR_GAIN, SQUELCH_ALPHA_DECAY,
|
||||
config.getSquelchThreshold(), config.isSquelchAutoTrack()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return DecoderType.AM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Overrides the broadcast of the final demodulated audio samples so that we can apply AGC
|
||||
* @param demodulatedSamples to broadcast
|
||||
*/
|
||||
@Override
|
||||
protected void broadcast(float[] demodulatedSamples)
|
||||
{
|
||||
//Apply audio gain and rebroadcast
|
||||
super.broadcast(mAGC.process(demodulatedSamples));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the notify call start so that we can reset the AGC
|
||||
*/
|
||||
@Override
|
||||
protected void notifyCallStart()
|
||||
{
|
||||
mAGC.reset();
|
||||
super.notifyCallStart();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.am;
|
||||
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.string.SimpleStringIdentifier;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.analog.AnalogDecoderState;
|
||||
|
||||
/**
|
||||
* AM decoder state
|
||||
*/
|
||||
public class AMDecoderState extends AnalogDecoderState
|
||||
{
|
||||
private String mChannelName;
|
||||
private Identifier mChannelNameIdentifier;
|
||||
private Identifier mTalkgroupIdentifier;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param channelName to use for this channel
|
||||
* @param decodeConfig with talkgroup identifier
|
||||
*/
|
||||
public AMDecoderState(String channelName, DecodeConfigAM decodeConfig)
|
||||
{
|
||||
mChannelName = (channelName != null && !channelName.isEmpty()) ? channelName : "AM CHANNEL";
|
||||
mChannelNameIdentifier = new SimpleStringIdentifier(mChannelName, IdentifierClass.CONFIGURATION, Form.CHANNEL_NAME, Role.ANY);
|
||||
mTalkgroupIdentifier = new AMTalkgroup(decodeConfig.getTalkgroup());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return DecoderType.AM;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Identifier getChannelNameIdentifier()
|
||||
{
|
||||
return mChannelNameIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Identifier getTalkgroupIdentifier()
|
||||
{
|
||||
return mTalkgroupIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivitySummary()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Activity Summary\n");
|
||||
sb.append("\tDecoder: AM");
|
||||
sb.append("\n\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.am;
|
||||
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
* AM talkgroup. Note: this is a logical identifier that is assignable from a user-specified
|
||||
* configuration so that AM audio events are compatible with other features of the sdrtrunk system.
|
||||
*/
|
||||
public class AMTalkgroup extends TalkgroupIdentifier
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param value 1-65,535
|
||||
*/
|
||||
public AMTalkgroup(int value)
|
||||
{
|
||||
super(value, Role.TO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return Protocol.AM;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -15,33 +14,35 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.am;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.module.decode.analog.DecodeConfigAnalog;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
|
||||
public class DecodeConfigAM extends DecodeConfiguration
|
||||
/**
|
||||
* AM decoder configuration
|
||||
*/
|
||||
public class DecodeConfigAM extends DecodeConfigAnalog
|
||||
{
|
||||
private boolean mRecordAudio = false;
|
||||
|
||||
public DecodeConfigAM()
|
||||
{
|
||||
}
|
||||
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "recordAudio")
|
||||
public boolean getRecordAudio()
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return mRecordAudio;
|
||||
return DecoderType.AM;
|
||||
}
|
||||
|
||||
public void setRecordAudio(boolean recordAudio)
|
||||
@Override
|
||||
protected Bandwidth getDefaultBandwidth()
|
||||
{
|
||||
mRecordAudio = recordAudio;
|
||||
return Bandwidth.BW_15_0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,13 +52,20 @@ public class DecodeConfigAM extends DecodeConfiguration
|
||||
@Override
|
||||
public ChannelSpecification getChannelSpecification()
|
||||
{
|
||||
return new ChannelSpecification(25000.0,
|
||||
3000, 3000.0, 5000.0);
|
||||
}
|
||||
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return DecoderType.AM;
|
||||
switch(getBandwidth())
|
||||
{
|
||||
case BW_3_0:
|
||||
return new ChannelSpecification(25000.0, 3000, 1500.0, 1700.0);
|
||||
case BW_5_0:
|
||||
return new ChannelSpecification(25000.0, 5000, 2500.0, 2700.0);
|
||||
case BW_8_33:
|
||||
return new ChannelSpecification(25000.0, 10000, 5000.0, 7000.0);
|
||||
case BW_15_0:
|
||||
return new ChannelSpecification(25000.0, 15000, 7500.0, 9500.0);
|
||||
case BW_25_0:
|
||||
return new ChannelSpecification(25000.0, 25000, 12500.0, 14500.0);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized AM bandwidth value: " + getBandwidth());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user