From 90a2aad491038513c6e871739df5988a1e460d72 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 May 2023 16:21:59 +0200 Subject: [PATCH 01/23] new class Mikrofon --- .../main/java/com/example/ueberwachungssystem/Mikrofon.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java diff --git a/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java b/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java new file mode 100644 index 0000000..510d104 --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java @@ -0,0 +1,4 @@ +package com.example.ueberwachungssystem; + +public class Mikrofon { +} From 620528302e929f634db62079325acf23a3c29994 Mon Sep 17 00:00:00 2001 From: Leon Market Date: Wed, 24 May 2023 20:39:31 +0200 Subject: [PATCH 02/23] added Beschleunigungssensor --- .../Beschleunigungssensor.java | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java diff --git a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java new file mode 100644 index 0000000..e15dc5b --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java @@ -0,0 +1,86 @@ +package com.example.ueberwachungssystem; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import android.widget.TextView; +import com.example.ueberwachungssystem.Logger; + +public class Beschleunigungssensor extends AppCompatActivity implements SensorEventListener +{ + + private Logger logger; + private SensorManager sensorManager; + private int sensorType = Sensor.TYPE_ACCELEROMETER; + private Sensor sensor; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setTitle(this.getClass().getSimpleName()); + TextView textView = new TextView(this); + setContentView(textView); + + logger = new Logger(this.getClass().getSimpleName(),textView,""); + + sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); + if(sensorManager.getSensorList(sensorType).size()==0) + { + logger.log("Es gibt den gewünschten Sensor nicht"); + sensor = null; + } + else + { + sensor = sensorManager.getSensorList(sensorType).get(0); + } + } + + @Override + protected void onResume() + { + super.onResume(); + if(sensor != null) + { + if(sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME)) + { + logger.log("Wir haben uns beim Sensor angemeldet."); + } + else + { + logger.log("Das Anmelden beim Sensor hat nicht so gut geklappt"); + } + } + } + + @Override + protected void onPause() + { + super.onPause(); + if(sensor != null) { + sensorManager.unregisterListener(this, sensor); + logger.log("Wir haben uns beim Sensor abgemeldet"); + } + } + + @Override + public void onSensorChanged(SensorEvent event) + { + StringBuilder sb = new StringBuilder(); + sb.append("t=").append(event.timestamp) + .append("\nx=").append(event.values[0]) + .append("\ny=").append(event.values[1]) + .append("\nz=").append(event.values[2]); + logger.clearLog(); + logger.log(sb.toString()); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) + { + } +} From 4999f1b99827960a425da38f087b1ae13985f022 Mon Sep 17 00:00:00 2001 From: Leon Market Date: Wed, 24 May 2023 20:39:31 +0200 Subject: [PATCH 03/23] added Detector, DetectorReport, Logger --- .../Beschleunigungssensor.java | 83 +++++++++++++++++++ .../ueberwachungssystem/DetectionReport.java | 36 ++++++++ .../example/ueberwachungssystem/Detector.java | 39 +++++++++ .../example/ueberwachungssystem/Logger.java | 44 ++++++++++ .../ueberwachungssystem/MainActivity.java | 7 +- app/src/main/res/layout/activity_main.xml | 2 +- 6 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/DetectionReport.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Detector.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Logger.java diff --git a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java new file mode 100644 index 0000000..f15ae8e --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java @@ -0,0 +1,83 @@ +package com.example.ueberwachungssystem; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import android.widget.TextView; + +public class Beschleunigungssensor extends AppCompatActivity implements SensorEventListener +{ + private Logger logger; + private SensorManager sensorManager; + private int sensorType = Sensor.TYPE_ACCELEROMETER; + private Sensor sensor; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setTitle(this.getClass().getSimpleName()); + TextView textView = new TextView(this); + setContentView(textView); + + logger = new Logger(this.getClass().getSimpleName(),textView,""); + + sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); + if(sensorManager.getSensorList(sensorType).size()==0) + { + logger.log("Es gibt den gewünschten Sensor nicht"); + sensor = null; + } + else + { + sensor = sensorManager.getSensorList(sensorType).get(0); + } + } + + @Override + protected void onResume() + { + super.onResume(); + if(sensor != null) + { + if(sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME)) + { + logger.log("Wir haben uns beim Sensor angemeldet."); + } + else + { + logger.log("Das Anmelden beim Sensor hat nicht so gut geklappt"); + } + } + } + + @Override + protected void onPause() + { + super.onPause(); + if(sensor != null) { + sensorManager.unregisterListener(this, sensor); + logger.log("Wir haben uns beim Sensor abgemeldet"); + } + } + + @Override + public void onSensorChanged(SensorEvent event) + { + String sb = "t=" + event.timestamp + + "\nx=" + event.values[0] + // Wert legend: x = 0.04 + "\ny=" + event.values[1] + // Wert liegend: y = 0.44 + "\nz=" + event.values[2]; // Wert liegend: z = 9.90 = Erdbeschleunigung --> Wenn Ausrichtung unbekannt ist, müsste kalibrierung bei Start der Bewegungsüberwachung vorgenommen werden + logger.clearLog(); + logger.log(sb); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) + { + } +} diff --git a/app/src/main/java/com/example/ueberwachungssystem/DetectionReport.java b/app/src/main/java/com/example/ueberwachungssystem/DetectionReport.java new file mode 100644 index 0000000..bfcb52c --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/DetectionReport.java @@ -0,0 +1,36 @@ +package com.example.ueberwachungssystem; + +import android.util.Log; + +import java.util.Calendar; + +/** Detection Report Class */ +public class DetectionReport { + public String timeStamp; + public String detectionType; + public float detectedValue; + public String detectorID; + + public DetectionReport(String detectorID, String detectionType, float detectedAmplitude) { + this.timeStamp = String.valueOf(Calendar.getInstance().getTime()); + this.detectionType = detectionType; + this.detectedValue = detectedAmplitude; + this.detectorID = detectorID; + } + + + /** Get Detection Report in String format */ + public String toString() { + String time = "Time: " + "[" + this.timeStamp + "]"; + String type = "Type: " + "[" + this.detectionType + "]"; + String value = "Value: " + "[" + this.detectedValue + "]"; + String id = "ID: " + "[" + this.detectorID + "]"; + + return String.join("\t", time, type, value, id); + } + + /** Debug Report */ + public void log(String tag) { + Log.d(tag, this.toString()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/ueberwachungssystem/Detector.java b/app/src/main/java/com/example/ueberwachungssystem/Detector.java new file mode 100644 index 0000000..d09fe1f --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Detector.java @@ -0,0 +1,39 @@ +package com.example.ueberwachungssystem; + +import android.content.Context; +import androidx.annotation.NonNull; + + +abstract public class Detector { + private OnDetectionListener listener; + + /** Constructor - takes context of current activity */ + public Detector(Context context) {}; + + + /** On Detection Listener - runs when violation is reported */ + public interface OnDetectionListener { + void onDetection(@NonNull DetectionReport detectionReport); + } + public void setOnDetectionListener(@NonNull OnDetectionListener listener) { + this.listener = listener; + } + + + /** Triggers onDetectionListener - call this to trigger violation/alarm */ + private void reportViolation(String detectorID, String detectionType, float amplitude) { + if (listener != null) { + DetectionReport detectionReport = new DetectionReport(detectorID, detectionType, amplitude); + listener.onDetection(detectionReport); + } else { + throw new IllegalStateException("No listener set for violation reporting"); + } + } + + + /** Starts Detection (abstract method: needs to be overridden in child class) */ + public abstract void startDetection(); + + /** Stops Detection (abstract method: needs to be overridden in child class) */ + public abstract void stopDetection(); +} \ No newline at end of file diff --git a/app/src/main/java/com/example/ueberwachungssystem/Logger.java b/app/src/main/java/com/example/ueberwachungssystem/Logger.java new file mode 100644 index 0000000..86299fb --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Logger.java @@ -0,0 +1,44 @@ +package com.example.ueberwachungssystem; + +import android.widget.TextView; +import android.util.Log; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class Logger { + private TextView textView; + private StringBuffer sb = new StringBuffer(); + private String tag; + + public Logger(String tag, TextView textView, String logInitText) { + this.tag = tag; + this.textView = textView; + sb.append(logInitText); + } + + public void log(String s) { + Log.d(tag, s); + sb.append(s).append("\n"); + if (textView != null) { + textView.setText(sb.toString()); + } + } + public void log(Exception e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + log(sw.toString()); + } + + public void clearLog() { + sb.setLength(0); + if (textView != null) { + textView.setText(""); + } + } + + public String getLoggedText() { + return sb.toString(); + } +} + + diff --git a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java index f4fdae7..5a5c92a 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java +++ b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java @@ -4,11 +4,16 @@ import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; -public class MainActivity extends AppCompatActivity { +public class MainActivity extends AppCompatActivity{ + + private Logger logger; + private Beschleunigungssensor beschleunigungssensor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setTitle(this.getClass().getSimpleName()); setContentView(R.layout.activity_main); + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 17eab17..7762181 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity"> + tools:context=".MainActivityBackup"> Date: Thu, 25 May 2023 16:58:08 +0200 Subject: [PATCH 04/23] Move from Mikrofon to MicrophoneDetector class and add of abstract Detector class --- app/src/main/AndroidManifest.xml | 7 + .../ueberwachungssystem/DetectionReport.java | 36 ++ .../example/ueberwachungssystem/Detector.java | 40 +++ .../ueberwachungssystem/MainActivity.java | 55 +++ .../MicrophoneDetector.java | 333 ++++++++++++++++++ .../example/ueberwachungssystem/Mikrofon.java | 325 +++++++++++++++++ .../ueberwachungssystem/logger/Logger.java | 61 ++++ app/src/main/res/layout/activity_main.xml | 14 +- 8 files changed, 869 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/example/ueberwachungssystem/DetectionReport.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Detector.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/MicrophoneDetector.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/logger/Logger.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cef8f3d..397d997 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,13 @@ + + + + + + + { + private AudioRecord recorder; + private final int sampleRateInHz = 44100; + private final int channelConfig = AudioFormat.CHANNEL_IN_MONO; + private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT; + private int minPufferGroesseInBytes; + private int pufferGroesseInBytes; + private RingPuffer ringPuffer = new RingPuffer(10); + + AufnahmeTask() { + minPufferGroesseInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); + pufferGroesseInBytes = minPufferGroesseInBytes * 2; + recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, pufferGroesseInBytes); + +// textViewMinPufferGroesseInBytes.setText("" + minPufferGroesseInBytes); +// textViewPufferGroesseInBytes.setText("" + pufferGroesseInBytes); +// textViewAbtastrate.setText("" + recorder.getSampleRate()); +// textViewAnzahlKanaele.setText("" + recorder.getChannelCount()); + + logger.log("Puffergroeße: "+ minPufferGroesseInBytes + " " + pufferGroesseInBytes); + logger.log("Recorder (SR, CH): "+ recorder.getSampleRate() + " " + recorder.getChannelCount()); + + int anzahlBytesProAbtastwert; + String s; + switch (recorder.getAudioFormat()) { + case AudioFormat.ENCODING_PCM_8BIT: + s = "8 Bit PCM "; + anzahlBytesProAbtastwert = 1; + break; + case AudioFormat.ENCODING_PCM_16BIT: + s = "16 Bit PCM"; + anzahlBytesProAbtastwert = 2; + break; + case AudioFormat.ENCODING_PCM_FLOAT: + s = "Float PCM"; + anzahlBytesProAbtastwert = 4; + break; + default: + throw new IllegalArgumentException(); + } +// textViewAudioFormat.setText(s); + + switch (recorder.getChannelConfiguration()) { + case AudioFormat.CHANNEL_IN_MONO: + s = "Mono"; + break; + case AudioFormat.CHANNEL_IN_STEREO: + s = "Stereo"; + anzahlBytesProAbtastwert *= 2; + break; + case AudioFormat.CHANNEL_INVALID: + s = "ungültig"; + break; + default: + throw new IllegalArgumentException(); + } +// textViewKanalKonfiguration.setText(s); + logger.log("Konfiguration: "+ s); + + int pufferGroesseInAnzahlAbtastwerten = pufferGroesseInBytes / anzahlBytesProAbtastwert; + int pufferGroesseInMillisekunden = 1000 * pufferGroesseInAnzahlAbtastwerten / recorder.getSampleRate(); + +// textViewPufferGroesseInAnzahlAbtastwerte.setText("" + pufferGroesseInAnzahlAbtastwerten); +// textViewPufferGroesseInMillisekunden.setText("" + pufferGroesseInMillisekunden); + } + + @Override + protected Void doInBackground(Long... params) { + recorder.startRecording(); + short[] puffer = new short[pufferGroesseInBytes / 2]; + long lastTime = System.currentTimeMillis(); + float verarbeitungsrate = 0; + final int maxZaehlerZeitMessung = 10; + int zaehlerZeitMessung = 0; + int anzahlVerarbeitet = 0; + GleitenderMittelwert gleitenderMittelwert = new GleitenderMittelwert(0.3f); + + for (; ; ) { + if (aufnahmeTask.isCancelled()) { + break; + } else { + int n = recorder.read(puffer, 0, puffer.length); + Verarbeitungsergebnis ergebnis = verarbeiten(puffer, n); + anzahlVerarbeitet += n; + + zaehlerZeitMessung++; + if (zaehlerZeitMessung == maxZaehlerZeitMessung) { + long time = System.currentTimeMillis(); + long deltaTime = time - lastTime; + verarbeitungsrate = 1000.0f * anzahlVerarbeitet / deltaTime; + verarbeitungsrate = gleitenderMittelwert.mittel(verarbeitungsrate); + zaehlerZeitMessung = 0; + anzahlVerarbeitet = 0; + lastTime = time; + } + + float noiseLevel = gleitenderMittelwert.MittelwertPuffer(puffer); + + // logger.log("Noise Level:" + noiseLevel); + ergebnis.noiseLevel = noiseLevel; + ergebnis.verarbeitungsrate = (int) verarbeitungsrate; + publishProgress(ergebnis); + + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + recorder.release(); + return null; + } + + private Verarbeitungsergebnis verarbeiten(short[] daten, int n) { + String status; + short maxAmp = -1; + if (n == AudioRecord.ERROR_INVALID_OPERATION) { + status = "ERROR_INVALID_OPERATION"; + } else if (n == AudioRecord.ERROR_BAD_VALUE) { + status = "ERROR_BAD_VALUE"; + } else { + status = "OK"; + short max = 0; + for (int i = 0; i < n; i++) { + if (daten[i] > max) { + max = daten[i]; + } + } + + ringPuffer.hinzufuegen(max); + maxAmp = ringPuffer.maximum(); + } + + return new Verarbeitungsergebnis(status, maxAmp, 0, 0); + } + + @Override + protected void onProgressUpdate(Verarbeitungsergebnis... progress) { + super.onProgressUpdate(progress); +// textViewMaxAmp.setText("" + progress[0].maxAmp); +// textViewVerarbeitungsrate.setText("" + progress[0].verarbeitungsrate); + logger.overwriteLastlog("VR, Max, NL:" + progress[0].verarbeitungsrate + ", " + progress[0].maxAmp + + ", " + progress[0].noiseLevel); + + if (progress[0].maxAmp >= Schwellwert_Alarm) { + Alarm = true; + } + } + } + + class Verarbeitungsergebnis { + String status; + short maxAmp; + int verarbeitungsrate; + float noiseLevel; + + Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate, float noiseLevel) { + this.status = status; + this.maxAmp = maxAmp; + this.verarbeitungsrate = verarbeitungsrate; + this.noiseLevel = noiseLevel; + } + } + + class RingPuffer { + private short[] puffer; + private final int laenge; + private int anzahlEnthaltenerDaten; + private int position; + + public RingPuffer(int n) { + laenge = n; + anzahlEnthaltenerDaten = 0; + position = 0; + puffer = new short[laenge]; + } + + public void hinzufuegen(short wert) { + puffer[position] = wert; + position++; + if (position >= laenge) { + position = 0; + } + if (anzahlEnthaltenerDaten < laenge) { + anzahlEnthaltenerDaten++; + } + } + + public void hinzufuegen(short[] daten) { + for (short d : daten) { + puffer[position] = d; + position++; + if (position >= laenge) { + position = 0; + } + } + if (anzahlEnthaltenerDaten < laenge) { + anzahlEnthaltenerDaten += daten.length; + if (anzahlEnthaltenerDaten >= laenge) { + anzahlEnthaltenerDaten = laenge; + } + } + } + + public short maximum() { + short max = 0; + for (int i = 0; i < anzahlEnthaltenerDaten; i++) { + if (puffer[i] > max) { + max = puffer[i]; + } + } + return max; + } + + public float mittelwert() { + float summe = 0; + for (int i = 0; i < anzahlEnthaltenerDaten; i++) { + summe += puffer[i]; + } + return summe / anzahlEnthaltenerDaten; + } + } + + class GleitenderMittelwert { + private final float wichtungNeuerWert; + private final float wichtungAlterWert; + private float mittelwert = 0; + private boolean istMittelwertGesetzt = false; + + GleitenderMittelwert(float wichtungNeuerWert) { + this.wichtungNeuerWert = wichtungNeuerWert; + this.wichtungAlterWert = 1 - this.wichtungNeuerWert; + } + + float MittelwertPuffer(short[] puffer) { + + for (int i = 0; i < puffer.length; i++) { + mittelwert = Math.abs(puffer[i]); + } + mittelwert = mittelwert/puffer.length; + + return mittelwert; + } + + float mittel(float wert) { + if (istMittelwertGesetzt) { + mittelwert = wert * wichtungNeuerWert + mittelwert * wichtungAlterWert; + } else { + mittelwert = wert; + istMittelwertGesetzt = true; + } + return mittelwert; + } + } +} diff --git a/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java b/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java index 510d104..2d3c815 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java +++ b/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java @@ -1,4 +1,329 @@ package com.example.ueberwachungssystem; +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.widget.TextView; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import com.example.ueberwachungssystem.logger.Logger; + +import java.io.File; + public class Mikrofon { + + Logger logger; + private static final int RECHTEANFORDERUNG_MIKROFON = 1; + + private Activity MainActivityForClass; + private AufnahmeTask aufnahmeTask; + public boolean Alarm = false; + public int Schwellwert_Alarm = 500; + + public void onCreate(Activity MainActivity, Logger MainLogger) { + MainActivityForClass = MainActivity; + logger = MainLogger; //Class uses the same logger as the MainActivity + logger.log(this.getClass().getSimpleName() + ".onCreate"); + + if (!istZugriffAufMikrofonErlaubt()) { + zugriffAufMikrofonAnfordern(); + } + } + + public void onResume() { + logger.log(this.getClass().getSimpleName() + ".onResume"); + if (!istZugriffAufMikrofonErlaubt()) { + zugriffAufMikrofonAnfordern(); + } + if (istZugriffAufMikrofonErlaubt()) { + aufnahmeTask = new AufnahmeTask(); + aufnahmeTask.execute(); + } + } + + public void onPause() { + logger.log(this.getClass().getSimpleName() + ".onPause"); + if(aufnahmeTask!=null) { + aufnahmeTask.cancel(true); + // aufnahmeTask = null; // if aufnahmeTask = null, break in for loop would not work (Nullpointer Exception) + } + } + + private boolean istZugriffAufMikrofonErlaubt() { + if (ContextCompat.checkSelfPermission(MainActivityForClass, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + logger.log("Zugriff auf Mikrofon ist verboten."); + return false; + } else { + logger.log("Zugriff auf Mikrofon ist erlaubt."); + return true; + } + } + private void zugriffAufMikrofonAnfordern() { + ActivityCompat.requestPermissions(MainActivityForClass, new String[]{Manifest.permission.RECORD_AUDIO}, RECHTEANFORDERUNG_MIKROFON); + } + + class AufnahmeTask extends AsyncTask { + private AudioRecord recorder; + private final int sampleRateInHz = 44100; + private final int channelConfig = AudioFormat.CHANNEL_IN_MONO; + private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT; + private int minPufferGroesseInBytes; + private int pufferGroesseInBytes; + private RingPuffer ringPuffer = new RingPuffer(10); + + AufnahmeTask() { + minPufferGroesseInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); + pufferGroesseInBytes = minPufferGroesseInBytes * 2; + recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, pufferGroesseInBytes); + +// textViewMinPufferGroesseInBytes.setText("" + minPufferGroesseInBytes); +// textViewPufferGroesseInBytes.setText("" + pufferGroesseInBytes); +// textViewAbtastrate.setText("" + recorder.getSampleRate()); +// textViewAnzahlKanaele.setText("" + recorder.getChannelCount()); + + logger.log("Puffergroeße: "+ minPufferGroesseInBytes + " " + pufferGroesseInBytes); + logger.log("Recorder (SR, CH): "+ recorder.getSampleRate() + " " + recorder.getChannelCount()); + + int anzahlBytesProAbtastwert; + String s; + switch (recorder.getAudioFormat()) { + case AudioFormat.ENCODING_PCM_8BIT: + s = "8 Bit PCM "; + anzahlBytesProAbtastwert = 1; + break; + case AudioFormat.ENCODING_PCM_16BIT: + s = "16 Bit PCM"; + anzahlBytesProAbtastwert = 2; + break; + case AudioFormat.ENCODING_PCM_FLOAT: + s = "Float PCM"; + anzahlBytesProAbtastwert = 4; + break; + default: + throw new IllegalArgumentException(); + } +// textViewAudioFormat.setText(s); + + switch (recorder.getChannelConfiguration()) { + case AudioFormat.CHANNEL_IN_MONO: + s = "Mono"; + break; + case AudioFormat.CHANNEL_IN_STEREO: + s = "Stereo"; + anzahlBytesProAbtastwert *= 2; + break; + case AudioFormat.CHANNEL_INVALID: + s = "ungültig"; + break; + default: + throw new IllegalArgumentException(); + } +// textViewKanalKonfiguration.setText(s); + logger.log("Konfiguration: "+ s); + + int pufferGroesseInAnzahlAbtastwerten = pufferGroesseInBytes / anzahlBytesProAbtastwert; + int pufferGroesseInMillisekunden = 1000 * pufferGroesseInAnzahlAbtastwerten / recorder.getSampleRate(); + +// textViewPufferGroesseInAnzahlAbtastwerte.setText("" + pufferGroesseInAnzahlAbtastwerten); +// textViewPufferGroesseInMillisekunden.setText("" + pufferGroesseInMillisekunden); + } + + @Override + protected Void doInBackground(Long... params) { + recorder.startRecording(); + short[] puffer = new short[pufferGroesseInBytes / 2]; + long lastTime = System.currentTimeMillis(); + float verarbeitungsrate = 0; + final int maxZaehlerZeitMessung = 10; + int zaehlerZeitMessung = 0; + int anzahlVerarbeitet = 0; + GleitenderMittelwert gleitenderMittelwert = new GleitenderMittelwert(0.3f); + + for (; ; ) { + if (aufnahmeTask.isCancelled()) { + break; + } else { + int n = recorder.read(puffer, 0, puffer.length); + Verarbeitungsergebnis ergebnis = verarbeiten(puffer, n); + anzahlVerarbeitet += n; + + zaehlerZeitMessung++; + if (zaehlerZeitMessung == maxZaehlerZeitMessung) { + long time = System.currentTimeMillis(); + long deltaTime = time - lastTime; + verarbeitungsrate = 1000.0f * anzahlVerarbeitet / deltaTime; + verarbeitungsrate = gleitenderMittelwert.mittel(verarbeitungsrate); + zaehlerZeitMessung = 0; + anzahlVerarbeitet = 0; + lastTime = time; + } + + float noiseLevel = gleitenderMittelwert.MittelwertPuffer(puffer); + + // logger.log("Noise Level:" + noiseLevel); + ergebnis.noiseLevel = noiseLevel; + ergebnis.verarbeitungsrate = (int) verarbeitungsrate; + publishProgress(ergebnis); + + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + recorder.release(); + return null; + } + + private Verarbeitungsergebnis verarbeiten(short[] daten, int n) { + String status; + short maxAmp = -1; + if (n == AudioRecord.ERROR_INVALID_OPERATION) { + status = "ERROR_INVALID_OPERATION"; + } else if (n == AudioRecord.ERROR_BAD_VALUE) { + status = "ERROR_BAD_VALUE"; + } else { + status = "OK"; + short max = 0; + for (int i = 0; i < n; i++) { + if (daten[i] > max) { + max = daten[i]; + } + } + + ringPuffer.hinzufuegen(max); + maxAmp = ringPuffer.maximum(); + } + + return new Verarbeitungsergebnis(status, maxAmp, 0, 0); + } + + @Override + protected void onProgressUpdate(Verarbeitungsergebnis... progress) { + super.onProgressUpdate(progress); +// textViewMaxAmp.setText("" + progress[0].maxAmp); +// textViewVerarbeitungsrate.setText("" + progress[0].verarbeitungsrate); + logger.overwriteLastlog("VR, Max, NL:" + progress[0].verarbeitungsrate + ", " + progress[0].maxAmp + + ", " + progress[0].noiseLevel); + + if (progress[0].maxAmp >= Schwellwert_Alarm) { + Alarm = true; + } + } + } + + class Verarbeitungsergebnis { + String status; + short maxAmp; + int verarbeitungsrate; + float noiseLevel; + + Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate, float noiseLevel) { + this.status = status; + this.maxAmp = maxAmp; + this.verarbeitungsrate = verarbeitungsrate; + this.noiseLevel = noiseLevel; + } + } + + class RingPuffer { + private short[] puffer; + private final int laenge; + private int anzahlEnthaltenerDaten; + private int position; + + public RingPuffer(int n) { + laenge = n; + anzahlEnthaltenerDaten = 0; + position = 0; + puffer = new short[laenge]; + } + + public void hinzufuegen(short wert) { + puffer[position] = wert; + position++; + if (position >= laenge) { + position = 0; + } + if (anzahlEnthaltenerDaten < laenge) { + anzahlEnthaltenerDaten++; + } + } + + public void hinzufuegen(short[] daten) { + for (short d : daten) { + puffer[position] = d; + position++; + if (position >= laenge) { + position = 0; + } + } + if (anzahlEnthaltenerDaten < laenge) { + anzahlEnthaltenerDaten += daten.length; + if (anzahlEnthaltenerDaten >= laenge) { + anzahlEnthaltenerDaten = laenge; + } + } + } + + public short maximum() { + short max = 0; + for (int i = 0; i < anzahlEnthaltenerDaten; i++) { + if (puffer[i] > max) { + max = puffer[i]; + } + } + return max; + } + + public float mittelwert() { + float summe = 0; + for (int i = 0; i < anzahlEnthaltenerDaten; i++) { + summe += puffer[i]; + } + return summe / anzahlEnthaltenerDaten; + } + } + + class GleitenderMittelwert { + private final float wichtungNeuerWert; + private final float wichtungAlterWert; + private float mittelwert = 0; + private boolean istMittelwertGesetzt = false; + + GleitenderMittelwert(float wichtungNeuerWert) { + this.wichtungNeuerWert = wichtungNeuerWert; + this.wichtungAlterWert = 1 - this.wichtungNeuerWert; + } + + float MittelwertPuffer(short[] puffer) { + + for (int i = 0; i < puffer.length; i++) { + mittelwert = Math.abs(puffer[i]); + } + mittelwert = mittelwert/puffer.length; + + return mittelwert; + } + + float mittel(float wert) { + if (istMittelwertGesetzt) { + mittelwert = wert * wichtungNeuerWert + mittelwert * wichtungAlterWert; + } else { + mittelwert = wert; + istMittelwertGesetzt = true; + } + return mittelwert; + } + } } diff --git a/app/src/main/java/com/example/ueberwachungssystem/logger/Logger.java b/app/src/main/java/com/example/ueberwachungssystem/logger/Logger.java new file mode 100644 index 0000000..07af51a --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/logger/Logger.java @@ -0,0 +1,61 @@ +package com.example.ueberwachungssystem.logger; + +import android.util.Log; +import android.widget.TextView; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class Logger { + private TextView textView; + private StringBuffer sb = new StringBuffer(); + private String tag; + private int lengthOfLastLog = 0; + private boolean overwrite = false; + + public Logger(String tag, TextView textView, String logInitText) { + this.tag = tag; + this.textView = textView; + sb.append(logInitText); + } + + public void log(String s) { + overwrite = false; + Log.d(tag, s); + sb.append(s).append("\n"); + if (textView != null) { + textView.setText(sb.toString()); + } + } + + public void overwriteLastlog(String s) { + Log.d(tag, s); + lengthOfLastLog = s.length(); + if (overwrite) + { + sb.setLength(sb.length() - (lengthOfLastLog + 1)); + } + sb.append(s).append("\n"); + overwrite = true; + if (textView != null) { + textView.setText(sb.toString()); + } + } + + public void log(Exception e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + log(sw.toString()); + } + + public void clearLog() { + sb.setLength(0); + if (textView != null) { + textView.setText(""); + } + } + + public String getLoggedText() { + return sb.toString(); + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 17eab17..bea580a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -7,12 +7,22 @@ tools:context=".MainActivity"> + + \ No newline at end of file From 8275d8bd5ae024369a531b04f221ead6ed3c10a3 Mon Sep 17 00:00:00 2001 From: Leon Market Date: Wed, 14 Jun 2023 22:11:17 +0200 Subject: [PATCH 05/23] Added --- Neues Textdokument.txt | 0 app/src/main/AndroidManifest.xml | 2 +- .../Beschleunigungssensor.java | 146 +++++++++++++++++- .../ueberwachungssystem/MainActivity.java | 44 +++++- app/src/main/res/layout/activity_main.xml | 25 +++ build.gradle | 4 +- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 8 files changed, 213 insertions(+), 14 deletions(-) delete mode 100644 Neues Textdokument.txt diff --git a/Neues Textdokument.txt b/Neues Textdokument.txt deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cef8f3d..c49da9f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:theme="@style/Theme.Ueberwachungssystem" tools:targetApi="31"> diff --git a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java index f15ae8e..7521863 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java +++ b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java @@ -1,21 +1,45 @@ package com.example.ueberwachungssystem; +import static java.lang.Math.sqrt; + import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import android.widget.TextView; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.OptionalDouble; +import java.util.Queue; + public class Beschleunigungssensor extends AppCompatActivity implements SensorEventListener { private Logger logger; private SensorManager sensorManager; - private int sensorType = Sensor.TYPE_ACCELEROMETER; + private static final int sensorType = Sensor.TYPE_LINEAR_ACCELERATION; private Sensor sensor; + //Matrizen für Datenverarbeitung: + double[] linear_acceleration = new double[3]; + int numberOfValues = 100; + double[][] calibrationMatrix = new double[3][numberOfValues]; + boolean alarm = false; + //Preallocate memory for the data of each axis of the acceleration sensor + double x; + double y; + double z; + double betrag; //Betrag aller drei Achsen sqrt(x*x + y*y + z*z) + @Override protected void onCreate(Bundle savedInstanceState) { @@ -44,7 +68,7 @@ public class Beschleunigungssensor extends AppCompatActivity implements SensorEv super.onResume(); if(sensor != null) { - if(sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME)) + if(sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)) { logger.log("Wir haben uns beim Sensor angemeldet."); } @@ -65,15 +89,106 @@ public class Beschleunigungssensor extends AppCompatActivity implements SensorEv } } + private void checkAlarm (SensorEvent event) { + x = event.values[0]; + y = event.values[1]; + z = event.values[2]; + betrag = sqrt(x*x + y*y + z*z); + double schwelle = 1.5; + + if (!alarm) { + if (betrag > schwelle) { + logger.log("Betragswert über Schwelle erkannt, Alarm wird gleich angeschaltet"); + alarm = true; + logger.log("Alarm an"); + logger.log("Betrag: " + betrag + event.timestamp); + } + } else { + if (betrag < schwelle) { + logger.log("Alarm ist noch an; Neuer Betragswert unter Schwellwert: " + betrag); + alarm = false; + logger.log("Alarm wieder ausgeschaltet"); + } else { + logger.log("Betragswert immer noch über Schwellwert: " + betrag + "; Alarm bleibt an."); + } + } + } + int i = 0; + boolean stopp_mal = false; + @Override public void onSensorChanged(SensorEvent event) { - String sb = "t=" + event.timestamp + - "\nx=" + event.values[0] + // Wert legend: x = 0.04 + checkAlarm(event); + + //Alter Code, erstmal wild mit if statement ausgeschlossen + if (stopp_mal) { + if (i + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index f05eacf..41532d1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.4.2' apply false - id 'com.android.library' version '7.4.2' apply false + id 'com.android.application' version '8.0.0' apply false + id 'com.android.library' version '8.0.0' apply false } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 3e927b1..3a131ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,6 @@ android.useAndroidX=true # Enables namespacing of each library's R class so that its R class includes only the # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true \ No newline at end of file +android.nonTransitiveRClass=true +android.defaults.buildfeatures.buildconfig=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a5dbc0d..3a67f74 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu May 11 15:04:30 CEST 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From 9e5b669986dd276078b25aae559b32bdcb29fa46 Mon Sep 17 00:00:00 2001 From: Leon Market Date: Wed, 14 Jun 2023 22:25:54 +0200 Subject: [PATCH 06/23] Added Accelerometer as Runnable Class and ThreadDemo as example --- .../ueberwachungssystem/Accelerometer.java | 124 ++++++++++++++++++ .../ueberwachungssystem/ThreadDemo.java | 70 ++++++++++ 2 files changed, 194 insertions(+) create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java diff --git a/app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java b/app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java new file mode 100644 index 0000000..f3c92f4 --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java @@ -0,0 +1,124 @@ +package com.example.ueberwachungssystem; + + + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + + +public class Accelerometer implements Runnable, SensorEventListener { + + Logger logger; + private volatile boolean running = false; + public SensorManager sensorManager; + private int sensorType = Sensor.TYPE_ACCELEROMETER; + private Sensor accelerometer; + private Context context; + private Thread thread; + private String threadName = "Accelerometer Thread"; + double[] gravity = new double[3]; + double[] linear_acceleration = new double[3]; + private TextView textViewWorkerThread; + + // In constructor pass Context from MainActivity in Accelerometer class + public Accelerometer(Context context, TextView textViewWorkerThread){ + this.context = context; + this.textViewWorkerThread = textViewWorkerThread; + } + // Passing Activity's instance as argument on worker thread + AppCompatActivity activity; + public Accelerometer(AppCompatActivity activity){ + this.activity = activity; + } + + private void print (final String s){ + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + textViewWorkerThread.setText(s); + } + }); + } + + @Override + public void run() { + while (running) { + sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + if (sensorManager.getSensorList(sensorType).size() == 0) { + logger.log("Es gibt den gewünschten Sensor nicht"); + accelerometer = null; + } else { + accelerometer = sensorManager.getSensorList(sensorType).get(0); + } + } + } + void start(){ + logger.log("Starting" + threadName); + running = true; + thread = new Thread(this); + thread.setName(threadName); + thread.start(); + logger.log("alright, " + threadName + " started!"); + + // register the sensor before using // + sensorManager.registerListener((SensorEventListener) context, accelerometer, SensorManager.SENSOR_DELAY_NORMAL); + logger.log("Accelerometer, du bist dran!"); + } + + void stop() { + // unregister from the sensor to stop using it // + sensorManager.unregisterListener((SensorEventListener) context, accelerometer); + logger.log("Das reicht Accelerometer, komm zurück!"); + if (!running){ + logger.log(threadName + " not running."); + } else { + logger.log("Stopping " + threadName); + running = false; + while (true) { + try { + thread.join(); + logger.log("..." + threadName + " stopped"); + break; + } catch (InterruptedException e){ + e.printStackTrace(); + } + } + } + } + + @Override + public void onSensorChanged(SensorEvent event) { + // Highpass filter to filter out gravity influence + final double alpha = 0.8; + + gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0]; + gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1]; + gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2]; + linear_acceleration[0] = event.values[0] - gravity[0]; + + linear_acceleration[1] = event.values[1] - gravity[1]; + linear_acceleration[2] = event.values[2] - gravity[2]; + + String sb = "t=" + event.timestamp + + "\nx=" + event.values[0] + // Wert liegend: x = 0.04 + "\ny=" + event.values[1] + // Wert liegend: y = 0.44 + "\nz=" + event.values[2] + // Wert liegend: z = 9.90 = Erdbeschleunigung --> Wenn Ausrichtung unbekannt ist, müsste kalibrierung bei Start der Bewegungsüberwachung vorgenommen werden + "\nlin_x=" + linear_acceleration[0] + + "\nlin_x=" + linear_acceleration[1] + + "\nlin_x=" + linear_acceleration[2]; + + logger.clearLog(); + logger.log(sb); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java b/app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java new file mode 100644 index 0000000..91bf39e --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java @@ -0,0 +1,70 @@ +package com.example.ueberwachungssystem; + +import android.content.Context; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +public class ThreadDemo implements Runnable { + private volatile boolean running = false; + private Thread thread; + private String threadname = "testThread"; + Logger logger; + + // Passing Activity's instance as argument on worker thread + AppCompatActivity activity; + public ThreadDemo(AppCompatActivity activity){ + this.activity = activity; + } + + //Method print which delegates access on MainActivity to runOnUiThread + private void print(final String s) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + //textViewWorkerThread.setText(s); + } + }); + } + + @Override + public void run() { + int i = 0; + while (running) { + i++; + print(String.valueOf(i)); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + //print(activity.getString(R.string.workerThread) + " endet mit " + i); + } + + void start() { + logger.log("Starting " + threadname + "..."); + running = true; + thread = new Thread(this); + thread.setName(threadname); + thread.start(); + logger.log("..." + threadname + " started"); + } + void stop() { + if (!running) { + logger.log(threadname + " not running"); + } else { + logger.log("Stopping " + threadname + "..."); + running = false; + while(true){ + try { + thread.join(); + logger.log("... " + threadname + " stopped"); + break; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } +} From 402b73e4bd91b0fd44b439c6fe9e0ceab78ed36c Mon Sep 17 00:00:00 2001 From: Leon Market Date: Wed, 14 Jun 2023 22:28:05 +0200 Subject: [PATCH 07/23] Removed calibration code and added method checkAlarm --- .../Beschleunigungssensor.java | 90 +------------------ 1 file changed, 1 insertion(+), 89 deletions(-) diff --git a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java index 7521863..e74d635 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java +++ b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java @@ -113,103 +113,15 @@ public class Beschleunigungssensor extends AppCompatActivity implements SensorEv } } } - int i = 0; - boolean stopp_mal = false; @Override public void onSensorChanged(SensorEvent event) { checkAlarm(event); - - //Alter Code, erstmal wild mit if statement ausgeschlossen - if (stopp_mal) { - if (i diff --git a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java index e74d635..d5fc8e2 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java +++ b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java @@ -28,11 +28,6 @@ public class Beschleunigungssensor extends AppCompatActivity implements SensorEv private SensorManager sensorManager; private static final int sensorType = Sensor.TYPE_LINEAR_ACCELERATION; private Sensor sensor; - - //Matrizen für Datenverarbeitung: - double[] linear_acceleration = new double[3]; - int numberOfValues = 100; - double[][] calibrationMatrix = new double[3][numberOfValues]; boolean alarm = false; //Preallocate memory for the data of each axis of the acceleration sensor double x; diff --git a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java index 0b13931..f3ba22b 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java +++ b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java @@ -4,6 +4,7 @@ import static java.lang.Boolean.TRUE; import androidx.appcompat.app.AppCompatActivity; +import android.content.Context; import android.os.Bundle; import android.view.View; import android.widget.TextView; @@ -12,10 +13,12 @@ import android.widget.ToggleButton; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Logger logger; + private Context context; //private Accelerometer beschleunigungssensor; - //private SensorManager sensorManager; + private ThreadDemo threadDemo; private TextView textViewLog; private TextView textViewWorkerThread; + //private WorkerUsingThread workerUsingThread; ToggleButton toggleButton1; @@ -32,7 +35,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe toggleButton1 = (ToggleButton) findViewById(R.id.toggleButton1); //togglebutton um Thread zu steuern toggleButton1.setOnClickListener(this); textViewWorkerThread = (TextView) findViewById(R.id.textViewWorkerThread); //TextView um Thread zu überwachen - + // beschleunigungssensor = new Accelerometer(this); + threadDemo = new ThreadDemo(this, textViewWorkerThread); logger.log("onCreate"); } @@ -44,6 +48,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe protected void onPause() { super.onPause(); //beschleunigungssensor.stop(); + threadDemo.stop(); + } @@ -52,8 +58,11 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe logger.log("toggleButton1 is clicked"); if (toggleButton1.isChecked()) { logger.log("ToggleButton is ON"); + //beschleunigungssensor.start(); + threadDemo.start(); } else { logger.log("ToggleButton is OFF"); + threadDemo.stop(); } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java b/app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java index 91bf39e..70f69bb 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java +++ b/app/src/main/java/com/example/ueberwachungssystem/ThreadDemo.java @@ -9,20 +9,21 @@ public class ThreadDemo implements Runnable { private volatile boolean running = false; private Thread thread; private String threadname = "testThread"; - Logger logger; + //Logger logger; + TextView textViewWorkerThread; // Passing Activity's instance as argument on worker thread AppCompatActivity activity; - public ThreadDemo(AppCompatActivity activity){ + public ThreadDemo(AppCompatActivity activity, TextView textViewWorkerThread){ this.activity = activity; + this.textViewWorkerThread = textViewWorkerThread; } - //Method print which delegates access on MainActivity to runOnUiThread private void print(final String s) { activity.runOnUiThread(new Runnable() { @Override public void run() { - //textViewWorkerThread.setText(s); + textViewWorkerThread.setText(s); } }); } @@ -43,23 +44,23 @@ public class ThreadDemo implements Runnable { } void start() { - logger.log("Starting " + threadname + "..."); + //logger.log("Starting " + threadname + "..."); running = true; thread = new Thread(this); thread.setName(threadname); thread.start(); - logger.log("..." + threadname + " started"); + //logger.log("..." + threadname + " started"); } void stop() { if (!running) { - logger.log(threadname + " not running"); + //logger.log(threadname + " not running"); } else { - logger.log("Stopping " + threadname + "..."); + //logger.log("Stopping " + threadname + "..."); running = false; while(true){ try { thread.join(); - logger.log("... " + threadname + " stopped"); + //logger.log("... " + threadname + " stopped"); break; } catch (InterruptedException e) { e.printStackTrace(); diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 33535a7..0726f26 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -10,7 +10,7 @@ android:id="@+id/textViewLog" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Hello World!" + android:text="TextViewLoggerMain" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -35,7 +35,7 @@ android:layout_marginStart="174dp" android:layout_marginTop="85dp" android:layout_marginEnd="179dp" - android:text="TextView" + android:text="textViewWorkerThreadTextView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/toggleButton1" /> From b94a1d98b7a35a77d5099857d992f774e2d90182 Mon Sep 17 00:00:00 2001 From: Tobias Wolz Date: Fri, 16 Jun 2023 16:49:20 +0200 Subject: [PATCH 09/23] Working detection with calibration and dB signals. FFT also implemented, but does not work properly at the moment. (Added Complex class, FFT class and imported jjoe64 Graphview (in gradle and gradle.properties) for visualising FFT results) --- app/build.gradle | 1 + .../ueberwachungssystem/MainActivity.java | 22 +- .../MicrophoneDetector.java | 148 +++++++- .../example/ueberwachungssystem/Mikrofon.java | 329 ------------------ .../Signalverarbeitung/Complex.java | 148 ++++++++ .../Signalverarbeitung/FFT.java | 248 +++++++++++++ app/src/main/res/layout/activity_main.xml | 19 +- gradle.properties | 3 +- 8 files changed, 551 insertions(+), 367 deletions(-) delete mode 100644 app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/Complex.java create mode 100644 app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/FFT.java diff --git a/app/build.gradle b/app/build.gradle index 631248a..784bb8a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,4 +36,5 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + implementation 'com.jjoe64:graphview:4.2.2' } \ No newline at end of file diff --git a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java index ab47b23..ee9c096 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java +++ b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java @@ -1,36 +1,32 @@ package com.example.ueberwachungssystem; import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; -import android.Manifest; import android.os.Bundle; import android.view.View; -import android.widget.Button; import android.widget.Switch; import android.widget.TextView; -import android.widget.ToggleButton; -import com.example.ueberwachungssystem.Mikrofon; import com.example.ueberwachungssystem.logger.Logger; +import com.jjoe64.graphview.GraphView; + public class MainActivity extends AppCompatActivity { Logger logger; + GraphView graph; private TextView tv_log; - Mikrofon Mikrofon_1= new Mikrofon(); - MicrophoneDetector Mic; private Switch TglBtn_Mic; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - TextView textView = new TextView(this); tv_log = (TextView) findViewById(R.id.tv_log); //Set textview for showing logged content logger = new Logger(this.getClass().getSimpleName(), tv_log, ""); logger.log(this.getClass().getSimpleName() + ".onCreate"); - Mic = new MicrophoneDetector(this, logger); + graph = (GraphView) findViewById(R.id.graph); + Mic = new MicrophoneDetector(this, logger, graph); setupMic(); } @@ -38,19 +34,16 @@ public class MainActivity extends AppCompatActivity { @Override public void onResume() { super.onResume(); - Mikrofon_1.onResume(); logger.log(this.getClass().getSimpleName() + ".onResume"); } @Override public void onPause() { super.onPause(); - Mikrofon_1.onPause(); logger.log(this.getClass().getSimpleName() + ".onPause"); } private void setupMic() { - Mikrofon_1.onCreate(this, logger); TglBtn_Mic = (Switch) findViewById(R.id.TglBtn_Mic); TglBtn_Mic.setOnClickListener(new View.OnClickListener() { @Override @@ -58,9 +51,10 @@ public class MainActivity extends AppCompatActivity { if (v == TglBtn_Mic) { logger.log("onClick toggleButtonThread " + TglBtn_Mic.isChecked()); if (TglBtn_Mic.isChecked()) { - Mikrofon_1.onResume(); + Mic.startDetection(); } else { - Mikrofon_1.onPause(); + Mic.stopDetection(); + logger.clearLog(); } } } diff --git a/app/src/main/java/com/example/ueberwachungssystem/MicrophoneDetector.java b/app/src/main/java/com/example/ueberwachungssystem/MicrophoneDetector.java index d897131..8cae886 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/MicrophoneDetector.java +++ b/app/src/main/java/com/example/ueberwachungssystem/MicrophoneDetector.java @@ -1,5 +1,7 @@ package com.example.ueberwachungssystem; +import static java.lang.Math.*; + import android.Manifest; import android.app.Activity; import android.content.Context; @@ -12,9 +14,14 @@ import android.os.AsyncTask; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import com.example.ueberwachungssystem.Signalverarbeitung.Complex; +import com.example.ueberwachungssystem.Signalverarbeitung.FFT; import com.example.ueberwachungssystem.logger.Logger; +import com.jjoe64.graphview.GraphView; +import com.jjoe64.graphview.series.DataPoint; +import com.jjoe64.graphview.series.LineGraphSeries; -public class MicrophoneDetector extends Detector{ +public class MicrophoneDetector extends Detector { /** * Constructor - takes context of current activity * @@ -24,17 +31,19 @@ public class MicrophoneDetector extends Detector{ private static final int RECHTEANFORDERUNG_MIKROFON = 1; private AufnahmeTask aufnahmeTask; - public boolean Alarm = false; - public int Schwellwert_Alarm = 500; + public boolean armed = false; + public int Schwellwert_Alarm = 100; + GraphView graph; Logger logger; - private Activity MainActivityForClass; - public MicrophoneDetector(Context context, Logger MainLogger) { + + public MicrophoneDetector(Context context, Logger MainLogger, GraphView MainGraph) { super(context); MainActivityForClass = (Activity) context; logger = MainLogger; //Class uses the same logger as the MainActivity logger.log(this.getClass().getSimpleName() + ".onCreate"); + graph = MainGraph; if (!istZugriffAufMikrofonErlaubt()) { zugriffAufMikrofonAnfordern(); @@ -44,6 +53,7 @@ public class MicrophoneDetector extends Detector{ @Override public void startDetection() { logger.log(this.getClass().getSimpleName() + ".startDetection"); + if (!istZugriffAufMikrofonErlaubt()) { zugriffAufMikrofonAnfordern(); } @@ -56,7 +66,7 @@ public class MicrophoneDetector extends Detector{ @Override public void stopDetection() { logger.log(this.getClass().getSimpleName() + ".stopDetection"); - if(aufnahmeTask!=null) { + if (aufnahmeTask != null) { aufnahmeTask.cancel(true); // aufnahmeTask = null; // if aufnahmeTask = null, break in for loop would not work (Nullpointer Exception) } @@ -71,6 +81,7 @@ public class MicrophoneDetector extends Detector{ return true; } } + private void zugriffAufMikrofonAnfordern() { ActivityCompat.requestPermissions(MainActivityForClass, new String[]{Manifest.permission.RECORD_AUDIO}, RECHTEANFORDERUNG_MIKROFON); } @@ -83,10 +94,23 @@ public class MicrophoneDetector extends Detector{ private int minPufferGroesseInBytes; private int pufferGroesseInBytes; private RingPuffer ringPuffer = new RingPuffer(10); + private float kalibierWert; + private DetectionReport detectionReport; AufnahmeTask() { minPufferGroesseInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); pufferGroesseInBytes = minPufferGroesseInBytes * 2; + if (ActivityCompat.checkSelfPermission(MainActivityForClass, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + ActivityCompat.requestPermissions(MainActivityForClass, new String[]{Manifest.permission.RECORD_AUDIO}, RECHTEANFORDERUNG_MIKROFON); + } + recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, pufferGroesseInBytes); // textViewMinPufferGroesseInBytes.setText("" + minPufferGroesseInBytes); @@ -152,6 +176,40 @@ public class MicrophoneDetector extends Detector{ int anzahlVerarbeitet = 0; GleitenderMittelwert gleitenderMittelwert = new GleitenderMittelwert(0.3f); + //Kalibrierung + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + int i = 0; + for (i = 0; i < 20; i++) { + int n = recorder.read(puffer, 0, puffer.length); + Verarbeitungsergebnis kalibrierErgebnis = verarbeiten(puffer, n); + kalibierWert += kalibrierErgebnis.maxAmp; + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + kalibierWert = kalibierWert/i; + +// Complex[] zeitSignal = new Complex[puffer.length]; +// for (int j = 0; j < puffer.length; j++) { +// zeitSignal[j] = new Complex(puffer[j], 0); +// } +// Complex[] spektrum = FFT.fft(zeitSignal); + double[] spektrum = calculateFFT(puffer); + DataPoint AddPoint; +// LineGraphSeries series = new LineGraphSeries(new DataPoint[]{}); +// for (i = 0; i < spektrum.length; i++) { +// AddPoint = new DataPoint(i, spektrum[i]); +// series.appendData(AddPoint, true, spektrum.length); +// } +// graph.addSeries(series); + // logger.log(spektrum.toString()); + for (; ; ) { if (aufnahmeTask.isCancelled()) { break; @@ -160,6 +218,14 @@ public class MicrophoneDetector extends Detector{ Verarbeitungsergebnis ergebnis = verarbeiten(puffer, n); anzahlVerarbeitet += n; + spektrum = calculateFFT(puffer); + LineGraphSeries newseries = new LineGraphSeries(new DataPoint[]{}); + for (i = 0; i < spektrum.length; i++) { + AddPoint = new DataPoint(i, spektrum[i]); + newseries.appendData(AddPoint, true, spektrum.length); + } + graph.removeAllSeries(); + graph.addSeries(newseries); zaehlerZeitMessung++; if (zaehlerZeitMessung == maxZaehlerZeitMessung) { long time = System.currentTimeMillis(); @@ -171,10 +237,7 @@ public class MicrophoneDetector extends Detector{ lastTime = time; } - float noiseLevel = gleitenderMittelwert.MittelwertPuffer(puffer); - // logger.log("Noise Level:" + noiseLevel); - ergebnis.noiseLevel = noiseLevel; ergebnis.verarbeitungsrate = (int) verarbeitungsrate; publishProgress(ergebnis); @@ -202,14 +265,18 @@ public class MicrophoneDetector extends Detector{ for (int i = 0; i < n; i++) { if (daten[i] > max) { max = daten[i]; + //max = 20 * log10(abs(daten[i]) / 32768); } } ringPuffer.hinzufuegen(max); maxAmp = ringPuffer.maximum(); + if (maxAmp <= Schwellwert_Alarm+kalibierWert) { + armed = true; + } } - return new Verarbeitungsergebnis(status, maxAmp, 0, 0); + return new Verarbeitungsergebnis(status, maxAmp, 0); } @Override @@ -217,26 +284,71 @@ public class MicrophoneDetector extends Detector{ super.onProgressUpdate(progress); // textViewMaxAmp.setText("" + progress[0].maxAmp); // textViewVerarbeitungsrate.setText("" + progress[0].verarbeitungsrate); - logger.overwriteLastlog("VR, Max, NL:" + progress[0].verarbeitungsrate + ", " + progress[0].maxAmp - + ", " + progress[0].noiseLevel); + float maxAmpPrint = round(20*log10(abs(progress[0].maxAmp/1.0))); + float kalibierWertPrint = round(20*log10(abs(kalibierWert))); + logger.overwriteLastlog("VR, Max, Kal:" + progress[0].verarbeitungsrate + ", " + maxAmpPrint + + " dB, " + kalibierWertPrint + " dB"); - if (progress[0].maxAmp >= Schwellwert_Alarm) { - Alarm = true; + if (progress[0].maxAmp >= Schwellwert_Alarm+kalibierWert && armed == true) { + armed = false; + detectionReport = new DetectionReport("Mic1", "Audio", maxAmpPrint); + logger.log(""); + logger.log("Alarm!"); + logger.log(detectionReport.toString()); + logger.log(""); } } } + private double[] calculateFFT(short[] zeitsignal) + { + byte signal[] = new byte[zeitsignal.length]; + // loops through all the values of a Short + for (int i = 0; i < zeitsignal.length-1; i++) { + signal[i] = (byte) (zeitsignal[i]); + signal[i+1] = (byte) (zeitsignal[i] >> 8); + } + + final int mNumberOfFFTPoints =1024; + double mMaxFFTSample; + + double temp; + Complex[] y; + Complex[] complexSignal = new Complex[mNumberOfFFTPoints]; + double[] absSignal = new double[mNumberOfFFTPoints/2]; + + for(int i = 0; i < mNumberOfFFTPoints; i++){ + temp = (double)((signal[2*i] & 0xFF) | (signal[2*i+1] << 8)) / 32768.0F; + complexSignal[i] = new Complex(temp,0.0); + } + + y = FFT.fft(complexSignal); + + mMaxFFTSample = 0.0; + // mPeakPos = 0; + for(int i = 0; i < (mNumberOfFFTPoints/2); i++) + { + absSignal[i] = y[i].abs(); +// absSignal[i] = Math.sqrt(Math.pow(y[i].re(), 2) + Math.pow(y[i].im(), 2)); +// if(absSignal[i] > mMaxFFTSample) +// { +// mMaxFFTSample = absSignal[i]; +// // mPeakPos = i; +// } + } + + return absSignal; + + } + class Verarbeitungsergebnis { String status; short maxAmp; int verarbeitungsrate; - float noiseLevel; - - Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate, float noiseLevel) { + Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate) { this.status = status; this.maxAmp = maxAmp; this.verarbeitungsrate = verarbeitungsrate; - this.noiseLevel = noiseLevel; } } diff --git a/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java b/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java deleted file mode 100644 index 2d3c815..0000000 --- a/app/src/main/java/com/example/ueberwachungssystem/Mikrofon.java +++ /dev/null @@ -1,329 +0,0 @@ -package com.example.ueberwachungssystem; - -import android.Manifest; -import android.app.Activity; -import android.content.Context; -import android.content.pm.PackageManager; -import android.media.AudioFormat; -import android.media.AudioRecord; -import android.media.MediaRecorder; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Environment; -import android.widget.TextView; - -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; - -import com.example.ueberwachungssystem.logger.Logger; - -import java.io.File; - -public class Mikrofon { - - Logger logger; - private static final int RECHTEANFORDERUNG_MIKROFON = 1; - - private Activity MainActivityForClass; - private AufnahmeTask aufnahmeTask; - public boolean Alarm = false; - public int Schwellwert_Alarm = 500; - - public void onCreate(Activity MainActivity, Logger MainLogger) { - MainActivityForClass = MainActivity; - logger = MainLogger; //Class uses the same logger as the MainActivity - logger.log(this.getClass().getSimpleName() + ".onCreate"); - - if (!istZugriffAufMikrofonErlaubt()) { - zugriffAufMikrofonAnfordern(); - } - } - - public void onResume() { - logger.log(this.getClass().getSimpleName() + ".onResume"); - if (!istZugriffAufMikrofonErlaubt()) { - zugriffAufMikrofonAnfordern(); - } - if (istZugriffAufMikrofonErlaubt()) { - aufnahmeTask = new AufnahmeTask(); - aufnahmeTask.execute(); - } - } - - public void onPause() { - logger.log(this.getClass().getSimpleName() + ".onPause"); - if(aufnahmeTask!=null) { - aufnahmeTask.cancel(true); - // aufnahmeTask = null; // if aufnahmeTask = null, break in for loop would not work (Nullpointer Exception) - } - } - - private boolean istZugriffAufMikrofonErlaubt() { - if (ContextCompat.checkSelfPermission(MainActivityForClass, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { - logger.log("Zugriff auf Mikrofon ist verboten."); - return false; - } else { - logger.log("Zugriff auf Mikrofon ist erlaubt."); - return true; - } - } - private void zugriffAufMikrofonAnfordern() { - ActivityCompat.requestPermissions(MainActivityForClass, new String[]{Manifest.permission.RECORD_AUDIO}, RECHTEANFORDERUNG_MIKROFON); - } - - class AufnahmeTask extends AsyncTask { - private AudioRecord recorder; - private final int sampleRateInHz = 44100; - private final int channelConfig = AudioFormat.CHANNEL_IN_MONO; - private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT; - private int minPufferGroesseInBytes; - private int pufferGroesseInBytes; - private RingPuffer ringPuffer = new RingPuffer(10); - - AufnahmeTask() { - minPufferGroesseInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); - pufferGroesseInBytes = minPufferGroesseInBytes * 2; - recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, pufferGroesseInBytes); - -// textViewMinPufferGroesseInBytes.setText("" + minPufferGroesseInBytes); -// textViewPufferGroesseInBytes.setText("" + pufferGroesseInBytes); -// textViewAbtastrate.setText("" + recorder.getSampleRate()); -// textViewAnzahlKanaele.setText("" + recorder.getChannelCount()); - - logger.log("Puffergroeße: "+ minPufferGroesseInBytes + " " + pufferGroesseInBytes); - logger.log("Recorder (SR, CH): "+ recorder.getSampleRate() + " " + recorder.getChannelCount()); - - int anzahlBytesProAbtastwert; - String s; - switch (recorder.getAudioFormat()) { - case AudioFormat.ENCODING_PCM_8BIT: - s = "8 Bit PCM "; - anzahlBytesProAbtastwert = 1; - break; - case AudioFormat.ENCODING_PCM_16BIT: - s = "16 Bit PCM"; - anzahlBytesProAbtastwert = 2; - break; - case AudioFormat.ENCODING_PCM_FLOAT: - s = "Float PCM"; - anzahlBytesProAbtastwert = 4; - break; - default: - throw new IllegalArgumentException(); - } -// textViewAudioFormat.setText(s); - - switch (recorder.getChannelConfiguration()) { - case AudioFormat.CHANNEL_IN_MONO: - s = "Mono"; - break; - case AudioFormat.CHANNEL_IN_STEREO: - s = "Stereo"; - anzahlBytesProAbtastwert *= 2; - break; - case AudioFormat.CHANNEL_INVALID: - s = "ungültig"; - break; - default: - throw new IllegalArgumentException(); - } -// textViewKanalKonfiguration.setText(s); - logger.log("Konfiguration: "+ s); - - int pufferGroesseInAnzahlAbtastwerten = pufferGroesseInBytes / anzahlBytesProAbtastwert; - int pufferGroesseInMillisekunden = 1000 * pufferGroesseInAnzahlAbtastwerten / recorder.getSampleRate(); - -// textViewPufferGroesseInAnzahlAbtastwerte.setText("" + pufferGroesseInAnzahlAbtastwerten); -// textViewPufferGroesseInMillisekunden.setText("" + pufferGroesseInMillisekunden); - } - - @Override - protected Void doInBackground(Long... params) { - recorder.startRecording(); - short[] puffer = new short[pufferGroesseInBytes / 2]; - long lastTime = System.currentTimeMillis(); - float verarbeitungsrate = 0; - final int maxZaehlerZeitMessung = 10; - int zaehlerZeitMessung = 0; - int anzahlVerarbeitet = 0; - GleitenderMittelwert gleitenderMittelwert = new GleitenderMittelwert(0.3f); - - for (; ; ) { - if (aufnahmeTask.isCancelled()) { - break; - } else { - int n = recorder.read(puffer, 0, puffer.length); - Verarbeitungsergebnis ergebnis = verarbeiten(puffer, n); - anzahlVerarbeitet += n; - - zaehlerZeitMessung++; - if (zaehlerZeitMessung == maxZaehlerZeitMessung) { - long time = System.currentTimeMillis(); - long deltaTime = time - lastTime; - verarbeitungsrate = 1000.0f * anzahlVerarbeitet / deltaTime; - verarbeitungsrate = gleitenderMittelwert.mittel(verarbeitungsrate); - zaehlerZeitMessung = 0; - anzahlVerarbeitet = 0; - lastTime = time; - } - - float noiseLevel = gleitenderMittelwert.MittelwertPuffer(puffer); - - // logger.log("Noise Level:" + noiseLevel); - ergebnis.noiseLevel = noiseLevel; - ergebnis.verarbeitungsrate = (int) verarbeitungsrate; - publishProgress(ergebnis); - - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - recorder.release(); - return null; - } - - private Verarbeitungsergebnis verarbeiten(short[] daten, int n) { - String status; - short maxAmp = -1; - if (n == AudioRecord.ERROR_INVALID_OPERATION) { - status = "ERROR_INVALID_OPERATION"; - } else if (n == AudioRecord.ERROR_BAD_VALUE) { - status = "ERROR_BAD_VALUE"; - } else { - status = "OK"; - short max = 0; - for (int i = 0; i < n; i++) { - if (daten[i] > max) { - max = daten[i]; - } - } - - ringPuffer.hinzufuegen(max); - maxAmp = ringPuffer.maximum(); - } - - return new Verarbeitungsergebnis(status, maxAmp, 0, 0); - } - - @Override - protected void onProgressUpdate(Verarbeitungsergebnis... progress) { - super.onProgressUpdate(progress); -// textViewMaxAmp.setText("" + progress[0].maxAmp); -// textViewVerarbeitungsrate.setText("" + progress[0].verarbeitungsrate); - logger.overwriteLastlog("VR, Max, NL:" + progress[0].verarbeitungsrate + ", " + progress[0].maxAmp - + ", " + progress[0].noiseLevel); - - if (progress[0].maxAmp >= Schwellwert_Alarm) { - Alarm = true; - } - } - } - - class Verarbeitungsergebnis { - String status; - short maxAmp; - int verarbeitungsrate; - float noiseLevel; - - Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate, float noiseLevel) { - this.status = status; - this.maxAmp = maxAmp; - this.verarbeitungsrate = verarbeitungsrate; - this.noiseLevel = noiseLevel; - } - } - - class RingPuffer { - private short[] puffer; - private final int laenge; - private int anzahlEnthaltenerDaten; - private int position; - - public RingPuffer(int n) { - laenge = n; - anzahlEnthaltenerDaten = 0; - position = 0; - puffer = new short[laenge]; - } - - public void hinzufuegen(short wert) { - puffer[position] = wert; - position++; - if (position >= laenge) { - position = 0; - } - if (anzahlEnthaltenerDaten < laenge) { - anzahlEnthaltenerDaten++; - } - } - - public void hinzufuegen(short[] daten) { - for (short d : daten) { - puffer[position] = d; - position++; - if (position >= laenge) { - position = 0; - } - } - if (anzahlEnthaltenerDaten < laenge) { - anzahlEnthaltenerDaten += daten.length; - if (anzahlEnthaltenerDaten >= laenge) { - anzahlEnthaltenerDaten = laenge; - } - } - } - - public short maximum() { - short max = 0; - for (int i = 0; i < anzahlEnthaltenerDaten; i++) { - if (puffer[i] > max) { - max = puffer[i]; - } - } - return max; - } - - public float mittelwert() { - float summe = 0; - for (int i = 0; i < anzahlEnthaltenerDaten; i++) { - summe += puffer[i]; - } - return summe / anzahlEnthaltenerDaten; - } - } - - class GleitenderMittelwert { - private final float wichtungNeuerWert; - private final float wichtungAlterWert; - private float mittelwert = 0; - private boolean istMittelwertGesetzt = false; - - GleitenderMittelwert(float wichtungNeuerWert) { - this.wichtungNeuerWert = wichtungNeuerWert; - this.wichtungAlterWert = 1 - this.wichtungNeuerWert; - } - - float MittelwertPuffer(short[] puffer) { - - for (int i = 0; i < puffer.length; i++) { - mittelwert = Math.abs(puffer[i]); - } - mittelwert = mittelwert/puffer.length; - - return mittelwert; - } - - float mittel(float wert) { - if (istMittelwertGesetzt) { - mittelwert = wert * wichtungNeuerWert + mittelwert * wichtungAlterWert; - } else { - mittelwert = wert; - istMittelwertGesetzt = true; - } - return mittelwert; - } - } -} diff --git a/app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/Complex.java b/app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/Complex.java new file mode 100644 index 0000000..26a3c28 --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/Complex.java @@ -0,0 +1,148 @@ +package com.example.ueberwachungssystem.Signalverarbeitung; + +import java.util.Objects; + +public class Complex { + private final double re; // the real part + private final double im; // the imaginary part + + // create a new object with the given real and imaginary parts + public Complex(double real, double imag) { + re = real; + im = imag; + } + + // return a string representation of the invoking com.example.ueberwachungssystem.Signalverarbeitung.Complex object + public String toString() { + if (im == 0) return re + ""; + if (re == 0) return im + "i"; + if (im < 0) return re + " - " + (-im) + "i"; + return re + " + " + im + "i"; + } + + // return abs/modulus/magnitude + public double abs() { + return Math.hypot(re, im); + } + + // return angle/phase/argument, normalized to be between -pi and pi + public double phase() { + return Math.atan2(im, re); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is (this + b) + public Complex plus(Complex b) { + Complex a = this; // invoking object + double real = a.re + b.re; + double imag = a.im + b.im; + return new Complex(real, imag); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is (this - b) + public Complex minus(Complex b) { + Complex a = this; + double real = a.re - b.re; + double imag = a.im - b.im; + return new Complex(real, imag); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is (this * b) + public Complex times(Complex b) { + Complex a = this; + double real = a.re * b.re - a.im * b.im; + double imag = a.re * b.im + a.im * b.re; + return new Complex(real, imag); + } + + // return a new object whose value is (this * alpha) + public Complex scale(double alpha) { + return new Complex(alpha * re, alpha * im); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is the conjugate of this + public Complex conjugate() { + return new Complex(re, -im); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is the reciprocal of this + public Complex reciprocal() { + double scale = re * re + im * im; + return new Complex(re / scale, -im / scale); + } + + // return the real or imaginary part + public double re() { + return re; + } + + public double im() { + return im; + } + + // return a / b + public Complex divides(Complex b) { + Complex a = this; + return a.times(b.reciprocal()); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is the complex exponential of this + public Complex exp() { + return new Complex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im)); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is the complex sine of this + public Complex sin() { + return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im)); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is the complex cosine of this + public Complex cos() { + return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im)); + } + + // return a new com.example.ueberwachungssystem.Signalverarbeitung.Complex object whose value is the complex tangent of this + public Complex tan() { + return sin().divides(cos()); + } + + // a static version of plus + public static Complex plus(Complex a, Complex b) { + double real = a.re + b.re; + double imag = a.im + b.im; + Complex sum = new Complex(real, imag); + return sum; + } + + // See Section 3.3. + public boolean equals(Object x) { + if (x == null) return false; + if (this.getClass() != x.getClass()) return false; + Complex that = (Complex) x; + return (this.re == that.re) && (this.im == that.im); + } + + // See Section 3.3. + public int hashCode() { + return Objects.hash(re, im); + } + + // sample client for testing + public static void main(String[] args) { + Complex a = new Complex(5.0, 6.0); + Complex b = new Complex(-3.0, 4.0); + + System.out.println("a = " + a); + System.out.println("b = " + b); + System.out.println("Re(a) = " + a.re()); + System.out.println("Im(a) = " + a.im()); + System.out.println("b + a = " + b.plus(a)); + System.out.println("a - b = " + a.minus(b)); + System.out.println("a * b = " + a.times(b)); + System.out.println("b * a = " + b.times(a)); + System.out.println("a / b = " + a.divides(b)); + System.out.println("(a / b) * b = " + a.divides(b).times(b)); + System.out.println("conj(a) = " + a.conjugate()); + System.out.println("|a| = " + a.abs()); + System.out.println("tan(a) = " + a.tan()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/FFT.java b/app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/FFT.java new file mode 100644 index 0000000..2543310 --- /dev/null +++ b/app/src/main/java/com/example/ueberwachungssystem/Signalverarbeitung/FFT.java @@ -0,0 +1,248 @@ +package com.example.ueberwachungssystem.Signalverarbeitung; +// Source: https://introcs.cs.princeton.edu/java/97data/FFT.java.html + +import android.util.Log; + +/****************************************************************************** + * Compilation: javac FFT.java + * Execution: java FFT n + * Dependencies: com.example.ueberwachungssystem.Signalverarbeitung.Complex.java + * + * Compute the FFT and inverse FFT of a length n complex sequence + * using the radix 2 Cooley-Tukey algorithm. + * Bare bones implementation that runs in O(n log n) time and O(n) + * space. Our goal is to optimize the clarity of the code, rather + * than performance. + * + * This implementation uses the primitive root of unity w = e^(-2 pi i / n). + * Some resources use w = e^(2 pi i / n). + * + * Reference: https://www.cs.princeton.edu/~wayne/kleinberg-tardos/pdf/05DivideAndConquerII.pdf + * + * Limitations + * ----------- + * - assumes n is a power of 2 + * + * - not the most memory efficient algorithm (because it uses + * an object type for representing complex numbers and because + * it re-allocates memory for the subarray, instead of doing + * in-place or reusing a single temporary array) + * + * For an in-place radix 2 Cooley-Tukey FFT, see + * https://introcs.cs.princeton.edu/java/97data/InplaceFFT.java.html + * + ******************************************************************************/ + +public class FFT { + + // compute the FFT of x[], assuming its length n is a power of 2 + public static Complex[] fft(Complex[] x) { + int n = x.length; + + // base case + if (n == 1) return new Complex[]{x[0]}; + + // radix 2 Cooley-Tukey FFT + if (n % 2 != 0) { + throw new IllegalArgumentException("n is not a power of 2"); + } + + // compute FFT of even terms + Complex[] even = new Complex[n / 2]; + for (int k = 0; k < n / 2; k++) { + even[k] = x[2 * k]; + } + Complex[] evenFFT = fft(even); + + // compute FFT of odd terms + Complex[] odd = even; // reuse the array (to avoid n log n space) + for (int k = 0; k < n / 2; k++) { + odd[k] = x[2 * k + 1]; + } + Complex[] oddFFT = fft(odd); + + // combine + Complex[] y = new Complex[n]; + for (int k = 0; k < n / 2; k++) { + double kth = -2 * k * Math.PI / n; + Complex wk = new Complex(Math.cos(kth), Math.sin(kth)); + y[k] = evenFFT[k].plus(wk.times(oddFFT[k])); + y[k + n / 2] = evenFFT[k].minus(wk.times(oddFFT[k])); + } + return y; + } + + + // compute the inverse FFT of x[], assuming its length n is a power of 2 + public static Complex[] ifft(Complex[] x) { + int n = x.length; + Complex[] y = new Complex[n]; + + // take conjugate + for (int i = 0; i < n; i++) { + y[i] = x[i].conjugate(); + } + + // compute forward FFT + y = fft(y); + + // take conjugate again + for (int i = 0; i < n; i++) { + y[i] = y[i].conjugate(); + } + + // divide by n + for (int i = 0; i < n; i++) { + y[i] = y[i].scale(1.0 / n); + } + + return y; + + } + + // compute the circular convolution of x and y + public static Complex[] cconvolve(Complex[] x, Complex[] y) { + + // should probably pad x and y with 0s so that they have same length + // and are powers of 2 + if (x.length != y.length) { + throw new IllegalArgumentException("Dimensions don't agree"); + } + + int n = x.length; + + // compute FFT of each sequence + Complex[] a = fft(x); + Complex[] b = fft(y); + + // point-wise multiply + Complex[] c = new Complex[n]; + for (int i = 0; i < n; i++) { + c[i] = a[i].times(b[i]); + } + + // compute inverse FFT + return ifft(c); + } + + + // compute the linear convolution of x and y + public static Complex[] convolve(Complex[] x, Complex[] y) { + Complex ZERO = new Complex(0, 0); + + Complex[] a = new Complex[2 * x.length]; + for (int i = 0; i < x.length; i++) a[i] = x[i]; + for (int i = x.length; i < 2 * x.length; i++) a[i] = ZERO; + + Complex[] b = new Complex[2 * y.length]; + for (int i = 0; i < y.length; i++) b[i] = y[i]; + for (int i = y.length; i < 2 * y.length; i++) b[i] = ZERO; + + return cconvolve(a, b); + } + + // compute the DFT of x[] via brute force (n^2 time) + public static Complex[] dft(Complex[] x) { + int n = x.length; + Complex ZERO = new Complex(0, 0); + Complex[] y = new Complex[n]; + for (int k = 0; k < n; k++) { + y[k] = ZERO; + for (int j = 0; j < n; j++) { + int power = (k * j) % n; + double kth = -2 * power * Math.PI / n; + Complex wkj = new Complex(Math.cos(kth), Math.sin(kth)); + y[k] = y[k].plus(x[j].times(wkj)); + } + } + return y; + } + + // display an array of com.example.ueberwachungssystem.Signalverarbeitung.Complex numbers to standard output + public static void show(Complex[] x, String title) { + System.out.println(title); + System.out.println("-------------------"); + for (int i = 0; i < x.length; i++) { + System.out.println(x[i]); + } + System.out.println(); + } + + /*************************************************************************** + * Test client and sample execution + * + * % java FFT 4 + * x + * ------------------- + * -0.03480425839330703 + * 0.07910192950176387 + * 0.7233322451735928 + * 0.1659819820667019 + * + * y = fft(x) + * ------------------- + * 0.9336118983487516 + * -0.7581365035668999 + 0.08688005256493803i + * 0.44344407521182005 + * -0.7581365035668999 - 0.08688005256493803i + * + * z = ifft(y) + * ------------------- + * -0.03480425839330703 + * 0.07910192950176387 + 2.6599344570851287E-18i + * 0.7233322451735928 + * 0.1659819820667019 - 2.6599344570851287E-18i + * + * c = cconvolve(x, x) + * ------------------- + * 0.5506798633981853 + * 0.23461407150576394 - 4.033186818023279E-18i + * -0.016542951108772352 + * 0.10288019294318276 + 4.033186818023279E-18i + * + * d = convolve(x, x) + * ------------------- + * 0.001211336402308083 - 3.122502256758253E-17i + * -0.005506167987577068 - 5.058885073636224E-17i + * -0.044092969479563274 + 2.1934338938072244E-18i + * 0.10288019294318276 - 3.6147323062478115E-17i + * 0.5494685269958772 + 3.122502256758253E-17i + * 0.240120239493341 + 4.655566391833896E-17i + * 0.02755001837079092 - 2.1934338938072244E-18i + * 4.01805098805014E-17i + * + ***************************************************************************/ + + public static void main(String[] args) { + int n = Integer.parseInt(args[0]); + Complex[] x = new Complex[n]; + + // original data + for (int i = 0; i < n; i++) { + x[i] = new Complex(i, 0); + } + show(x, "x"); + + // FFT of original data + Complex[] y = fft(x); + show(y, "y = fft(x)"); + + // FFT of original data + Complex[] y2 = dft(x); + show(y2, "y2 = dft(x)"); + + // take inverse FFT + Complex[] z = ifft(y); + show(z, "z = ifft(y)"); + + // circular convolution of x with itself + Complex[] c = cconvolve(x, x); + show(c, "c = cconvolve(x, x)"); + + // linear convolution of x with itself + Complex[] d = convolve(x, x); + show(d, "d = convolve(x, x)"); + } +} + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bea580a..edd41b2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,18 +11,27 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Log" - app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/TglBtn_Mic" /> + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 3e927b1..92b9117 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,5 @@ android.useAndroidX=true # Enables namespacing of each library's R class so that its R class includes only the # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true \ No newline at end of file +android.nonTransitiveRClass=true +android.enableJetifier=true \ No newline at end of file From 2cff334056d53b94e538cde47707957b588a79bc Mon Sep 17 00:00:00 2001 From: Leon Market Date: Sat, 17 Jun 2023 19:00:44 +0200 Subject: [PATCH 10/23] Added detection report --- .../ueberwachungssystem/Accelerometer.java | 175 ++++++++++-------- .../Beschleunigungssensor.java | 3 +- .../ueberwachungssystem/MainActivity.java | 51 +++-- app/src/main/res/layout/activity_main.xml | 30 ++- 4 files changed, 159 insertions(+), 100 deletions(-) diff --git a/app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java b/app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java index f3c92f4..a8731bc 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java +++ b/app/src/main/java/com/example/ueberwachungssystem/Accelerometer.java @@ -1,6 +1,6 @@ package com.example.ueberwachungssystem; - +import static java.lang.Math.sqrt; import android.content.Context; import android.hardware.Sensor; @@ -11,114 +11,129 @@ import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; - -public class Accelerometer implements Runnable, SensorEventListener { +public class Accelerometer extends Detector implements SensorEventListener { Logger logger; + private volatile boolean running = false; public SensorManager sensorManager; - private int sensorType = Sensor.TYPE_ACCELEROMETER; + private static final int sensorType = Sensor.TYPE_LINEAR_ACCELERATION; private Sensor accelerometer; private Context context; - private Thread thread; - private String threadName = "Accelerometer Thread"; - double[] gravity = new double[3]; - double[] linear_acceleration = new double[3]; - private TextView textViewWorkerThread; - // In constructor pass Context from MainActivity in Accelerometer class - public Accelerometer(Context context, TextView textViewWorkerThread){ + private String threadName = "Accelerometer Thread"; + boolean alarm = false; + //Preallocate memory for the data of each axis of the acceleration sensor + float x; + float y; + float z; + float betrag; //Betrag aller drei Achsen sqrt(x*x + y*y + z*z) + private TextView textViewWorkerThread; + private AppCompatActivity activity; + private DetectionReport detectionReport; + + + // In constructor pass Activity, Context and TextView from MainActivity in Accelerometer class + public Accelerometer(Context context, Logger mainLogger, TextView textViewWorkerThread){ + super(context); //von Detektor + logger = mainLogger; this.context = context; this.textViewWorkerThread = textViewWorkerThread; - } - // Passing Activity's instance as argument on worker thread - AppCompatActivity activity; - public Accelerometer(AppCompatActivity activity){ - this.activity = activity; + Logger logger = new Logger(this.getClass().getSimpleName(), textViewWorkerThread, ""); } - private void print (final String s){ - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - textViewWorkerThread.setText(s); - } - }); - } - - @Override - public void run() { - while (running) { - sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - if (sensorManager.getSensorList(sensorType).size() == 0) { - logger.log("Es gibt den gewünschten Sensor nicht"); - accelerometer = null; - } else { - accelerometer = sensorManager.getSensorList(sensorType).get(0); - } + public void getSensor(){ + sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); + if(sensorManager.getSensorList(sensorType).size()==0) { + logger.log("Es gibt den gewünschten Sensor nicht"); + accelerometer = null; + } + else { + accelerometer = sensorManager.getSensorList(sensorType).get(0); + logger.log("Sensor gefunden"); } } - void start(){ - logger.log("Starting" + threadName); - running = true; - thread = new Thread(this); - thread.setName(threadName); - thread.start(); - logger.log("alright, " + threadName + " started!"); + + void start() { // register the sensor before using // - sensorManager.registerListener((SensorEventListener) context, accelerometer, SensorManager.SENSOR_DELAY_NORMAL); - logger.log("Accelerometer, du bist dran!"); + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); + logger.log("Accelerometer, start!"); } + void stop() { // unregister from the sensor to stop using it // - sensorManager.unregisterListener((SensorEventListener) context, accelerometer); - logger.log("Das reicht Accelerometer, komm zurück!"); - if (!running){ - logger.log(threadName + " not running."); - } else { - logger.log("Stopping " + threadName); - running = false; - while (true) { - try { - thread.join(); - logger.log("..." + threadName + " stopped"); - break; - } catch (InterruptedException e){ - e.printStackTrace(); - } - } - } + sensorManager.unregisterListener(this, accelerometer); + logger.log("Accelerometer unregistered!"); } + @Override public void onSensorChanged(SensorEvent event) { - // Highpass filter to filter out gravity influence - final double alpha = 0.8; + checkAlarm(event); + } - gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0]; - gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1]; - gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2]; - linear_acceleration[0] = event.values[0] - gravity[0]; + StringBuffer stringBuffer = new StringBuffer(); + public void checkAlarm (SensorEvent event) { + x = event.values[0]; + y = event.values[1]; + z = event.values[2]; + betrag = (float) sqrt(x*x + y*y + z*z); + double schwelle = 1.5; + //stringBuffer.append("\nBetrag =" + betrag); + //logger.log("Betrag" + betrag); - linear_acceleration[1] = event.values[1] - gravity[1]; - linear_acceleration[2] = event.values[2] - gravity[2]; - - String sb = "t=" + event.timestamp + - "\nx=" + event.values[0] + // Wert liegend: x = 0.04 - "\ny=" + event.values[1] + // Wert liegend: y = 0.44 - "\nz=" + event.values[2] + // Wert liegend: z = 9.90 = Erdbeschleunigung --> Wenn Ausrichtung unbekannt ist, müsste kalibrierung bei Start der Bewegungsüberwachung vorgenommen werden - "\nlin_x=" + linear_acceleration[0] + - "\nlin_x=" + linear_acceleration[1] + - "\nlin_x=" + linear_acceleration[2]; - - logger.clearLog(); - logger.log(sb); + if (!alarm) { + if (betrag > schwelle) { + stringBuffer.append("\n Betragswert über Schwelle, Detection Report wird gleich aufgerufen"); + //logger.log("Betragswert über Schwelle erkannt, Alarm wird gleich angeschaltet"); + alarm = true; + stringBuffer.append("\nAlarm = " + alarm); + detectionReport = new DetectionReport("Accelerometer1", "Bewegung", betrag); + stringBuffer.append("\nDetectionReport = " + detectionReport) + .append("\nAlarm an" + betrag + event.timestamp); + //logger.log("Alarm an"); + //logger.log("Betrag: " + betrag + event.timestamp); + logger.clearLog(); + logger.log(stringBuffer.toString()); + stringBuffer.delete(0, stringBuffer.length()); + } + } else { + if (betrag < schwelle) { + stringBuffer.append("\nAlarm noch an; Neuer Betragswert unter Schwellwert:" + betrag); + //logger.log("Alarm ist noch an; Neuer Betragswert unter Schwellwert: " + betrag); + alarm = false; + //logger.log("Alarm" + alarm); + //logger.log("Alarm wieder ausgeschaltet"); + stringBuffer.append("\nAlarm = " + alarm); + } else { + logger.log("Betragswert immer noch über Schwellwert: " + betrag + "; Alarm bleibt an."); + logger.log("Betragswert immer noch über Schwellwert: " + betrag + "; Alarm bleibt an."); + } + logger.clearLog(); + logger.log(stringBuffer.toString()); + stringBuffer.delete(0, stringBuffer.length()); + } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + @Override + public void startDetection() { + // entspricht void start() + if (accelerometer != null) { + sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); + logger.log("Sensor registriert"); + } + } + + @Override + public void stopDetection() { + // entspricht void stop() + sensorManager.unregisterListener(this, accelerometer); + logger.log("Vom Sensor abgemeldet"); } } \ No newline at end of file diff --git a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java index d5fc8e2..64b41fa 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java +++ b/app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java @@ -54,6 +54,7 @@ public class Beschleunigungssensor extends AppCompatActivity implements SensorEv else { sensor = sensorManager.getSensorList(sensorType).get(0); + logger.log("Accelerometer gefunden."); } } @@ -89,7 +90,7 @@ public class Beschleunigungssensor extends AppCompatActivity implements SensorEv y = event.values[1]; z = event.values[2]; betrag = sqrt(x*x + y*y + z*z); - double schwelle = 1.5; + double schwelle = 0.05; if (!alarm) { if (betrag > schwelle) { diff --git a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java index f3ba22b..de11afe 100644 --- a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java +++ b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java @@ -5,8 +5,11 @@ import static java.lang.Boolean.TRUE; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; +import android.hardware.SensorEvent; import android.os.Bundle; +import android.text.method.ScrollingMovementMethod; import android.view.View; +import android.widget.Button; import android.widget.TextView; import android.widget.ToggleButton; @@ -14,14 +17,17 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe private Logger logger; private Context context; - //private Accelerometer beschleunigungssensor; - private ThreadDemo threadDemo; + private Accelerometer beschleunigungssensor; + //private ThreadDemo threadDemo; private TextView textViewLog; + private Button button1; private TextView textViewWorkerThread; + SensorEvent event; - //private WorkerUsingThread workerUsingThread; ToggleButton toggleButton1; + boolean currentAlarm; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -35,8 +41,16 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe toggleButton1 = (ToggleButton) findViewById(R.id.toggleButton1); //togglebutton um Thread zu steuern toggleButton1.setOnClickListener(this); textViewWorkerThread = (TextView) findViewById(R.id.textViewWorkerThread); //TextView um Thread zu überwachen - // beschleunigungssensor = new Accelerometer(this); - threadDemo = new ThreadDemo(this, textViewWorkerThread); + textViewWorkerThread.setMovementMethod(new ScrollingMovementMethod()); + + //Button to clear Log while Debugging + button1 = (Button) findViewById(R.id.button1); + button1.setOnClickListener(this); + + //Accelerometer Setup + beschleunigungssensor = new Accelerometer(this, logger, textViewWorkerThread); + beschleunigungssensor.getSensor(); + logger.log("onCreate"); } @@ -48,21 +62,30 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe protected void onPause() { super.onPause(); //beschleunigungssensor.stop(); - threadDemo.stop(); + //threadDemo.stop(); } - @Override public void onClick(View v) { logger.log("toggleButton1 is clicked"); - if (toggleButton1.isChecked()) { - logger.log("ToggleButton is ON"); - //beschleunigungssensor.start(); - threadDemo.start(); - } else { - logger.log("ToggleButton is OFF"); - threadDemo.stop(); + if(v == toggleButton1) { + if (toggleButton1.isChecked()) { + logger.log("ToggleButton is ON"); + //beschleunigungssensor.start(); + beschleunigungssensor.startDetection(); + logger.log("Detection started"); + //logger.log(stringBuffer.toString()); + + } else { + logger.log("ToggleButton is OFF"); + //threadDemo.stop(); + //beschleunigungssensor.stop(); + beschleunigungssensor.stopDetection(); + logger.log("Detection stopped"); + } + } else if (v == button1) { + logger.clearLog(); } } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0726f26..c3db55a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,17 +4,23 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivityBackup"> + tools:context=".MainActivity"> + app:layout_constraintTop_toBottomOf="@+id/textViewWorkerThread" + app:layout_constraintVertical_bias="0.0" /> +